[evolution/wip/webkit2] Be able to use multiple WebKit editors independently



commit 6c609d23b3f1792cc2fdd802ba4a2866d60ad187
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jun 29 12:27:32 2016 +0200

    Be able to use multiple WebKit editors independently
    
    + some code reorganization and rename (mostly prefixed) in the webkit-editor extension

 e-util/e-util-enums.h                              |   24 +
 modules/webkit-editor/e-webkit-editor.c            |  315 +-
 modules/webkit-editor/web-extension/Makefile.am    |   54 +-
 ...-dom-functions.c => e-composer-dom-functions.c} |  239 +-
 ...-dom-functions.h => e-composer-dom-functions.h} |   31 +-
 .../web-extension/e-dialogs-dom-functions.c        | 1319 ++
 .../web-extension/e-dialogs-dom-functions.h        |  132 +
 .../web-extension/e-editor-dom-functions.c         |17578 ++++++++++++++++++++
 .../web-extension/e-editor-dom-functions.h         |  374 +
 .../webkit-editor/web-extension/e-editor-page.c    |  960 ++
 .../webkit-editor/web-extension/e-editor-page.h    |  203 +
 ...redo-manager.c => e-editor-undo-redo-manager.c} |  908 +-
 .../web-extension/e-editor-undo-redo-manager.h     |  175 +
 ...ension-main.c => e-editor-web-extension-main.c} |   14 +-
 ...-functions.h => e-editor-web-extension-names.h} |   23 +-
 ...or-web-extension.c => e-editor-web-extension.c} | 2024 +--
 .../web-extension/e-editor-web-extension.h         |   82 +
 .../e-html-editor-actions-dom-functions.c          |  416 -
 .../e-html-editor-actions-dom-functions.h          |   64 -
 .../e-html-editor-cell-dialog-dom-functions.c      |  421 -
 .../e-html-editor-cell-dialog-dom-functions.h      |   79 -
 .../web-extension/e-html-editor-history-event.h    |  100 -
 .../e-html-editor-hrule-dialog-dom-functions.c     |  124 -
 .../e-html-editor-hrule-dialog-dom-functions.h     |   39 -
 .../e-html-editor-image-dialog-dom-functions.c     |  147 -
 .../e-html-editor-image-dialog-dom-functions.h     |   46 -
 .../e-html-editor-link-dialog-dom-functions.c      |  164 -
 .../e-html-editor-link-dialog-dom-functions.h      |   37 -
 .../e-html-editor-page-dialog-dom-functions.c      |   72 -
 .../e-html-editor-page-dialog-dom-functions.h      |   38 -
 .../e-html-editor-selection-dom-functions.c        | 6686 --------
 .../e-html-editor-selection-dom-functions.h        |  281 -
 ...-html-editor-spell-check-dialog-dom-functions.c |  190 -
 ...-html-editor-spell-check-dialog-dom-functions.h |   40 -
 .../e-html-editor-table-dialog-dom-functions.c     |  314 -
 .../e-html-editor-table-dialog-dom-functions.h     |   51 -
 .../e-html-editor-test-dom-functions.c             |   69 -
 .../e-html-editor-test-dom-functions.h             |   26 -
 .../e-html-editor-undo-redo-manager.h              |  111 -
 .../e-html-editor-view-dom-functions.c             |10267 ------------
 .../e-html-editor-view-dom-functions.h             |  229 -
 .../e-html-editor-web-extension-names.h            |   26 -
 .../web-extension/e-html-editor-web-extension.h    |  246 -
 .../web-extension/e-msg-composer-dom-functions.c   |   79 -
 44 files changed, 22199 insertions(+), 22618 deletions(-)
---
diff --git a/e-util/e-util-enums.h b/e-util/e-util-enums.h
index 35002a7..55a6960 100644
--- a/e-util/e-util-enums.h
+++ b/e-util/e-util-enums.h
@@ -227,6 +227,30 @@ typedef enum {
 } EContentEditorNodeFlags;
 
 /**
+ * EContentEditorStyleFlags:
+ * @E_CONTENT_EDITOR_STYLE_NONE: None from the below.
+ * @E_CONTENT_EDITOR_STYLE_IS_BOLD:
+ * @E_CONTENT_EDITOR_STYLE_IS_ITALIC:
+ * @E_CONTENT_EDITOR_STYLE_IS_UNDERLINE:
+ * @E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH:
+ * @E_CONTENT_EDITOR_STYLE_IS_MONOSPACE:
+ * @E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT:
+ * @E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT:
+ *
+ * Since: 3.22
+ **/
+typedef enum {
+       E_CONTENT_EDITOR_STYLE_NONE             = 0,
+       E_CONTENT_EDITOR_STYLE_IS_BOLD          = 1 << 0,
+       E_CONTENT_EDITOR_STYLE_IS_ITALIC        = 1 << 1,
+       E_CONTENT_EDITOR_STYLE_IS_UNDERLINE     = 1 << 2,
+       E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH = 1 << 3,
+       E_CONTENT_EDITOR_STYLE_IS_MONOSPACE     = 1 << 4,
+       E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT     = 1 << 5,
+       E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT   = 1 << 6
+} EContentEditorStyleFlags;
+
+/**
  * EContentEditorBlockFormat:
  * @E_CONTENT_EDITOR_BLOCK_FORMAT_NONE:
  * @E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH:
diff --git a/modules/webkit-editor/e-webkit-editor.c b/modules/webkit-editor/e-webkit-editor.c
index 8af3259..19865a8 100644
--- a/modules/webkit-editor/e-webkit-editor.c
+++ b/modules/webkit-editor/e-webkit-editor.c
@@ -20,7 +20,7 @@
 
 #include "e-webkit-editor.h"
 
-#include "web-extension/e-html-editor-web-extension-names.h"
+#include "web-extension/e-editor-web-extension-names.h"
 
 #include <e-util/e-util.h>
 #include <string.h>
@@ -86,14 +86,8 @@ struct _EWebKitEditorPrivate {
        gboolean copy_cut_actions_triggered;
        gboolean pasting_primary_clipboard;
 
-       gboolean is_bold;
-       gboolean is_italic;
-       gboolean is_underline;
-       gboolean is_monospaced;
-       gboolean is_strikethrough;
+       guint32 style_flags;
        gboolean is_indented;
-       gboolean is_superscript;
-       gboolean is_subscript;
 
        GdkRGBA *background_color;
        GdkRGBA *font_color;
@@ -298,7 +292,14 @@ web_extension_content_changed_cb (GDBusConnection *connection,
        if (g_strcmp0 (signal_name, "ContentChanged") != 0)
                return;
 
-       webkit_editor_set_changed (wk_editor, TRUE);
+       if (parameters) {
+               guint64 page_id = 0;
+
+               g_variant_get (parameters, "(t)", &page_id);
+
+               if (page_id == webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor)))
+                       webkit_editor_set_changed (wk_editor, TRUE);
+       }
 }
 
 static void
@@ -310,7 +311,10 @@ web_extension_selection_changed_cb (GDBusConnection *connection,
                                     GVariant *parameters,
                                     EWebKitEditor *wk_editor)
 {
+       guint64 page_id = 0;
        gchar *font_color = NULL;
+       guint32 alignment, block_format, style_flags, font_size;
+       gboolean is_indented;
 
        if (g_strcmp0 (signal_name, "SelectionChanged") != 0)
                return;
@@ -318,6 +322,22 @@ web_extension_selection_changed_cb (GDBusConnection *connection,
        if (!parameters)
                return;
 
+       g_variant_get (
+               parameters,
+               "(tiibiis)",
+               &page_id,
+               &alignment,
+               &block_format,
+               &is_indented,
+               &style_flags,
+               &font_size,
+               &font_color);
+
+       if (page_id != webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor))) {
+               g_free (font_color);
+               return;
+       }
+
        webkit_web_view_can_execute_editing_command (
                WEBKIT_WEB_VIEW (wk_editor),
                WEBKIT_EDITING_COMMAND_COPY,
@@ -341,23 +361,11 @@ web_extension_selection_changed_cb (GDBusConnection *connection,
 
        g_object_freeze_notify (G_OBJECT (wk_editor));
 
-       g_variant_get (
-               parameters,
-               "(iibbbbbbbbbis)",
-               &wk_editor->priv->alignment,
-               &wk_editor->priv->block_format,
-               &wk_editor->priv->is_indented,
-               &wk_editor->priv->is_bold,
-               &wk_editor->priv->is_italic,
-               &wk_editor->priv->is_underline,
-               &wk_editor->priv->is_strikethrough,
-               &wk_editor->priv->is_monospaced,
-               &wk_editor->priv->is_subscript,
-               &wk_editor->priv->is_superscript,
-               &wk_editor->priv->is_underline,
-               &wk_editor->priv->font_size,
-               &font_color);
-
+       wk_editor->priv->alignment = alignment;
+       wk_editor->priv->block_format = block_format;
+       wk_editor->priv->is_indented = is_indented;
+       wk_editor->priv->style_flags = style_flags;
+       wk_editor->priv->font_size = font_size;
 
        if (wk_editor->priv->html_mode) {
                GdkRGBA color;
@@ -468,9 +476,9 @@ web_extension_proxy_created_cb (GDBusProxy *proxy,
                        g_dbus_connection_signal_subscribe (
                                g_dbus_proxy_get_connection (wk_editor->priv->web_extension),
                                g_dbus_proxy_get_name (wk_editor->priv->web_extension),
-                               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
                                "SelectionChanged",
-                               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
                                NULL,
                                G_DBUS_SIGNAL_FLAGS_NONE,
                                (GDBusSignalCallback) web_extension_selection_changed_cb,
@@ -483,9 +491,9 @@ web_extension_proxy_created_cb (GDBusProxy *proxy,
                        g_dbus_connection_signal_subscribe (
                                g_dbus_proxy_get_connection (wk_editor->priv->web_extension),
                                g_dbus_proxy_get_name (wk_editor->priv->web_extension),
-                               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
                                "ContentChanged",
-                               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
                                NULL,
                                G_DBUS_SIGNAL_FLAGS_NONE,
                                (GDBusSignalCallback) web_extension_content_changed_cb,
@@ -498,9 +506,9 @@ web_extension_proxy_created_cb (GDBusProxy *proxy,
                        g_dbus_connection_signal_subscribe (
                                g_dbus_proxy_get_connection (wk_editor->priv->web_extension),
                                g_dbus_proxy_get_name (wk_editor->priv->web_extension),
-                               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
                                "UndoRedoStateChanged",
-                               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
                                NULL,
                                G_DBUS_SIGNAL_FLAGS_NONE,
                                (GDBusSignalCallback) web_extension_undo_redo_state_changed_cb,
@@ -531,8 +539,8 @@ web_extension_appeared_cb (GDBusConnection *connection,
                G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
                NULL,
                name,
-               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
-               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
                NULL,
                (GAsyncReadyCallback) web_extension_proxy_created_cb,
                wk_editor);
@@ -552,7 +560,7 @@ webkit_editor_watch_web_extension (EWebKitEditor *wk_editor)
        wk_editor->priv->web_extension_watch_name_id =
                g_bus_watch_name (
                        G_BUS_TYPE_SESSION,
-                       E_HTML_EDITOR_WEB_EXTENSION_SERVICE_NAME,
+                       E_WEBKIT_EDITOR_WEB_EXTENSION_SERVICE_NAME,
                        G_BUS_NAME_WATCHER_FLAGS_NONE,
                        (GBusNameAppearedCallback) web_extension_appeared_cb,
                        (GBusNameVanishedCallback) web_extension_vanished_cb,
@@ -2307,7 +2315,7 @@ webkit_editor_selection_save (EContentEditor *editor)
        wk_editor = E_WEBKIT_EDITOR (editor);
 
        webkit_editor_call_simple_extension_function (
-               wk_editor, "DOMSelectionSave");
+               wk_editor, "DOMSaveSelection");
 }
 
 static void
@@ -2318,7 +2326,7 @@ webkit_editor_selection_restore (EContentEditor *editor)
        wk_editor = E_WEBKIT_EDITOR (editor);
 
        webkit_editor_call_simple_extension_function (
-               wk_editor, "DOMSelectionRestore");
+               wk_editor, "DOMRestoreSelection");
 }
 
 static void
@@ -3400,164 +3408,28 @@ webkit_editor_get_font_size (EWebKitEditor *wk_editor)
 }
 
 static void
-webkit_editor_set_bold (EWebKitEditor *wk_editor,
-                        gboolean bold)
+webkit_editor_set_style_flag (EWebKitEditor *wk_editor,
+                             EContentEditorStyleFlags flag,
+                             gboolean do_set,
+                             const gchar *dom_function_name)
 {
        g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
 
-       if (wk_editor->priv->is_bold == bold)
+       if (((wk_editor->priv->style_flags & flag) != 0 ? 1 : 0) == (do_set ? 1 : 0))
                return;
 
-       wk_editor->priv->is_bold = bold;
+       wk_editor->priv->style_flags = (wk_editor->priv->style_flags & ~flag) | (do_set ? flag : 0);
 
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetBold", bold);
+       webkit_editor_set_format_boolean (wk_editor, dom_function_name, do_set);
 }
 
 static gboolean
-webkit_editor_is_bold (EWebKitEditor *wk_editor)
+webkit_editor_get_style_flag (EWebKitEditor *wk_editor,
+                             EContentEditorStyleFlags flag)
 {
        g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
 
-       return wk_editor->priv->is_bold;
-}
-
-static void
-webkit_editor_set_italic (EWebKitEditor *wk_editor,
-                          gboolean italic)
-{
-       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
-       if (wk_editor->priv->is_italic == italic)
-               return;
-
-       wk_editor->priv->is_italic = italic;
-
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetItalic", italic);
-}
-
-static gboolean
-webkit_editor_is_italic (EWebKitEditor *wk_editor)
-{
-       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
-
-       return wk_editor->priv->is_italic;
-}
-
-static void
-webkit_editor_set_monospaced (EWebKitEditor *wk_editor,
-                              gboolean monospaced)
-{
-       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
-       if (wk_editor->priv->is_monospaced == monospaced)
-               return;
-
-       wk_editor->priv->is_monospaced = monospaced;
-
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetMonospaced", monospaced);
-}
-
-static gboolean
-webkit_editor_is_monospaced (EWebKitEditor *wk_editor)
-{
-       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
-
-       return wk_editor->priv->is_monospaced;
-}
-
-static void
-webkit_editor_set_strikethrough (EWebKitEditor *wk_editor,
-                                 gboolean strikethrough)
-{
-       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
-       if (wk_editor->priv->is_strikethrough == strikethrough)
-               return;
-
-       wk_editor->priv->is_strikethrough = strikethrough;
-
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetStrikethrough", strikethrough);
-}
-
-static gboolean
-webkit_editor_is_strikethrough (EWebKitEditor *wk_editor)
-{
-       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
-
-       return wk_editor->priv->is_strikethrough;
-}
-
-static void
-webkit_editor_set_subscript (EWebKitEditor *wk_editor,
-                             gboolean subscript)
-{
-       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
-       if (wk_editor->priv->is_subscript == subscript)
-               return;
-
-       wk_editor->priv->is_subscript = subscript;
-
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetSubscript", subscript);
-}
-
-static gboolean
-webkit_editor_is_subscript (EWebKitEditor *wk_editor)
-{
-       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
-
-       return wk_editor->priv->is_subscript;
-}
-
-static void
-webkit_editor_set_superscript (EWebKitEditor *wk_editor,
-                               gboolean superscript)
-{
-       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
-       if (wk_editor->priv->is_superscript == superscript)
-               return;
-
-       wk_editor->priv->is_superscript = superscript;
-
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetSuperscript", superscript);
-}
-
-static gboolean
-webkit_editor_is_superscript (EWebKitEditor *wk_editor)
-{
-       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
-
-       return wk_editor->priv->is_superscript;
-}
-
-static void
-webkit_editor_set_underline (EWebKitEditor *wk_editor,
-                             gboolean underline)
-{
-       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
-
-       if (wk_editor->priv->is_underline == underline)
-               return;
-
-       wk_editor->priv->is_underline = underline;
-
-       webkit_editor_set_format_boolean (
-               wk_editor, "DOMSelectionSetUnderline", underline);
-}
-
-static gboolean
-webkit_editor_is_underline (EWebKitEditor *wk_editor)
-{
-       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), FALSE);
-
-       return wk_editor->priv->is_underline;
+       return (wk_editor->priv->style_flags & flag) != 0;
 }
 
 static void
@@ -5202,9 +5074,11 @@ webkit_editor_set_property (GObject *object,
                        return;
 
                case PROP_BOLD:
-                       webkit_editor_set_bold (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_BOLD,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetBold");
                        return;
 
                case PROP_FONT_COLOR:
@@ -5232,39 +5106,51 @@ webkit_editor_set_property (GObject *object,
                        return;
 
                case PROP_ITALIC:
-                       webkit_editor_set_italic (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_ITALIC,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetItalic");
                        return;
 
                case PROP_MONOSPACED:
-                       webkit_editor_set_monospaced (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_MONOSPACE,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetMonospaced");
                        return;
 
                case PROP_STRIKETHROUGH:
-                       webkit_editor_set_strikethrough (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetStrikethrough");
                        return;
 
                case PROP_SUBSCRIPT:
-                       webkit_editor_set_subscript (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetSubscript");
                        return;
 
                case PROP_SUPERSCRIPT:
-                       webkit_editor_set_superscript (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetSuperscript");
                        return;
 
                case PROP_UNDERLINE:
-                       webkit_editor_set_underline (
+                       webkit_editor_set_style_flag (
                                E_WEBKIT_EDITOR (object),
-                               g_value_get_boolean (value));
+                               E_CONTENT_EDITOR_STYLE_IS_UNDERLINE,
+                               g_value_get_boolean (value),
+                               "DOMSelectionSetUnderline");
                        return;
 
                case PROP_SPELL_CHECK_ENABLED:
@@ -5362,8 +5248,9 @@ webkit_editor_get_property (GObject *object,
                case PROP_BOLD:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_bold (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_BOLD));
                        return;
 
                case PROP_FONT_COLOR:
@@ -5397,43 +5284,49 @@ webkit_editor_get_property (GObject *object,
                case PROP_ITALIC:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_italic (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_ITALIC));
                        return;
 
                case PROP_MONOSPACED:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_monospaced (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_MONOSPACE));
                        return;
 
                case PROP_STRIKETHROUGH:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_strikethrough (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH));
                        return;
 
                case PROP_SUBSCRIPT:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_subscript (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT));
                        return;
 
                case PROP_SUPERSCRIPT:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_superscript (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT));
                        return;
 
                case PROP_UNDERLINE:
                        g_value_set_boolean (
                                value,
-                               webkit_editor_is_underline (
-                                       E_WEBKIT_EDITOR (object)));
+                               webkit_editor_get_style_flag (
+                                       E_WEBKIT_EDITOR (object),
+                                       E_CONTENT_EDITOR_STYLE_IS_UNDERLINE));
                        return;
 
                case PROP_SPELL_CHECK_ENABLED:
diff --git a/modules/webkit-editor/web-extension/Makefile.am b/modules/webkit-editor/web-extension/Makefile.am
index 340392b..f2a7b02 100644
--- a/modules/webkit-editor/web-extension/Makefile.am
+++ b/modules/webkit-editor/web-extension/Makefile.am
@@ -1,41 +1,23 @@
 webextensionswebkiteditor_LTLIBRARIES = libewebkiteditorwebextension.la
 
-libewebkiteditorwebextension_la_SOURCES =      \
-       e-composer-private-dom-functions.h              \
-       e-html-editor-actions-dom-functions.h           \
-       e-html-editor-cell-dialog-dom-functions.h       \
-       e-html-editor-history-event.h                   \
-       e-html-editor-hrule-dialog-dom-functions.h      \
-       e-html-editor-image-dialog-dom-functions.h      \
-       e-html-editor-link-dialog-dom-functions.h       \
-       e-html-editor-page-dialog-dom-functions.h       \
-       e-html-editor-selection-dom-functions.h         \
-       e-html-editor-spell-check-dialog-dom-functions.h\
-       e-html-editor-table-dialog-dom-functions.h      \
-       e-html-editor-test-dom-functions.h              \
-       e-html-editor-undo-redo-manager.h               \
-       e-html-editor-view-dom-functions.h              \
-       e-msg-composer-dom-functions.h                  \
-       e-composer-private-dom-functions.c              \
-       e-html-editor-actions-dom-functions.c           \
-       e-html-editor-cell-dialog-dom-functions.c       \
-       e-html-editor-hrule-dialog-dom-functions.c      \
-       e-html-editor-image-dialog-dom-functions.c      \
-       e-html-editor-link-dialog-dom-functions.c       \
-       e-html-editor-page-dialog-dom-functions.c       \
-       e-html-editor-selection-dom-functions.c         \
-       e-html-editor-spell-check-dialog-dom-functions.c\
-       e-html-editor-table-dialog-dom-functions.c      \
-       e-html-editor-test-dom-functions.c              \
-       e-html-editor-undo-redo-manager.c               \
-       e-html-editor-view-dom-functions.c              \
-       e-msg-composer-dom-functions.c                  \
-       e-html-editor-web-extension.c                   \
-       e-html-editor-web-extension.h                   \
-       e-html-editor-web-extension-names.h             \
-       e-html-editor-web-extension-main.c
+libewebkiteditorwebextension_la_SOURCES = \
+       e-composer-dom-functions.c      \
+       e-composer-dom-functions.h      \
+       e-dialogs-dom-functions.c       \
+       e-dialogs-dom-functions.h       \
+       e-editor-dom-functions.c        \
+       e-editor-dom-functions.h        \
+       e-editor-page.c                 \
+       e-editor-page.h                 \
+       e-editor-undo-redo-manager.c    \
+       e-editor-undo-redo-manager.h    \
+       e-editor-web-extension.c        \
+       e-editor-web-extension.h        \
+       e-editor-web-extension-main.c   \
+       e-editor-web-extension-names.h  \
+       $(NULL)
 
-libewebkiteditorwebextension_la_CPPFLAGS =     \
+libewebkiteditorwebextension_la_CPPFLAGS = \
        $(AM_CPPFLAGS)                                  \
        -I$(top_srcdir)                                 \
        -DEVOLUTION_IMAGESDIR=\""$(imagesdir)"\"        \
@@ -50,7 +32,7 @@ libewebkiteditorwebextension_la_LIBADD =              \
        $(GNOME_PLATFORM_LIBS)                          \
        $(WEB_EXTENSIONS_LIBS)
 
-libewebkiteditorwebextension_la_LDFLAGS =      \
+libewebkiteditorwebextension_la_LDFLAGS = \
        -module -avoid-version -no-undefined
 
 -include $(top_srcdir)/git.mk
diff --git a/modules/webkit-editor/web-extension/e-composer-private-dom-functions.c 
b/modules/webkit-editor/web-extension/e-composer-dom-functions.c
similarity index 81%
rename from modules/webkit-editor/web-extension/e-composer-private-dom-functions.c
rename to modules/webkit-editor/web-extension/e-composer-dom-functions.c
index 147840f..5b528d0 100644
--- a/modules/webkit-editor/web-extension/e-composer-private-dom-functions.c
+++ b/modules/webkit-editor/web-extension/e-composer-dom-functions.c
@@ -22,32 +22,34 @@
 
 #include <string.h>
 
-#include "e-composer-private-dom-functions.h"
-
-#include "e-html-editor-web-extension.h"
-#include "e-html-editor-selection-dom-functions.h"
-#include "e-html-editor-view-dom-functions.h"
-
 #define WEBKIT_DOM_USE_UNSTABLE_API
 #include <webkitdom/WebKitDOMDOMSelection.h>
 #include <webkitdom/WebKitDOMDOMWindowUnstable.h>
 #include <webkitdom/WebKitDOMHTMLElementUnstable.h>
-
-#include <web-extensions/e-dom-utils.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
 
 #include <camel/camel.h>
 
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-composer-dom-functions.h"
+
 gchar *
-dom_remove_signatures (WebKitDOMDocument *document,
-                       EHTMLEditorWebExtension *extension,
-                       gboolean top_signature)
+e_composer_dom_remove_signatures (EEditorPage *editor_page,
+                                 gboolean top_signature)
 {
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLCollection *signatures;
        gchar *ret_val = NULL;
        gulong length, ii;
-       WebKitDOMHTMLCollection *signatures;
 
-       g_return_val_if_fail (WEBKIT_DOM_IS_HTML_DOCUMENT (document), NULL);
-       g_return_val_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension), NULL);
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
 
        signatures = webkit_dom_document_get_elements_by_class_name_as_html_collection (
                document, "-x-evo-signature-wrapper");
@@ -95,12 +97,11 @@ dom_remove_signatures (WebKitDOMDocument *document,
 }
 
 static WebKitDOMElement *
-prepare_top_signature_spacer (WebKitDOMDocument *document,
-                              EHTMLEditorWebExtension *extension)
+prepare_top_signature_spacer (EEditorPage *editor_page)
 {
        WebKitDOMElement *element;
 
-       element = dom_prepare_paragraph (document, extension, FALSE);
+       element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
        webkit_dom_element_remove_attribute (element, "id");
        element_add_class (element, "-x-evo-top-signature-spacer");
 
@@ -147,9 +148,12 @@ start_typing_at_bottom (void)
 }
 
 static void
-move_caret_after_signature_inserted (WebKitDOMDocument *document,
-                                     EHTMLEditorWebExtension *extension)
+move_caret_after_signature_inserted (EEditorPage *editor_page)
 {
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *signature;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMNodeList *paragraphs;
        EContentEditorContentFlags flags;
        gboolean is_message_from_draft;
        gboolean is_message_from_edit_as_new;
@@ -157,11 +161,11 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
        gboolean top_signature;
        gboolean start_bottom;
        gboolean has_paragraphs_in_body = TRUE;
-       WebKitDOMElement *element, *signature;
-       WebKitDOMHTMLElement *body;
-       WebKitDOMNodeList *paragraphs;
 
-       flags = e_html_editor_web_extension_get_current_content_flags (extension);
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       flags = e_editor_page_get_current_content_flags (editor_page);
 
        is_message_from_draft = (flags & E_CONTENT_EDITOR_MESSAGE_DRAFT);
        is_message_from_edit_as_new = (flags & E_CONTENT_EDITOR_MESSAGE_EDIT_AS_NEW);
@@ -189,14 +193,14 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
 
                if (is_message_from_edit_as_new && !is_message_from_draft) {
                        element = WEBKIT_DOM_ELEMENT (body);
-                       e_html_editor_web_extension_block_selection_changed_callback (extension);
+                       e_editor_page_block_selection_changed (editor_page);
                        goto move_caret;
                } else
-                       dom_scroll_to_caret (document);
+                       e_editor_dom_scroll_to_caret (editor_page);
 
                return;
        }
-       e_html_editor_web_extension_block_selection_changed_callback (extension);
+       e_editor_page_block_selection_changed (editor_page);
 
        /* When the new message is written from the beginning - note it into body */
        if (is_from_new_message)
@@ -226,7 +230,7 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
        if (signature && top_signature) {
                WebKitDOMElement *spacer;
 
-               spacer = prepare_top_signature_spacer (document, extension);
+               spacer = prepare_top_signature_spacer (editor_page);
                webkit_dom_node_insert_before (
                        WEBKIT_DOM_NODE (body),
                        WEBKIT_DOM_NODE (spacer),
@@ -241,7 +245,7 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
        if (!signature) {
                if (start_bottom) {
                        if (!element) {
-                               element = dom_prepare_paragraph (document, extension, FALSE);
+                               element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
                                webkit_dom_element_set_id (element, "-x-evo-input-start");
                                webkit_dom_node_append_child (
                                        WEBKIT_DOM_NODE (body),
@@ -258,7 +262,7 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
        /* When there is an option composer-reply-start-bottom set we have
         * to move the caret between reply and signature. */
        if (!has_paragraphs_in_body) {
-               element = dom_prepare_paragraph (document, extension, FALSE);
+               element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
                webkit_dom_element_set_id (element, "-x-evo-input-start");
                if (top_signature) {
                        if (start_bottom) {
@@ -285,7 +289,7 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
                }
        } else {
                if (!element && top_signature) {
-                       element = dom_prepare_paragraph (document, extension, FALSE);
+                       element = e_editor_dom_prepare_paragraph (editor_page, FALSE);
                        webkit_dom_element_set_id (element, "-x-evo-input-start");
                        if (start_bottom) {
                                        webkit_dom_node_append_child (
@@ -334,42 +338,42 @@ move_caret_after_signature_inserted (WebKitDOMDocument *document,
        }
 
        if (start_bottom)
-               dom_scroll_to_caret (document);
+               e_editor_dom_scroll_to_caret (editor_page);
 
-       dom_force_spell_check_in_viewport (document, extension);
-       e_html_editor_web_extension_unblock_selection_changed_callback (extension);
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+       e_editor_page_unblock_selection_changed (editor_page);
 }
 
 gchar *
-dom_insert_signature (WebKitDOMDocument *document,
-                      EHTMLEditorWebExtension *extension,
-                      const gchar *content,
-                     gboolean is_html,
-                     const gchar *id,
-                     gboolean *set_signature_from_message,
-                     gboolean *check_if_signature_is_changed,
-                     gboolean *ignore_next_signature_change)
+e_composer_dom_insert_signature (EEditorPage *editor_page,
+                                const gchar *content,
+                                gboolean is_html,
+                                const gchar *id,
+                                gboolean *set_signature_from_message,
+                                gboolean *check_if_signature_is_changed,
+                                gboolean *ignore_next_signature_change)
 {
-       EContentEditorContentFlags flags;
-       gchar *new_signature_id = NULL;
-       gchar *signature_text = NULL;
-       gboolean top_signature, html_mode, is_message_from_edit_as_new;
-       gboolean is_message_from_draft, is_from_new_message;
-       gulong list_length, ii;
+       WebKitDOMDocument *document;
        WebKitDOMElement *signature_to_insert;
        WebKitDOMElement *insert_signature_in = NULL;
        WebKitDOMElement *signature_wrapper;
        WebKitDOMElement *element, *converted_signature = NULL;
        WebKitDOMHTMLElement *body;
        WebKitDOMHTMLCollection *signatures;
+       EContentEditorContentFlags flags;
+       gchar *new_signature_id = NULL;
+       gchar *signature_text = NULL;
+       gboolean top_signature, html_mode, is_message_from_edit_as_new;
+       gboolean is_message_from_draft, is_from_new_message;
+       gulong list_length, ii;
 
-       g_return_val_if_fail (WEBKIT_DOM_IS_HTML_DOCUMENT (document), NULL);
-       g_return_val_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension), NULL);
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
        g_return_val_if_fail (set_signature_from_message != NULL, NULL);
        g_return_val_if_fail (check_if_signature_is_changed != NULL, NULL);
        g_return_val_if_fail (ignore_next_signature_change != NULL, NULL);
 
-       flags = e_html_editor_web_extension_get_current_content_flags (extension);
+       document = e_editor_page_get_document (editor_page);
+       flags = e_editor_page_get_current_content_flags (editor_page);
 
        is_message_from_draft = (flags & E_CONTENT_EDITOR_MESSAGE_DRAFT);
        is_message_from_edit_as_new = (flags & E_CONTENT_EDITOR_MESSAGE_EDIT_AS_NEW);
@@ -382,7 +386,7 @@ dom_insert_signature (WebKitDOMDocument *document,
                !is_message_from_edit_as_new &&
                !is_from_new_message;
 
-       html_mode = e_html_editor_web_extension_get_html_mode (extension);
+       html_mode = e_editor_page_get_html_mode (editor_page);
 
        /* Create the DOM signature that is the same across all types of signatures. */
        signature_to_insert = webkit_dom_document_create_element (document, "span", NULL);
@@ -421,7 +425,7 @@ dom_insert_signature (WebKitDOMDocument *document,
                 * while inserting it into the view. */
                converted_signature = webkit_dom_document_create_element (document, "pre", NULL);
                webkit_dom_element_set_inner_html (converted_signature, signature_text, NULL);
-               dom_convert_element_from_html_to_plain_text (document, extension, converted_signature);
+               e_editor_dom_convert_element_from_html_to_plain_text (editor_page, converted_signature);
                inner_text = webkit_dom_html_element_get_inner_text (WEBKIT_DOM_HTML_ELEMENT 
(converted_signature));
 
                g_free (signature_text);
@@ -581,11 +585,11 @@ insert:
                        NULL);
        }
 
-/* FIXME WK2 - dom_fix_file_uri_images
+/* FIXME WK2 - e_editor_dom_fix_file_uri_images
        if (is_html && html_mode) {
                e_html_editor_view_fix_file_uri_images (view);*/
 
-       move_caret_after_signature_inserted (document, extension);
+       move_caret_after_signature_inserted (editor_page);
 
        /* Make sure the flag will be unset and won't influence user's choice */
        *set_signature_from_message = FALSE;
@@ -593,19 +597,88 @@ insert:
        return NULL;
 }
 
+gchar *
+e_composer_dom_get_active_signature_uid (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+       gchar *uid = NULL;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       if ((element = webkit_dom_document_query_selector (document, ".-x-evo-signature[id]", NULL)))
+               uid = webkit_dom_element_get_id (element);
+
+       return uid;
+}
+
+gchar *
+e_composer_dom_get_raw_body_content_without_signature (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       GString* content;
+       gulong ii, length;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       content = g_string_new (NULL);
+
+       list = webkit_dom_document_query_selector_all (
+               document, "body > *:not(.-x-evo-signature-wrapper)", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) {
+                       gchar *text;
+
+                       text = webkit_dom_html_element_get_inner_text (WEBKIT_DOM_HTML_ELEMENT (node));
+                       g_string_append (content, text);
+                       g_free (text);
+
+                       if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (node))
+                               g_string_append (content, "\n");
+                       else
+                               g_string_append (content, " ");
+               }
+       }
+
+       return g_string_free (content, FALSE);
+}
+
+gchar *
+e_composer_dom_get_raw_body_content (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       body = webkit_dom_document_get_body (document);
+
+       return  webkit_dom_html_element_get_inner_text (body);
+}
+
 static void
 insert_nbsp_history_event (WebKitDOMDocument *document,
-                          EHTMLEditorUndoRedoManager *manager,
+                          EEditorUndoRedoManager *manager,
                            gboolean delete,
                            guint x,
                            guint y)
 {
-       EHTMLEditorHistoryEvent *event;
+       EEditorHistoryEvent *event;
        WebKitDOMDocumentFragment *fragment;
 
-       event = g_new0 (EHTMLEditorHistoryEvent, 1);
+       event = g_new0 (EEditorHistoryEvent, 1);
        event->type = HISTORY_AND;
-       e_html_editor_undo_redo_manager_insert_history_event (manager, event);
+       e_editor_undo_redo_manager_insert_history_event (manager, event);
 
        fragment = webkit_dom_document_create_document_fragment (document);
        webkit_dom_node_append_child (
@@ -614,7 +687,7 @@ insert_nbsp_history_event (WebKitDOMDocument *document,
                        webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
                NULL);
 
-       event = g_new0 (EHTMLEditorHistoryEvent, 1);
+       event = g_new0 (EEditorHistoryEvent, 1);
        event->type = HISTORY_DELETE;
 
        if (delete)
@@ -632,25 +705,28 @@ insert_nbsp_history_event (WebKitDOMDocument *document,
        event->after.end.x = x;
        event->after.end.y = y;
 
-       e_html_editor_undo_redo_manager_insert_history_event (manager, event);
+       e_editor_undo_redo_manager_insert_history_event (manager, event);
 }
 
 void
-dom_save_drag_and_drop_history (WebKitDOMDocument *document,
-                               EHTMLEditorWebExtension *extension)
+e_composer_dom_save_drag_and_drop_history (EEditorPage *editor_page)
 {
-       EHTMLEditorHistoryEvent *event;
-       EHTMLEditorUndoRedoManager *manager;
-       gboolean start_to_start, end_to_end;
-       gchar *range_text;
-       guint x, y;
+       WebKitDOMDocument *document;
        WebKitDOMDocumentFragment *fragment;
        WebKitDOMDOMSelection *dom_selection;
        WebKitDOMDOMWindow *dom_window;
        WebKitDOMRange *beginning_of_line = NULL;
        WebKitDOMRange *range = NULL, *range_clone = NULL;
+       EEditorHistoryEvent *event;
+       EEditorUndoRedoManager *manager;
+       gboolean start_to_start, end_to_end;
+       gchar *range_text;
+       guint x, y;
 
-       manager = e_html_editor_web_extension_get_undo_redo_manager (extension, document);
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
 
        if (!(dom_window = webkit_dom_document_get_default_view (document)))
                return;
@@ -672,11 +748,10 @@ dom_save_drag_and_drop_history (WebKitDOMDocument *document,
 
        /* Create the history event for the content that will
         * be removed by DnD. */
-       event = g_new0 (EHTMLEditorHistoryEvent, 1);
+       event = g_new0 (EEditorHistoryEvent, 1);
        event->type = HISTORY_DELETE;
 
-       dom_selection_get_coordinates (
-               document,
+       e_editor_dom_selection_get_coordinates (editor_page,
                &event->before.start.x,
                &event->before.start.y,
                &event->before.end.x,
@@ -739,12 +814,11 @@ dom_save_drag_and_drop_history (WebKitDOMDocument *document,
                beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
 
                container = webkit_dom_range_get_end_container (range, NULL);
-               actual_block = get_parent_block_node_from_child (container);
+               actual_block = e_editor_dom_get_parent_block_node_from_child (container);
 
                tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
-               if ((tmp_block = get_parent_block_node_from_child (tmp_block))) {
-                       dom_selection_get_coordinates (
-                               document,
+               if ((tmp_block = e_editor_dom_get_parent_block_node_from_child (tmp_block))) {
+                       e_editor_dom_selection_get_coordinates (editor_page,
                                &event->before.start.x,
                                &event->before.start.y,
                                &event->before.end.x,
@@ -775,7 +849,7 @@ dom_save_drag_and_drop_history (WebKitDOMDocument *document,
        }
 
        event->data.fragment = fragment;
-       e_html_editor_undo_redo_manager_insert_history_event (manager, event);
+       e_editor_undo_redo_manager_insert_history_event (manager, event);
 
        /* Selection is ending on the end of the line, check if
         * there is a space before the selection start. If so, it
@@ -816,9 +890,9 @@ dom_save_drag_and_drop_history (WebKitDOMDocument *document,
        /* All the things above were about removing the content,
         * create an AND event to continue later with inserting
         * the dropped content. */
-       event = g_new0 (EHTMLEditorHistoryEvent, 1);
+       event = g_new0 (EEditorHistoryEvent, 1);
        event->type = HISTORY_AND;
-       e_html_editor_undo_redo_manager_insert_history_event (manager, event);
+       e_editor_undo_redo_manager_insert_history_event (manager, event);
 
        g_object_unref (dom_selection);
        g_object_unref (dom_window);
@@ -828,9 +902,10 @@ dom_save_drag_and_drop_history (WebKitDOMDocument *document,
 }
 
 void
-dom_clean_after_drag_and_drop (WebKitDOMDocument *document,
-                               EHTMLEditorWebExtension *extension)
+e_composer_dom_clean_after_drag_and_drop (EEditorPage *editor_page)
 {
-       dom_save_history_for_drop (document, extension);
-       dom_check_magic_links (document, extension, FALSE);
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_dom_save_history_for_drop (editor_page);
+       e_editor_dom_check_magic_links (editor_page, FALSE);
 }
diff --git a/modules/webkit-editor/web-extension/e-composer-private-dom-functions.h 
b/modules/webkit-editor/web-extension/e-composer-dom-functions.h
similarity index 57%
rename from modules/webkit-editor/web-extension/e-composer-private-dom-functions.h
rename to modules/webkit-editor/web-extension/e-composer-dom-functions.h
index 0c44130..1e0298f 100644
--- a/modules/webkit-editor/web-extension/e-composer-private-dom-functions.h
+++ b/modules/webkit-editor/web-extension/e-composer-dom-functions.h
@@ -1,5 +1,5 @@
 /*
- * e-composer-private-dom-functions.h
+ * e-composer-dom-functions.h
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,31 +16,36 @@
  *
  */
 
-#ifndef E_COMPOSER_PRIVATE_DOM_FUNCTIONS_H
-#define E_COMPOSER_PRIVATE_DOM_FUNCTIONS_H
+#ifndef E_COMPOSER_DOM_FUNCTIONS_H
+#define E_COMPOSER_DOM_FUNCTIONS_H
 
 #include <webkitdom/webkitdom.h>
 
-#include "e-html-editor-web-extension.h"
+#include "e-editor-page.h"
 
 G_BEGIN_DECLS
 
-gchar *                dom_remove_signatures           (WebKitDOMDocument *document,
-                                                EHTMLEditorWebExtension *extension,
+gchar *                e_composer_dom_remove_signatures
+                                               (EEditorPage *editor_page,
                                                 gboolean top_signature);
-gchar *                dom_insert_signature            (WebKitDOMDocument *document,
-                                                EHTMLEditorWebExtension *extension,
+gchar *                e_composer_dom_insert_signature (EEditorPage *editor_page,
                                                 const gchar *content,
                                                 gboolean is_html,
                                                 const gchar *id,
                                                 gboolean *set_signature_from_message,
                                                 gboolean *check_if_signature_is_changed,
                                                 gboolean *ignore_next_signature_change);
-void           dom_save_drag_and_drop_history  (WebKitDOMDocument *document,
-                                                EHTMLEditorWebExtension *extension);
-void           dom_clean_after_drag_and_drop   (WebKitDOMDocument *document,
-                                                EHTMLEditorWebExtension *extension);
+gchar *                e_composer_dom_get_active_signature_uid
+                                               (EEditorPage *editor_page);
+gchar *                e_composer_dom_get_raw_body_content_without_signature
+                                               (EEditorPage *editor_page);
+gchar *                e_composer_dom_get_raw_body_content
+                                               (EEditorPage *editor_page);
+void           e_composer_dom_save_drag_and_drop_history
+                                               (EEditorPage *editor_page);
+void           e_composer_dom_clean_after_drag_and_drop
+                                               (EEditorPage *editor_page);
 
 G_END_DECLS
 
-#endif /* E_COMPOSER_PRIVATE_DOM_FUNCTIONS_H */
+#endif /* E_COMPOSER_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c 
b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
new file mode 100644
index 0000000..8c49a53
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.c
@@ -0,0 +1,1319 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-dialogs-dom-functions.h"
+
+/* ******************** Cell Dialog ***************** */
+
+typedef void (*DOMStrFunc) (WebKitDOMHTMLTableCellElement *cell, const gchar *val, gpointer user_data);
+typedef void (*DOMUlongFunc) (WebKitDOMHTMLTableCellElement *cell, gulong val, gpointer user_data);
+typedef void (*DOMBoolFunc) (WebKitDOMHTMLTableCellElement *cell, gboolean val, gpointer user_data);
+
+static WebKitDOMElement *
+get_current_cell_element (WebKitDOMDocument *document)
+{
+       return webkit_dom_document_get_element_by_id (document, "-x-evo-current-cell");
+}
+
+static void
+call_cell_dom_func (WebKitDOMHTMLTableCellElement *cell,
+                    gpointer func,
+                    GValue *value,
+                    gpointer user_data)
+{
+       if (G_VALUE_HOLDS_STRING (value)) {
+               DOMStrFunc f = func;
+               f (cell, g_value_get_string (value), user_data);
+       } else if (G_VALUE_HOLDS_LONG (value)) {
+               DOMUlongFunc f = func;
+               f (cell, g_value_get_ulong (value), user_data);
+       } else if (G_VALUE_HOLDS_BOOLEAN (value)) {
+               DOMBoolFunc f = func;
+               f (cell, g_value_get_boolean (value), user_data);
+       }
+}
+
+static void
+for_each_cell_do (WebKitDOMElement *row,
+                  gpointer func,
+                  GValue *value,
+                  gpointer user_data)
+{
+       WebKitDOMHTMLCollection *cells;
+       gulong ii, length;
+       cells = webkit_dom_html_table_row_element_get_cells (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+       length = webkit_dom_html_collection_get_length (cells);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *cell;
+               cell = webkit_dom_html_collection_item (cells, ii);
+               if (!cell) {
+                       continue;
+               }
+
+               call_cell_dom_func (
+                       WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell), func, value, user_data);
+               g_object_unref (cell);
+       }
+       g_object_unref (cells);
+}
+
+static void
+cell_dialog_set_attribute (WebKitDOMDocument *document,
+                          EContentEditorScope scope,
+                          gpointer func,
+                          GValue *value,
+                          gpointer user_data)
+{
+       WebKitDOMElement *cell = get_current_cell_element (document);
+
+       if (scope == E_CONTENT_EDITOR_SCOPE_CELL) {
+
+               call_cell_dom_func (
+                       WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell),
+                       func, value, user_data);
+
+       } else if (scope == E_CONTENT_EDITOR_SCOPE_COLUMN) {
+               gulong index, ii, length;
+               WebKitDOMElement *table;
+               WebKitDOMHTMLCollection *rows;
+
+               index = webkit_dom_html_table_cell_element_get_cell_index (
+                               WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+               table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+               if (!table) {
+                       return;
+               }
+
+               rows = webkit_dom_html_table_element_get_rows (
+                               WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+               length = webkit_dom_html_collection_get_length (rows);
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *row, *cell;
+                       WebKitDOMHTMLCollection *cells;
+
+                       row = webkit_dom_html_collection_item (rows, ii);
+                       cells = webkit_dom_html_table_row_element_get_cells (
+                                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+                       cell = webkit_dom_html_collection_item (cells, index);
+                       if (!cell) {
+                               g_object_unref (row);
+                               g_object_unref (cells);
+                               continue;
+                       }
+
+                       call_cell_dom_func (
+                               WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell),
+                               func, value, user_data);
+                       g_object_unref (row);
+                       g_object_unref (cells);
+                       g_object_unref (cell);
+               }
+               g_object_unref (rows);
+
+       } else if (scope == E_CONTENT_EDITOR_SCOPE_ROW) {
+               WebKitDOMElement *row;
+
+               row = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
+               if (!row) {
+                       return;
+               }
+
+               for_each_cell_do (row, func, value, user_data);
+
+       } else if (scope == E_CONTENT_EDITOR_SCOPE_TABLE) {
+               gulong ii, length;
+               WebKitDOMElement *table;
+               WebKitDOMHTMLCollection *rows;
+
+               table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+               if (!table) {
+                       return;
+               }
+
+               rows = webkit_dom_html_table_element_get_rows (
+                               WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+               length = webkit_dom_html_collection_get_length (rows);
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *row;
+
+                       row = webkit_dom_html_collection_item (rows, ii);
+                       if (!row) {
+                               g_object_unref (row);
+                               continue;
+                       }
+
+                       for_each_cell_do (
+                               WEBKIT_DOM_ELEMENT (row), func, value, user_data);
+                       g_object_unref (row);
+               }
+               g_object_unref (rows);
+       }
+}
+
+static void
+cell_set_header_style (WebKitDOMHTMLTableCellElement *cell,
+                       gboolean header_style,
+                      gpointer user_data)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *nodes;
+       WebKitDOMElement *new_cell;
+       gulong length, ii;
+       gchar *tagname;
+
+       document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (cell));
+       tagname = webkit_dom_element_get_tag_name (WEBKIT_DOM_ELEMENT (cell));
+
+       if (header_style && (g_ascii_strncasecmp (tagname, "TD", 2) == 0)) {
+
+               new_cell = webkit_dom_document_create_element (document, "TH", NULL);
+
+       } else if (!header_style && (g_ascii_strncasecmp (tagname, "TH", 2) == 0)) {
+
+               new_cell = webkit_dom_document_create_element (document, "TD", NULL);
+
+       } else {
+               g_free (tagname);
+               return;
+       }
+
+       webkit_dom_element_set_id (new_cell, "-x-evo-current-cell");
+
+       /* Move all child nodes from cell to new_cell */
+       nodes = webkit_dom_node_get_child_nodes (WEBKIT_DOM_NODE (cell));
+       length = webkit_dom_node_list_get_length (nodes);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (nodes, ii);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (new_cell), node, NULL);
+               g_object_unref (node);
+       }
+       g_object_unref (nodes);
+
+       /* Insert new_cell before cell and remove cell */
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (
+                       WEBKIT_DOM_NODE (cell)),
+               WEBKIT_DOM_NODE (new_cell),
+               WEBKIT_DOM_NODE (cell), NULL);
+
+       webkit_dom_node_remove_child (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (cell)),
+               WEBKIT_DOM_NODE (cell), NULL);
+
+       g_free (tagname);
+}
+
+void
+e_dialogs_dom_cell_mark_current_cell_element (EEditorPage *editor_page,
+                                             const gchar *id)
+{
+       EEditorUndoRedoManager *manager;
+       WebKitDOMElement *element, *parent = NULL;
+       WebKitDOMDocument *document;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (id != NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       element = webkit_dom_document_get_element_by_id (document, id);
+
+       parent = dom_node_find_parent_element (WEBKIT_DOM_NODE (element), "TD");
+       if (!parent)
+               parent = dom_node_find_parent_element (WEBKIT_DOM_NODE (element), "TH");
+
+       element = webkit_dom_document_get_element_by_id (document, "-x-evo-current-cell");
+       if (element)
+               webkit_dom_element_remove_attribute (element, "id");
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev;
+               WebKitDOMElement *table;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_TABLE_DIALOG;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               table = dom_node_find_parent_element (
+                       WEBKIT_DOM_NODE (parent), "TABLE");
+               ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+                       WEBKIT_DOM_NODE (table), TRUE, NULL);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       webkit_dom_element_set_id (parent, "-x-evo-current-cell");
+}
+
+void
+e_dialogs_dom_cell_save_history_on_exit (EEditorPage *editor_page)
+{
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       WebKitDOMElement *cell, *table;
+       WebKitDOMDocument *document;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       cell = get_current_cell_element (document);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       webkit_dom_element_remove_attribute (cell, "id");
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+       ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (table), TRUE, NULL);
+
+       if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+       } else {
+               e_editor_undo_redo_manager_remove_current_history_event (manager);
+       }
+}
+
+void
+e_dialogs_dom_cell_set_element_v_align (EEditorPage *editor_page,
+                                       const gchar *v_align,
+                                       EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_STRING);
+       g_value_set_string (&val, v_align);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_v_align, &val, NULL);
+
+       g_value_unset (&val);
+}
+
+void
+e_dialogs_dom_cell_set_element_align (EEditorPage *editor_page,
+                                     const gchar *align,
+                                     EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_STRING);
+       g_value_set_string (&val, align);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_align, &val, NULL);
+
+       g_value_unset (&val);
+}
+
+void
+e_dialogs_dom_cell_set_element_no_wrap (EEditorPage *editor_page,
+                                       gboolean wrap_text,
+                                       EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_BOOLEAN);
+       g_value_set_boolean (&val, wrap_text);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_no_wrap, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_header_style (EEditorPage *editor_page,
+                                            gboolean header_style,
+                                            EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_BOOLEAN);
+       g_value_set_boolean (&val, header_style);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, cell_set_header_style, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_width (EEditorPage *editor_page,
+                                     const gchar *width,
+                                     EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_STRING);
+       g_value_set_string (&val, width);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_width, &val, NULL);
+
+       g_value_unset (&val);
+}
+
+void
+e_dialogs_dom_cell_set_element_col_span (EEditorPage *editor_page,
+                                        glong span,
+                                        EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_LONG);
+       g_value_set_long (&val, span);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_col_span, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_row_span (EEditorPage *editor_page,
+                                        glong span,
+                                        EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_LONG);
+       g_value_set_long (&val, span);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_row_span, &val, NULL);
+}
+
+void
+e_dialogs_dom_cell_set_element_bg_color (EEditorPage *editor_page,
+                                        const gchar *color,
+                                        EContentEditorScope scope)
+{
+       GValue val = { 0 };
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_value_init (&val, G_TYPE_STRING);
+       g_value_set_string (&val, color);
+
+       cell_dialog_set_attribute (e_editor_page_get_document (editor_page),
+               scope, webkit_dom_html_table_cell_element_set_bg_color, &val, NULL);
+}
+
+/* ******************** HRule Dialog ***************** */
+
+static WebKitDOMElement *
+get_current_hrule_element (WebKitDOMDocument *document)
+{
+       return webkit_dom_document_get_element_by_id (document, "-x-evo-current-hr");
+}
+
+gboolean
+e_dialogs_dom_hrule_find_hrule (EEditorPage *editor_page,
+                               WebKitDOMNode *node_under_mouse_click)
+{
+       EEditorUndoRedoManager *manager;
+       gboolean created = FALSE;
+       WebKitDOMDocument *document;
+       WebKitDOMElement *rule;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       if (node_under_mouse_click && WEBKIT_DOM_IS_HTML_HR_ELEMENT (node_under_mouse_click)) {
+               rule = WEBKIT_DOM_ELEMENT (node_under_mouse_click);
+               webkit_dom_element_set_id (rule, "-x-evo-current-hr");
+       } else {
+               WebKitDOMElement *selection_start, *parent;
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start));
+
+               rule = webkit_dom_document_create_element (document, "HR", NULL);
+               webkit_dom_element_set_id (rule, "-x-evo-current-hr");
+
+               /* Insert horizontal rule into body below the caret */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
+                       WEBKIT_DOM_NODE (rule),
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
+                       NULL);
+
+               e_editor_dom_selection_restore (editor_page);
+
+               e_editor_page_emit_content_changed (editor_page);
+
+               created = TRUE;
+       }
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_HRULE_DIALOG;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+               if (!created)
+                       ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+                               WEBKIT_DOM_NODE (rule), FALSE, NULL);
+               else
+                       ev->data.dom.from = NULL;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       return created;
+}
+
+void
+e_dialogs_dom_save_history_on_exit (EEditorPage *editor_page)
+{
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       element = get_current_hrule_element (document);
+       g_return_if_fail (element != NULL);
+
+       webkit_dom_element_remove_attribute (element, "id");
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+       ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+       if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+       } else {
+               e_editor_undo_redo_manager_remove_current_history_event (manager);
+       }
+}
+
+/* ******************** Image Dialog ***************** */
+
+static WebKitDOMElement *
+get_current_image_element (WebKitDOMDocument *document)
+{
+       return webkit_dom_document_get_element_by_id (document, "-x-evo-current-img");
+}
+
+void
+e_dialogs_dom_image_mark_image (EEditorPage *editor_page,
+                               WebKitDOMNode *node_under_mouse_click)
+{
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (node_under_mouse_click && WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT 
(node_under_mouse_click));
+
+       webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (node_under_mouse_click), "-x-evo-current-img");
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_IMAGE_DIALOG;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+               ev->data.dom.from = webkit_dom_node_clone_node_with_error (node_under_mouse_click, FALSE, 
NULL);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
+void
+e_dialogs_dom_image_save_history_on_exit (EEditorPage *editor_page)
+{
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       element = get_current_image_element (document);
+       g_return_if_fail (element != NULL);
+
+       webkit_dom_element_remove_attribute (element, "id");
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+       ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+       e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+}
+
+void
+e_dialogs_dom_image_set_element_url (EEditorPage *editor_page,
+                                    const gchar *url)
+{
+       WebKitDOMElement *image, *link;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       image = get_current_image_element (e_editor_page_get_document (editor_page));
+       link = dom_node_find_parent_element (WEBKIT_DOM_NODE (image), "A");
+
+       if (link) {
+               if (!url || !*url) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (link)),
+                               WEBKIT_DOM_NODE (image),
+                               WEBKIT_DOM_NODE (link), NULL);
+                       webkit_dom_node_remove_child (
+                               webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (link)),
+                               WEBKIT_DOM_NODE (link), NULL);
+               } else {
+                       webkit_dom_html_anchor_element_set_href (
+                               WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
+               }
+       } else {
+               if (url && *url) {
+                       WebKitDOMDocument *document;
+
+                       document = webkit_dom_node_get_owner_document (
+                                       WEBKIT_DOM_NODE (image));
+                       link = webkit_dom_document_create_element (
+                                       document, "A", NULL);
+
+                       webkit_dom_html_anchor_element_set_href (
+                               WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
+
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (image)),
+                               WEBKIT_DOM_NODE (link),
+                               WEBKIT_DOM_NODE (image), NULL);
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (link),
+                               WEBKIT_DOM_NODE (image), NULL);
+               }
+       }
+}
+
+gchar *
+e_dialogs_dom_image_get_element_url (EEditorPage *editor_page)
+{
+       gchar *value;
+       WebKitDOMElement *image, *link;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       image = get_current_image_element (e_editor_page_get_document (editor_page));
+       link = dom_node_find_parent_element (WEBKIT_DOM_NODE (image), "A");
+
+       value = webkit_dom_html_anchor_element_get_href (
+               WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link));
+
+       return value;
+}
+
+/* ******************** Link Dialog ***************** */
+
+/* FIXME WK2 apply changes from commit 18c5e81 */
+void
+e_dialogs_dom_link_commit (EEditorPage *editor_page,
+                          const gchar *url,
+                          const gchar *inner_text)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *link;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       link = webkit_dom_document_get_element_by_id (document, "-x-evo-current-anchor");
+
+       if (link) {
+               webkit_dom_html_anchor_element_set_href (
+                       WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link), url);
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (link), inner_text, NULL);
+               webkit_dom_element_remove_attribute (link, "id");
+       } else {
+               gchar *text;
+               WebKitDOMDOMWindow *dom_window;
+               WebKitDOMDOMSelection *dom_selection;
+               WebKitDOMRange *range;
+
+               dom_window = webkit_dom_document_get_default_view (document);
+               dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+               g_object_unref (dom_window);
+
+               if (!dom_selection ||
+                   (webkit_dom_dom_selection_get_range_count (dom_selection) == 0)) {
+                       g_object_unref (dom_selection);
+                       return;
+               }
+
+               range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+               /* Check whether a text is selected or not */
+               text = webkit_dom_range_get_text (range);
+               if (text && *text) {
+                       e_editor_dom_create_link (editor_page, url);
+               } else {
+                       gchar *html = g_strdup_printf (
+                               "<a href=\"%s\">%s</a>", url, inner_text);
+
+                       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_HTML, html);
+                       g_free (html);
+               }
+
+               g_free (text);
+
+               g_object_unref (range);
+               g_object_unref (dom_selection);
+       }
+}
+
+GVariant *
+e_dialogs_dom_link_show (EEditorPage *editor_page)
+{
+       GVariant *result = NULL;
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range;
+       WebKitDOMElement *link;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       /* No selection at all */
+       if (!dom_selection ||
+           webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+               result = g_variant_new ("(ss)", "", "");
+               return result;
+       }
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       link = dom_node_find_parent_element (
+               webkit_dom_range_get_start_container (range, NULL), "A");
+       if (!link) {
+               if ((webkit_dom_range_get_start_container (range, NULL) !=
+                       webkit_dom_range_get_end_container (range, NULL)) ||
+                   (webkit_dom_range_get_start_offset (range, NULL) !=
+                       webkit_dom_range_get_end_offset (range, NULL))) {
+
+                       WebKitDOMDocumentFragment *fragment;
+                       fragment = webkit_dom_range_clone_contents (range, NULL);
+                       link = dom_node_find_child_element (WEBKIT_DOM_NODE (fragment), "A");
+               } else {
+                       /* get element that was clicked on */
+                       WebKitDOMNode *node;
+
+                       node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+                       if (node && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+                               link = dom_node_find_parent_element (node, "A");
+                               if (link && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (link))
+                                       link = NULL;
+                       } else
+                               link = WEBKIT_DOM_ELEMENT (node);
+               }
+       }
+
+       if (link) {
+               gchar *href, *text;
+
+               href = webkit_dom_html_anchor_element_get_href (
+                               WEBKIT_DOM_HTML_ANCHOR_ELEMENT (link));
+               text = webkit_dom_html_element_get_inner_text (
+                               WEBKIT_DOM_HTML_ELEMENT (link));
+
+               webkit_dom_element_set_id (
+                       WEBKIT_DOM_ELEMENT (link), "-x-evo-current-anchor");
+
+               result = g_variant_new ("(ss)", href, text);
+
+               g_free (text);
+               g_free (href);
+       } else {
+               gchar *text;
+
+               text = webkit_dom_range_get_text (range);
+               if (text && *text)
+                       result = g_variant_new ("(ss)", "", text);
+
+               g_free (text);
+       }
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+
+       return result;
+}
+
+/* ******************** Page Dialog ***************** */
+
+void
+e_dialogs_dom_page_save_history (EEditorPage *editor_page)
+{
+       EEditorUndoRedoManager *manager;
+       WebKitDOMDocument *document;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev;
+               WebKitDOMHTMLElement *body;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_PAGE_DIALOG;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+               body = webkit_dom_document_get_body (document);
+               ev->data.dom.from = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), FALSE, 
NULL);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
+void
+e_dialogs_dom_page_save_history_on_exit (EEditorPage *editor_page)
+{
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+       body = webkit_dom_document_get_body (document);
+       ev->data.dom.to = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), FALSE, NULL);
+
+       if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+       } else {
+               e_editor_undo_redo_manager_remove_current_history_event (manager);
+       }
+}
+
+/* ******************** Spell Check Dialog ***************** */
+
+static gboolean
+select_next_word (WebKitDOMDOMSelection *dom_selection)
+{
+       gulong anchor_offset, focus_offset;
+       WebKitDOMNode *anchor, *focus;
+
+       anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+       anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+       focus = webkit_dom_dom_selection_get_focus_node (dom_selection);
+       focus_offset = webkit_dom_dom_selection_get_focus_offset (dom_selection);
+
+       /* Jump _behind_ next word */
+       webkit_dom_dom_selection_modify (dom_selection, "move", "forward", "word");
+       /* Jump before the word */
+       webkit_dom_dom_selection_modify (dom_selection, "move", "backward", "word");
+       /* Select it */
+       webkit_dom_dom_selection_modify (dom_selection, "extend", "forward", "word");
+
+       /* If the selection didn't change, then we have most probably
+        * reached the end of document - return FALSE */
+       return !((anchor == webkit_dom_dom_selection_get_anchor_node (dom_selection)) &&
+                (anchor_offset == webkit_dom_dom_selection_get_anchor_offset (dom_selection)) &&
+                (focus == webkit_dom_dom_selection_get_focus_node (dom_selection)) &&
+                (focus_offset == webkit_dom_dom_selection_get_focus_offset (dom_selection)));
+}
+
+static gboolean
+select_previous_word (WebKitDOMDOMSelection *dom_selection)
+{
+       WebKitDOMNode *old_anchor_node;
+       WebKitDOMNode *new_anchor_node;
+       gulong old_anchor_offset;
+       gulong new_anchor_offset;
+
+       old_anchor_node = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+       old_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+       /* Jump on the beginning of current word */
+       webkit_dom_dom_selection_modify (dom_selection, "move", "backward", "word");
+       /* Jump before previous word */
+       webkit_dom_dom_selection_modify (dom_selection, "move", "backward", "word");
+       /* Select it */
+       webkit_dom_dom_selection_modify (dom_selection, "extend", "forward", "word");
+
+       /* If the selection start didn't change, then we have most probably
+        * reached the beginnig of document. Return FALSE */
+
+       new_anchor_node = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+       new_anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+       return (new_anchor_node != old_anchor_node) ||
+               (new_anchor_offset != old_anchor_offset);
+}
+
+static gchar *
+e_dialogs_dom_spell_check_run (EEditorPage *editor_page,
+                              gboolean run_next,
+                              const gchar *from_word,
+                              const gchar * const *languages)
+{
+       gulong start_offset = 0, end_offset = 0;
+       WebKitDOMDocument *document;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMNode *start = NULL, *end = NULL;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (!from_word || !*from_word) {
+               if (run_next) {
+                       webkit_dom_dom_selection_modify (
+                               dom_selection, "move", "left", "documentboundary");
+               } else {
+                       webkit_dom_dom_selection_modify (
+                               dom_selection, "move", "right", "documentboundary");
+                       webkit_dom_dom_selection_modify (
+                               dom_selection, "extend", "backward", "word");
+               }
+       } else {
+               /* Remember last selected word */
+               start = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+               end = webkit_dom_dom_selection_get_focus_node (dom_selection);
+               start_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+               end_offset = webkit_dom_dom_selection_get_focus_offset (dom_selection);
+       }
+
+       while ((run_next ? select_next_word (dom_selection) : select_previous_word (dom_selection))) {
+               WebKitDOMRange *range;
+               gchar *word;
+
+               range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+               word = webkit_dom_range_get_text (range);
+               g_object_unref (range);
+
+               if (!e_editor_page_check_word_spelling (editor_page, word, languages)) {
+                       /* Found misspelled word! */
+                       return word;
+               }
+
+               g_free (word);
+       }
+
+       /* Restore the selection to contain the last misspelled word. This is
+        * reached only when we reach the beginning/end of the document */
+       if (start && end)
+               webkit_dom_dom_selection_set_base_and_extent (
+                       dom_selection, start, start_offset, end, end_offset, NULL);
+
+       g_object_unref (dom_selection);
+
+       return NULL;
+}
+
+gchar *
+e_dialogs_dom_spell_check_next (EEditorPage *editor_page,
+                               const gchar *from_word,
+                               const gchar * const *languages)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return e_dialogs_dom_spell_check_run (editor_page, TRUE, from_word, languages);
+}
+
+gchar *
+e_dialogs_dom_spell_check_prev (EEditorPage *editor_page,
+                               const gchar *from_word,
+                               const gchar * const *languages)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return e_dialogs_dom_spell_check_run (editor_page, FALSE, from_word, languages);
+}
+
+/* ******************** Table Dialog ***************** */
+
+static WebKitDOMHTMLTableElement *
+get_current_table_element (WebKitDOMDocument *document)
+{
+       return WEBKIT_DOM_HTML_TABLE_ELEMENT (webkit_dom_document_get_element_by_id (document, 
"-x-evo-current-table"));
+}
+
+void
+e_dialogs_dom_table_set_row_count (EEditorPage *editor_page,
+                                  gulong expected_count)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLTableElement *table_element;
+       WebKitDOMHTMLCollection *rows;
+       gulong ii, current_count;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_element = get_current_table_element (document);
+       if (!table_element)
+               return;
+
+       rows = webkit_dom_html_table_element_get_rows (table_element);
+       current_count = webkit_dom_html_collection_get_length (rows);
+
+       if (current_count < expected_count) {
+               for (ii = 0; ii < expected_count - current_count; ii++) {
+                       webkit_dom_html_table_element_insert_row (
+                               table_element, -1, NULL);
+               }
+       } else if (current_count > expected_count) {
+               for (ii = 0; ii < current_count - expected_count; ii++) {
+                       webkit_dom_html_table_element_delete_row (
+                               table_element, -1, NULL);
+               }
+       }
+       g_object_unref (rows);
+}
+
+gulong
+e_dialogs_dom_table_get_row_count (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLTableElement *table_element;
+       WebKitDOMHTMLCollection *rows;
+       glong count;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_element = get_current_table_element (document);
+       if (!table_element)
+               return 0;
+
+       rows = webkit_dom_html_table_element_get_rows (table_element);
+
+       count = webkit_dom_html_collection_get_length (rows);
+       g_object_unref (rows);
+
+       return count;
+}
+
+void
+e_dialogs_dom_table_set_column_count (EEditorPage *editor_page,
+                                     gulong expected_columns)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLTableElement *table_element;
+       WebKitDOMHTMLCollection *rows;
+       gulong ii, row_count;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_element = get_current_table_element (document);
+       if (!table_element)
+               return;
+
+       rows = webkit_dom_html_table_element_get_rows (table_element);
+       row_count = webkit_dom_html_collection_get_length (rows);
+
+       for (ii = 0; ii < row_count; ii++) {
+               WebKitDOMHTMLTableRowElement *row;
+               WebKitDOMHTMLCollection *cells;
+               gulong jj, current_columns;
+
+               row = WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (
+                       webkit_dom_html_collection_item (rows, ii));
+
+               cells = webkit_dom_html_table_row_element_get_cells (row);
+               current_columns = webkit_dom_html_collection_get_length (cells);
+
+               if (current_columns < expected_columns) {
+                       for (jj = 0; jj < expected_columns - current_columns; jj++) {
+                               webkit_dom_html_table_row_element_insert_cell (
+                                       row, -1, NULL);
+                       }
+               } else if (expected_columns < current_columns) {
+                       for (jj = 0; jj < current_columns - expected_columns; jj++) {
+                               webkit_dom_html_table_row_element_delete_cell (
+                                       row, -1, NULL);
+                       }
+               }
+               g_object_unref (row);
+               g_object_unref (cells);
+       }
+       g_object_unref (rows);
+}
+
+gulong
+e_dialogs_dom_table_get_column_count (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLTableElement *table_element;
+       WebKitDOMHTMLCollection *rows, *columns;
+       WebKitDOMNode *row;
+       glong count;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_element = get_current_table_element (document);
+       if (!table_element)
+               return 0;
+
+       rows = webkit_dom_html_table_element_get_rows (table_element);
+       row = webkit_dom_html_collection_item (rows, 0);
+
+       columns = webkit_dom_html_table_row_element_get_cells (
+               WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+       count = webkit_dom_html_collection_get_length (columns);
+
+       g_object_unref (row);
+       g_object_unref (rows);
+       g_object_unref (columns);
+
+       return count;
+}
+
+static WebKitDOMElement *
+create_table (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *table, *br, *caret, *element, *cell;
+       WebKitDOMNode *clone;
+       gboolean empty = FALSE;
+       gchar *text_content;
+       gint i;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* Default 3x3 table */
+       table = webkit_dom_document_create_element (document, "TABLE", NULL);
+       for (i = 0; i < 3; i++) {
+               WebKitDOMHTMLElement *row;
+               gint j;
+
+               row = webkit_dom_html_table_element_insert_row (
+                       WEBKIT_DOM_HTML_TABLE_ELEMENT (table), -1, NULL);
+
+               for (j = 0; j < 3; j++) {
+                       webkit_dom_html_table_row_element_insert_cell (
+                               WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), -1, NULL);
+               }
+       }
+
+       webkit_dom_element_set_id (table, "-x-evo-current-table");
+
+       e_editor_dom_selection_save (editor_page);
+       caret = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+
+
+       element = get_parent_block_element (WEBKIT_DOM_NODE (caret));
+       text_content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (element));
+       empty = text_content && !*text_content;
+       g_free (text_content);
+
+       clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), FALSE, NULL);
+       br = webkit_dom_document_create_element (document, "BR", NULL);
+       webkit_dom_node_append_child (clone, WEBKIT_DOM_NODE (br), NULL);
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+               clone,
+               webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)),
+               NULL);
+
+       /* Move caret to the first cell */
+       cell = webkit_dom_element_query_selector (table, "td", NULL);
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (cell), WEBKIT_DOM_NODE (caret), NULL);
+       caret = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       webkit_dom_node_insert_before (
+               WEBKIT_DOM_NODE (cell),
+               WEBKIT_DOM_NODE (caret),
+               webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (cell)),
+               NULL);
+
+       /* Insert the table into body unred the current block (if current block is not empty)
+        * otherwise replace the current block. */
+       if (empty) {
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       WEBKIT_DOM_NODE (table),
+                       WEBKIT_DOM_NODE (element),
+                       NULL);
+       } else {
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       WEBKIT_DOM_NODE (table),
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)),
+                       NULL);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_page_emit_content_changed (editor_page);
+
+       return table;
+}
+
+gboolean
+e_dialogs_dom_table_show (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMElement *table = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean created = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+       if (dom_selection && (webkit_dom_dom_selection_get_range_count (dom_selection) > 0)) {
+               WebKitDOMRange *range;
+
+               range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+               table = dom_node_find_parent_element (
+                       webkit_dom_range_get_start_container (range, NULL), "TABLE");
+               g_object_unref (range);
+
+               if (table) {
+                       webkit_dom_element_set_id (table, "-x-evo-current-table");
+               } else {
+                       table = create_table (editor_page);
+                       created = TRUE;
+               }
+       }
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_TABLE_DIALOG;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+               if (!created)
+                       ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+                               WEBKIT_DOM_NODE (table), TRUE, NULL);
+               else
+                       ev->data.dom.from = NULL;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       g_object_unref (dom_selection);
+
+       return created;
+}
+
+void
+e_dialogs_dom_table_save_history_on_exit (EEditorPage *editor_page)
+{
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       element = WEBKIT_DOM_ELEMENT (get_current_table_element (document));
+       g_return_if_fail (element != NULL);
+
+       webkit_dom_element_remove_attribute (element, "id");
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+       ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+       if (!webkit_dom_node_is_equal_node (ev->data.dom.from, ev->data.dom.to)) {
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+       } else {
+               e_editor_undo_redo_manager_remove_current_history_event (manager);
+       }
+}
diff --git a/modules/webkit-editor/web-extension/e-dialogs-dom-functions.h 
b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.h
new file mode 100644
index 0000000..ac5f286
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-dialogs-dom-functions.h
@@ -0,0 +1,132 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (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/>.
+ */
+
+#ifndef E_DIALOGS_DOM_FUNCTIONS_H
+#define E_DIALOGS_DOM_FUNCTIONS_H
+
+#include <webkit2/webkit-web-extension.h>
+
+#include "e-editor-page.h"
+
+G_BEGIN_DECLS
+
+/* ******************** Cell Dialog ***************** */
+
+void           e_dialogs_dom_cell_mark_current_cell_element
+                                               (EEditorPage *editor_page,
+                                                const gchar *id);
+void           e_dialogs_dom_cell_save_history_on_exit
+                                               (EEditorPage *editor_page);
+void           e_dialogs_dom_cell_set_element_v_align
+                                               (EEditorPage *editor_page,
+                                                const gchar *v_align,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_align
+                                               (EEditorPage *editor_page,
+                                                const gchar *align,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_no_wrap
+                                               (EEditorPage *editor_page,
+                                                gboolean wrap_text,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_header_style
+                                               (EEditorPage *editor_page,
+                                                gboolean header_style,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_width
+                                               (EEditorPage *editor_page,
+                                                const gchar *width,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_col_span
+                                               (EEditorPage *editor_page,
+                                                glong span,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_row_span
+                                               (EEditorPage *editor_page,
+                                                glong span,
+                                                guint scope);
+void           e_dialogs_dom_cell_set_element_bg_color
+                                               (EEditorPage *editor_page,
+                                                const gchar *color,
+                                                guint scope);
+
+/* ******************** HRule Dialog ***************** */
+
+gboolean       e_dialogs_dom_hrule_find_hrule  (EEditorPage *editor_page,
+                                                WebKitDOMNode *node_under_mouse_click);
+void           e_dialogs_dom_save_history_on_exit
+                                               (EEditorPage *editor_page);
+
+/* ******************** Image Dialog ***************** */
+
+void           e_dialogs_dom_image_mark_image  (EEditorPage *editor_page,
+                                                WebKitDOMNode *node_under_mouse_click);
+void           e_dialogs_dom_image_save_history_on_exit
+                                               (EEditorPage *editor_page);
+void           e_dialogs_dom_image_set_element_url
+                                               (EEditorPage *editor_page,
+                                                const gchar *url);
+gchar *                e_dialogs_dom_image_get_element_url
+                                               (EEditorPage *editor_page);
+
+/* ******************** Link Dialog ***************** */
+
+void           e_dialogs_dom_link_commit       (EEditorPage *editor_page,
+                                                const gchar *url,
+                                                const gchar *inner_text);
+GVariant *     e_dialogs_dom_link_show         (EEditorPage *editor_page);
+
+/* ******************** Page Dialog ***************** */
+
+void           e_dialogs_dom_page_save_history (EEditorPage *editor_page);
+void           e_dialogs_dom_page_save_history_on_exit
+                                               (EEditorPage *editor_page);
+
+/* ******************** Spell Check Dialog ***************** */
+
+gchar *        e_dialogs_dom_spell_check_prev  (EEditorPage *editor_page,
+                                                const gchar *from_word,
+                                                const gchar * const *languages);
+
+gchar *        e_dialogs_dom_spell_check_next  (EEditorPage *editor_page,
+                                                const gchar *from_word,
+                                                const gchar * const *languages);
+
+/* ******************** Table Dialog ***************** */
+
+void           e_dialogs_dom_table_set_row_count
+                                               (EEditorPage *editor_page,
+                                                gulong expected_count);
+
+gulong         e_dialogs_dom_table_get_row_count
+                                               (EEditorPage *editor_page);
+
+void           e_dialogs_dom_table_set_column_count
+                                               (EEditorPage *editor_page,
+                                                gulong expected_columns);
+
+gulong         e_dialogs_dom_table_get_column_count
+                                               (EEditorPage *editor_page);
+
+gboolean       e_dialogs_dom_table_show        (EEditorPage *editor_page);
+
+void           e_dialogs_dom_table_save_history_on_exit
+                                               (EEditorPage *editor_page);
+
+G_END_DECLS
+
+#endif /* E_DIALOGS_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-dom-functions.c 
b/modules/webkit-editor/web-extension/e-editor-dom-functions.c
new file mode 100644
index 0000000..49e7dbd
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-dom-functions.c
@@ -0,0 +1,17578 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#define WEBKIT_DOM_USE_UNSTABLE_API
+#include <webkitdom/WebKitDOMDocumentUnstable.h>
+#include <webkitdom/WebKitDOMDocumentFragmentUnstable.h>
+#include <webkitdom/WebKitDOMDOMSelection.h>
+#include <webkitdom/WebKitDOMDOMWindowUnstable.h>
+#include <webkitdom/WebKitDOMHTMLElementUnstable.h>
+#include <webkitdom/WebKitDOMRangeUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-editor-dom-functions.h"
+
+#define HTML_KEY_CODE_BACKSPACE 8
+#define HTML_KEY_CODE_RETURN 13
+#define HTML_KEY_CODE_CONTROL 17
+#define HTML_KEY_CODE_SPACE 32
+#define HTML_KEY_CODE_DELETE 46
+#define HTML_KEY_CODE_TABULATOR 9
+
+#define TRY_TO_PRESERVE_BLOCKS 0
+
+/* ******************** Tests ******************** */
+
+gboolean
+e_editor_dom_test_html_equal (WebKitDOMDocument *document,
+                             const gchar *html1,
+                             const gchar *html2)
+{
+       WebKitDOMElement *elem1, *elem2;
+       gboolean res = FALSE;
+       GError *error = NULL;
+
+       g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), FALSE);
+       g_return_val_if_fail (html1 != NULL, FALSE);
+       g_return_val_if_fail (html2 != NULL, FALSE);
+
+       elem1 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error);
+       if (error || !elem1) {
+               g_warning ("%s: Failed to create elem1: %s", G_STRFUNC, error ? error->message : "Unknown 
error");
+               g_clear_error (&error);
+               return FALSE;
+       }
+
+       elem2 = webkit_dom_document_create_element (document, "TestHtmlEqual", &error);
+       if (error || !elem2) {
+               g_warning ("%s: Failed to create elem2: %s", G_STRFUNC, error ? error->message : "Unknown 
error");
+               g_clear_error (&error);
+               return FALSE;
+       }
+
+       webkit_dom_element_set_inner_html (elem1, html1, &error);
+       if (!error) {
+               webkit_dom_element_set_inner_html (elem2, html2, &error);
+
+               if (!error) {
+                       webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem1));
+                       webkit_dom_node_normalize (WEBKIT_DOM_NODE (elem2));
+
+                       res = webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (elem1), WEBKIT_DOM_NODE 
(elem2));
+               } else {
+                       g_warning ("%s: Failed to set inner html2: %s", G_STRFUNC, error->message);
+               }
+       } else {
+               g_warning ("%s: Failed to set inner html1: %s", G_STRFUNC, error->message);
+       }
+
+       g_clear_error (&error);
+
+       return res;
+}
+
+/* ******************** Actions ******************** */
+
+static WebKitDOMElement *
+get_table_cell_element (WebKitDOMDocument *document)
+{
+       return webkit_dom_document_get_element_by_id (document, "-x-evo-table-cell");
+}
+
+static void
+prepare_history_for_table (EEditorPage *editor_page,
+                           WebKitDOMElement *table,
+                           EEditorHistoryEvent *ev)
+{
+       ev->type = HISTORY_TABLE_DIALOG;
+
+       e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y, 
&ev->before.end.x, &ev->before.end.y);
+
+       ev->data.dom.from = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (table), TRUE, NULL);
+}
+
+
+static void
+save_history_for_table (EEditorPage *editor_page,
+                        WebKitDOMElement *table,
+                        EEditorHistoryEvent *ev)
+{
+       EEditorUndoRedoManager *manager;
+
+       if (table)
+               ev->data.dom.to = webkit_dom_node_clone_node_with_error (
+                       WEBKIT_DOM_NODE (table), TRUE, NULL);
+       else
+               ev->data.dom.to = NULL;
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &ev->after.start.x, &ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+void
+e_editor_dom_delete_cell_contents (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *node;
+       WebKitDOMElement *cell, *table_cell, *table;
+       EEditorHistoryEvent *ev = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+       if (!cell)
+               cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+       g_return_if_fail (cell != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       while ((node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (cell))))
+               remove_node (node);
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_delete_column (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *cell, *table, *table_cell;
+       WebKitDOMHTMLCollection *rows;
+       EEditorHistoryEvent *ev = NULL;
+       gulong index, length, ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       /* Find TD in which the selection starts */
+       cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+       if (!cell)
+               cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+       g_return_if_fail (cell != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       rows = webkit_dom_html_table_element_get_rows (
+                       WEBKIT_DOM_HTML_TABLE_ELEMENT (table));
+       length = webkit_dom_html_collection_get_length (rows);
+
+       index = webkit_dom_html_table_cell_element_get_cell_index (
+                       WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *row;
+
+               row = webkit_dom_html_collection_item (rows, ii);
+
+               webkit_dom_html_table_row_element_delete_cell (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index, NULL);
+               g_object_unref (row);
+       }
+
+       g_object_unref (rows);
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_delete_row (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *row, *table, *table_cell;
+       EEditorHistoryEvent *ev = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+       g_return_if_fail (row != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       remove_node (WEBKIT_DOM_NODE (row));
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_delete_table (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *table, *table_cell;
+       EEditorHistoryEvent *ev = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       remove_node (WEBKIT_DOM_NODE (table));
+
+       save_history_for_table (editor_page, NULL, ev);
+}
+
+void
+e_editor_dom_insert_column_after (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *cell, *row, *table_cell, *table;
+       EEditorHistoryEvent *ev = NULL;
+       gulong index;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+       if (!cell)
+               cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+       g_return_if_fail (cell != NULL);
+
+       row = dom_node_find_parent_element (WEBKIT_DOM_NODE (cell), "TR");
+       g_return_if_fail (row != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       /* Get the first row in the table */
+       row = WEBKIT_DOM_ELEMENT (
+               webkit_dom_node_get_first_child (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
+
+       index = webkit_dom_html_table_cell_element_get_cell_index (
+                       WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+       while (row) {
+               webkit_dom_html_table_row_element_insert_cell (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index + 1, NULL);
+
+               row = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
+       }
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_insert_column_before (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *cell, *row, *table_cell, *table;
+       EEditorHistoryEvent *ev = NULL;
+       gulong index;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TD");
+       if (!cell) {
+               cell = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TH");
+       }
+       g_return_if_fail (cell != NULL);
+
+       row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+       g_return_if_fail (row != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       /* Get the first row in the table */
+       row = WEBKIT_DOM_ELEMENT (
+               webkit_dom_node_get_first_child (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (row))));
+
+       index = webkit_dom_html_table_cell_element_get_cell_index (
+                       WEBKIT_DOM_HTML_TABLE_CELL_ELEMENT (cell));
+
+       while (row) {
+               webkit_dom_html_table_row_element_insert_cell (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row), index - 1, NULL);
+
+               row = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (row)));
+       }
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_insert_row_above (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *row, *table, *table_cell;
+       WebKitDOMHTMLCollection *cells;
+       WebKitDOMHTMLElement *new_row;
+       EEditorHistoryEvent *ev = NULL;
+       gulong index, cell_count, ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+       g_return_if_fail (row != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       index = webkit_dom_html_table_row_element_get_row_index (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+       new_row = webkit_dom_html_table_element_insert_row (
+                       WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index, NULL);
+
+       cells = webkit_dom_html_table_row_element_get_cells (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+       cell_count = webkit_dom_html_collection_get_length (cells);
+       for (ii = 0; ii < cell_count; ii++) {
+               webkit_dom_html_table_row_element_insert_cell (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+       }
+
+       g_object_unref (cells);
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_insert_row_below (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *row, *table, *table_cell;
+       WebKitDOMHTMLCollection *cells;
+       WebKitDOMHTMLElement *new_row;
+       EEditorHistoryEvent *ev = NULL;
+       gulong index, cell_count, ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       table_cell = get_table_cell_element (document);
+       g_return_if_fail (table_cell != NULL);
+
+       row = dom_node_find_parent_element (WEBKIT_DOM_NODE (table_cell), "TR");
+       g_return_if_fail (row != NULL);
+
+       table = dom_node_find_parent_element (WEBKIT_DOM_NODE (row), "TABLE");
+       g_return_if_fail (table != NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       prepare_history_for_table (editor_page, table, ev);
+
+       index = webkit_dom_html_table_row_element_get_row_index (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+
+       new_row = webkit_dom_html_table_element_insert_row (
+                       WEBKIT_DOM_HTML_TABLE_ELEMENT (table), index + 1, NULL);
+
+       cells = webkit_dom_html_table_row_element_get_cells (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (row));
+       cell_count = webkit_dom_html_collection_get_length (cells);
+       for (ii = 0; ii < cell_count; ii++) {
+               webkit_dom_html_table_row_element_insert_cell (
+                       WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (new_row), -1, NULL);
+       }
+
+       g_object_unref (cells);
+
+       save_history_for_table (editor_page, table, ev);
+}
+
+void
+e_editor_dom_save_history_for_cut (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range;
+       EEditorHistoryEvent *ev;
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection) ||
+           webkit_dom_dom_selection_get_is_collapsed (dom_selection)) {
+               g_object_unref (dom_selection);
+               return;
+       }
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       ev->type = HISTORY_DELETE;
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &ev->before.start.x,
+               &ev->before.start.y,
+               &ev->before.end.x,
+               &ev->before.end.y);
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       ev->after.start.x = ev->before.start.x;
+       ev->after.start.y = ev->before.start.y;
+       ev->after.end.x = ev->before.start.x;
+       ev->after.end.y = ev->before.start.y;
+
+       /* Save the fragment. */
+       fragment = webkit_dom_range_clone_contents (range, NULL);
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       ev->data.fragment = g_object_ref (fragment);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+/* ******************** View ******************** */
+
+/*
+ * e_editor_dom_exec_command:
+ * @document: a #WebKitDOMDocument
+ * @command: an #EContentEditorCommand to execute
+ * @value: value of the command (or @NULL if the command does not require value)
+ *
+ * The function will fail when @value is @NULL or empty but the current @command
+ * requires a value to be passed. The @value is ignored when the @command does
+ * not expect any value.
+ *
+ * Returns: @TRUE when the command was succesfully executed, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_exec_command (EEditorPage *editor_page,
+                          EContentEditorCommand command,
+                          const gchar *value)
+{
+       const gchar *cmd_str = 0;
+       gboolean has_value = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+#define CHECK_COMMAND(cmd,str,val) case cmd:\
+       if (val) {\
+               g_return_val_if_fail (value && *value, FALSE);\
+       }\
+       has_value = val; \
+       cmd_str = str;\
+       break;
+
+       switch (command) {
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR, "BackColor", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_BOLD, "Bold", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_COPY, "Copy", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_CREATE_LINK, "CreateLink", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_CUT, "Cut", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR, 
"DefaultParagraphSeparator", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_DELETE, "Delete", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FIND_STRING, "FindString", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_NAME, "FontName", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_SIZE, "FontSize", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FONT_SIZE_DELTA, "FontSizeDelta", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORE_COLOR, "ForeColor", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORMAT_BLOCK, "FormatBlock", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE, "ForwardDelete", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_HILITE_COLOR, "HiliteColor", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INDENT, "Indent", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_HORIZONTAL_RULE, "InsertHorizontalRule", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_HTML, "InsertHTML", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_IMAGE, "InsertImage", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_LINE_BREAK, "InsertLineBreak", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, 
"InsertNewlineInQuotedContent", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_ORDERED_LIST, "InsertOrderedList", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_PARAGRAPH, "InsertParagraph", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, "InsertText", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_INSERT_UNORDERED_LIST, "InsertUnorderedList", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_ITALIC, "Italic", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_CENTER, "JustifyCenter", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_FULL, "JustifyFull", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_LEFT, "JustifyLeft", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_NONE, "JustifyNone", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_JUSTIFY_RIGHT, "JustifyRight", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_OUTDENT, "Outdent", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE, "Paste", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE_AND_MATCH_STYLE, "PasteAndMatchStyle", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PASTE_AS_PLAIN_TEXT, "PasteAsPlainText", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_PRINT, "Print", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_REDO, "Redo", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_REMOVE_FORMAT, "RemoveFormat", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SELECT_ALL, "SelectAll", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH, "Strikethrough", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS, "StyleWithCSS", TRUE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SUBSCRIPT, "Subscript", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT, "Superscript", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_TRANSPOSE, "Transpose", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNDERLINE, "Underline", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNDO, "Undo", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNLINK, "Unlink", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_UNSELECT, "Unselect", FALSE)
+               CHECK_COMMAND (E_CONTENT_EDITOR_COMMAND_USE_CSS, "UseCSS", TRUE)
+       }
+
+       e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
+
+       return webkit_dom_document_exec_command (
+               e_editor_page_get_document (editor_page), cmd_str, FALSE, has_value ? value : "" );
+}
+
+static void
+perform_spell_check (WebKitDOMDOMSelection *dom_selection,
+                     WebKitDOMRange *start_range,
+                     WebKitDOMRange *end_range)
+{
+       WebKitDOMRange *actual = start_range;
+
+       /* FIXME WK2: this doesn't work, the cursor is moved, but the spellcheck is not updated */
+       /* Go through all words to spellcheck them. To avoid this we have to wait for
+        * http://www.w3.org/html/wg/drafts/html/master/editing.html#dom-forcespellcheck */
+       /* We are moving forward word by word until we hit the text on the end. */
+       while (actual && webkit_dom_range_compare_boundary_points (end_range, WEBKIT_DOM_RANGE_END_TO_END, 
actual, NULL) != 0) {
+               g_object_unref (actual);
+               webkit_dom_dom_selection_modify (
+                       dom_selection, "move", "forward", "word");
+               actual = webkit_dom_dom_selection_get_range_at (
+                       dom_selection, 0, NULL);
+       }
+       g_clear_object (&actual);
+}
+
+void
+e_editor_dom_force_spell_check_for_current_paragraph (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMElement *parent, *element;
+       WebKitDOMRange *end_range, *actual;
+       WebKitDOMText *text;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       if (!e_editor_page_get_inline_spelling_enabled (editor_page))
+               return;
+
+       document = e_editor_page_get_document (editor_page);
+       element = webkit_dom_document_query_selector (
+               document, "body[spellcheck=true]", NULL);
+
+       if (!element)
+               return;
+
+       if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))
+               return;
+
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker || !selection_end_marker)
+               return;
+
+       /* Block callbacks of selection-changed signal as we don't want to
+        * recount all the block format things in EEditorSelection and here as well
+        * when we are moving with caret */
+       e_editor_page_block_selection_changed (editor_page);
+
+       parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_end_marker));
+
+       /* Append some text on the end of the element */
+       text = webkit_dom_document_create_text_node (document, "-x-evo-end");
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (parent),
+               WEBKIT_DOM_NODE (text),
+               NULL);
+
+       parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker));
+
+       /* Create range that's pointing on the end of this text */
+       end_range = webkit_dom_document_create_range (document);
+       webkit_dom_range_select_node_contents (
+               end_range, WEBKIT_DOM_NODE (text), NULL);
+       webkit_dom_range_collapse (end_range, FALSE, NULL);
+
+       /* Move on the beginning of the paragraph */
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       actual = webkit_dom_document_create_range (document);
+       webkit_dom_range_select_node_contents (
+               actual, WEBKIT_DOM_NODE (parent), NULL);
+       webkit_dom_range_collapse (actual, TRUE, NULL);
+       webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+       webkit_dom_dom_selection_add_range (dom_selection, actual);
+
+       actual = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       perform_spell_check (dom_selection, actual, end_range);
+
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+       g_object_unref (end_range);
+
+       /* Remove the text that we inserted on the end of the paragraph */
+       remove_node (WEBKIT_DOM_NODE (text));
+
+       /* Unblock the callbacks */
+       e_editor_page_unblock_selection_changed (editor_page);
+
+       e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+refresh_spell_check (EEditorPage *editor_page,
+                     gboolean enable_spell_check)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMRange *end_range, *actual;
+       WebKitDOMText *text;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       body = webkit_dom_document_get_body (document);
+
+       if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)))
+               return;
+
+       /* Enable/Disable spellcheck in composer */
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (body),
+               "spellcheck",
+               enable_spell_check ? "true" : "false",
+               NULL);
+       webkit_dom_html_element_set_spellcheck (body, FALSE);
+       webkit_dom_html_element_set_spellcheck (body, enable_spell_check);
+       return;
+
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       /* Sometimes the web view is not focused, so we have to save the selection
+        * manually into the body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMNode *child;
+
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+               if (!WEBKIT_DOM_IS_HTML_ELEMENT (child))
+                       return;
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+       }
+
+       /* Block callbacks of selection-changed signal as we don't want to
+        * recount all the block format things in EEditorSelection and here as well
+        * when we are moving with caret */
+       e_editor_page_block_selection_changed (editor_page);
+
+       /* Append some text on the end of the body */
+       text = webkit_dom_document_create_text_node (document, "-x-evo-end");
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (text), NULL);
+
+       /* Create range that's pointing on the end of this text */
+       end_range = webkit_dom_document_create_range (document);
+       webkit_dom_range_select_node_contents (
+               end_range, WEBKIT_DOM_NODE (text), NULL);
+       webkit_dom_range_collapse (end_range, FALSE, NULL);
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       /* Move on the beginning of the document */
+       webkit_dom_dom_selection_modify (
+               dom_selection, "move", "backward", "documentboundary");
+
+       actual = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       perform_spell_check (dom_selection, actual, end_range);
+
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+       g_object_unref (end_range);
+
+       /* Remove the text that we inserted on the end of the body */
+       remove_node (WEBKIT_DOM_NODE (text));
+
+       /* Unblock the callbacks */
+       e_editor_page_unblock_selection_changed (editor_page);
+
+       e_editor_dom_selection_restore (editor_page);
+}
+
+void
+e_editor_dom_turn_spell_check_off (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       refresh_spell_check (editor_page, FALSE);
+}
+
+void
+e_editor_dom_force_spell_check_in_viewport (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMElement *last_element;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMRange *end_range, *actual;
+       WebKitDOMText *text;
+       glong viewport_height;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!e_editor_page_get_inline_spelling_enabled (editor_page))
+               return;
+
+       document = e_editor_page_get_document (editor_page);
+       body = WEBKIT_DOM_HTML_ELEMENT (webkit_dom_document_query_selector (
+               document, "body[spellcheck=true]", NULL));
+
+       if (!body) {
+               body = webkit_dom_document_get_body (document);
+               webkit_dom_element_set_attribute (
+                       WEBKIT_DOM_ELEMENT (body), "spellcheck", "true", NULL);
+       }
+
+       if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)))
+               return;
+
+       e_editor_dom_selection_save (editor_page);
+
+       /* Block callbacks of selection-changed signal as we don't want to
+        * recount all the block format things in EEditorSelection and here as well
+        * when we are moving with caret */
+       e_editor_page_block_selection_changed (editor_page);
+
+       /* We have to add 10 px offset as otherwise just the HTML element will be returned */
+       actual = webkit_dom_document_caret_range_from_point (document, 10, 10);
+       if (!actual)
+               return;
+
+       /* Append some text on the end of the body */
+       text = webkit_dom_document_create_text_node (document, "-x-evo-end");
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       /* We have to add 10 px offset as otherwise just the HTML element will be returned */
+       viewport_height = webkit_dom_dom_window_get_inner_height (dom_window);
+       last_element = webkit_dom_document_element_from_point (document, 10, viewport_height - 10);
+       if (last_element && !WEBKIT_DOM_IS_HTML_HTML_ELEMENT (last_element) &&
+           !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (last_element)) {
+               WebKitDOMElement *parent;
+
+               parent = get_parent_block_element (WEBKIT_DOM_NODE (last_element));
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (parent), WEBKIT_DOM_NODE (text), NULL);
+       } else
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (text), NULL);
+
+       /* Create range that's pointing on the end of viewport */
+       end_range = webkit_dom_document_create_range (document);
+       webkit_dom_range_select_node_contents (
+               end_range, WEBKIT_DOM_NODE (text), NULL);
+       webkit_dom_range_collapse (end_range, FALSE, NULL);
+
+       webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+       webkit_dom_dom_selection_add_range (dom_selection, actual);
+       perform_spell_check (dom_selection, actual, end_range);
+
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+       g_object_unref (end_range);
+
+       /* Remove the text that we inserted on the end of the body */
+       remove_node (WEBKIT_DOM_NODE (text));
+
+       /* Unblock the callbacks */
+       e_editor_page_unblock_selection_changed (editor_page);
+
+       e_editor_dom_selection_restore (editor_page);
+}
+
+void
+e_editor_dom_force_spell_check (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_get_inline_spelling_enabled (editor_page))
+               refresh_spell_check (editor_page, TRUE);
+}
+
+gboolean
+e_editor_dom_node_is_citation_node (WebKitDOMNode *node)
+{
+       gchar *value;
+
+       if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node))
+               return FALSE;
+
+       value = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "type");
+
+       /* citation == <blockquote type='cite'> */
+       if (value && g_strcmp0 (value, "cite") == 0) {
+               g_free (value);
+               return TRUE;
+       } else {
+               g_free (value);
+               return FALSE;
+       }
+}
+
+gint
+e_editor_dom_get_citation_level (WebKitDOMNode *node,
+                                gboolean set_plaintext_quoted)
+{
+       WebKitDOMNode *parent = node;
+       gint level = 0;
+
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+                   webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "type")) {
+                       level++;
+
+                       if (set_plaintext_quoted) {
+                               element_add_class (
+                                       WEBKIT_DOM_ELEMENT (parent),
+                                       "-x-evo-plaintext-quoted");
+                       }
+               }
+
+               parent = webkit_dom_node_get_parent_node (parent);
+       }
+
+       return level;
+}
+
+static gchar *
+get_quotation_for_level (gint quote_level)
+{
+       gint ii;
+       GString *output = g_string_new ("");
+
+       for (ii = 0; ii < quote_level; ii++) {
+               g_string_append (output, "<span class=\"-x-evo-quote-character\">");
+               g_string_append (output, QUOTE_SYMBOL);
+               g_string_append (output, " ");
+               g_string_append (output, "</span>");
+       }
+
+       return g_string_free (output, FALSE);
+}
+
+void
+e_editor_dom_quote_plain_text_element_after_wrapping (EEditorPage *editor_page,
+                                                     WebKitDOMElement *element,
+                                                     gint quote_level)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       WebKitDOMNode *quoted_node;
+       gint length, ii;
+       gchar *quotation;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       quoted_node = WEBKIT_DOM_NODE (
+               webkit_dom_document_create_element (document, "SPAN", NULL));
+       webkit_dom_element_set_class_name (
+               WEBKIT_DOM_ELEMENT (quoted_node), "-x-evo-quoted");
+       quotation = get_quotation_for_level (quote_level);
+       webkit_dom_element_set_inner_html (
+               WEBKIT_DOM_ELEMENT (quoted_node), quotation, NULL);
+
+       list = webkit_dom_element_query_selector_all (
+               element, "br.-x-evo-wrap-br", NULL);
+       webkit_dom_node_insert_before (
+               WEBKIT_DOM_NODE (element),
+               quoted_node,
+               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)),
+               NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *br = webkit_dom_node_list_item (list, ii);
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (br),
+                       webkit_dom_node_clone_node_with_error (quoted_node, TRUE, NULL),
+                       webkit_dom_node_get_next_sibling (br),
+                       NULL);
+               g_object_unref (br);
+       }
+
+       g_object_unref (list);
+       g_free (quotation);
+}
+
+static gboolean
+return_pressed_in_empty_line (EEditorPage *editor_page)
+{
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return FALSE;
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (!WEBKIT_DOM_IS_TEXT (node)) {
+               WebKitDOMNode *first_child;
+
+               first_child = webkit_dom_node_get_first_child (node);
+               if (first_child && WEBKIT_DOM_IS_ELEMENT (first_child) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (first_child), "-x-evo-quoted")) {
+                       WebKitDOMNode *prev_sibling;
+
+                       prev_sibling = webkit_dom_node_get_previous_sibling (node);
+                       if (!prev_sibling) {
+                               gboolean collapsed;
+
+                               collapsed = webkit_dom_range_get_collapsed (range, NULL);
+                               g_object_unref (range);
+                               return collapsed;
+                       }
+               }
+       }
+
+       g_object_unref (range);
+
+       return FALSE;
+}
+
+WebKitDOMNode *
+e_editor_dom_get_parent_block_node_from_child (WebKitDOMNode *node)
+{
+       WebKitDOMNode *parent = node;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (parent) ||
+           e_editor_dom_is_selection_position_node (parent))
+               parent = webkit_dom_node_get_parent_node (parent);
+
+       if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-temp-text-wrapper") ||
+           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quoted") ||
+           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quote-character") ||
+           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-signature") ||
+           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper") ||
+           WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) ||
+           element_has_tag (WEBKIT_DOM_ELEMENT (parent), "b") ||
+           element_has_tag (WEBKIT_DOM_ELEMENT (parent), "i") ||
+           element_has_tag (WEBKIT_DOM_ELEMENT (parent), "u"))
+               parent = webkit_dom_node_get_parent_node (parent);
+
+       if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quoted") ||
+           element_has_class (WEBKIT_DOM_ELEMENT (parent), "Apple-tab-span"))
+               parent = webkit_dom_node_get_parent_node (parent);
+
+       return parent;
+}
+
+WebKitDOMElement *
+e_editor_dom_wrap_and_quote_element (EEditorPage *editor_page,
+                                    WebKitDOMElement *element)
+{
+       gint citation_level;
+       WebKitDOMElement *tmp_element = element;
+
+       g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (element), element);
+
+       if (e_editor_page_get_html_mode (editor_page))
+               return element;
+
+       citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (element), FALSE);
+
+       e_editor_dom_remove_quoting_from_element (element);
+       e_editor_dom_remove_wrapping_from_element (element);
+
+       if (WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (element) &&
+           webkit_dom_element_has_attribute (element, "data-evo-paragraph")) {
+               gint word_wrap_length, length;
+
+               word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+               length = word_wrap_length - 2 * citation_level;
+               tmp_element = e_editor_dom_wrap_paragraph_length (
+                       editor_page, element, length);
+       }
+
+       if (citation_level > 0) {
+
+               webkit_dom_node_normalize (WEBKIT_DOM_NODE (tmp_element));
+               e_editor_dom_quote_plain_text_element_after_wrapping (
+                       editor_page, tmp_element, citation_level);
+       }
+
+       return tmp_element;
+}
+
+WebKitDOMElement *
+e_editor_dom_insert_new_line_into_citation (EEditorPage *editor_page,
+                                           const gchar *html_to_insert)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *paragraph = NULL;
+       WebKitDOMNode *last_block;
+       gboolean html_mode = FALSE, ret_val, avoid_editor_call;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       avoid_editor_call = return_pressed_in_empty_line (editor_page);
+
+       if (avoid_editor_call) {
+               WebKitDOMElement *selection_start_marker;
+               WebKitDOMNode *current_block, *parent, *parent_block, *block_clone;
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+
+               current_block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+               block_clone = webkit_dom_node_clone_node_with_error (current_block, TRUE, NULL);
+               /* Find selection start marker and restore it after the new line
+                * is inserted */
+               selection_start_marker = webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block_clone), "#-x-evo-selection-start-marker", NULL);
+
+               /* Find parent node that is immediate child of the BODY */
+               /* Build the same structure of parent nodes of the current block */
+               parent_block = current_block;
+               parent = webkit_dom_node_get_parent_node (parent_block);
+               while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+                       WebKitDOMNode *node;
+
+                       parent_block = parent;
+                       node = webkit_dom_node_clone_node_with_error (parent_block, FALSE, NULL);
+                       webkit_dom_node_append_child (node, block_clone, NULL);
+                       block_clone = node;
+                       parent = webkit_dom_node_get_parent_node (parent_block);
+               }
+
+               paragraph = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (paragraph),
+                       WEBKIT_DOM_NODE (
+                               webkit_dom_document_create_element (document, "BR", NULL)),
+                       NULL);
+
+               /* Insert the selection markers to right place */
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (paragraph),
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_start_marker)),
+                       webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)),
+                       NULL);
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (paragraph),
+                       WEBKIT_DOM_NODE (selection_start_marker),
+                       webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (paragraph)),
+                       NULL);
+
+               /* Insert the cloned nodes before the BODY parent node */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (parent_block),
+                       block_clone,
+                       parent_block,
+                       NULL);
+
+               /* Insert the new empty paragraph before the BODY parent node */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (parent_block),
+                       WEBKIT_DOM_NODE (paragraph),
+                       parent_block,
+                       NULL);
+
+               /* Remove the old block (its copy was moved to the right place) */
+               remove_node (current_block);
+
+               e_editor_dom_selection_restore (editor_page);
+
+               return NULL;
+       } else {
+               e_editor_dom_remove_input_event_listener_from_body (editor_page);
+               e_editor_page_block_selection_changed (editor_page);
+
+               ret_val = e_editor_dom_exec_command (
+                       editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, NULL);
+
+               e_editor_page_unblock_selection_changed (editor_page);
+               e_editor_dom_register_input_event_listener_on_body (editor_page);
+
+               if (!ret_val)
+                       return NULL;
+
+               element = webkit_dom_document_query_selector (
+                       document, "body>br", NULL);
+
+               if (!element)
+                       return NULL;
+       }
+
+       last_block = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+       while (last_block && e_editor_dom_node_is_citation_node (last_block))
+               last_block = webkit_dom_node_get_last_child (last_block);
+
+       if (last_block) {
+               WebKitDOMNode *last_child;
+
+               if ((last_child = webkit_dom_node_get_last_child (last_block))) {
+                       if (WEBKIT_DOM_IS_ELEMENT (last_child) &&
+                           element_has_class (WEBKIT_DOM_ELEMENT (last_child), "-x-evo-quoted"))
+                               webkit_dom_node_append_child (
+                                       last_block,
+                                       WEBKIT_DOM_NODE (
+                                               webkit_dom_document_create_element (
+                                                       document, "br", NULL)),
+                                       NULL);
+               }
+       }
+
+       if (!html_mode) {
+               WebKitDOMNode *sibling;
+
+               sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+               if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (sibling)) {
+                       WebKitDOMNode *node;
+
+                       node = webkit_dom_node_get_first_child (sibling);
+                       while (node && e_editor_dom_node_is_citation_node (node))
+                               node = webkit_dom_node_get_first_child (node);
+
+                       /* Rewrap and requote nodes that were created by split. */
+                       if (WEBKIT_DOM_IS_ELEMENT (node))
+                               e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (node));
+
+                       if (WEBKIT_DOM_IS_ELEMENT (last_block))
+                               e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT 
(last_block));
+
+                       e_editor_dom_force_spell_check_in_viewport (editor_page);
+               }
+       }
+
+       if (html_to_insert && *html_to_insert) {
+               paragraph = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+               webkit_dom_element_set_inner_html (
+                       paragraph, html_to_insert, NULL);
+               if (!webkit_dom_element_query_selector (paragraph, "#-x-evo-selection-start-marker", NULL))
+                       dom_add_selection_markers_into_element_end (
+                               document, paragraph, NULL, NULL);
+       } else
+               paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+               WEBKIT_DOM_NODE (paragraph),
+               WEBKIT_DOM_NODE (element),
+               NULL);
+
+       remove_node (WEBKIT_DOM_NODE (element));
+
+       e_editor_dom_selection_restore (editor_page);
+
+       return paragraph;
+}
+
+/* For purpose of this function see e-mail-formatter-quote.c */
+static void
+put_body_in_citation (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *cite_body = webkit_dom_document_query_selector (
+               document, "span.-x-evo-cite-body", NULL);
+
+       if (cite_body) {
+               WebKitDOMHTMLElement *body = webkit_dom_document_get_body (document);
+               WebKitDOMNode *citation;
+               WebKitDOMNode *sibling;
+
+               citation = WEBKIT_DOM_NODE (
+                       webkit_dom_document_create_element (document, "blockquote", NULL));
+               webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (citation), "-x-evo-main-cite");
+               webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (citation), "type", "cite", NULL);
+
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (body),
+                       citation,
+                       webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)),
+                       NULL);
+
+               while ((sibling = webkit_dom_node_get_next_sibling (citation)))
+                       webkit_dom_node_append_child (citation, sibling, NULL);
+
+               remove_node (WEBKIT_DOM_NODE (cite_body));
+       }
+}
+
+/* For purpose of this function see e-mail-formatter-quote.c */
+static void
+move_elements_to_body (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMNodeList *list;
+       gint ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       body = webkit_dom_document_get_body (document);
+       list = webkit_dom_document_query_selector_all (
+               document, "div[data-headers]", NULL);
+       for (ii = webkit_dom_node_list_get_length (list) - 1; ii >= 0; ii--) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               webkit_dom_element_remove_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "data-headers");
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (body),
+                       node,
+                       webkit_dom_node_get_first_child (
+                               WEBKIT_DOM_NODE (body)),
+                       NULL);
+
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       list = webkit_dom_document_query_selector_all (
+               document, "span.-x-evo-to-body[data-credits]", NULL);
+       for (ii = webkit_dom_node_list_get_length (list) - 1; ii >= 0; ii--) {
+               char *credits;
+               WebKitDOMElement *element;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+               credits = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "data-credits");
+               if (credits)
+                       webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (element), credits, 
NULL);
+               g_free (credits);
+
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (body),
+                       WEBKIT_DOM_NODE (element),
+                       webkit_dom_node_get_first_child (
+                               WEBKIT_DOM_NODE (body)),
+                       NULL);
+
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+}
+
+static void
+repair_gmail_blockquotes (WebKitDOMDocument *document)
+{
+       WebKitDOMNodeList *list;
+       gint ii, length;
+
+       list = webkit_dom_document_query_selector_all (
+               document, "blockquote.gmail_quote", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "class");
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "style");
+               webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (node), "type", "cite", NULL);
+
+               if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (node)))
+                       webkit_dom_node_append_child (
+                               node,
+                               WEBKIT_DOM_NODE (
+                                       webkit_dom_document_create_element (
+                                               document, "br", NULL)),
+                               NULL);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+}
+
+static void
+remove_thunderbird_signature (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *signature;
+
+       signature = webkit_dom_document_query_selector (
+               document, "pre.moz-signature", NULL);
+       if (signature)
+               remove_node (WEBKIT_DOM_NODE (signature));
+}
+
+void
+e_editor_dom_check_magic_links (EEditorPage *editor_page,
+                               gboolean include_space_by_user)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       gchar *node_text;
+       gchar **urls;
+       gboolean include_space = FALSE;
+       gboolean is_email_address = FALSE;
+       gboolean return_key_pressed;
+       GRegex *regex = NULL;
+       GMatchInfo *match_info;
+       gint start_pos_url, end_pos_url;
+       gboolean has_selection;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!e_editor_page_get_magic_links_enabled (editor_page))
+               return;
+
+       return_key_pressed = e_editor_page_get_return_key_pressed (editor_page);
+       document = e_editor_page_get_document (editor_page);
+
+       if (include_space_by_user)
+               include_space = TRUE;
+       else
+               include_space = e_editor_page_get_return_key_pressed (editor_page);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       node = webkit_dom_range_get_end_container (range, NULL);
+       has_selection = !webkit_dom_range_get_collapsed (range, NULL);
+       g_object_unref (range);
+
+       if (return_key_pressed) {
+               WebKitDOMNode* block;
+
+               block = e_editor_dom_get_parent_block_node_from_child (node);
+               /* Get previous block */
+               if (!(block = webkit_dom_node_get_previous_sibling (block)))
+                       return;
+
+               /* If block is quoted content, get the last block there */
+               while (block && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (block))
+                       block = webkit_dom_node_get_last_child (block);
+
+               /* Get the last non-empty node */
+               node = webkit_dom_node_get_last_child (block);
+               if (WEBKIT_DOM_IS_CHARACTER_DATA (node) &&
+                   webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)) == 0)
+                       node = webkit_dom_node_get_previous_sibling (node);
+       } else {
+               e_editor_dom_selection_save (editor_page);
+               if (has_selection) {
+                       WebKitDOMElement *selection_end_marker;
+
+                       selection_end_marker = webkit_dom_document_get_element_by_id (
+                               document, "-x-evo-selection-end-marker");
+
+                       node = webkit_dom_node_get_previous_sibling (
+                               WEBKIT_DOM_NODE (selection_end_marker));
+               }
+       }
+
+       if (!node || WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node))
+               goto out;
+
+       if (!WEBKIT_DOM_IS_TEXT (node)) {
+               if (webkit_dom_node_has_child_nodes (node))
+                       node = webkit_dom_node_get_first_child (node);
+               if (!WEBKIT_DOM_IS_TEXT (node))
+                       goto out;
+       }
+
+       node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node));
+       if (!(node_text && *node_text) || !g_utf8_validate (node_text, -1, NULL)) {
+               g_free (node_text);
+               goto out;
+       }
+
+       if (strstr (node_text, "@") && !strstr (node_text, "://")) {
+               is_email_address = TRUE;
+               regex = g_regex_new (include_space ? E_MAIL_PATTERN_SPACE : E_MAIL_PATTERN, 0, 0, NULL);
+       } else
+               regex = g_regex_new (include_space ? URL_PATTERN_SPACE : URL_PATTERN, 0, 0, NULL);
+
+       if (!regex) {
+               g_free (node_text);
+               goto out;
+       }
+
+       g_regex_match_all (regex, node_text, G_REGEX_MATCH_NOTEMPTY, &match_info);
+       urls = g_match_info_fetch_all (match_info);
+
+       if (urls) {
+               const gchar *end_of_match = NULL;
+               gchar *final_url, *url_end_raw, *url_text;
+               glong url_start, url_end, url_length;
+               WebKitDOMNode *url_text_node;
+               WebKitDOMElement *anchor;
+
+               g_match_info_fetch_pos (match_info, 0, &start_pos_url, &end_pos_url);
+
+               /* Get start and end position of url in node's text because positions
+                * that we get from g_match_info_fetch_pos are not UTF-8 aware */
+               url_end_raw = g_strndup(node_text, end_pos_url);
+               url_end = g_utf8_strlen (url_end_raw, -1);
+               url_length = g_utf8_strlen (urls[0], -1);
+
+               end_of_match = url_end_raw + end_pos_url - (include_space ? 3 : 2);
+               /* URLs are extremely unlikely to end with any punctuation, so
+                * strip any trailing punctuation off from link and put it after
+                * the link. Do the same for any closing double-quotes as well. */
+               while (end_of_match && end_of_match != url_end_raw && strchr (URL_INVALID_TRAILING_CHARS, 
*end_of_match)) {
+                       url_length--;
+                       url_end--;
+                       end_of_match--;
+               }
+
+               url_start = url_end - url_length;
+
+               webkit_dom_text_split_text (
+                       WEBKIT_DOM_TEXT (node),
+                       include_space ? url_end - 1 : url_end,
+                       NULL);
+
+               webkit_dom_text_split_text (
+                       WEBKIT_DOM_TEXT (node), url_start, NULL);
+               url_text_node = webkit_dom_node_get_next_sibling (node);
+               url_text = webkit_dom_character_data_get_data (
+                       WEBKIT_DOM_CHARACTER_DATA (url_text_node));
+
+               if (g_str_has_prefix (url_text, "www."))
+                       final_url = g_strconcat ("http://"; , url_text, NULL);
+               else if (is_email_address)
+                       final_url = g_strconcat ("mailto:"; , url_text, NULL);
+               else
+                       final_url = g_strdup (url_text);
+
+               /* Create and prepare new anchor element */
+               anchor = webkit_dom_document_create_element (document, "A", NULL);
+
+               webkit_dom_element_set_inner_html (anchor, url_text, NULL);
+
+               webkit_dom_html_anchor_element_set_href (
+                       WEBKIT_DOM_HTML_ANCHOR_ELEMENT (anchor),
+                       final_url);
+
+               /* Insert new anchor element into document */
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (node),
+                       WEBKIT_DOM_NODE (anchor),
+                       WEBKIT_DOM_NODE (url_text_node),
+                       NULL);
+
+               g_free (url_end_raw);
+               g_free (final_url);
+               g_free (url_text);
+       } else {
+               gboolean appending_to_link = FALSE;
+               gchar *href, *text, *url, *text_to_append = NULL;
+               gint diff;
+               WebKitDOMElement *parent;
+               WebKitDOMNode *prev_sibling;
+
+               parent = webkit_dom_node_get_parent_element (node);
+               prev_sibling = webkit_dom_node_get_previous_sibling (node);
+
+               /* If previous sibling is ANCHOR and actual text node is not beginning with
+                * space => we're appending to link */
+               if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) {
+                       text_to_append = webkit_dom_node_get_text_content (node);
+                       if (text_to_append && *text_to_append &&
+                           !strstr (text_to_append, " ") &&
+                           !(strchr (URL_INVALID_TRAILING_CHARS, *text_to_append) &&
+                             !(*text_to_append == '?' && strlen(text_to_append) > 1)) &&
+                           !g_str_has_prefix (text_to_append, UNICODE_NBSP)) {
+
+                               appending_to_link = TRUE;
+                               parent = WEBKIT_DOM_ELEMENT (prev_sibling);
+                               /* If the node(text) contains the some of unwanted characters
+                                * split it into two nodes and select the right one. */
+                               if (g_str_has_suffix (text_to_append, UNICODE_NBSP) ||
+                                   g_str_has_suffix (text_to_append, UNICODE_ZERO_WIDTH_SPACE)) {
+                                       webkit_dom_text_split_text (
+                                               WEBKIT_DOM_TEXT (node),
+                                               g_utf8_strlen (text_to_append, -1) - 1,
+                                               NULL);
+                                       g_free (text_to_append);
+                                       text_to_append = webkit_dom_node_get_text_content (node);
+                               }
+                       }
+               }
+
+               /* If parent is ANCHOR => we're editing the link */
+               if ((!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) && !appending_to_link) || !text_to_append) {
+                       g_match_info_free (match_info);
+                       g_regex_unref (regex);
+                       g_free (node_text);
+                       g_free (text_to_append);
+                       goto out;
+               }
+
+               /* edit only if href and description are the same */
+               href = webkit_dom_html_anchor_element_get_href (
+                       WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent));
+
+               if (appending_to_link) {
+                       gchar *inner_text;
+
+                       inner_text =
+                               webkit_dom_html_element_get_inner_text (
+                                       WEBKIT_DOM_HTML_ELEMENT (parent)),
+
+                       text = g_strconcat (inner_text, text_to_append, NULL);
+                       g_free (inner_text);
+               } else
+                       text = webkit_dom_html_element_get_inner_text (
+                                       WEBKIT_DOM_HTML_ELEMENT (parent));
+
+               element_remove_class (parent, "-x-evo-visited-link");
+
+               if (strstr (href, "://") && !strstr (text, "://")) {
+                       url = strstr (href, "://") + 3;
+                       diff = strlen (text) - strlen (url);
+
+                       if (text [strlen (text) - 1] != '/')
+                               diff++;
+
+                       if ((g_strcmp0 (url, text) != 0 && ABS (diff) == 1) || appending_to_link) {
+                               gchar *inner_html, *protocol, *new_href;
+
+                               protocol = g_strndup (href, strstr (href, "://") - href + 3);
+                               inner_html = webkit_dom_element_get_inner_html (parent);
+                               new_href = g_strconcat (
+                                       protocol, inner_html, appending_to_link ? text_to_append : "", NULL);
+
+                               webkit_dom_html_anchor_element_set_href (
+                                       WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent),
+                                       new_href);
+
+                               if (appending_to_link) {
+                                       webkit_dom_html_element_insert_adjacent_html (
+                                               WEBKIT_DOM_HTML_ELEMENT (parent),
+                                               "beforeend",
+                                               text_to_append,
+                                               NULL);
+
+                                       remove_node (node);
+                               }
+
+                               g_free (new_href);
+                               g_free (protocol);
+                               g_free (inner_html);
+                       }
+               } else {
+                       diff = strlen (text) - strlen (href);
+                       if (text [strlen (text) - 1] != '/')
+                               diff++;
+
+                       if ((g_strcmp0 (href, text) != 0 && ABS (diff) == 1) || appending_to_link) {
+                               gchar *inner_html;
+                               gchar *new_href;
+
+                               inner_html = webkit_dom_element_get_inner_html (parent);
+                               new_href = g_strconcat (
+                                               inner_html,
+                                               appending_to_link ? text_to_append : "",
+                                               NULL);
+
+                               webkit_dom_html_anchor_element_set_href (
+                                       WEBKIT_DOM_HTML_ANCHOR_ELEMENT (parent),
+                                       new_href);
+
+                               if (appending_to_link) {
+                                       webkit_dom_html_element_insert_adjacent_html (
+                                               WEBKIT_DOM_HTML_ELEMENT (parent),
+                                               "beforeend",
+                                               text_to_append,
+                                               NULL);
+
+                                       remove_node (node);
+                               }
+
+                               g_free (new_href);
+                               g_free (inner_html);
+                       }
+
+               }
+               g_free (text_to_append);
+               g_free (text);
+               g_free (href);
+       }
+
+       g_match_info_free (match_info);
+       g_regex_unref (regex);
+       g_free (node_text);
+
+ out:
+       if (!return_key_pressed)
+               e_editor_dom_selection_restore (editor_page);
+}
+
+void
+e_editor_dom_embed_style_sheet (EEditorPage *editor_page,
+                               const gchar *style_sheet_content)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *sheet;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       e_dom_utils_create_and_add_css_style_sheet (document, "-x-evo-composer-sheet");
+
+       sheet = webkit_dom_document_get_element_by_id (document, "-x-evo-composer-sheet");
+       webkit_dom_element_set_attribute (
+               sheet,
+               "type",
+               "text/css",
+               NULL);
+
+       webkit_dom_element_set_inner_html (sheet, style_sheet_content, NULL);
+}
+
+void
+e_editor_dom_remove_embedded_style_sheet (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *sheet;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       sheet = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-composer-sheet");
+
+       remove_node (WEBKIT_DOM_NODE (sheet));
+}
+
+static void
+insert_delete_event (EEditorPage *editor_page,
+                     WebKitDOMRange *range)
+{
+       EEditorHistoryEvent *ev;
+       WebKitDOMDocumentFragment *fragment;
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (e_editor_undo_redo_manager_is_operation_in_progress (manager))
+               return;
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       ev->type = HISTORY_DELETE;
+
+       fragment = webkit_dom_range_clone_contents (range, NULL);
+       ev->data.fragment = fragment;
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &ev->before.start.x,
+               &ev->before.start.y,
+               &ev->before.end.x,
+               &ev->before.end.y);
+
+       ev->after.start.x = ev->before.start.x;
+       ev->after.start.y = ev->before.start.y;
+       ev->after.end.x = ev->before.start.x;
+       ev->after.end.y = ev->before.start.y;
+
+       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       ev->type = HISTORY_AND;
+
+       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+/* Based on original use_pictograms() from GtkHTML */
+static const gchar *emoticons_chars =
+       /*  0 */ "DO)(|/PQ*!"
+       /* 10 */ "S\0:-\0:\0:-\0"
+       /* 20 */ ":\0:;=-\"\0:;"
+       /* 30 */ "B\"|\0:-'\0:X"
+       /* 40 */ "\0:\0:-\0:\0:-"
+       /* 50 */ "\0:\0:-\0:\0:-"
+       /* 60 */ "\0:\0:\0:-\0:\0"
+       /* 70 */ ":-\0:\0:-\0:\0";
+static gint emoticons_states[] = {
+       /*  0 */  12,  17,  22,  34,  43,  48,  53,  58,  65,  70,
+       /* 10 */  75,   0, -15,  15,   0, -15,   0, -17,  20,   0,
+       /* 20 */ -17,   0, -14, -20, -14,  28,  63,   0, -14, -20,
+       /* 30 */  -3,  63, -18,   0, -12,  38,  41,   0, -12,  -2,
+       /* 40 */   0,  -4,   0, -10,  46,   0, -10,   0, -19,  51,
+       /* 50 */   0, -19,   0, -11,  56,   0, -11,   0, -13,  61,
+       /* 60 */   0, -13,   0,  -6,   0,  68,  -7,   0,  -7,   0,
+       /* 70 */ -16,  73,   0, -16,   0, -21,  78,   0, -21,   0 };
+static const gchar *emoticons_icon_names[] = {
+       "face-angel",
+       "face-angry",
+       "face-cool",
+       "face-crying",
+       "face-devilish",
+       "face-embarrassed",
+       "face-kiss",
+       "face-laugh",           /* not used */
+       "face-monkey",          /* not used */
+       "face-plain",
+       "face-raspberry",
+       "face-sad",
+       "face-sick",
+       "face-smile",
+       "face-smile-big",
+       "face-smirk",
+       "face-surprise",
+       "face-tired",
+       "face-uncertain",
+       "face-wink",
+       "face-worried"
+};
+
+typedef struct _EmoticonLoadContext {
+       EEmoticon *emoticon;
+       EEditorPage *editor_page;
+       gchar *content_type;
+       gchar *name;
+} EmoticonLoadContext;
+
+static EmoticonLoadContext *
+emoticon_load_context_new (EEditorPage *editor_page,
+                           EEmoticon *emoticon)
+{
+       EmoticonLoadContext *load_context;
+
+       load_context = g_slice_new0 (EmoticonLoadContext);
+       load_context->emoticon = emoticon;
+       load_context->editor_page = editor_page;
+
+       return load_context;
+}
+
+static void
+emoticon_load_context_free (EmoticonLoadContext *load_context)
+{
+       g_free (load_context->content_type);
+       g_free (load_context->name);
+       g_slice_free (EmoticonLoadContext, load_context);
+}
+
+static void
+emoticon_insert_span (EEmoticon *emoticon,
+                      EmoticonLoadContext *load_context,
+                      WebKitDOMElement *span)
+{
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       EEditorPage *editor_page = load_context->editor_page;
+       gboolean misplaced_selection = FALSE, smiley_written;
+       gchar *node_text = NULL;
+       const gchar *emoticon_start;
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *node, *insert_before, *prev_sibling, *next_sibling;
+       WebKitDOMNode *selection_end_marker_parent, *inserted_node;
+       WebKitDOMRange *range;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       smiley_written = e_editor_page_get_is_smiley_written (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (e_editor_dom_selection_is_collapsed (editor_page)) {
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               selection_end_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+
+               if (!smiley_written) {
+                       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+                               ev = g_new0 (EEditorHistoryEvent, 1);
+                               if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+                                       ev->type = HISTORY_INPUT;
+                               else {
+                                       ev->type = HISTORY_SMILEY;
+
+                                       e_editor_dom_selection_get_coordinates (editor_page,
+                                               &ev->before.start.x,
+                                               &ev->before.start.y,
+                                               &ev->before.end.x,
+                                               &ev->before.end.y);
+                               }
+                       }
+               }
+       } else {
+               WebKitDOMRange *tmp_range;
+
+               tmp_range = e_editor_dom_get_current_range (editor_page);
+               insert_delete_event (editor_page, tmp_range);
+               g_object_unref (tmp_range);
+
+               e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+               if (!smiley_written) {
+                       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+                               ev = g_new0 (EEditorHistoryEvent, 1);
+
+                               if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+                                       ev->type = HISTORY_INPUT;
+                               else {
+                                       ev->type = HISTORY_SMILEY;
+
+                                       e_editor_dom_selection_get_coordinates (editor_page,
+                                               &ev->before.start.x,
+                                               &ev->before.start.y,
+                                               &ev->before.end.x,
+                                               &ev->before.end.y);
+                               }
+                       }
+               }
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               selection_end_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+       }
+
+       /* If the selection was not saved, move it into the first child of body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMHTMLElement *body;
+               WebKitDOMNode *child;
+
+               body = webkit_dom_document_get_body (document);
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+
+               if (ev && !e_editor_page_get_unicode_smileys_enabled (editor_page))
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->before.start.x,
+                               &ev->before.start.y,
+                               &ev->before.end.x,
+                               &ev->before.end.y);
+       }
+
+       /* Sometimes selection end marker is in body. Move it into next sibling */
+       selection_end_marker_parent = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_end_marker));
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (selection_end_marker_parent)) {
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (
+                               WEBKIT_DOM_NODE (selection_start_marker)),
+                       WEBKIT_DOM_NODE (selection_end_marker),
+                       WEBKIT_DOM_NODE (selection_start_marker),
+                       NULL);
+               if (ev && !e_editor_page_get_unicode_smileys_enabled (editor_page))
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->before.start.x,
+                               &ev->before.start.y,
+                               &ev->before.end.x,
+                               &ev->before.end.y);
+       }
+       selection_end_marker_parent = webkit_dom_node_get_parent_node (
+               WEBKIT_DOM_NODE (selection_end_marker));
+
+       /* Determine before what node we have to insert the smiley */
+       insert_before = WEBKIT_DOM_NODE (selection_start_marker);
+       prev_sibling = webkit_dom_node_get_previous_sibling (
+               WEBKIT_DOM_NODE (selection_start_marker));
+       if (prev_sibling) {
+               if (webkit_dom_node_is_same_node (
+                       prev_sibling, WEBKIT_DOM_NODE (selection_end_marker))) {
+                       insert_before = WEBKIT_DOM_NODE (selection_end_marker);
+               } else {
+                       prev_sibling = webkit_dom_node_get_previous_sibling (prev_sibling);
+                       if (prev_sibling &&
+                           webkit_dom_node_is_same_node (
+                               prev_sibling, WEBKIT_DOM_NODE (selection_end_marker))) {
+                               insert_before = WEBKIT_DOM_NODE (selection_end_marker);
+                       }
+               }
+       } else
+               insert_before = WEBKIT_DOM_NODE (selection_start_marker);
+
+       /* Look if selection is misplaced - that means that the selection was
+        * restored before the previously inserted smiley in situations when we
+        * are writing more smileys in a row */
+       next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+       if (next_sibling && WEBKIT_DOM_IS_ELEMENT (next_sibling))
+               if (element_has_class (WEBKIT_DOM_ELEMENT (next_sibling), "-x-evo-smiley-wrapper"))
+                       misplaced_selection = TRUE;
+
+       range = e_editor_dom_get_current_range (editor_page);
+       node = webkit_dom_range_get_end_container (range, NULL);
+       g_object_unref (range);
+       if (WEBKIT_DOM_IS_TEXT (node))
+               node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node));
+
+       if (misplaced_selection) {
+               /* Insert smiley and selection markers after it */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (insert_before),
+                       WEBKIT_DOM_NODE (selection_start_marker),
+                       webkit_dom_node_get_next_sibling (next_sibling),
+                       NULL);
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (insert_before),
+                       WEBKIT_DOM_NODE (selection_end_marker),
+                       webkit_dom_node_get_next_sibling (next_sibling),
+                       NULL);
+               if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+                       inserted_node = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (insert_before),
+                               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (span)),
+                               webkit_dom_node_get_next_sibling (next_sibling),
+                               NULL);
+               else
+                       inserted_node = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (insert_before),
+                               WEBKIT_DOM_NODE (span),
+                               webkit_dom_node_get_next_sibling (next_sibling),
+                               NULL);
+       } else {
+               if (e_editor_page_get_unicode_smileys_enabled (editor_page))
+                       inserted_node = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (insert_before),
+                               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (span)),
+                               insert_before,
+                               NULL);
+               else
+                       inserted_node = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (insert_before),
+                               WEBKIT_DOM_NODE (span),
+                               insert_before,
+                               NULL);
+       }
+
+       if (!e_editor_page_get_unicode_smileys_enabled (editor_page)) {
+               /* &#8203 == UNICODE_ZERO_WIDTH_SPACE */
+               webkit_dom_html_element_insert_adjacent_html (
+                       WEBKIT_DOM_HTML_ELEMENT (span), "afterend", "&#8203;", NULL);
+       }
+
+       if (ev) {
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMNode *node;
+
+               fragment = webkit_dom_document_create_document_fragment (document);
+               node = webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (inserted_node), TRUE, NULL),
+                       NULL);
+               if (e_editor_page_get_unicode_smileys_enabled (editor_page)) {
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               WEBKIT_DOM_NODE (
+                                       dom_create_selection_marker (document, TRUE)),
+                               NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               WEBKIT_DOM_NODE (
+                                       dom_create_selection_marker (document, FALSE)),
+                               NULL);
+               } else
+                       webkit_dom_html_element_insert_adjacent_html (
+                               WEBKIT_DOM_HTML_ELEMENT (node), "afterend", "&#8203;", NULL);
+               ev->data.fragment = fragment;
+       }
+
+       /* Remove the text that represents the text version of smiley that was
+        * written into the composer. */
+       if (node_text && smiley_written) {
+               emoticon_start = g_utf8_strrchr (
+                       node_text, -1, g_utf8_get_char (emoticon->text_face));
+               /* Check if the written smiley is really the one that we inserted. */
+               if (emoticon_start) {
+                       /* The written smiley is the same as text version. */
+                       if (g_str_has_prefix (emoticon_start, emoticon->text_face)) {
+                               webkit_dom_character_data_delete_data (
+                                       WEBKIT_DOM_CHARACTER_DATA (node),
+                                       g_utf8_strlen (node_text, -1) - strlen (emoticon_start),
+                                       strlen (emoticon->text_face),
+                                       NULL);
+                       } else if (strstr (emoticon->text_face, "-")) {
+                               gboolean same = TRUE, compensate = FALSE;
+                               gint ii = 0, jj = 0;
+
+                               /* Try to recognize smileys without the dash e.g. :). */
+                               while (emoticon_start[ii] && emoticon->text_face[jj]) {
+                                       if (emoticon_start[ii] == emoticon->text_face[jj]) {
+                                               if (emoticon->text_face[jj+1] && emoticon->text_face[jj+1] == 
'-') {
+                                                       ii++;
+                                                       jj+=2;
+                                                       compensate = TRUE;
+                                               } else {
+                                                       ii++;
+                                                       jj++;
+                                               }
+                                       } else {
+                                               same = FALSE;
+                                               break;
+                                       }
+                               }
+
+                               if (same) {
+                                       webkit_dom_character_data_delete_data (
+                                               WEBKIT_DOM_CHARACTER_DATA (node),
+                                               g_utf8_strlen (node_text, -1) - strlen (emoticon_start),
+                                               ii,
+                                               NULL);
+                               }
+                               /* If we recognize smiley without dash, but we inserted
+                                * the text version with dash we need it insert new
+                                * history input event with that dash. */
+                               if (compensate)
+                                       e_editor_undo_redo_manager_insert_dash_history_event (manager);
+                       }
+               }
+
+               e_editor_page_set_is_smiley_written (editor_page, FALSE);
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_page_emit_content_changed (editor_page);
+
+       g_free (node_text);
+}
+
+static void
+emoticon_read_async_cb (GFile *file,
+                        GAsyncResult *result,
+                        EmoticonLoadContext *load_context)
+{
+       EEmoticon *emoticon = load_context->emoticon;
+       EEditorPage *editor_page = load_context->editor_page;
+       GError *error = NULL;
+       gboolean html_mode;
+       gchar *mime_type;
+       gchar *base64_encoded, *output, *data;
+       GFileInputStream *input_stream;
+       GOutputStream *output_stream;
+       gssize size;
+       WebKitDOMElement *wrapper, *image, *smiley_text;
+       WebKitDOMDocument *document;
+
+       input_stream = g_file_read_finish (file, result, &error);
+       g_return_if_fail (!error && input_stream);
+
+       output_stream = g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+
+       size = g_output_stream_splice (
+               output_stream, G_INPUT_STREAM (input_stream),
+               G_OUTPUT_STREAM_SPLICE_NONE, NULL, &error);
+
+       if (error || (size == -1))
+               goto out;
+
+       mime_type = g_content_type_get_mime_type (load_context->content_type);
+
+       data = g_memory_output_stream_get_data (G_MEMORY_OUTPUT_STREAM (output_stream));
+       base64_encoded = g_base64_encode ((const guchar *) data, size);
+       output = g_strconcat ("data:", mime_type, ";base64,", base64_encoded, NULL);
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+       document = e_editor_page_get_document (editor_page);
+
+       /* Insert span with image representation and another one with text
+        * represetation and hide/show them dependant on active composer mode */
+       wrapper = webkit_dom_document_create_element (document, "SPAN", NULL);
+       if (html_mode)
+               webkit_dom_element_set_attribute (
+                       wrapper, "class", "-x-evo-smiley-wrapper -x-evo-resizable-wrapper", NULL);
+       else
+               webkit_dom_element_set_attribute (
+                       wrapper, "class", "-x-evo-smiley-wrapper", NULL);
+
+       image = webkit_dom_document_create_element (document, "IMG", NULL);
+       webkit_dom_element_set_attribute (image, "src", output, NULL);
+       webkit_dom_element_set_attribute (image, "data-inline", "", NULL);
+       webkit_dom_element_set_attribute (image, "data-name", load_context->name, NULL);
+       webkit_dom_element_set_attribute (image, "alt", emoticon->text_face, NULL);
+       webkit_dom_element_set_attribute (image, "class", "-x-evo-smiley-img", NULL);
+       if (!html_mode)
+               webkit_dom_element_set_attribute (image, "style", "display: none;", NULL);
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (image), NULL);
+
+       smiley_text = webkit_dom_document_create_element (document, "SPAN", NULL);
+       webkit_dom_element_set_attribute (smiley_text, "class", "-x-evo-smiley-text", NULL);
+       if (html_mode)
+               webkit_dom_element_set_attribute (smiley_text, "style", "display: none;", NULL);
+       webkit_dom_html_element_set_inner_text (
+               WEBKIT_DOM_HTML_ELEMENT (smiley_text), emoticon->text_face, NULL);
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (smiley_text), NULL);
+
+       emoticon_insert_span (emoticon, load_context, wrapper);
+
+       g_free (base64_encoded);
+       g_free (output);
+       g_free (mime_type);
+       g_object_unref (output_stream);
+ out:
+       emoticon_load_context_free (load_context);
+}
+
+static void
+emoticon_query_info_async_cb (GFile *file,
+                              GAsyncResult *result,
+                              EmoticonLoadContext *load_context)
+{
+       GError *error = NULL;
+       GFileInfo *info;
+
+       info = g_file_query_info_finish (file, result, &error);
+       g_return_if_fail (!error && info);
+
+       load_context->content_type = g_strdup (g_file_info_get_content_type (info));
+       load_context->name = g_strdup (g_file_info_get_name (info));
+
+       g_file_read_async (
+               file, G_PRIORITY_DEFAULT, NULL,
+               (GAsyncReadyCallback) emoticon_read_async_cb, load_context);
+
+       g_object_unref (info);
+}
+
+void
+e_editor_dom_insert_smiley (EEditorPage *editor_page,
+                           EEmoticon *emoticon)
+{
+       WebKitDOMDocument *document;
+       GFile *file;
+       gchar *filename_uri;
+       EmoticonLoadContext *load_context;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       if (e_editor_page_get_unicode_smileys_enabled (editor_page)) {
+               WebKitDOMElement *wrapper;
+
+               wrapper = webkit_dom_document_create_element (document, "SPAN", NULL);
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (wrapper), emoticon->unicode_character, NULL);
+
+               load_context = emoticon_load_context_new (editor_page, emoticon);
+               emoticon_insert_span (emoticon, load_context, wrapper);
+               emoticon_load_context_free (load_context);
+       } else {
+               filename_uri = e_emoticon_get_uri (emoticon);
+               g_return_if_fail (filename_uri != NULL);
+
+               load_context = emoticon_load_context_new (editor_page, emoticon);
+
+               file = g_file_new_for_uri (filename_uri);
+               g_file_query_info_async (
+                       file,  "standard::*", G_FILE_QUERY_INFO_NONE,
+                       G_PRIORITY_DEFAULT, NULL,
+                       (GAsyncReadyCallback) emoticon_query_info_async_cb, load_context);
+
+               g_free (filename_uri);
+               g_object_unref (file);
+       }
+}
+
+void
+e_editor_dom_insert_smiley_by_name (EEditorPage *editor_page,
+                                   const gchar *name)
+{
+       const EEmoticon *emoticon;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       emoticon = e_emoticon_chooser_lookup_emoticon (name);
+       e_editor_page_set_is_smiley_written (editor_page, FALSE);
+       e_editor_dom_insert_smiley (editor_page, (EEmoticon *) emoticon);
+}
+
+void
+e_editor_dom_check_magic_smileys (EEditorPage *editor_page)
+{
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       gint pos, state, relative, start;
+       gchar *node_text;
+       gunichar uc;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!e_editor_page_get_magic_smileys_enabled (editor_page))
+               return;
+
+       range = e_editor_dom_get_current_range (editor_page);
+       node = webkit_dom_range_get_end_container (range, NULL);
+       if (!WEBKIT_DOM_IS_TEXT (node))
+               return;
+
+       node_text = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (node));
+       if (node_text == NULL)
+               return;
+
+       start = webkit_dom_range_get_end_offset (range, NULL) - 1;
+       pos = start;
+       state = 0;
+       while (pos >= 0) {
+               uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos));
+               relative = 0;
+               while (emoticons_chars[state + relative]) {
+                       if (emoticons_chars[state + relative] == uc)
+                               break;
+                       relative++;
+               }
+               state = emoticons_states[state + relative];
+               /* 0 .. not found, -n .. found n-th */
+               if (state <= 0)
+                       break;
+               pos--;
+       }
+
+       /* Special case needed to recognize angel and devilish. */
+       if (pos > 0 && state == -14) {
+               uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+               if (uc == 'O') {
+                       state = -1;
+                       pos--;
+               } else if (uc == '>') {
+                       state = -5;
+                       pos--;
+               }
+       }
+
+       if (state < 0) {
+               const EEmoticon *emoticon;
+
+               if (pos > 0) {
+                       uc = g_utf8_get_char (g_utf8_offset_to_pointer (node_text, pos - 1));
+                       if (!g_unichar_isspace (uc)) {
+                               g_free (node_text);
+                               return;
+                       }
+               }
+
+               emoticon = e_emoticon_chooser_lookup_emoticon (
+                       emoticons_icon_names[-state - 1]);
+               e_editor_page_set_is_smiley_written (editor_page, TRUE);
+               e_editor_dom_insert_smiley (editor_page, (EEmoticon *) emoticon);
+       }
+
+       g_free (node_text);
+}
+
+static void
+dom_set_links_active (WebKitDOMDocument *document,
+                      gboolean active)
+{
+       WebKitDOMElement *style;
+
+       style = webkit_dom_document_get_element_by_id (document, "-x-evo-style-a");
+       if (style)
+               remove_node (WEBKIT_DOM_NODE (style));
+
+       if (!active) {
+               WebKitDOMHTMLHeadElement *head;
+               head = webkit_dom_document_get_head (document);
+
+               style = webkit_dom_document_create_element (document, "STYLE", NULL);
+               webkit_dom_element_set_id (style, "-x-evo-style-a");
+               webkit_dom_element_set_attribute (style, "type", "text/css", NULL);
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (style), "a { cursor: text; }", NULL);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style), NULL);
+       }
+}
+
+static void
+fix_paragraph_structure_after_pressing_enter_after_smiley (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_query_selector (
+               document, "span.-x-evo-smiley-wrapper > br", NULL);
+
+       if (element) {
+               WebKitDOMNode *parent;
+
+               parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+               webkit_dom_element_set_inner_html (
+                       webkit_dom_node_get_parent_element (parent),
+                       UNICODE_ZERO_WIDTH_SPACE,
+                       NULL);
+       }
+}
+
+static gboolean
+fix_paragraph_structure_after_pressing_enter (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       gboolean prev_is_heading = FALSE;
+       gint ii, length;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* When pressing Enter on empty line in the list (or after heading elements)
+        * WebKit will end that list and inserts <div><br></div> so mark it for wrapping. */
+       list = webkit_dom_document_query_selector_all (
+               document, "body > div > br", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *prev_sibling;
+               WebKitDOMNode *node = webkit_dom_node_get_parent_node (
+                       webkit_dom_node_list_item (list, ii));
+
+               prev_sibling = webkit_dom_node_get_previous_sibling (node);
+               if (prev_sibling && WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (prev_sibling))
+                       prev_is_heading = TRUE;
+               e_editor_dom_set_paragraph_style (editor_page, WEBKIT_DOM_ELEMENT (node), -1, 0, "");
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       return prev_is_heading;
+}
+
+static gboolean
+surround_text_with_paragraph_if_needed (EEditorPage *editor_page,
+                                        WebKitDOMNode *node)
+{
+       WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (node);
+       WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (node);
+       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+       WebKitDOMElement *element;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       /* All text in composer has to be written in div elements, so if
+        * we are writing something straight to the body, surround it with
+        * paragraph */
+       if (WEBKIT_DOM_IS_TEXT (node) &&
+           (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent) ||
+            WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent))) {
+               element = e_editor_dom_put_node_into_paragraph (editor_page, node, TRUE);
+               if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent))
+                       webkit_dom_element_remove_attribute (element, "style");
+
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+                       remove_node (next_sibling);
+
+               /* Tab character */
+               if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "Apple-tab-span")) {
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (element),
+                               prev_sibling,
+                               webkit_dom_node_get_first_child (
+                                       WEBKIT_DOM_NODE (element)),
+                               NULL);
+               }
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gboolean
+selection_is_in_table (WebKitDOMDocument *document,
+                       gboolean *first_cell,
+                       WebKitDOMNode **table_node)
+{
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMNode *node, *parent;
+       WebKitDOMRange *range;
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (first_cell != NULL)
+               *first_cell = FALSE;
+
+       if (table_node != NULL)
+               *table_node = NULL;
+
+       if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+               g_object_unref (dom_selection);
+               return FALSE;
+       }
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       node = webkit_dom_range_get_start_container (range, NULL);
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+
+       parent = node;
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent)) {
+                       if (first_cell != NULL) {
+                               if (!webkit_dom_node_get_previous_sibling (parent)) {
+                                       gboolean on_start = TRUE;
+                                       WebKitDOMNode *tmp;
+
+                                       tmp = webkit_dom_node_get_previous_sibling (node);
+                                       if (!tmp && WEBKIT_DOM_IS_TEXT (node))
+                                               on_start = webkit_dom_range_get_start_offset (range, NULL) == 
0;
+                                       else if (tmp)
+                                               on_start = FALSE;
+
+                                       if (on_start) {
+                                               node = webkit_dom_node_get_parent_node (parent);
+                                               if (node && WEBKIT_DOM_HTML_TABLE_ROW_ELEMENT (node))
+                                                       if (!webkit_dom_node_get_previous_sibling (node))
+                                                               *first_cell = TRUE;
+                                       }
+                               }
+                       } else
+                               return TRUE;
+               }
+               if (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (parent)) {
+                       if (table_node != NULL)
+                               *table_node = parent;
+                       else
+                               return TRUE;
+               }
+               parent = webkit_dom_node_get_parent_node (parent);
+       }
+
+       if (table_node == NULL)
+               return FALSE;
+
+       return *table_node != NULL;
+}
+
+static gboolean
+jump_to_next_table_cell (WebKitDOMDocument *document,
+                         gboolean jump_back)
+{
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMNode *node, *cell;
+       WebKitDOMRange *range;
+
+       if (!selection_is_in_table (document, NULL, NULL))
+               return FALSE;
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       node = webkit_dom_range_get_start_container (range, NULL);
+
+       cell = node;
+       while (cell && !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (cell)) {
+               cell = webkit_dom_node_get_parent_node (cell);
+       }
+
+       if (!WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (cell)) {
+               g_object_unref (range);
+               g_object_unref (dom_selection);
+               return FALSE;
+       }
+
+       if (jump_back) {
+               /* Get previous cell */
+               node = webkit_dom_node_get_previous_sibling (cell);
+               if (!node || !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) {
+                       /* No cell, go one row up. */
+                       node = webkit_dom_node_get_parent_node (cell);
+                       node = webkit_dom_node_get_previous_sibling (node);
+                       if (node && WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT (node)) {
+                               node = webkit_dom_node_get_last_child (node);
+                       } else {
+                               /* No row above, move to the block before table. */
+                               node = webkit_dom_node_get_parent_node (cell);
+                               while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node 
(node)))
+                                       node = webkit_dom_node_get_parent_node (node);
+
+                               node = webkit_dom_node_get_previous_sibling (node);
+                       }
+               }
+       } else {
+               /* Get next cell */
+               node = webkit_dom_node_get_next_sibling (cell);
+               if (!node || !WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node)) {
+                       /* No cell, go one row below. */
+                       node = webkit_dom_node_get_parent_node (cell);
+                       node = webkit_dom_node_get_next_sibling (node);
+                       if (node && WEBKIT_DOM_IS_HTML_TABLE_ROW_ELEMENT (node)) {
+                               node = webkit_dom_node_get_first_child (node);
+                       } else {
+                               /* No row below, move to the block after table. */
+                               node = webkit_dom_node_get_parent_node (cell);
+                               while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node 
(node)))
+                                       node = webkit_dom_node_get_parent_node (node);
+
+                               node = webkit_dom_node_get_next_sibling (node);
+                       }
+               }
+       }
+
+       if (!node)
+               return FALSE;
+
+       webkit_dom_range_select_node_contents (range, node, NULL);
+       webkit_dom_range_collapse (range, TRUE, NULL);
+       webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+       webkit_dom_dom_selection_add_range (dom_selection, range);
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+
+       return TRUE;
+}
+
+static gboolean
+save_history_before_event_in_table (EEditorPage *editor_page,
+                                    WebKitDOMRange *range)
+{
+       WebKitDOMNode *node;
+       WebKitDOMElement *block;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+               block = WEBKIT_DOM_ELEMENT (node);
+       else
+               block = get_parent_block_element (node);
+
+       if (block && WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (block)) {
+               EEditorUndoRedoManager *manager;
+               EEditorHistoryEvent *ev;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_TABLE_INPUT;
+
+               if (block) {
+                       e_editor_dom_selection_save (editor_page);
+                       ev->data.dom.from = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block), 
TRUE, NULL);
+                       e_editor_dom_selection_restore (editor_page);
+               } else
+                       ev->data.dom.from = NULL;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static gboolean
+insert_tabulator (EEditorPage *editor_page)
+{
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INPUT;
+
+               if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+                       WebKitDOMRange *tmp_range;
+
+                       tmp_range = e_editor_dom_get_current_range (editor_page);
+                       insert_delete_event (editor_page, tmp_range);
+                       g_object_unref (tmp_range);
+               }
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->before.end.x = ev->before.start.x;
+               ev->before.end.y = ev->before.start.y;
+       }
+
+       success = e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, "\t");
+
+       if (ev) {
+               if (success) {
+                       WebKitDOMDocument *document;
+                       WebKitDOMElement *element;
+                       WebKitDOMDocumentFragment *fragment;
+
+                       document = e_editor_page_get_document (editor_page);
+
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->after.start.x,
+                               &ev->after.start.y,
+                               &ev->after.end.x,
+                               &ev->after.end.y);
+
+                       fragment = webkit_dom_document_create_document_fragment (document);
+                       element = webkit_dom_document_create_element (document, "span", NULL);
+                       webkit_dom_html_element_set_inner_text (
+                               WEBKIT_DOM_HTML_ELEMENT (element), "\t", NULL);
+                       webkit_dom_element_set_attribute (
+                               element, "class", "Apple-tab-span", NULL);
+                       webkit_dom_element_set_attribute (
+                               element, "style", "white-space:pre", NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment), WEBKIT_DOM_NODE (element), NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               WEBKIT_DOM_NODE (dom_create_selection_marker (document, TRUE)),
+                               NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               WEBKIT_DOM_NODE (dom_create_selection_marker (document, FALSE)),
+                               NULL);
+                       ev->data.fragment = fragment;
+
+                       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+                       e_editor_page_emit_content_changed (editor_page);
+               } else {
+                       e_editor_undo_redo_manager_remove_current_history_event (manager);
+                       e_editor_undo_redo_manager_remove_current_history_event (manager);
+                       g_free (ev);
+               }
+       }
+
+       return success;
+}
+
+static void
+body_keypress_event_cb (WebKitDOMElement *element,
+                        WebKitDOMUIEvent *event,
+                        EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window = NULL;
+       WebKitDOMDOMSelection *dom_selection = NULL;
+       WebKitDOMRange *range = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       if (!webkit_dom_range_get_collapsed (range, NULL))
+               insert_delete_event (editor_page, range);
+}
+
+static void
+set_monospace_font_family_on_body (WebKitDOMElement *body,
+                                   gboolean html_mode)
+{
+       /* If copying some content in view, WebKit adds various information about
+        * the content's style (such as color, font size, ..) to the resulting HTML
+        * to correctly apply the style when pasting the content later. The thing
+        * is that in plain text mode the only font allowed is the monospaced one,
+        * but we are forcing it through user style sheet in WebKitWebSettings and
+        * sadly WebKit doesn't count with it, so when the content is pasted,
+        * WebKit wraps it inside SPANs and sets the font-family style on them.
+        * The problem is that when we switch to the HTML mode, the pasted content
+        * will have the monospaced font set. To avoid it we need to set the
+        * font-family style to the body, so WebKit will know about it and will
+        * avoid the described behaviour. */
+       /* When we are deleting a content from the PRE elements we need to turn
+        * this off, otherwise we will end with the same unwanted behavior (the
+        * text between the caret and the end of the element will be wrapped
+        * inside a SPAN element. */
+       if (!html_mode) {
+               element_rename_attribute (WEBKIT_DOM_ELEMENT (body), "data-style", "style");
+               webkit_dom_element_set_attribute (
+                       WEBKIT_DOM_ELEMENT (body),
+                       "style",
+                       "font-family: Monospace;",
+                       NULL);
+       } else {
+               element_rename_attribute (WEBKIT_DOM_ELEMENT (body), "style", "data-style");
+       }
+}
+
+static void
+body_keydown_event_cb (WebKitDOMElement *element,
+                       WebKitDOMUIEvent *event,
+                       EEditorPage *editor_page)
+{
+       gboolean backspace_key, delete_key, space_key, return_key;
+       gboolean shift_key, control_key;
+       glong key_code;
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window = NULL;
+       WebKitDOMDOMSelection *dom_selection = NULL;
+       WebKitDOMRange *range = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+
+       key_code = webkit_dom_ui_event_get_key_code (event);
+       delete_key = key_code == HTML_KEY_CODE_DELETE;
+       return_key = key_code == HTML_KEY_CODE_RETURN;
+       backspace_key = key_code == HTML_KEY_CODE_BACKSPACE;
+       space_key = key_code == HTML_KEY_CODE_SPACE;
+
+       if (key_code == HTML_KEY_CODE_CONTROL) {
+               dom_set_links_active (document, TRUE);
+               return;
+       }
+
+       e_editor_page_set_dont_save_history_in_body_input (editor_page, delete_key || backspace_key);
+
+       if (!(delete_key || return_key || backspace_key || space_key))
+               return;
+
+       shift_key = webkit_dom_keyboard_event_get_shift_key (WEBKIT_DOM_KEYBOARD_EVENT (event));
+       control_key = webkit_dom_keyboard_event_get_ctrl_key (WEBKIT_DOM_KEYBOARD_EVENT (event));
+
+       e_editor_page_set_return_key_pressed (editor_page, return_key);
+       e_editor_page_set_space_key_pressed (editor_page, space_key);
+
+       if (key_code == HTML_KEY_CODE_TABULATOR) {
+               if (jump_to_next_table_cell (document, shift_key)) {
+                       webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+                       goto out;
+               }
+
+               if (!shift_key && insert_tabulator (editor_page))
+                       webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+
+               goto out;
+       }
+
+       if (return_key && e_editor_dom_key_press_event_process_return_key (editor_page)) {
+               webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+               goto out;
+       }
+
+       if (backspace_key && e_editor_dom_key_press_event_process_backspace_key (editor_page)) {
+               webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+               goto out;
+       }
+
+       if (delete_key || backspace_key) {
+               if (e_editor_dom_key_press_event_process_delete_or_backspace_key (editor_page, key_code, 
control_key, delete_key))
+                       webkit_dom_event_prevent_default (WEBKIT_DOM_EVENT (event));
+               else if (!e_editor_page_get_html_mode (editor_page))
+                       set_monospace_font_family_on_body (element, TRUE);
+               goto out;
+       }
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       if (save_history_before_event_in_table (editor_page, range))
+               goto out;
+
+       if (return_key) {
+               EEditorHistoryEvent *ev;
+               EEditorUndoRedoManager *manager;
+
+               /* Insert new history event for Return to have the right coordinates.
+                * The fragment will be added later. */
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INPUT;
+
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+ out:
+       g_clear_object (&range);
+       g_clear_object (&dom_selection);
+}
+
+static gboolean
+save_history_after_event_in_table (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       EEditorHistoryEvent *ev;
+       EEditorUndoRedoManager *manager;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+               g_object_unref (dom_selection);
+               return FALSE;
+       }
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       /* Find if writing into table. */
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+               element = WEBKIT_DOM_ELEMENT (node);
+       else
+               element = get_parent_block_element (node);
+
+       g_object_unref (dom_selection);
+       g_object_unref (range);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       /* If writing to table we have to create different history event. */
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (element)) {
+               ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+               if (ev->type != HISTORY_TABLE_INPUT)
+                       return FALSE;
+       } else
+               return FALSE;
+
+       e_editor_dom_selection_save (editor_page);
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &ev->after.start.x,
+               &ev->after.start.y,
+               &ev->after.end.x,
+               &ev->after.end.y);
+
+       ev->data.dom.to = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), TRUE, NULL);
+
+       e_editor_dom_selection_restore (editor_page);
+
+       return TRUE;
+}
+
+static void
+save_history_for_input (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range, *range_clone;
+       WebKitDOMNode *start_container;
+       EEditorHistoryEvent *ev;
+       EEditorUndoRedoManager *manager;
+       glong offset;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+               g_object_unref (dom_selection);
+               return;
+       }
+
+       if (e_editor_page_get_return_key_pressed (editor_page)) {
+               ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+               if (ev->type != HISTORY_INPUT) {
+                       g_object_unref (dom_selection);
+                       return;
+               }
+       } else {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INPUT;
+       }
+
+       e_editor_page_block_selection_changed (editor_page);
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &ev->after.start.x,
+               &ev->after.start.y,
+               &ev->after.end.x,
+               &ev->after.end.y);
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       range_clone = webkit_dom_range_clone_range (range, NULL);
+       offset = webkit_dom_range_get_start_offset (range_clone, NULL);
+       start_container = webkit_dom_range_get_start_container (range_clone, NULL);
+       if (offset > 0)
+               webkit_dom_range_set_start (
+                       range_clone,
+                       start_container,
+                       offset - 1,
+                       NULL);
+       fragment = webkit_dom_range_clone_contents (range_clone, NULL);
+       /* We have to specially handle Return key press */
+       if (e_editor_page_get_return_key_pressed (editor_page)) {
+               WebKitDOMElement *element_start, *element_end;
+               WebKitDOMNode *parent_start, *parent_end, *node;
+
+               element_start = webkit_dom_document_create_element (document, "span", NULL);
+               webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element_start), NULL);
+               webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character");
+               g_object_unref (range);
+               range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+               element_end = webkit_dom_document_create_element (document, "span", NULL);
+               webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element_end), NULL);
+
+               parent_start = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element_start));
+               parent_end = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element_end));
+
+               while (parent_start && parent_end && !webkit_dom_node_is_same_node (parent_start, 
parent_end)) {
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (fragment),
+                               webkit_dom_node_clone_node_with_error (parent_start, FALSE, NULL),
+                               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+                               NULL);
+                       parent_start = webkit_dom_node_get_parent_node (parent_start);
+                       parent_end = webkit_dom_node_get_parent_node (parent_end);
+               }
+
+               node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+               while (webkit_dom_node_get_next_sibling (node)) {
+                       WebKitDOMNode *last_child;
+
+                       last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+                       webkit_dom_node_append_child (
+                               webkit_dom_node_get_previous_sibling (last_child),
+                               last_child,
+                               NULL);
+               }
+
+               node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+               while (webkit_dom_node_get_last_child (node)) {
+                       node = webkit_dom_node_get_last_child (node);
+               }
+
+               webkit_dom_node_append_child (
+                       node,
+                       WEBKIT_DOM_NODE (
+                               webkit_dom_document_create_element (document, "br", NULL)),
+                       NULL);
+               webkit_dom_node_append_child (
+                       node,
+                       WEBKIT_DOM_NODE (
+                               dom_create_selection_marker (document, TRUE)),
+                       NULL);
+               webkit_dom_node_append_child (
+                       node,
+                       WEBKIT_DOM_NODE (
+                               dom_create_selection_marker (document, FALSE)),
+                       NULL);
+
+               remove_node (WEBKIT_DOM_NODE (element_start));
+               remove_node (WEBKIT_DOM_NODE (element_end));
+
+               g_object_set_data (
+                       G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+
+
+               webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character");
+       } else {
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       WEBKIT_DOM_NODE (
+                               dom_create_selection_marker (document, TRUE)),
+                       NULL);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       WEBKIT_DOM_NODE (
+                               dom_create_selection_marker (document, FALSE)),
+                       NULL);
+       }
+
+       g_object_unref (dom_selection);
+       g_object_unref (range);
+       g_object_unref (range_clone);
+
+       e_editor_page_unblock_selection_changed (editor_page);
+
+       ev->data.fragment = fragment;
+
+       if (!e_editor_page_get_return_key_pressed (editor_page))
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+typedef struct _TimeoutContext TimeoutContext;
+
+struct _TimeoutContext {
+       EEditorPage *editor_page;
+};
+
+static void
+timeout_context_free (TimeoutContext *context)
+{
+       g_slice_free (TimeoutContext, context);
+}
+
+static gboolean
+force_spell_check_on_timeout (TimeoutContext *context)
+{
+       e_editor_dom_force_spell_check_in_viewport (context->editor_page);
+       e_editor_page_set_spell_check_on_scroll_event_source_id (context->editor_page, 0);
+       return FALSE;
+}
+
+static void
+body_scroll_event_cb (WebKitDOMElement *element,
+                      WebKitDOMEvent *event,
+                      EEditorPage *editor_page)
+{
+       TimeoutContext *context;
+       guint id;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!e_editor_page_get_inline_spelling_enabled (editor_page))
+               return;
+
+       context = g_slice_new0 (TimeoutContext);
+       context->editor_page = editor_page;
+
+       id = e_editor_page_get_spell_check_on_scroll_event_source_id (editor_page);
+       if (id > 0)
+               g_source_remove (id);
+
+       id = g_timeout_add_seconds_full (
+               1,
+               G_PRIORITY_DEFAULT,
+               (GSourceFunc)force_spell_check_on_timeout,
+               context,
+               (GDestroyNotify)timeout_context_free);
+
+       e_editor_page_set_spell_check_on_scroll_event_source_id (editor_page, id);
+}
+
+void
+e_editor_dom_body_input_event_process (EEditorPage *editor_page,
+                                      WebKitDOMEvent *event)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       EEditorUndoRedoManager *manager;
+       gboolean do_spell_check = FALSE;
+       gboolean html_mode;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       range = e_editor_dom_get_current_range (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+       e_editor_page_emit_content_changed (editor_page);
+
+       if (e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
+               e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+               do_spell_check = TRUE;
+               goto out;
+       }
+
+       /* When the Backspace is pressed in a bulleted list item with just one
+        * character left in it, WebKit will create another BR element in the
+        * item. */
+       if (!html_mode) {
+               WebKitDOMElement *element;
+
+               element = webkit_dom_document_query_selector (
+                       document, "ul[data-evo-plain-text] > li > br + br", NULL);
+
+               if (element)
+                       remove_node (WEBKIT_DOM_NODE (element));
+       }
+
+       if (!save_history_after_event_in_table (editor_page)) {
+               if (!e_editor_page_get_dont_save_history_in_body_input (editor_page))
+                       save_history_for_input (editor_page);
+               else
+                       do_spell_check = TRUE;
+       }
+
+       /* Don't try to look for smileys if we are deleting text. */
+       if (!e_editor_page_get_dont_save_history_in_body_input (editor_page))
+               e_editor_dom_check_magic_smileys (editor_page);
+
+       e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+
+       if (e_editor_page_get_return_key_pressed (editor_page) ||
+           e_editor_page_get_space_key_pressed (editor_page)) {
+               e_editor_dom_check_magic_links (editor_page, FALSE);
+               if (e_editor_page_get_return_key_pressed (editor_page)) {
+                       if (fix_paragraph_structure_after_pressing_enter (editor_page) &&
+                           html_mode) {
+                               /* When the return is pressed in a H1-6 element, WebKit doesn't
+                                * continue with the same element, but creates normal paragraph,
+                                * so we have to unset the bold font. */
+                               e_editor_undo_redo_manager_set_operation_in_progress (manager, TRUE);
+                               e_editor_dom_selection_set_bold (editor_page, FALSE);
+                               e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
+                       }
+
+                       fix_paragraph_structure_after_pressing_enter_after_smiley (document);
+
+                       do_spell_check = TRUE;
+               }
+       } else {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_range_get_end_container (range, NULL);
+
+               if (surround_text_with_paragraph_if_needed (editor_page, node)) {
+                       WebKitDOMElement *element;
+
+                       element = webkit_dom_document_get_element_by_id (
+                               document, "-x-evo-selection-start-marker");
+                       node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+                       e_editor_dom_selection_restore (editor_page);
+               }
+
+               if (WEBKIT_DOM_IS_TEXT (node)) {
+                       gchar *text;
+
+                       text = webkit_dom_node_get_text_content (node);
+
+                       if (text && *text && *text != ' ' && !g_str_has_prefix (text, UNICODE_NBSP)) {
+                               gboolean valid = FALSE;
+
+                               if (*text == '?' && strlen (text) > 1)
+                                       valid = TRUE;
+                               else if (!strchr (URL_INVALID_TRAILING_CHARS, *text))
+                                       valid = TRUE;
+
+                               if (valid) {
+                                       WebKitDOMNode *prev_sibling;
+
+                                       prev_sibling = webkit_dom_node_get_previous_sibling (node);
+
+                                       if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling))
+                                               e_editor_dom_check_magic_links (editor_page, FALSE);
+                               }
+                       }
+                       g_free (text);
+               }
+       }
+
+       node = webkit_dom_range_get_end_container (range, NULL);
+
+       /* After toggling monospaced format, we are using UNICODE_ZERO_WIDTH_SPACE
+        * to move caret into right space. When this callback is called it is not
+        * necessary anymore so remove it */
+       if (html_mode) {
+               WebKitDOMElement *parent = webkit_dom_node_get_parent_element (node);
+
+               if (parent) {
+                       WebKitDOMNode *prev_sibling;
+
+                       prev_sibling = webkit_dom_node_get_previous_sibling (
+                               WEBKIT_DOM_NODE (parent));
+
+                       if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling)) {
+                               gchar *text = webkit_dom_node_get_text_content (
+                                       prev_sibling);
+
+                               if (g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0)
+                                       remove_node (prev_sibling);
+
+                               g_free (text);
+                       }
+
+               }
+       }
+
+       /* If text before caret includes UNICODE_ZERO_WIDTH_SPACE character, remove it */
+       if (WEBKIT_DOM_IS_TEXT (node)) {
+               gchar *text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (node));
+               glong length = webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node));
+               WebKitDOMNode *parent;
+
+               /* We have to preserve empty paragraphs with just UNICODE_ZERO_WIDTH_SPACE
+                * character as when we will remove it it will collapse */
+               if (length > 1) {
+                       if (g_str_has_prefix (text, UNICODE_ZERO_WIDTH_SPACE))
+                               webkit_dom_character_data_replace_data (
+                                       WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL);
+                       else if (g_str_has_suffix (text, UNICODE_ZERO_WIDTH_SPACE))
+                               webkit_dom_character_data_replace_data (
+                                       WEBKIT_DOM_CHARACTER_DATA (node), length - 1, 1, "", NULL);
+               }
+               g_free (text);
+
+               parent = webkit_dom_node_get_parent_node (node);
+               if (WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (parent) &&
+                   !webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-evo-paragraph")) {
+                       if (html_mode)
+                               webkit_dom_element_set_attribute (
+                                       WEBKIT_DOM_ELEMENT (parent),
+                                       "data-evo-paragraph",
+                                       "",
+                                       NULL);
+                       else
+                               e_editor_dom_set_paragraph_style (
+                                       editor_page, WEBKIT_DOM_ELEMENT (parent), -1, 0, "");
+               }
+
+               /* When new smiley is added we have to use UNICODE_HIDDEN_SPACE to set the
+                * caret position to right place. It is removed when user starts typing. But
+                * when the user will press left arrow he will move the caret into
+                * smiley wrapper. If he will start to write there we have to move the written
+                * text out of the wrapper and move caret to right place */
+               if (WEBKIT_DOM_IS_ELEMENT (parent) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text")) {
+                       gchar *text;
+                       WebKitDOMCharacterData *data;
+                       WebKitDOMText *text_node;
+
+                       /* Split out the newly written character to its own text node, */
+                       data = WEBKIT_DOM_CHARACTER_DATA (node);
+                       parent = webkit_dom_node_get_parent_node (parent);
+                       text = webkit_dom_character_data_substring_data (
+                               data,
+                               webkit_dom_character_data_get_length (data) - 1,
+                               1,
+                               NULL);
+                       webkit_dom_character_data_delete_data (
+                               data,
+                               webkit_dom_character_data_get_length (data) - 1,
+                               1,
+                               NULL);
+                       text_node = webkit_dom_document_create_text_node (document, text);
+                       g_free (text);
+
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               WEBKIT_DOM_NODE (
+                                       dom_create_selection_marker (document, FALSE)),
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               WEBKIT_DOM_NODE (
+                                       dom_create_selection_marker (document, TRUE)),
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+                       /* Move the text node outside of smiley. */
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               WEBKIT_DOM_NODE (text_node),
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+                       e_editor_dom_selection_restore (editor_page);
+               }
+       }
+
+       /* Writing into quoted content */
+       if (html_mode) {
+               gint citation_level;
+               WebKitDOMElement *selection_start_marker, *selection_end_marker;
+               WebKitDOMNode *node, *parent;
+
+               node = webkit_dom_range_get_end_container (range, NULL);
+
+               citation_level = e_editor_dom_get_citation_level (node, FALSE);
+               if (citation_level == 0)
+                       goto out;
+
+               selection_start_marker = webkit_dom_document_query_selector (
+                       document, "span#-x-evo-selection-start-marker", NULL);
+               if (selection_start_marker)
+                       goto out;
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_query_selector (
+                       document, "span#-x-evo-selection-start-marker", NULL);
+               selection_end_marker = webkit_dom_document_query_selector (
+                       document, "span#-x-evo-selection-end-marker", NULL);
+               /* If the selection was not saved, move it into the first child of body */
+               if (!selection_start_marker || !selection_end_marker) {
+                       WebKitDOMHTMLElement *body;
+                       WebKitDOMNode *child;
+
+                       body = webkit_dom_document_get_body (document);
+                       child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+                       dom_add_selection_markers_into_element_start (
+                               document,
+                               WEBKIT_DOM_ELEMENT (child),
+                               &selection_start_marker,
+                               &selection_end_marker);
+               }
+
+               /* We have to process elements only inside normal block */
+               parent = WEBKIT_DOM_NODE (get_parent_block_element (
+                       WEBKIT_DOM_NODE (selection_start_marker)));
+               if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent)) {
+                       e_editor_dom_selection_restore (editor_page);
+                       goto out;
+               }
+
+               if (selection_start_marker) {
+                       gchar *content;
+                       gint text_length, word_wrap_length, length;
+                       WebKitDOMElement *block;
+                       gboolean remove_quoting = FALSE;
+
+                       word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+                       length = word_wrap_length - 2 * citation_level;
+
+                       block = WEBKIT_DOM_ELEMENT (parent);
+                       if (webkit_dom_element_query_selector (
+                               WEBKIT_DOM_ELEMENT (block), ".-x-evo-quoted", NULL)) {
+                               WebKitDOMNode *prev_sibling;
+
+                               prev_sibling = webkit_dom_node_get_previous_sibling (
+                                       WEBKIT_DOM_NODE (selection_end_marker));
+
+                               if (WEBKIT_DOM_IS_ELEMENT (prev_sibling))
+                                       remove_quoting = element_has_class (
+                                               WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted");
+                       }
+
+                       content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (block));
+                       text_length = g_utf8_strlen (content, -1);
+                       g_free (content);
+
+                       /* Wrap and quote the line */
+                       if (!remove_quoting && text_length >= word_wrap_length) {
+                               e_editor_dom_remove_quoting_from_element (block);
+
+                               block = e_editor_dom_wrap_paragraph_length (editor_page, block, length);
+                               webkit_dom_node_normalize (WEBKIT_DOM_NODE (block));
+                               e_editor_dom_quote_plain_text_element_after_wrapping (
+                                       editor_page, WEBKIT_DOM_ELEMENT (block), citation_level);
+                               selection_start_marker = webkit_dom_document_query_selector (
+                                       document, "span#-x-evo-selection-start-marker", NULL);
+                               if (!selection_start_marker)
+                                       dom_add_selection_markers_into_element_end (
+                                               document,
+                                               WEBKIT_DOM_ELEMENT (block),
+                                               NULL,
+                                               NULL);
+
+                               e_editor_dom_selection_restore (editor_page);
+                               do_spell_check = TRUE;
+                               goto out;
+                       }
+               }
+               e_editor_dom_selection_restore (editor_page);
+       }
+ out:
+       if (do_spell_check)
+               e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+       g_object_unref (range);
+}
+
+static void
+body_input_event_cb (WebKitDOMElement *element,
+                     WebKitDOMEvent *event,
+                     EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_dom_body_input_event_process (editor_page, event);
+}
+
+void
+e_editor_dom_remove_input_event_listener_from_body (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!e_editor_page_get_body_input_event_removed (editor_page)) {
+               WebKitDOMDocument *document;
+
+               document = e_editor_page_get_document (editor_page);
+
+               webkit_dom_event_target_remove_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (webkit_dom_document_get_body (document)),
+                       "input",
+                       G_CALLBACK (body_input_event_cb),
+                       FALSE);
+
+               e_editor_page_set_body_input_event_removed (editor_page, TRUE);
+       }
+}
+
+void
+e_editor_dom_register_input_event_listener_on_body (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_get_body_input_event_removed (editor_page)) {
+               WebKitDOMDocument *document;
+
+               document = e_editor_page_get_document (editor_page);
+
+               webkit_dom_event_target_add_event_listener (
+                       WEBKIT_DOM_EVENT_TARGET (webkit_dom_document_get_body (document)),
+                       "input",
+                       G_CALLBACK (body_input_event_cb),
+                       FALSE,
+                       editor_page);
+
+               e_editor_page_set_body_input_event_removed (editor_page, FALSE);
+       }
+}
+
+static void
+remove_empty_blocks (WebKitDOMDocument *document)
+{
+       gint ii, length;
+       WebKitDOMNodeList *list;
+
+       list = webkit_dom_document_query_selector_all (
+       document, "blockquote[type=cite] > :empty", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+
+       list = webkit_dom_document_query_selector_all (
+               document, "blockquote[type=cite]:empty", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       for  (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+
+       g_object_unref (list);
+}
+
+/* Following two functions are used when deleting the selection inside
+ * the quoted content. The thing is that normally the quote marks are not
+ * selectable by user. But this caused a lof of problems for WebKit when removing
+ * the selection. This will avoid it as when the delete or backspace key is pressed
+ * we will make the quote marks user selectable so they will act as any other text.
+ * On HTML keyup event callback we will make them again non-selectable. */
+void
+e_editor_dom_disable_quote_marks_select (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLHeadElement *head;
+       WebKitDOMElement *style_element;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       head = webkit_dom_document_get_head (document);
+
+       if (!webkit_dom_document_get_element_by_id (document, "-x-evo-quote-style")) {
+               style_element = webkit_dom_document_create_element (document, "style", NULL);
+               webkit_dom_element_set_id (style_element, "-x-evo-quote-style");
+               webkit_dom_element_set_attribute (style_element, "type", "text/css", NULL);
+               webkit_dom_element_set_inner_html (
+                       style_element,
+                       ".-x-evo-quoted { -webkit-user-select: none; }",
+                       NULL);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style_element), NULL);
+       }
+}
+
+static void
+enable_quote_marks_select (WebKitDOMDocument *document)
+{
+       WebKitDOMElement *style_element;
+
+       if ((style_element = webkit_dom_document_get_element_by_id (document, "-x-evo-quote-style")))
+               remove_node (WEBKIT_DOM_NODE (style_element));
+}
+
+void
+e_editor_dom_remove_node_and_parents_if_empty (WebKitDOMNode *node)
+{
+       WebKitDOMNode *parent;
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (node));
+
+       remove_node (WEBKIT_DOM_NODE (node));
+
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               WebKitDOMNode *prev_sibling, *next_sibling;
+
+               prev_sibling = webkit_dom_node_get_previous_sibling (parent);
+               next_sibling = webkit_dom_node_get_next_sibling (parent);
+               /* Empty or BR as sibling, but no sibling after it. */
+               if ((!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)))) {
+                       WebKitDOMNode *tmp;
+
+                       tmp = webkit_dom_node_get_parent_node (parent);
+                       remove_node (parent);
+                       parent = tmp;
+               } else {
+                       if (!webkit_dom_node_get_first_child (parent))
+                               remove_node (parent);
+                       return;
+               }
+       }
+}
+
+void
+e_editor_dom_merge_siblings_if_necessary (EEditorPage *editor_page,
+                                         WebKitDOMDocumentFragment *deleted_content)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *prev_element;
+       WebKitDOMNode *child;
+       WebKitDOMNodeList *list;
+       gboolean equal_nodes;
+       gint ii, length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       if ((element = webkit_dom_document_get_element_by_id (document, "-x-evo-main-cite")))
+               webkit_dom_element_remove_attribute (element, "id");
+
+       element = webkit_dom_document_query_selector (document, "blockquote:not([data-evo-query-skip]) + 
blockquote", NULL);
+       if (!element)
+               goto signature;
+ repeat:
+       child = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+       if (WEBKIT_DOM_IS_ELEMENT (child))
+               prev_element = WEBKIT_DOM_ELEMENT (child);
+       else
+               goto signature;
+
+       equal_nodes = webkit_dom_node_is_equal_node (
+               webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), FALSE, NULL),
+               webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (prev_element), FALSE, NULL));
+
+       if (equal_nodes) {
+               if (webkit_dom_element_get_child_element_count (element) >
+                   webkit_dom_element_get_child_element_count (prev_element)) {
+                       while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+                               webkit_dom_node_append_child (
+                                       WEBKIT_DOM_NODE (prev_element), child, NULL);
+                       remove_node (WEBKIT_DOM_NODE (element));
+               } else {
+                       while ((child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (prev_element))))
+                               webkit_dom_node_insert_before (
+                                       WEBKIT_DOM_NODE (element),
+                                       child,
+                                       webkit_dom_node_get_first_child (
+                                               WEBKIT_DOM_NODE (element)),
+                                       NULL);
+                       remove_node (WEBKIT_DOM_NODE (prev_element));
+               }
+       } else
+               webkit_dom_element_set_attribute (element, "data-evo-query-skip", "", NULL);
+
+       element = webkit_dom_document_query_selector (document, "blockquote:not([data-evo-query-skip]) + 
blockquote", NULL);
+       if (element)
+               goto repeat;
+
+ signature:
+       list = webkit_dom_document_query_selector_all (
+               document, "blockquote[data-evo-query-skip]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for  (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               webkit_dom_element_remove_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "data-evo-query-skip");
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       if (!deleted_content)
+               return;
+
+       /* Replace the corrupted signatures with the right one. */
+       element = webkit_dom_document_query_selector (
+               document, ".-x-evo-signature-wrapper + .-x-evo-signature-wrapper", NULL);
+       if (element) {
+               WebKitDOMElement *right_signature;
+
+               right_signature = webkit_dom_document_fragment_query_selector (
+                       deleted_content, ".-x-evo-signature-wrapper", NULL);
+               remove_node (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element)));
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (right_signature), TRUE, NULL),
+                       WEBKIT_DOM_NODE (element),
+                       NULL);
+       }
+}
+
+/* This will fix the structure after the situations where some text
+ * inside the quoted content is selected and afterwards deleted with
+ * BackSpace or Delete. */
+void
+e_editor_dom_body_key_up_event_process_backspace_or_delete (EEditorPage *editor_page,
+                                                           gboolean delete)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *parent, *node;
+       gint level;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_get_html_mode (editor_page))
+               return;
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_disable_quote_marks_select (editor_page);
+       /* Remove empty blocks if presented. */
+       remove_empty_blocks (document);
+
+       e_editor_dom_selection_save (editor_page);
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       selection_end_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+
+       /* If we deleted a selection the caret will be inside the quote marks, fix it. */
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+       if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-quote-character")) {
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (
+                               webkit_dom_node_get_parent_node (parent)),
+                       WEBKIT_DOM_NODE (selection_end_marker),
+                       webkit_dom_node_get_next_sibling (
+                               webkit_dom_node_get_parent_node (parent)),
+                       NULL);
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (
+                               webkit_dom_node_get_parent_node (parent)),
+                       WEBKIT_DOM_NODE (selection_start_marker),
+                       webkit_dom_node_get_next_sibling (
+                               webkit_dom_node_get_parent_node (parent)),
+                       NULL);
+       }
+
+       /* Under some circumstances we will end with block inside the citation
+        * that has the quote marks removed and we have to reinsert them back. */
+       level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_start_marker), FALSE);
+       node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+       if (level > 0 && node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+               WebKitDOMElement *block;
+
+               block = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker)));
+
+               e_editor_dom_remove_quoting_from_element (block);
+               if (webkit_dom_element_has_attribute (block, "data-evo-paragraph")) {
+                       gint length, word_wrap_length;
+
+                       word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+                       length =  word_wrap_length - 2 * level;
+                       block = e_editor_dom_wrap_paragraph_length (editor_page, block, length);
+                       webkit_dom_node_normalize (WEBKIT_DOM_NODE (block));
+               }
+               e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, block, level);
+       } else if (level > 0 && !node) {
+               WebKitDOMNode *prev_sibling;
+
+               prev_sibling = webkit_dom_node_get_previous_sibling (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted") &&
+                   !webkit_dom_node_get_previous_sibling (prev_sibling))
+                       webkit_dom_node_append_child (
+                               parent,
+                               WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)),
+                               NULL);
+       }
+
+       e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
+
+       e_editor_dom_selection_restore (editor_page);
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+void
+e_editor_dom_body_key_up_event_process_return_key (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *parent;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       /* If the return is pressed in an unordered list in plain text mode
+        * the caret is moved to the "*" character before the newly inserted
+        * item. It looks like it is not enough that the item has BR element
+        * inside, but we have to again use the zero width space character
+        * to fix the situation. */
+       if (e_editor_page_get_html_mode (editor_page))
+               return;
+
+       /* FIXME WK2 this is called twice */
+       /* e_editor_dom_selection_save (editor_page); */
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       selection_end_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+       if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent) ||
+           !WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (webkit_dom_node_get_parent_node (parent))) {
+               e_editor_dom_selection_restore (editor_page);
+               return;
+       }
+
+       if (!webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)) &&
+           (!webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker)) ||
+            WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE 
(selection_end_marker)))))
+               webkit_dom_html_element_insert_adjacent_text (
+                       WEBKIT_DOM_HTML_ELEMENT (parent),
+                       "afterbegin",
+                       UNICODE_ZERO_WIDTH_SPACE,
+                       NULL);
+
+       e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+body_keyup_event_cb (WebKitDOMElement *element,
+                     WebKitDOMUIEvent *event,
+                     EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       glong key_code;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = webkit_dom_node_get_owner_document (WEBKIT_DOM_NODE (element));
+       if (!e_editor_page_is_composition_in_progress (editor_page))
+               e_editor_dom_register_input_event_listener_on_body (editor_page);
+
+       if (!e_editor_dom_selection_is_collapsed (editor_page))
+               return;
+
+       key_code = webkit_dom_ui_event_get_key_code (event);
+       if (key_code == HTML_KEY_CODE_BACKSPACE || key_code == HTML_KEY_CODE_DELETE) {
+               if (!e_editor_page_get_html_mode (editor_page)) {
+                       WebKitDOMHTMLElement *body;
+
+                       body = webkit_dom_document_get_body (document);
+
+                       set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (body), FALSE);
+               }
+               e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, key_code == 
HTML_KEY_CODE_DELETE);
+
+               /* The content was wrapped and the coordinates
+                * of caret could be changed, so renew them. But
+                * only do that when we are not redoing a history
+                * event, otherwise it would modify the history. */
+               if (e_editor_page_get_renew_history_after_coordinates (editor_page)) {
+                       EEditorHistoryEvent *ev = NULL;
+                       EEditorUndoRedoManager *manager;
+
+                       manager = e_editor_page_get_undo_redo_manager (editor_page);
+                       ev = e_editor_undo_redo_manager_get_current_history_event (manager);
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->after.start.x,
+                               &ev->after.start.y,
+                               &ev->after.end.x,
+                               &ev->after.end.y);
+               }
+       } else if (key_code == HTML_KEY_CODE_CONTROL)
+               dom_set_links_active (document, FALSE);
+       else if (key_code == HTML_KEY_CODE_RETURN)
+               e_editor_dom_body_key_up_event_process_return_key (editor_page);
+}
+
+static void
+fix_structure_after_pasting_multiline_content (WebKitDOMNode *node)
+{
+       WebKitDOMNode *first_child, *parent;
+
+       /* When pasting content that does not contain just the
+        * one line text WebKit inserts all the content after the
+        * first line into one element. So we have to take it out
+        * of this element and insert it after that element. */
+       parent = webkit_dom_node_get_parent_node (node);
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent))
+               return;
+       first_child = webkit_dom_node_get_first_child (parent);
+       while (first_child) {
+               WebKitDOMNode *next_child =
+                       webkit_dom_node_get_next_sibling  (first_child);
+               if (webkit_dom_node_has_child_nodes (first_child))
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               first_child,
+                               parent,
+                               NULL);
+               first_child = next_child;
+       }
+}
+
+static gboolean
+delete_hidden_space (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker, *block;
+       gint citation_level;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker || !selection_end_marker)
+               return FALSE;
+
+       block = WEBKIT_DOM_ELEMENT (e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker)));
+
+       citation_level = e_editor_dom_get_citation_level (
+               WEBKIT_DOM_NODE (selection_start_marker), FALSE);
+
+       if (selection_start_marker && citation_level > 0) {
+               EEditorUndoRedoManager *manager;
+               EEditorHistoryEvent *ev = NULL;
+               WebKitDOMNode *node;
+               WebKitDOMDocumentFragment *fragment;
+
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+               node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+               if (!(WEBKIT_DOM_IS_ELEMENT (node) &&
+                     element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted")))
+                       return FALSE;
+
+               node = webkit_dom_node_get_previous_sibling (node);
+               if (!(WEBKIT_DOM_IS_ELEMENT (node) &&
+                     element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br")))
+                       return FALSE;
+
+               node = webkit_dom_node_get_previous_sibling (node);
+               if (!(WEBKIT_DOM_IS_ELEMENT (node) &&
+                     webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), "data-hidden-space")))
+                       return FALSE;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_DELETE;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+
+               remove_node (node);
+
+               e_editor_dom_wrap_and_quote_element (editor_page, block);
+
+               fragment = webkit_dom_document_create_document_fragment (document);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       WEBKIT_DOM_NODE (
+                               webkit_dom_document_create_text_node (document, " ")),
+                       NULL);
+               ev->data.fragment = fragment;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+gboolean
+e_editor_dom_move_quoted_block_level_up (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean html_mode;
+       gint citation_level, success = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker || !selection_end_marker)
+               return FALSE;
+
+       block = e_editor_dom_get_parent_block_node_from_child (WEBKIT_DOM_NODE (selection_start_marker));
+
+       citation_level = e_editor_dom_get_citation_level (
+               WEBKIT_DOM_NODE (selection_start_marker), FALSE);
+
+       if (selection_start_marker && citation_level > 0) {
+               if (webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block), ".-x-evo-quoted", NULL)) {
+
+                       WebKitDOMNode *prev_sibling;
+
+                       webkit_dom_node_normalize (block);
+
+                       prev_sibling = webkit_dom_node_get_previous_sibling (
+                               WEBKIT_DOM_NODE (selection_start_marker));
+
+                       if (!prev_sibling) {
+                               WebKitDOMNode *parent;
+
+                               parent = webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (selection_start_marker));
+                               if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+                                       prev_sibling = webkit_dom_node_get_previous_sibling (parent);
+                       }
+
+                       if (WEBKIT_DOM_IS_ELEMENT (prev_sibling))
+                               success = element_has_class (
+                                       WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-quoted");
+
+                       /* We really have to be in the beginning of paragraph and
+                        * not on the beginning of some line in the paragraph */
+                       if (success && webkit_dom_node_get_previous_sibling (prev_sibling))
+                               success = FALSE;
+               }
+
+               if (html_mode)
+                       success = WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (
+                               webkit_dom_node_get_parent_element (block));
+       }
+
+       if (!success)
+               return FALSE;
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_UNQUOTE;
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+               ev->data.dom.from = webkit_dom_node_clone_node_with_error (block, TRUE, NULL);
+       }
+
+       if (citation_level == 1) {
+               gchar *inner_html;
+               WebKitDOMElement *paragraph, *element;
+
+               inner_html = webkit_dom_element_get_inner_html (WEBKIT_DOM_ELEMENT (block));
+               webkit_dom_element_set_id (WEBKIT_DOM_ELEMENT (block), "-x-evo-to-remove");
+
+               paragraph = e_editor_dom_insert_new_line_into_citation (editor_page, inner_html);
+               g_free (inner_html);
+
+               if (paragraph) {
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (paragraph),
+                               WEBKIT_DOM_NODE (selection_start_marker),
+                               webkit_dom_node_get_first_child (
+                                       WEBKIT_DOM_NODE (paragraph)),
+                               NULL);
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (paragraph),
+                               WEBKIT_DOM_NODE (selection_end_marker),
+                               webkit_dom_node_get_first_child (
+                                       WEBKIT_DOM_NODE (paragraph)),
+                               NULL);
+
+                       e_editor_dom_remove_quoting_from_element (paragraph);
+                       e_editor_dom_remove_wrapping_from_element (paragraph);
+
+                       /* Moving PRE block from citation to body */
+                       if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block)) {
+                               WebKitDOMElement *pre;
+                               WebKitDOMNode *child;
+
+                               pre = webkit_dom_document_create_element (document, "pre", NULL);
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (
+                                               WEBKIT_DOM_NODE (paragraph)),
+                                       WEBKIT_DOM_NODE (pre),
+                                       WEBKIT_DOM_NODE (paragraph),
+                                       NULL);
+
+                               while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE 
(paragraph))))
+                                       webkit_dom_node_append_child (WEBKIT_DOM_NODE (pre), child, NULL);
+
+                               remove_node (WEBKIT_DOM_NODE (paragraph));
+                               paragraph = pre;
+                       }
+               }
+
+               if (block)
+                       remove_node (block);
+
+               while ((element = webkit_dom_document_get_element_by_id (document, "-x-evo-to-remove")))
+                       remove_node (WEBKIT_DOM_NODE (element));
+
+               if (paragraph)
+                       remove_node_if_empty (
+                               webkit_dom_node_get_next_sibling (
+                                       WEBKIT_DOM_NODE (paragraph)));
+       }
+
+       if (citation_level > 1) {
+               WebKitDOMNode *parent;
+
+               if (html_mode) {
+                       webkit_dom_node_insert_before (
+                               block,
+                               WEBKIT_DOM_NODE (selection_start_marker),
+                               webkit_dom_node_get_first_child (block),
+                               NULL);
+                       webkit_dom_node_insert_before (
+                               block,
+                               WEBKIT_DOM_NODE (selection_end_marker),
+                               webkit_dom_node_get_first_child (block),
+                               NULL);
+
+               }
+
+               e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+
+               parent = webkit_dom_node_get_parent_node (block);
+
+               if (!webkit_dom_node_get_previous_sibling (block)) {
+                       /* Currect block is in the beginning of citation, just move it
+                        * before the citation where already is */
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               block,
+                               parent,
+                               NULL);
+               } else if (!webkit_dom_node_get_next_sibling (block)) {
+                       /* Currect block is at the end of the citation, just move it
+                        * after the citation where already is */
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               block,
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+               } else {
+                       /* Current block is somewhere in the middle of the citation
+                        * so we need to split the citation and insert the block into
+                        * the citation that is one level lower */
+                       WebKitDOMNode *clone, *child;
+
+                       clone = webkit_dom_node_clone_node_with_error (parent, FALSE, NULL);
+
+                       /* Move nodes that are after the currect block into the
+                        * new blockquote */
+                       child = webkit_dom_node_get_next_sibling (block);
+                       while (child) {
+                               WebKitDOMNode *next = webkit_dom_node_get_next_sibling (child);
+                               webkit_dom_node_append_child (clone, child, NULL);
+                               child = next;
+                       }
+
+                       clone = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               clone,
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               block,
+                               clone,
+                               NULL);
+               }
+
+               e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (block));
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       return success;
+}
+
+static gboolean
+prevent_from_deleting_last_element_in_body (WebKitDOMDocument *document)
+{
+       gboolean ret_val = FALSE;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMNode *node;
+
+       body = webkit_dom_document_get_body (document);
+
+       node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+       if (!node || !webkit_dom_node_get_next_sibling (node)) {
+               gchar *content;
+
+               content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (body));
+
+               if (!content || !*content)
+                       ret_val = TRUE;
+
+               g_free (content);
+
+               if (webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (body), "img", NULL))
+                       ret_val = FALSE;
+       }
+
+       return ret_val;
+}
+
+static void
+insert_quote_symbols (WebKitDOMElement *element,
+                      gint quote_level,
+                      gboolean skip_first,
+                      gboolean insert_newline)
+{
+       gchar *text;
+       gint ii;
+       GString *output;
+       gchar *quotation;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (element))
+               return;
+
+       text = webkit_dom_element_get_inner_html (element);
+       output = g_string_new ("");
+       quotation = get_quotation_for_level (quote_level);
+
+       if (g_strcmp0 (text, "\n") == 0) {
+               g_string_append (output, "<span class=\"-x-evo-quoted\">");
+               g_string_append (output, quotation);
+               g_string_append (output, "</span>");
+               g_string_append (output, "\n");
+       } else {
+               gchar **lines;
+
+               lines = g_strsplit (text, "\n", 0);
+
+               for (ii = 0; lines[ii]; ii++) {
+                       if (ii == 0 && skip_first) {
+                               if (g_strv_length (lines) == 1) {
+                                       g_strfreev (lines);
+                                       goto exit;
+                               }
+                               g_string_append (output, lines[ii]);
+                               g_string_append (output, "\n");
+                       }
+
+                       g_string_append (output, "<span class=\"-x-evo-quoted\">");
+                       g_string_append (output, quotation);
+                       g_string_append (output, "</span>");
+
+                       /* Insert line of text */
+                       g_string_append (output, lines[ii]);
+                       if ((ii == g_strv_length (lines) - 1) &&
+                           !g_str_has_suffix (text, "\n") && !insert_newline) {
+                               /* If we are on last line and node's text doesn't
+                                * end with \n, don't insert it */
+                               break;
+                       }
+                       g_string_append (output, "\n");
+               }
+
+               g_strfreev (lines);
+       }
+
+       webkit_dom_element_set_inner_html (element, output->str, NULL);
+ exit:
+       g_free (quotation);
+       g_free (text);
+       g_string_free (output, TRUE);
+}
+
+static void
+quote_node (WebKitDOMDocument *document,
+            WebKitDOMNode *node,
+            gint quote_level)
+{
+       gboolean skip_first = FALSE;
+       gboolean insert_newline = FALSE;
+       gboolean is_html_node = FALSE;
+       WebKitDOMElement *wrapper;
+       WebKitDOMNode *node_clone, *prev_sibling, *next_sibling;
+
+       /* Don't quote when we are not in citation */
+       if (quote_level == 0)
+               return;
+
+       if (WEBKIT_DOM_IS_COMMENT (node))
+               return;
+
+       if (WEBKIT_DOM_IS_ELEMENT (node)) {
+               insert_quote_symbols (WEBKIT_DOM_ELEMENT (node), quote_level, FALSE, FALSE);
+               return;
+       }
+
+       prev_sibling = webkit_dom_node_get_previous_sibling (node);
+       next_sibling = webkit_dom_node_get_next_sibling (node);
+
+       is_html_node =
+               !WEBKIT_DOM_IS_TEXT (prev_sibling) &&
+               !WEBKIT_DOM_IS_COMMENT (prev_sibling) && (
+               WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling) ||
+               element_has_tag (WEBKIT_DOM_ELEMENT (prev_sibling), "b") ||
+               element_has_tag (WEBKIT_DOM_ELEMENT (prev_sibling), "i") ||
+               element_has_tag (WEBKIT_DOM_ELEMENT (prev_sibling), "u") ||
+               element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "Apple-tab-span"));
+
+       if (prev_sibling && is_html_node)
+               skip_first = TRUE;
+
+       /* Skip the BR between first blockquote and pre */
+       if (quote_level == 1 && next_sibling && WEBKIT_DOM_IS_HTML_PRE_ELEMENT (next_sibling))
+               return;
+
+       /* Do temporary wrapper */
+       wrapper = webkit_dom_document_create_element (document, "SPAN", NULL);
+       webkit_dom_element_set_class_name (wrapper, "-x-evo-temp-text-wrapper");
+
+       node_clone = webkit_dom_node_clone_node_with_error (node, TRUE, NULL);
+
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (wrapper),
+               node_clone,
+               NULL);
+
+       insert_quote_symbols (
+               wrapper,
+               quote_level,
+               skip_first,
+               insert_newline);
+
+       webkit_dom_node_replace_child (
+               webkit_dom_node_get_parent_node (node),
+               WEBKIT_DOM_NODE (wrapper),
+               node,
+               NULL);
+}
+
+static void
+insert_quote_symbols_before_node (WebKitDOMDocument *document,
+                                  WebKitDOMNode *node,
+                                  gint quote_level,
+                                  gboolean is_html_node)
+{
+       gboolean skip, wrap_br;
+       gchar *quotation;
+       WebKitDOMElement *element;
+
+       quotation = get_quotation_for_level (quote_level);
+       element = webkit_dom_document_create_element (document, "SPAN", NULL);
+       element_add_class (element, "-x-evo-quoted");
+       webkit_dom_element_set_inner_html (element, quotation, NULL);
+
+       /* Don't insert temporary BR before BR that is used for wrapping */
+       skip = WEBKIT_DOM_IS_HTML_BR_ELEMENT (node);
+       wrap_br = element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br");
+       skip = skip && wrap_br;
+
+       if (is_html_node && !skip) {
+               WebKitDOMElement *new_br;
+
+               new_br = webkit_dom_document_create_element (document, "br", NULL);
+               element_add_class (new_br, "-x-evo-temp-br");
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (node),
+                       WEBKIT_DOM_NODE (new_br),
+                       node,
+                       NULL);
+       }
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (node),
+               WEBKIT_DOM_NODE (element),
+               node,
+               NULL);
+
+       if (is_html_node && !wrap_br)
+               remove_node (node);
+
+       g_free (quotation);
+}
+
+static gboolean
+check_if_suppress_next_node (WebKitDOMNode *node)
+{
+       if (!node)
+               return FALSE;
+
+       if (node && WEBKIT_DOM_IS_ELEMENT (node))
+               if (e_editor_dom_is_selection_position_node (node))
+                       if (!webkit_dom_node_get_previous_sibling (node))
+                               return FALSE;
+
+       return TRUE;
+}
+
+static void
+quote_br_node (WebKitDOMNode *node,
+               gint quote_level)
+{
+       gchar *quotation, *content;
+
+       quotation = get_quotation_for_level (quote_level);
+
+       content = g_strconcat (
+               "<span class=\"-x-evo-quoted\">",
+               quotation,
+               "</span><br class=\"-x-evo-temp-br\">",
+               NULL);
+
+       webkit_dom_element_set_outer_html (
+               WEBKIT_DOM_ELEMENT (node),
+               content,
+               NULL);
+
+       g_free (content);
+       g_free (quotation);
+}
+
+static void
+quote_plain_text_recursive (WebKitDOMDocument *document,
+                            WebKitDOMNode *node,
+                            WebKitDOMNode *start_node,
+                            gint quote_level)
+{
+       gboolean skip_node = FALSE;
+       gboolean move_next = FALSE;
+       gboolean suppress_next = FALSE;
+       gboolean is_html_node = FALSE;
+       gboolean next = FALSE;
+       WebKitDOMNode *next_sibling, *prev_sibling;
+
+       node = webkit_dom_node_get_first_child (node);
+
+       while (node) {
+               gchar *text_content;
+
+               skip_node = FALSE;
+               move_next = FALSE;
+               is_html_node = FALSE;
+
+               if (WEBKIT_DOM_IS_COMMENT (node) ||
+                   WEBKIT_DOM_IS_HTML_META_ELEMENT (node) ||
+                   WEBKIT_DOM_IS_HTML_STYLE_ELEMENT (node) ||
+                   WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node)) {
+
+                       move_next = TRUE;
+                       goto next_node;
+               }
+
+               prev_sibling = webkit_dom_node_get_previous_sibling (node);
+               next_sibling = webkit_dom_node_get_next_sibling (node);
+
+               if (WEBKIT_DOM_IS_TEXT (node)) {
+                       /* Start quoting after we are in blockquote */
+                       if (quote_level > 0 && !suppress_next) {
+                               /* When quoting text node, we are wrappering it and
+                                * afterwards replacing it with that wrapper, thus asking
+                                * for next_sibling after quoting will return NULL bacause
+                                * that node don't exist anymore */
+                               quote_node (document, node, quote_level);
+                               node = next_sibling;
+                               skip_node = TRUE;
+                       }
+
+                       goto next_node;
+               }
+
+               if (!(WEBKIT_DOM_IS_ELEMENT (node) || WEBKIT_DOM_IS_HTML_ELEMENT (node)))
+                       goto next_node;
+
+               if (e_editor_dom_is_selection_position_node (node)) {
+                       /* If there is collapsed selection in the beginning of line
+                        * we cannot suppress first text that is after the end of
+                        * selection */
+                       suppress_next = check_if_suppress_next_node (prev_sibling);
+                       if (suppress_next)
+                               next = FALSE;
+                       move_next = TRUE;
+                       goto next_node;
+               }
+
+               if (!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) &&
+                   webkit_dom_element_get_child_element_count (WEBKIT_DOM_ELEMENT (node)) != 0)
+                       goto with_children;
+
+               /* Even in plain text mode we can have some basic html element
+                * like anchor and others. When Forwaring e-mail as Quoted EMFormat
+                * generates header that contatains <b> tags (bold font).
+                * We have to treat these elements separately to avoid
+                * modifications of theirs inner texts */
+               is_html_node =
+                       WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) ||
+                       element_has_tag (WEBKIT_DOM_ELEMENT (node), "b") ||
+                       element_has_tag (WEBKIT_DOM_ELEMENT (node), "i") ||
+                       element_has_tag (WEBKIT_DOM_ELEMENT (node), "u") ||
+                       element_has_class (WEBKIT_DOM_ELEMENT (node), "Apple-tab-span");
+
+               if (is_html_node) {
+                       gboolean wrap_br;
+
+                       wrap_br =
+                               prev_sibling &&
+                               WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) &&
+                               element_has_class (
+                                       WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-wrap-br");
+
+                       if (!prev_sibling || wrap_br) {
+                               insert_quote_symbols_before_node (
+                                       document, node, quote_level, FALSE);
+                               if (!prev_sibling && next_sibling && WEBKIT_DOM_IS_TEXT (next_sibling))
+                                       suppress_next = TRUE;
+                       }
+
+                       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) && !wrap_br)
+                               insert_quote_symbols_before_node (
+                                       document, prev_sibling, quote_level, TRUE);
+
+                       move_next = TRUE;
+                       goto next_node;
+               }
+
+               /* If element doesn't have children, we can quote it */
+               if (e_editor_dom_node_is_citation_node (node)) {
+                       /* Citation with just text inside */
+                       quote_node (document, node, quote_level + 1);
+                       /* Set citation as quoted */
+                       element_add_class (
+                               WEBKIT_DOM_ELEMENT (node),
+                               "-x-evo-plaintext-quoted");
+
+                       move_next = TRUE;
+                       goto next_node;
+               }
+
+               if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+                       if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (prev_sibling)) {
+                               move_next = TRUE;
+                               goto next_node;
+                       }
+                       goto not_br;
+               } else if (element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-first-br") ||
+                          element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-last-br")) {
+                       quote_br_node (node, quote_level);
+                       node = next_sibling;
+                       skip_node = TRUE;
+                       goto next_node;
+               }
+
+               if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+                   WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (next_sibling) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-temp-text-wrapper")) {
+                       /* Situation when anchors are alone on line */
+                       text_content = webkit_dom_node_get_text_content (prev_sibling);
+
+                       if (g_str_has_suffix (text_content, "\n")) {
+                               insert_quote_symbols_before_node (
+                                       document, node, quote_level, FALSE);
+                               remove_node (node);
+                               g_free (text_content);
+                               node = next_sibling;
+                               skip_node = TRUE;
+                               goto next_node;
+                       }
+                       g_free (text_content);
+               }
+
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling)) {
+                       quote_br_node (prev_sibling, quote_level);
+                       node = next_sibling;
+                       skip_node = TRUE;
+                       goto next_node;
+               }
+
+               if (!prev_sibling && !next_sibling) {
+                       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+                       if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (parent) ||
+                           WEBKIT_DOM_IS_HTML_PRE_ELEMENT (parent) ||
+                           (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+                            !e_editor_dom_node_is_citation_node (parent))) {
+                               insert_quote_symbols_before_node (
+                                       document, node, quote_level, FALSE);
+
+                               goto next_node;
+                       }
+               }
+
+               if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), "-x-evo-temp-text-wrapper")) {
+                       text_content = webkit_dom_node_get_text_content (prev_sibling);
+                       if (text_content && !*text_content) {
+                               insert_quote_symbols_before_node (
+                                       document, node, quote_level, FALSE);
+
+                               g_free (text_content);
+                               goto next_node;
+
+                       }
+
+                       g_free (text_content);
+               }
+
+               if (e_editor_dom_node_is_citation_node (prev_sibling)) {
+                       insert_quote_symbols_before_node (
+                               document, node, quote_level, FALSE);
+                       goto next_node;
+               }
+
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) &&
+                   !next_sibling && WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+                   e_editor_dom_is_selection_position_node (prev_sibling)) {
+                       insert_quote_symbols_before_node (
+                               document, node, quote_level, FALSE);
+                       goto next_node;
+               }
+
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+                       move_next = TRUE;
+                       goto next_node;
+               }
+
+ not_br:
+               text_content = webkit_dom_node_get_text_content (node);
+               if (text_content && !*text_content) {
+                       g_free (text_content);
+                       move_next = TRUE;
+                       goto next_node;
+               }
+               g_free (text_content);
+
+               quote_node (document, node, quote_level);
+
+               move_next = TRUE;
+               goto next_node;
+
+ with_children:
+               if (e_editor_dom_node_is_citation_node (node)) {
+                       /* Go deeper and increase level */
+                       quote_plain_text_recursive (
+                               document, node, start_node, quote_level + 1);
+                       /* set citation as quoted */
+                       element_add_class (
+                               WEBKIT_DOM_ELEMENT (node),
+                               "-x-evo-plaintext-quoted");
+                       move_next = TRUE;
+               } else {
+                       quote_plain_text_recursive (
+                               document, node, start_node, quote_level);
+                       move_next = TRUE;
+               }
+ next_node:
+               if (next) {
+                       suppress_next = FALSE;
+                       next = FALSE;
+               }
+
+               if (suppress_next)
+                       next = TRUE;
+
+               if (!skip_node) {
+                       /* Move to next node */
+                       if (!move_next && webkit_dom_node_has_child_nodes (node)) {
+                               node = webkit_dom_node_get_first_child (node);
+                       } else if (webkit_dom_node_get_next_sibling (node)) {
+                               node = webkit_dom_node_get_next_sibling (node);
+                       } else {
+                               return;
+                       }
+               }
+       }
+}
+
+WebKitDOMElement *
+e_editor_dom_quote_plain_text_element (EEditorPage *editor_page,
+                                      WebKitDOMElement *element)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *element_clone;
+       WebKitDOMNodeList *list;
+       gint ii, length, level;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       element_clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (element), TRUE, NULL);
+       level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (element), TRUE);
+
+       /* Remove old quote characters if the exists */
+       list = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (element_clone), "span.-x-evo-quoted", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       webkit_dom_node_normalize (element_clone);
+       quote_plain_text_recursive (
+               document, element_clone, element_clone, level);
+
+       /* Set citation as quoted */
+       if (e_editor_dom_node_is_citation_node (element_clone))
+               element_add_class (
+                       WEBKIT_DOM_ELEMENT (element_clone),
+                       "-x-evo-plaintext-quoted");
+
+       /* Replace old element with one, that is quoted */
+       webkit_dom_node_replace_child (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+               element_clone,
+               WEBKIT_DOM_NODE (element),
+               NULL);
+
+       return WEBKIT_DOM_ELEMENT (element_clone);
+}
+
+/*
+ * dom_quote_plain_text:
+ *
+ * Quote text inside citation blockquotes in plain text mode.
+ *
+ * As this function is cloning and replacing all citation blockquotes keep on
+ * mind that any pointers to nodes inside these blockquotes will be invalidated.
+ */
+static WebKitDOMElement *
+dom_quote_plain_text (WebKitDOMDocument *document)
+{
+       WebKitDOMHTMLElement *body;
+       WebKitDOMNode *body_clone;
+       WebKitDOMNamedNodeMap *attributes;
+       WebKitDOMNodeList *list;
+       WebKitDOMElement *element;
+       gint ii, length;
+       gulong attributes_length;
+
+       /* Check if the document is already quoted */
+       element = webkit_dom_document_query_selector (
+               document, ".-x-evo-plaintext-quoted", NULL);
+       if (element)
+               return NULL;
+
+       body = webkit_dom_document_get_body (document);
+       body_clone = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), TRUE, NULL);
+
+       /* Clean unwanted spaces before and after blockquotes */
+       list = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (body_clone), "blockquote[type|=cite]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *blockquote = webkit_dom_node_list_item (list, ii);
+               WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (blockquote);
+               WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (blockquote);
+
+               if (prev_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling))
+                       remove_node (prev_sibling);
+
+               if (next_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+                       remove_node (next_sibling);
+
+               if (webkit_dom_node_has_child_nodes (blockquote)) {
+                       WebKitDOMNode *child = webkit_dom_node_get_first_child (blockquote);
+                       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+                               remove_node (child);
+               }
+               g_object_unref (blockquote);
+       }
+       g_object_unref (list);
+
+       webkit_dom_node_normalize (body_clone);
+       quote_plain_text_recursive (document, body_clone, body_clone, 0);
+
+       /* Copy attributes */
+       attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+       attributes_length = webkit_dom_named_node_map_get_length (attributes);
+       for (ii = 0; ii < attributes_length; ii++) {
+               gchar *name, *value;
+               WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+               name = webkit_dom_node_get_local_name (node);
+               value = webkit_dom_node_get_node_value (node);
+
+               webkit_dom_element_set_attribute (
+                       WEBKIT_DOM_ELEMENT (body_clone), name, value, NULL);
+
+               g_object_unref (node);
+               g_free (name);
+               g_free (value);
+       }
+       g_object_unref (attributes);
+
+       /* Replace old BODY with one, that is quoted */
+       webkit_dom_node_replace_child (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (body)),
+               body_clone,
+               WEBKIT_DOM_NODE (body),
+               NULL);
+
+       return WEBKIT_DOM_ELEMENT (body_clone);
+}
+
+/*
+ * dom_dequote_plain_text:
+ *
+ * Dequote already quoted plain text in editor.
+ * Editor have to be quoted with e_html_editor_view_quote_plain_text otherwise
+ * it's not working.
+ */
+static void
+dom_dequote_plain_text (WebKitDOMDocument *document)
+{
+       WebKitDOMNodeList *paragraphs;
+       gint length, ii;
+
+       paragraphs = webkit_dom_document_query_selector_all (
+               document, "blockquote.-x-evo-plaintext-quoted", NULL);
+       length = webkit_dom_node_list_get_length (paragraphs);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *element;
+
+               element = WEBKIT_DOM_ELEMENT (webkit_dom_node_list_item (paragraphs, ii));
+
+               if (e_editor_dom_node_is_citation_node (WEBKIT_DOM_NODE (element))) {
+                       element_remove_class (element, "-x-evo-plaintext-quoted");
+                       e_editor_dom_remove_quoting_from_element (element);
+               }
+               g_object_unref (element);
+       }
+       g_object_unref (paragraphs);
+}
+
+static gboolean
+create_anchor_for_link (const GMatchInfo *info,
+                        GString *res,
+                        gpointer data)
+{
+       gboolean link_surrounded, with_nbsp = FALSE;
+       gint offset = 0, truncate_from_end = 0;
+       gint match_start, match_end;
+       gchar *match_with_nbsp, *match_without_nbsp;
+       const gchar *end_of_match = NULL;
+       const gchar *match, *match_extra_characters;
+
+       match_with_nbsp = g_match_info_fetch (info, 1);
+       /* E-mail addresses will be here. */
+       match_without_nbsp = g_match_info_fetch (info, 0);
+
+       if (!match_with_nbsp || (strstr (match_with_nbsp, "&nbsp;") && !g_str_has_prefix (match_with_nbsp, 
"&nbsp;"))) {
+               match = match_without_nbsp;
+               match_extra_characters = match_with_nbsp;
+               g_match_info_fetch_pos (info, 0, &match_start, &match_end);
+               with_nbsp = TRUE;
+       } else {
+               match = match_with_nbsp;
+               match_extra_characters = match_without_nbsp;
+               g_match_info_fetch_pos (info, 1, &match_start, &match_end);
+       }
+
+       if (g_str_has_prefix (match, "&nbsp;"))
+               offset += 6;
+
+       end_of_match = match + match_end - match_start - 1;
+       /* Taken from camel-url-scanner.c */
+       /* URLs are extremely unlikely to end with any punctuation, so
+        * strip any trailing punctuation off from link and put it after
+        * the link. Do the same for any closing double-quotes as well. */
+       while (end_of_match && end_of_match != match && strchr (URL_INVALID_TRAILING_CHARS, *end_of_match)) {
+               truncate_from_end++;
+               end_of_match--;
+       }
+       end_of_match++;
+
+       link_surrounded =
+               g_str_has_suffix (res->str, "&lt;");
+
+       if (link_surrounded) {
+               if (end_of_match && *end_of_match && strlen (match) > strlen (end_of_match) + 3)
+                       link_surrounded = link_surrounded && g_str_has_prefix (end_of_match - 3, "&gt;");
+               else
+                       link_surrounded = link_surrounded && g_str_has_suffix (match, "&gt;");
+
+               if (link_surrounded) {
+                       /* ";" is already counted by code above */
+                       truncate_from_end += 3;
+                       end_of_match -= 3;
+               }
+       }
+
+       g_string_append (res, "<a href=\"");
+       if (strstr (match, "@") && !strstr (match, "://"))
+               g_string_append (res, "mailto:";);
+       g_string_append (res, match + offset);
+       if (truncate_from_end > 0)
+               g_string_truncate (res, res->len - truncate_from_end);
+
+       g_string_append (res, "\">");
+       g_string_append (res, match + offset);
+       if (truncate_from_end > 0)
+               g_string_truncate (res, res->len - truncate_from_end);
+
+       g_string_append (res, "</a>");
+
+       if (truncate_from_end > 0)
+               g_string_append (res, end_of_match);
+
+       if (!with_nbsp && match_extra_characters)
+               g_string_append (res, match_extra_characters + (match_end - match_start));
+
+       g_free (match_with_nbsp);
+       g_free (match_without_nbsp);
+
+       return FALSE;
+}
+
+static gboolean
+replace_to_nbsp (const GMatchInfo *info,
+                 GString *res)
+{
+       gchar *match;
+       gint ii = 0;
+
+       match = g_match_info_fetch (info, 0);
+
+       while (match[ii] != '\0') {
+               if (match[ii] == ' ') {
+                       /* Alone spaces or spaces before/after tabulator. */
+                       g_string_append (res, "&nbsp;");
+               } else if (match[ii] == '\t') {
+                       /* Replace tabs with their WebKit HTML representation. */
+                       g_string_append (res, "<span class=\"Apple-tab-span\" 
style=\"white-space:pre\">\t</span>");
+               }
+
+               ii++;
+       }
+
+       g_free (match);
+
+       return FALSE;
+}
+
+static gboolean
+surround_links_with_anchor (const gchar *text)
+{
+       return (strstr (text, "http") || strstr (text, "ftp") ||
+               strstr (text, "www") || strstr (text, "@"));
+}
+
+static void
+append_new_block (WebKitDOMElement *parent,
+                  WebKitDOMElement **block)
+{
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (parent),
+               WEBKIT_DOM_NODE (*block),
+               NULL);
+
+       *block = NULL;
+}
+
+static WebKitDOMElement *
+create_and_append_new_block (EEditorPage *editor_page,
+                             WebKitDOMElement *parent,
+                             WebKitDOMElement *block_template,
+                             const gchar *content)
+{
+       WebKitDOMElement *block;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (block_template))
+               block = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+       else
+               block = WEBKIT_DOM_ELEMENT (webkit_dom_node_clone_node_with_error (
+                       WEBKIT_DOM_NODE (block_template), FALSE, NULL));
+
+       webkit_dom_element_set_inner_html (block, content, NULL);
+
+       append_new_block (parent, &block);
+
+       return block;
+}
+
+static void
+append_citation_mark (WebKitDOMDocument *document,
+                      WebKitDOMElement *parent,
+                      const gchar *citation_mark_text)
+{
+       WebKitDOMText *text;
+
+       text = webkit_dom_document_create_text_node (document, citation_mark_text);
+
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (parent),
+               WEBKIT_DOM_NODE (text),
+               NULL);
+}
+
+static glong
+get_decoded_line_length (WebKitDOMDocument *document,
+                         const gchar *line_text)
+{
+       glong total_length = 0, length = 0;
+       WebKitDOMElement *decode;
+       WebKitDOMNode *node;
+
+       decode = webkit_dom_document_create_element (document, "DIV", NULL);
+       webkit_dom_element_set_inner_html (decode, line_text, NULL);
+
+       node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (decode));
+       while (node) {
+               if (WEBKIT_DOM_IS_TEXT (node)) {
+                       gulong text_length = 0;
+
+                       text_length = webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node));
+                       total_length += text_length;
+                       length += text_length;
+               } else if (WEBKIT_DOM_IS_ELEMENT (node)) {
+                       if (element_has_class (WEBKIT_DOM_ELEMENT (node), "Apple-tab-span")) {
+                               total_length += TAB_LENGTH - length % TAB_LENGTH;
+                               length = 0;
+                       }
+               }
+               node = webkit_dom_node_get_next_sibling (node);
+       }
+
+       g_object_unref (decode);
+
+       return total_length;
+}
+
+static gboolean
+check_if_end_block (const gchar *input,
+                    glong length,
+                    gboolean preserve_next_line)
+{
+       const gchar *next_space;
+
+       next_space = strstr (input, " ");
+       if (next_space) {
+               const gchar *next_br;
+               glong length_next_word =
+                       next_space - input - 4;
+
+               if (g_str_has_prefix (input + 4, "<br>"))
+                       length_next_word = 0;
+
+               if (length_next_word > 0)
+                       next_br = strstr (input + 4, "<br>");
+
+               if (length_next_word > 0 && next_br < next_space)
+                       length_next_word = 0;
+
+               if (length_next_word + length < 72)
+                       return TRUE;
+       } else {
+               /* If the current text to insert doesn't contain space we
+                * have to look on the previous line if we were preserving
+                * the block or not */
+               return !preserve_next_line;
+       }
+
+       return FALSE;
+}
+
+static void
+replace_selection_markers (gchar **text)
+{
+       if (!text)
+               return;
+
+       if (strstr (*text, "##SELECTION_START##")) {
+               GString *tmp;
+
+               tmp = e_str_replace_string (
+                       *text,
+                       "##SELECTION_START##",
+                       "<span id=\"-x-evo-selection-start-marker\"></span>");
+
+               g_free (*text);
+               *text = g_string_free (tmp, FALSE);
+       }
+
+       if (strstr (*text, "##SELECTION_END##")) {
+               GString *tmp;
+
+               tmp = e_str_replace_string (
+                       *text,
+                       "##SELECTION_END##",
+                       "<span id=\"-x-evo-selection-end-marker\"></span>");
+
+               g_free (*text);
+               *text = g_string_free (tmp, FALSE);
+       }
+}
+
+/* This parses the HTML code (that contains just text, &nbsp; and BR elements)
+ * into blocks.
+ * HTML code in that format we can get by taking innerText from some element,
+ * setting it to another one and finally getting innerHTML from it */
+static void
+parse_html_into_blocks (EEditorPage *editor_page,
+                        WebKitDOMElement *parent,
+                        WebKitDOMElement *passed_block_template,
+                        const gchar *html)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *block = NULL, *block_template = passed_block_template;
+       gboolean ignore_next_br = FALSE;
+       gboolean first_element = TRUE;
+       gboolean citation_was_first_element = FALSE;
+       gboolean preserve_next_line = FALSE;
+       gboolean has_citation = FALSE;
+       gboolean previously_had_empty_citation_start = FALSE;
+       const gchar *prev_br, *next_br;
+       GRegex *regex_nbsp = NULL, *regex_link = NULL, *regex_email = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       webkit_dom_element_set_inner_html (parent, "", NULL);
+
+       if (!block_template) {
+               if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent)) {
+                       gboolean use_paragraphs;
+                       GSettings *settings;
+
+                       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+
+                       use_paragraphs = g_settings_get_boolean (
+                               settings, "composer-wrap-quoted-text-in-replies");
+
+                       if (use_paragraphs)
+                               block_template = e_editor_dom_get_paragraph_element (
+                                       editor_page, -1, 0);
+                       else
+                               block_template = webkit_dom_document_create_element (document, "pre", NULL);
+
+                       g_object_unref (settings);
+               } else
+                       block_template = e_editor_dom_get_paragraph_element (
+                               editor_page, -1, 0);
+       }
+
+       prev_br = html;
+       next_br = strstr (prev_br, "<br>");
+
+       /* Replace the tabulators with SPAN elements that corresponds to them.
+        * If not inserting the content into the PRE element also replace single
+        * spaces on the beginning of line, 2+ spaces and with non breaking
+        * spaces. */
+       if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block_template))
+               regex_nbsp = g_regex_new ("\x9", 0, 0, NULL);
+       else
+               regex_nbsp = g_regex_new ("^\\s{1}|\\s{2,}|\x9|\\s$", 0, 0, NULL);
+
+       while (next_br) {
+               gboolean local_ignore_next_br = ignore_next_br;
+               gboolean local_preserve_next_line = preserve_next_line;
+               gboolean preserve_block = TRY_TO_PRESERVE_BLOCKS;
+               const gchar *citation = NULL, *citation_end = NULL;
+               const gchar *rest = NULL, *with_br = NULL;
+               gchar *to_insert = NULL;
+
+               ignore_next_br = FALSE;
+               preserve_next_line = TRUE;
+
+               to_insert = g_utf8_substring (
+                       prev_br, 0, g_utf8_pointer_to_offset (prev_br, next_br));
+
+               with_br = strstr (to_insert, "<br>");
+               citation = strstr (to_insert, "##CITATION_");
+               if (citation) {
+                       gboolean processed = FALSE;
+
+                       while (!processed) {
+                               gchar *citation_mark;
+                               gboolean citation_start = TRUE;
+
+                               has_citation = TRUE;
+                               if (g_str_has_prefix (citation + 11, "END##")) {
+                                       citation_start = FALSE;
+                                       if (block)
+                                               append_new_block (parent, &block);
+                               } else
+                                       previously_had_empty_citation_start = TRUE;
+
+                               citation_end = strstr (citation + 2, "##");
+                               if (citation_end)
+                                       rest = citation_end + 2;
+
+                               if (rest && *rest && !g_str_has_prefix (rest, "##CITATION_"))
+                                       previously_had_empty_citation_start = FALSE;
+
+                               if (first_element)
+                                       citation_was_first_element = TRUE;
+
+                               if (block)
+                                       append_new_block (parent, &block);
+                               else if (with_br && rest && !*rest &&
+                                        previously_had_empty_citation_start &&
+                                        ignore_next_br) {
+                                       /* Insert an empty block for an empty blockquote */
+                                       block = create_and_append_new_block (
+                                               editor_page, parent, block_template, "<br>");
+                                       previously_had_empty_citation_start = FALSE;
+                               }
+
+                               if (citation_start)
+                                       ignore_next_br = TRUE;
+
+                               citation_mark = g_utf8_substring (
+                                       citation,
+                                       0,
+                                       g_utf8_pointer_to_offset (citation, rest));
+
+                               append_citation_mark (document, parent, citation_mark);
+
+                               g_free (citation_mark);
+
+                               if (rest && *rest) {
+                                       if (g_str_has_prefix (rest, "##CITATION_"))
+                                               citation = rest;
+                                       else
+                                               processed = TRUE;
+                               } else
+                                       processed = TRUE;
+                       }
+               } else {
+                       rest = with_br ?
+                               to_insert + 4 + (with_br - to_insert) : to_insert;
+                       previously_had_empty_citation_start = FALSE;
+               }
+
+               if (!rest) {
+                       preserve_next_line = FALSE;
+                       goto next;
+               }
+
+               if (*rest) {
+                       gboolean empty = FALSE;
+                       gchar *truncated = g_strdup (rest);
+                       gchar *rest_to_insert;
+
+                       empty = !*truncated && strlen (rest) > 0;
+
+                       rest_to_insert = g_regex_replace_eval (
+                               regex_nbsp,
+                               empty ? rest : truncated,
+                               -1,
+                               0,
+                               0,
+                               (GRegexEvalCallback) replace_to_nbsp,
+                               NULL,
+                               NULL);
+                       g_free (truncated);
+
+                       replace_selection_markers (&rest_to_insert);
+
+                       if (strchr (" +- *=\t;#", *rest))
+                               preserve_block = FALSE;
+
+                       if (surround_links_with_anchor (rest_to_insert)) {
+                               gboolean is_email_address =
+                                       strstr (rest_to_insert, "@") &&
+                                       !strstr (rest_to_insert, "://");
+
+                               if (is_email_address && !regex_email)
+                                       regex_email = g_regex_new (E_MAIL_PATTERN, 0, 0, NULL);
+                               if (!is_email_address && !regex_link)
+                                       regex_link = g_regex_new (URL_PATTERN, 0, 0, NULL);
+
+                               truncated = g_regex_replace_eval (
+                                       is_email_address ? regex_email : regex_link,
+                                       rest_to_insert,
+                                       -1,
+                                       0,
+                                       G_REGEX_MATCH_NOTEMPTY,
+                                       create_anchor_for_link,
+                                       NULL,
+                                       NULL);
+
+                               g_free (rest_to_insert);
+                               rest_to_insert = truncated;
+                       }
+
+                       if (g_strcmp0 (rest_to_insert, UNICODE_ZERO_WIDTH_SPACE) == 0) {
+                               if (block)
+                                       append_new_block (parent, &block);
+
+                               block = create_and_append_new_block (
+                                       editor_page, parent, block_template, "<br>");
+                       } else if (preserve_block) {
+                               gchar *html;
+                               gchar *content_to_append;
+
+                              if (!block) {
+                                     if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (block_template))
+                                              block = e_editor_dom_get_paragraph_element (editor_page, -1, 
0);
+                                      else
+                                              block = WEBKIT_DOM_ELEMENT 
(webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block_template), FALSE, NULL));
+                              }
+
+                               html = webkit_dom_element_get_inner_html (block);
+
+                               content_to_append = g_strconcat (
+                                       html && *html ? " " : "",
+                                       rest_to_insert ? rest_to_insert : "<br>",
+                                       NULL),
+
+                               webkit_dom_html_element_insert_adjacent_html (
+                                       WEBKIT_DOM_HTML_ELEMENT (block),
+                                       "beforeend",
+                                       content_to_append,
+                                       NULL);
+
+                               g_free (html);
+                               g_free (content_to_append);
+                       } else {
+                               if (block)
+                                       append_new_block (parent, &block);
+
+                               block = create_and_append_new_block (
+                                       editor_page, parent, block_template, rest_to_insert);
+                       }
+
+                       if (rest_to_insert && *rest_to_insert && preserve_block && block) {
+                               glong length = 0;
+
+                               /* If the line contains some encoded chracters (i.e. &gt;)
+                                * we can't use the strlen functions. */
+                               if (strstr (rest_to_insert, "&"))
+                                       length = get_decoded_line_length (document, rest_to_insert);
+                               else
+                                       length = g_utf8_strlen (rest_to_insert, -1);
+
+                               /* End the block if there is line with less that 62 characters. */
+                               /* The shorter line can also mean that there is a long word on next
+                                * line (and the line was wrapped). So look at it and decide what to do. */
+                               if (length < 62 && check_if_end_block (next_br, length, 
local_preserve_next_line)) {
+                                       append_new_block (parent, &block);
+                                       preserve_next_line = FALSE;
+                               }
+
+                               if (length > 72) {
+                                       append_new_block (parent, &block);
+                                       preserve_next_line = FALSE;
+                               }
+                       }
+
+                       citation_was_first_element = FALSE;
+
+                       g_free (rest_to_insert);
+               } else if (with_br) {
+                       if (!citation && (!local_ignore_next_br || citation_was_first_element)) {
+                               if (block)
+                                       append_new_block (parent, &block);
+
+                               block = create_and_append_new_block (
+                                       editor_page, parent, block_template, "<br>");
+
+                               citation_was_first_element = FALSE;
+                       } else if (first_element && !citation_was_first_element) {
+                               block = create_and_append_new_block (editor_page,
+                                       parent,
+                                       block_template,
+                                       "<br id=\"-x-evo-first-br\">");
+                       } else
+                               preserve_next_line = FALSE;
+               } else if (first_element && !citation_was_first_element) {
+                       block = create_and_append_new_block (editor_page,
+                               parent,
+                               block_template,
+                               "<br id=\"-x-evo-first-br\">");
+               } else
+                       preserve_next_line = FALSE;
+ next:
+               first_element = FALSE;
+               prev_br = next_br;
+               next_br = strstr (prev_br + 4, "<br>");
+               g_free (to_insert);
+       }
+
+       if (block)
+               append_new_block (parent, &block);
+
+       if (g_utf8_strlen (prev_br, -1) > 0) {
+               gchar *rest_to_insert;
+               gchar *truncated = g_strdup (
+                       g_str_has_prefix (prev_br, "<br>") ? prev_br + 4 : prev_br);
+
+               /* On the end on the HTML there is always an extra BR element,
+                * so skip it and if there was another BR element before it mark it. */
+               if (truncated && !*truncated) {
+                       WebKitDOMNode *child;
+
+                       child = webkit_dom_node_get_last_child (
+                               WEBKIT_DOM_NODE (parent));
+                       if (child) {
+                               EContentEditorContentFlags flags;
+
+                               flags = e_editor_page_get_current_content_flags (editor_page);
+
+                               child = webkit_dom_node_get_first_child (child);
+                               if (child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)) {
+                                       /* If the processed HTML contained just
+                                        * the BR don't overwrite its id. */
+                                       if (!element_has_id (WEBKIT_DOM_ELEMENT (child), "-x-evo-first-br"))
+                                               webkit_dom_element_set_id (
+                                                       WEBKIT_DOM_ELEMENT (child),
+                                                       "-x-evo-last-br");
+                               } else if (!(flags & E_CONTENT_EDITOR_MESSAGE_EDITTING))
+                                       create_and_append_new_block (editor_page, parent, block_template, 
"<br>");
+                       } else
+                               create_and_append_new_block (editor_page, parent, block_template, "<br>");
+                       g_free (truncated);
+                       goto end;
+               }
+
+               if (g_ascii_strncasecmp (truncated, "##CITATION_END##", 16) == 0) {
+                       append_citation_mark (document, parent, truncated);
+                       g_free (truncated);
+                       goto end;
+               }
+
+               rest_to_insert = g_regex_replace_eval (
+                       regex_nbsp,
+                       truncated,
+                       -1,
+                       0,
+                       0,
+                       (GRegexEvalCallback) replace_to_nbsp,
+                       NULL,
+                       NULL);
+               g_free (truncated);
+
+               replace_selection_markers (&rest_to_insert);
+
+               if (surround_links_with_anchor (rest_to_insert)) {
+                       gboolean is_email_address =
+                               strstr (rest_to_insert, "@") &&
+                               !strstr (rest_to_insert, "://");
+
+                       if (is_email_address && !regex_email)
+                               regex_email = g_regex_new (E_MAIL_PATTERN, 0, 0, NULL);
+                       if (!is_email_address && !regex_link)
+                               regex_link = g_regex_new (URL_PATTERN, 0, 0, NULL);
+
+                       truncated = g_regex_replace_eval (
+                               is_email_address ? regex_email : regex_link,
+                               rest_to_insert,
+                               -1,
+                               0,
+                               G_REGEX_MATCH_NOTEMPTY,
+                               create_anchor_for_link,
+                               NULL,
+                               NULL);
+
+                       g_free (rest_to_insert);
+                       rest_to_insert = truncated;
+               }
+
+               if (g_strcmp0 (rest_to_insert, UNICODE_ZERO_WIDTH_SPACE) == 0)
+                       create_and_append_new_block (editor_page, parent, block_template, "<br>");
+               else
+                       create_and_append_new_block (editor_page, parent, block_template, rest_to_insert);
+
+               g_free (rest_to_insert);
+       }
+
+ end:
+       if (has_citation) {
+               gchar *inner_html;
+               GString *start, *end;
+
+               /* Replace text markers with actual HTML blockquotes */
+               inner_html = webkit_dom_element_get_inner_html (parent);
+               start = e_str_replace_string (
+                       inner_html, "##CITATION_START##","<blockquote type=\"cite\">");
+               end = e_str_replace_string (
+                       start->str, "##CITATION_END##", "</blockquote>");
+               webkit_dom_element_set_inner_html (parent, end->str, NULL);
+
+               g_free (inner_html);
+               g_string_free (start, TRUE);
+               g_string_free (end, TRUE);
+       }
+
+       if (regex_email != NULL)
+               g_regex_unref (regex_email);
+       if (regex_link != NULL)
+               g_regex_unref (regex_link);
+       g_regex_unref (regex_nbsp);
+}
+
+void
+e_editor_dom_quote_and_insert_text_into_selection (EEditorPage *editor_page,
+                                                  const gchar *text)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *blockquote, *element, *selection_start;
+       WebKitDOMNode *node;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gchar *escaped_text, *inner_html;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!text || !*text)
+               return;
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* This is a trick to escape any HTML characters (like <, > or &).
+        * <textarea> automatically replaces all these unsafe characters
+        * by &lt;, &gt; etc. */
+       element = webkit_dom_document_create_element (document, "textarea", NULL);
+       webkit_dom_element_set_inner_html (element, text, NULL);
+       escaped_text = webkit_dom_element_get_inner_html (element);
+
+       webkit_dom_html_element_set_inner_text (
+               WEBKIT_DOM_HTML_ELEMENT (element), escaped_text, NULL);
+
+       inner_html = webkit_dom_element_get_inner_html (element);
+
+       e_editor_dom_selection_save (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_PASTE_QUOTED;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.string.from = NULL;
+               ev->data.string.to = g_strdup (text);
+       }
+
+       blockquote = webkit_dom_document_create_element (document, "blockquote", NULL);
+       webkit_dom_element_set_attribute (blockquote, "type", "cite", NULL);
+
+       selection_start = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start));
+       /* Check if block is empty. If so, replace it otherwise insert the quoted
+        * content after current block. */
+       if (!node || WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+               node = webkit_dom_node_get_next_sibling (
+                       WEBKIT_DOM_NODE (selection_start));
+               node = webkit_dom_node_get_next_sibling (node);
+               if (!node || WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+                       webkit_dom_node_replace_child (
+                               webkit_dom_node_get_parent_node (
+                                       webkit_dom_node_get_parent_node (
+                                               WEBKIT_DOM_NODE (selection_start))),
+                               WEBKIT_DOM_NODE (blockquote),
+                               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start)),
+                               NULL);
+               }
+       } else {
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (webkit_dom_document_get_body (document)),
+                       WEBKIT_DOM_NODE (blockquote),
+                       webkit_dom_node_get_next_sibling (
+                               webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (selection_start))),
+                       NULL);
+       }
+
+       parse_html_into_blocks (editor_page, blockquote, NULL, inner_html);
+
+       if (e_editor_page_get_html_mode (editor_page)) {
+               node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (blockquote));
+       } else {
+               gint word_wrap_length;
+
+               element_add_class (blockquote, "-x-evo-plaintext-quoted");
+
+               word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+               node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (blockquote));
+               while (node) {
+                       WebKitDOMNode *next_sibling;
+
+                       node = WEBKIT_DOM_NODE (e_editor_dom_wrap_paragraph_length (editor_page, 
WEBKIT_DOM_ELEMENT (node), word_wrap_length - 2));
+
+                       webkit_dom_node_normalize (node);
+                       e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT 
(node), 1);
+
+                       next_sibling = webkit_dom_node_get_next_sibling (node);
+                       if (!next_sibling)
+                               break;
+
+                       node = next_sibling;
+               }
+       }
+
+       dom_add_selection_markers_into_element_end (
+               document, WEBKIT_DOM_ELEMENT (node), NULL, NULL);
+
+       e_editor_dom_selection_restore (editor_page);
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+       e_editor_page_emit_content_changed (editor_page);
+
+       g_free (escaped_text);
+       g_free (inner_html);
+}
+
+static void
+mark_citation (WebKitDOMElement *citation)
+{
+       webkit_dom_html_element_insert_adjacent_text (
+               WEBKIT_DOM_HTML_ELEMENT (citation),
+               "beforebegin",
+               "##CITATION_START##",
+               NULL);
+
+       webkit_dom_html_element_insert_adjacent_text (
+               WEBKIT_DOM_HTML_ELEMENT (citation),
+               "afterend",
+               "##CITATION_END##",
+               NULL);
+
+       element_add_class (citation, "marked");
+}
+
+static gint
+create_text_markers_for_citations_in_element (WebKitDOMElement *element)
+{
+       gint count = 0;
+       WebKitDOMElement *citation;
+
+       citation = webkit_dom_element_query_selector (
+               element, "blockquote[type=cite]:not(.marked)", NULL);
+
+       while (citation) {
+               mark_citation (citation);
+               count ++;
+
+               citation = webkit_dom_element_query_selector (
+                       element, "blockquote[type=cite]:not(.marked)", NULL);
+       }
+
+       return count;
+}
+
+static void
+create_text_markers_for_selection_in_element (WebKitDOMElement *element)
+{
+       WebKitDOMElement *selection_marker;
+
+       selection_marker = webkit_dom_element_query_selector (
+               element, "#-x-evo-selection-start-marker", NULL);
+       if (selection_marker)
+               webkit_dom_html_element_insert_adjacent_text (
+                       WEBKIT_DOM_HTML_ELEMENT (selection_marker),
+                       "afterend",
+                       "##SELECTION_START##",
+                       NULL);
+
+       selection_marker = webkit_dom_element_query_selector (
+               element, "#-x-evo-selection-end-marker", NULL);
+       if (selection_marker)
+               webkit_dom_html_element_insert_adjacent_text (
+                       WEBKIT_DOM_HTML_ELEMENT (selection_marker),
+                       "afterend",
+                       "##SELECTION_END##",
+                       NULL);
+}
+
+static void
+quote_plain_text_elements_after_wrapping_in_document (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       gint length, ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* Also quote the PRE elements as well. */
+       list = webkit_dom_document_query_selector_all (
+               document, "blockquote[type=cite] > p[data-evo-paragraph], blockquote[type=cite] > pre", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               gint citation_level;
+               WebKitDOMNode *child;
+
+               child = webkit_dom_node_list_item (list, ii);
+               citation_level = e_editor_dom_get_citation_level (child, TRUE);
+               e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT 
(child), citation_level);
+               g_object_unref (child);
+       }
+       g_object_unref (list);
+}
+
+static void
+clear_attributes (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNamedNodeMap *attributes;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMHTMLHeadElement *head;
+       WebKitDOMElement *document_element;
+       gint length, ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       body = webkit_dom_document_get_body (document);
+       head = webkit_dom_document_get_head (document);
+       document_element = webkit_dom_document_get_document_element (document);
+
+       /* Remove all attributes from HTML element */
+       attributes = webkit_dom_element_get_attributes (document_element);
+       length = webkit_dom_named_node_map_get_length (attributes);
+       for (ii = length - 1; ii >= 0; ii--) {
+               WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+               webkit_dom_element_remove_attribute_node (
+                       document_element, WEBKIT_DOM_ATTR (node), NULL);
+               g_object_unref (node);
+       }
+       g_object_unref (attributes);
+
+       /* Remove everything from HEAD element */
+       while (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (head)))
+               remove_node (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (head)));
+
+       /* Make the quote marks non-selectable. */
+       e_editor_dom_disable_quote_marks_select (editor_page);
+
+       /* Remove non Evolution attributes from BODY element */
+       attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
+       length = webkit_dom_named_node_map_get_length (attributes);
+       for (ii = length - 1; ii >= 0; ii--) {
+               gchar *name;
+               WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+               name = webkit_dom_node_get_local_name (node);
+
+               if (!g_str_has_prefix (name, "data-") && (g_strcmp0 (name, "spellcheck") != 0))
+                       webkit_dom_element_remove_attribute_node (
+                               WEBKIT_DOM_ELEMENT (body),
+                               WEBKIT_DOM_ATTR (node),
+                               NULL);
+
+               g_object_unref (node);
+               g_free (name);
+       }
+       g_object_unref (attributes);
+}
+
+static void
+body_compositionstart_event_cb (WebKitDOMElement *element,
+                                WebKitDOMUIEvent *event,
+                                EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_page_set_composition_in_progress (editor_page, TRUE);
+       e_editor_dom_remove_input_event_listener_from_body (editor_page);
+}
+
+static void
+body_compositionend_event_cb (WebKitDOMElement *element,
+                              WebKitDOMUIEvent *event,
+                              EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_page_set_composition_in_progress (editor_page, FALSE);
+       e_editor_dom_remove_input_event_listener_from_body (editor_page);
+}
+
+static void
+register_html_events_handlers (EEditorPage *editor_page,
+                              WebKitDOMHTMLElement *body)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (body),
+               "keydown",
+               G_CALLBACK (body_keydown_event_cb),
+               FALSE,
+               editor_page);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (body),
+               "keypress",
+               G_CALLBACK (body_keypress_event_cb),
+               FALSE,
+               editor_page);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (body),
+               "keyup",
+               G_CALLBACK (body_keyup_event_cb),
+               FALSE,
+               editor_page);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (body),
+               "compositionstart",
+               G_CALLBACK (body_compositionstart_event_cb),
+               FALSE,
+               editor_page);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (body),
+               "compositionend",
+               G_CALLBACK (body_compositionend_event_cb),
+               FALSE,
+               editor_page);
+}
+
+void
+e_editor_dom_convert_content (EEditorPage *editor_page,
+                             const gchar *preferred_text)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *paragraph, *content_wrapper, *top_signature;
+       WebKitDOMElement *cite_body, *signature, *wrapper;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMNodeList *list;
+       WebKitDOMNode *node;
+       WebKitDOMDOMWindow *dom_window;
+       EContentEditorContentFlags flags;
+       gboolean start_bottom, empty = FALSE;
+       gchar *inner_html;
+       gint ii, length;
+       GSettings *settings;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+       start_bottom = g_settings_get_boolean (settings, "composer-reply-start-bottom");
+       g_object_unref (settings);
+
+       flags = e_editor_page_get_current_content_flags (editor_page);
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       body = webkit_dom_document_get_body (document);
+       /* Wrapper that will represent the new body. */
+       wrapper = webkit_dom_document_create_element (document, "div", NULL);
+
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-converted", "", NULL);
+
+       cite_body = webkit_dom_document_query_selector (
+               document, "span.-x-evo-cite-body", NULL);
+
+       /* content_wrapper when the processed text will be placed. */
+       content_wrapper = webkit_dom_document_create_element (
+               document, cite_body ? "blockquote" : "div", NULL);
+       if (cite_body) {
+               webkit_dom_element_set_attribute (content_wrapper, "type", "cite", NULL);
+               webkit_dom_element_set_attribute (content_wrapper, "id", "-x-evo-main-cite", NULL);
+       }
+
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (wrapper), WEBKIT_DOM_NODE (content_wrapper), NULL);
+
+       /* Remove all previously inserted paragraphs. */
+       list = webkit_dom_document_query_selector_all (
+               document, "p[data-evo-paragraph]:not([data-headers])", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       /* Insert the paragraph where the caret will be. */
+       paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+       webkit_dom_element_set_id (paragraph, "-x-evo-input-start");
+       webkit_dom_node_insert_before (
+               WEBKIT_DOM_NODE (wrapper),
+               WEBKIT_DOM_NODE (paragraph),
+               start_bottom ?
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (content_wrapper)) :
+                       WEBKIT_DOM_NODE (content_wrapper),
+               NULL);
+
+       /* Insert signature (if presented) to the right position. */
+       top_signature = webkit_dom_document_query_selector (
+               document, ".-x-evo-top-signature", NULL);
+       signature = webkit_dom_document_query_selector (
+               document, ".-x-evo-signature-content_wrapper", NULL);
+       if (signature) {
+               if (top_signature) {
+                       WebKitDOMElement *spacer;
+
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (wrapper),
+                               WEBKIT_DOM_NODE (signature),
+                               start_bottom ?
+                                       WEBKIT_DOM_NODE (content_wrapper) :
+                                       webkit_dom_node_get_next_sibling (
+                                               WEBKIT_DOM_NODE (paragraph)),
+                               NULL);
+                       /* Insert NL after the signature */
+                       spacer = e_editor_dom_prepare_paragraph (editor_page, FALSE);
+                       element_add_class (spacer, "-x-evo-top-signature-spacer");
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (wrapper),
+                               WEBKIT_DOM_NODE (spacer),
+                               webkit_dom_node_get_next_sibling (
+                                       WEBKIT_DOM_NODE (signature)),
+                               NULL);
+               } else {
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (wrapper),
+                               WEBKIT_DOM_NODE (signature),
+                               webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (
+                                       start_bottom ? paragraph : content_wrapper)),
+                               NULL);
+               }
+       }
+
+       /* Move credits to the body */
+       list = webkit_dom_document_query_selector_all (
+               document, "span.-x-evo-to-body[data-credits]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               char *credits;
+               WebKitDOMElement *element;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+               credits = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "data-credits");
+               if (credits)
+                       webkit_dom_html_element_set_inner_text (WEBKIT_DOM_HTML_ELEMENT (element), credits, 
NULL);
+               g_free (credits);
+
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (wrapper),
+                       WEBKIT_DOM_NODE (element),
+                       WEBKIT_DOM_NODE (content_wrapper),
+                       NULL);
+
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       /* Move headers to body */
+       list = webkit_dom_document_query_selector_all (
+               document, "div[data-headers]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (list, ii);
+               webkit_dom_element_remove_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "data-headers");
+               e_editor_dom_set_paragraph_style (editor_page, WEBKIT_DOM_ELEMENT (node), -1, 0, "");
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (wrapper),
+                       node,
+                       WEBKIT_DOM_NODE (content_wrapper),
+                       NULL);
+
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       repair_gmail_blockquotes (document);
+       remove_thunderbird_signature (document);
+       create_text_markers_for_citations_in_element (WEBKIT_DOM_ELEMENT (body));
+
+       if (preferred_text && *preferred_text)
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (content_wrapper), preferred_text, NULL);
+       else {
+               gchar *inner_text;
+
+               inner_text = webkit_dom_html_element_get_inner_text (body);
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (content_wrapper), inner_text, NULL);
+
+               g_free (inner_text);
+       }
+
+       inner_html = webkit_dom_element_get_inner_html (content_wrapper);
+
+       /* Replace the old body with the new one. */
+       node = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), FALSE, NULL);
+       webkit_dom_node_replace_child (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (body)),
+               node,
+               WEBKIT_DOM_NODE (body),
+               NULL);
+       body = WEBKIT_DOM_HTML_ELEMENT (node);
+
+       /* Copy all to nodes to the new body. */
+       while ((node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (wrapper)))) {
+               webkit_dom_node_insert_before (
+                       WEBKIT_DOM_NODE (body),
+                       WEBKIT_DOM_NODE (node),
+                       webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)),
+                       NULL);
+       }
+       remove_node (WEBKIT_DOM_NODE (wrapper));
+
+       if (inner_html && !*inner_html)
+               empty = TRUE;
+
+       length = webkit_dom_element_get_child_element_count (WEBKIT_DOM_ELEMENT (body));
+       if (length <= 1) {
+               empty = TRUE;
+               if (length == 1) {
+                       WebKitDOMNode *child;
+
+                       child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+                       empty = child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child);
+               }
+       }
+
+       if (preferred_text && *preferred_text)
+               empty = FALSE;
+
+       if (!empty)
+               parse_html_into_blocks (editor_page, content_wrapper, NULL, inner_html);
+       else
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (content_wrapper),
+                       WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, FALSE)),
+                       NULL);
+
+       if (!cite_body) {
+               if (!empty) {
+                       WebKitDOMNode *child;
+
+                       while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (content_wrapper)))) 
{
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (content_wrapper)),
+                                       child,
+                                       WEBKIT_DOM_NODE (content_wrapper),
+                                       NULL);
+                       }
+               }
+
+               remove_node (WEBKIT_DOM_NODE (content_wrapper));
+       }
+
+       /* If not editting a message, don't add any new block and just place
+        * the carret in the beginning of content. We want to have the same
+        * behaviour when editting message as new or we start replying on top. */
+       if ((flags & E_CONTENT_EDITOR_MESSAGE_EDIT_AS_NEW) ||
+           !(flags & E_CONTENT_EDITOR_MESSAGE_EDITTING) ||
+            !start_bottom) {
+               WebKitDOMNode *child;
+
+               remove_node (WEBKIT_DOM_NODE (paragraph));
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+               if (child)
+                       dom_add_selection_markers_into_element_start (
+                               document, WEBKIT_DOM_ELEMENT (child), NULL, NULL);
+       }
+
+       if ((paragraph = webkit_dom_document_get_element_by_id (document, "-x-evo-last-br")))
+               webkit_dom_element_remove_attribute (paragraph, "id");
+       if ((paragraph = webkit_dom_document_get_element_by_id (document, "-x-evo-first-br")))
+               webkit_dom_element_remove_attribute (paragraph, "id");
+
+       e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
+
+       if (!e_editor_page_get_html_mode (editor_page)) {
+               e_editor_dom_wrap_paragraphs_in_document (editor_page);
+
+               quote_plain_text_elements_after_wrapping_in_document (editor_page);
+       }
+
+       clear_attributes (editor_page);
+
+       e_editor_dom_selection_restore (editor_page);
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+       /* Register on input event that is called when the content (body) is modified */
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (body),
+               "input",
+               G_CALLBACK (body_input_event_cb),
+               FALSE,
+               editor_page);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (dom_window),
+               "scroll",
+               G_CALLBACK (body_scroll_event_cb),
+               FALSE,
+               editor_page);
+
+       register_html_events_handlers (editor_page, body);
+       set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (body), e_editor_page_get_html_mode 
(editor_page));
+
+       g_free (inner_html);
+}
+
+void
+e_editor_dom_convert_and_insert_html_into_selection (EEditorPage *editor_page,
+                                                    const gchar *html,
+                                                    gboolean is_html)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker, *element;
+       WebKitDOMNode *node, *current_block;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean has_selection;
+       gchar *inner_html;
+       gint citation_level;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       e_editor_dom_remove_input_event_listener_from_body (editor_page);
+
+       e_editor_dom_selection_save (editor_page);
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       selection_end_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+       current_block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (current_block))
+               current_block = NULL;
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               gboolean collapsed;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_PASTE;
+/* FIXME WK2
+               ev->type = HISTORY_PASTE_AS_TEXT;*/
+
+               collapsed = e_editor_dom_selection_is_collapsed (editor_page);
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               if (!collapsed) {
+                       ev->before.end.x = ev->before.start.x;
+                       ev->before.end.y = ev->before.start.y;
+               }
+
+               ev->data.string.from = NULL;
+               ev->data.string.to = g_strdup (html);
+       }
+
+       element = webkit_dom_document_create_element (document, "div", NULL);
+       if (is_html) {
+               gchar *inner_text;
+
+               if (strstr (html, "\n")) {
+                       GRegex *regex;
+                       gchar *tmp;
+
+                       /* Strip new lines between tags to avoid unwanted line breaks. */
+                       regex = g_regex_new ("\\>[\\s]+\\<", 0, 0, NULL);
+                       tmp = g_regex_replace (
+                               regex, html, -1, 0, "> <", 0, NULL);
+                       webkit_dom_element_set_inner_html (element, tmp, NULL);
+                       g_free (tmp);
+                       g_regex_unref (regex);
+               } else {
+                       webkit_dom_element_set_inner_html (element, html, NULL);
+               }
+
+               inner_text = webkit_dom_html_element_get_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (element));
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (element), inner_text, NULL);
+
+               g_free (inner_text);
+       } else
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (element), html, NULL);
+
+       inner_html = webkit_dom_element_get_inner_html (element);
+       parse_html_into_blocks (editor_page, element, WEBKIT_DOM_ELEMENT (current_block), inner_html);
+
+       g_free (inner_html);
+
+       has_selection = !e_editor_dom_selection_is_collapsed (editor_page);
+       if (has_selection && !e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               /* FIXME WK2 - useless if(), see one line above */
+               if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+                       WebKitDOMRange *range;
+
+                       range = e_editor_dom_get_current_range (editor_page);
+                       insert_delete_event (editor_page, range);
+                       g_object_unref (range);
+               }
+
+               /* Remove the text that was meant to be replaced by the pasted text */
+               e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               selection_end_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+               current_block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (current_block))
+                       current_block = NULL;
+       }
+
+       citation_level = e_editor_dom_get_citation_level (WEBKIT_DOM_NODE (selection_end_marker), FALSE);
+       /* Pasting into the citation */
+       if (citation_level > 0) {
+               gint length;
+               gint word_wrap_length;
+               WebKitDOMElement *br;
+               WebKitDOMNode *first_paragraph, *last_paragraph;
+               WebKitDOMNode *child, *parent, *current_block;
+
+               first_paragraph = webkit_dom_node_get_first_child (
+                       WEBKIT_DOM_NODE (element));
+               last_paragraph = webkit_dom_node_get_last_child (
+                       WEBKIT_DOM_NODE (element));
+
+               word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+               length = word_wrap_length - 2 * citation_level;
+
+               /* Pasting text that was parsed just into one paragraph */
+               if (webkit_dom_node_is_same_node (first_paragraph, last_paragraph)) {
+                       WebKitDOMNode *child, *parent, *parent_block;
+
+                       parent_block = e_editor_dom_get_parent_block_node_from_child (
+                               WEBKIT_DOM_NODE (selection_start_marker));
+
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (parent_block));
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (parent_block));
+
+                       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+                       while ((child = webkit_dom_node_get_first_child (first_paragraph))) {
+                               if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) &&
+                                   WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (child)) {
+                                       WebKitDOMNode *anchor_child;
+
+                                       while ((anchor_child = webkit_dom_node_get_first_child (child)))
+                                               webkit_dom_node_insert_before (
+                                                       webkit_dom_node_get_parent_node (
+                                                               WEBKIT_DOM_NODE (selection_start_marker)),
+                                                       anchor_child,
+                                                       WEBKIT_DOM_NODE (selection_start_marker),
+                                                       NULL);
+                                       remove_node (child);
+                               } else
+                                       webkit_dom_node_insert_before (
+                                               webkit_dom_node_get_parent_node (
+                                                       WEBKIT_DOM_NODE (selection_start_marker)),
+                                               child,
+                                               WEBKIT_DOM_NODE (selection_start_marker),
+                                               NULL);
+                       }
+
+                       if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent)) {
+                               gchar *text_content;
+
+                               text_content = webkit_dom_node_get_text_content (parent);
+
+                               webkit_dom_element_set_attribute (
+                                       WEBKIT_DOM_ELEMENT (parent),
+                                       "href",
+                                       text_content,
+                                       NULL);
+                               g_free (text_content);
+                       }
+
+                       parent_block = WEBKIT_DOM_NODE (
+                               e_editor_dom_wrap_paragraph_length (editor_page, WEBKIT_DOM_ELEMENT 
(parent_block), length));
+                       webkit_dom_node_normalize (parent_block);
+                       e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT 
(parent_block), citation_level);
+
+                       e_editor_dom_selection_restore (editor_page);
+
+                       g_object_unref (element);
+                       goto out;
+               }
+
+               /* Pasting content parsed into the multiple paragraphs */
+               parent = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+               e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (parent));
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (parent));
+
+               /* Move the elements from the first paragraph before the selection start element */
+               while ((child = webkit_dom_node_get_first_child (first_paragraph)))
+                       webkit_dom_node_insert_before (
+                               parent,
+                               child,
+                               WEBKIT_DOM_NODE (selection_start_marker),
+                               NULL);
+
+               remove_node (first_paragraph);
+
+               /* If the BR element is on the last position, remove it as we don't need it */
+               child = webkit_dom_node_get_last_child (parent);
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+                       remove_node (child);
+
+               parent = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_end_marker));
+
+               child = webkit_dom_node_get_next_sibling (
+                       WEBKIT_DOM_NODE (selection_end_marker));
+               /* Move the elements that are in the same paragraph as the selection end
+                * on the end of pasted text, but avoid BR on the end of paragraph */
+               while (child) {
+                       WebKitDOMNode *next_child =
+                               webkit_dom_node_get_next_sibling  (child);
+                       if (!(!next_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)))
+                               webkit_dom_node_append_child (last_paragraph, child, NULL);
+                       child = next_child;
+               }
+
+               current_block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+               dom_remove_selection_markers (document);
+
+               /* Caret will be restored on the end of pasted text */
+               webkit_dom_node_append_child (
+                       last_paragraph,
+                       WEBKIT_DOM_NODE (dom_create_selection_marker (document, TRUE)),
+                       NULL);
+
+               webkit_dom_node_append_child (
+                       last_paragraph,
+                       WEBKIT_DOM_NODE (dom_create_selection_marker (document, FALSE)),
+                       NULL);
+
+               /* Insert the paragraph with the end of the pasted text after
+                * the paragraph that contains the selection end */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (parent),
+                       last_paragraph,
+                       webkit_dom_node_get_next_sibling (parent),
+                       NULL);
+
+               /* Wrap, quote and move all paragraphs from pasted text into the body */
+               while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))) {
+                       child = WEBKIT_DOM_NODE (e_editor_dom_wrap_paragraph_length (
+                               editor_page, WEBKIT_DOM_ELEMENT (child), length));
+                       e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT 
(child), citation_level);
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (last_paragraph),
+                               child,
+                               last_paragraph,
+                               NULL);
+               }
+
+               webkit_dom_node_normalize (last_paragraph);
+
+               last_paragraph = WEBKIT_DOM_NODE (
+                       e_editor_dom_wrap_paragraph_length (
+                               editor_page, WEBKIT_DOM_ELEMENT (last_paragraph), length));
+               e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT 
(last_paragraph), citation_level);
+
+               e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (parent));
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (parent));
+
+               current_block = WEBKIT_DOM_NODE (e_editor_dom_wrap_paragraph_length (
+                       editor_page, WEBKIT_DOM_ELEMENT (current_block), length));
+               e_editor_dom_quote_plain_text_element_after_wrapping (editor_page, WEBKIT_DOM_ELEMENT 
(current_block), citation_level);
+
+               if ((br = webkit_dom_document_get_element_by_id (document, "-x-evo-last-br")))
+                       webkit_dom_element_remove_attribute (br, "class");
+
+               if ((br = webkit_dom_document_get_element_by_id (document, "-x-evo-first-br")))
+                       webkit_dom_element_remove_attribute (br, "class");
+
+               if (ev) {
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->after.start.x,
+                               &ev->after.start.y,
+                               &ev->after.end.x,
+                               &ev->after.end.y);
+                       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+               }
+
+               e_editor_dom_selection_restore (editor_page);
+
+               g_object_unref (element);
+               goto out;
+       }
+
+       remove_node (WEBKIT_DOM_NODE (selection_start_marker));
+       remove_node (WEBKIT_DOM_NODE (selection_end_marker));
+
+       /* If the text to insert was converted just to one block, pass just its
+        * text to WebKit otherwise WebKit will insert unwanted block with
+        * extra new line. */
+       if (!webkit_dom_node_get_next_sibling (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+               inner_html = webkit_dom_element_get_inner_html (
+                       WEBKIT_DOM_ELEMENT (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))));
+       else
+               inner_html = webkit_dom_element_get_inner_html (WEBKIT_DOM_ELEMENT (element));
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_HTML, inner_html);
+
+       if (g_str_has_suffix (inner_html, " "))
+               e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, " ");
+
+       g_free (inner_html);
+
+       g_object_unref (element);
+       e_editor_dom_selection_save (editor_page);
+
+       element = webkit_dom_document_query_selector (
+               document, "* > br#-x-evo-first-br", NULL);
+       if (element) {
+               WebKitDOMNode *sibling;
+               WebKitDOMNode *parent;
+
+               parent = webkit_dom_node_get_parent_node (
+                       WEBKIT_DOM_NODE (element));
+
+               sibling = webkit_dom_node_get_previous_sibling (parent);
+               if (sibling)
+                       remove_node (WEBKIT_DOM_NODE (parent));
+               else
+                       webkit_dom_element_remove_attribute (element, "class");
+       }
+
+       element = webkit_dom_document_query_selector (
+               document, "* > br#-x-evo-last-br", NULL);
+       if (element) {
+               WebKitDOMNode *parent;
+               WebKitDOMNode *child;
+
+               parent = webkit_dom_node_get_parent_node (
+                       WEBKIT_DOM_NODE (element));
+
+               node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
+               if (node) {
+                       node = webkit_dom_node_get_first_child (node);
+                       if (node) {
+                               inner_html = webkit_dom_node_get_text_content (node);
+                               if (g_str_has_prefix (inner_html, UNICODE_NBSP))
+                                       webkit_dom_character_data_replace_data (
+                                               WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL);
+                               g_free (inner_html);
+                       }
+               }
+
+               selection_end_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+
+               if (has_selection) {
+                       /* Everything after the selection end marker have to be in separate
+                        * paragraph */
+                       child = webkit_dom_node_get_next_sibling (
+                               WEBKIT_DOM_NODE (selection_end_marker));
+                       /* Move the elements that are in the same paragraph as the selection end
+                        * on the end of pasted text, but avoid BR on the end of paragraph */
+                       while (child) {
+                               WebKitDOMNode *next_child =
+                                       webkit_dom_node_get_next_sibling  (child);
+                               if (!(!next_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)))
+                                       webkit_dom_node_append_child (parent, child, NULL);
+                               child = next_child;
+                       }
+
+                       remove_node (WEBKIT_DOM_NODE (element));
+
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (
+                                       webkit_dom_node_get_parent_node (
+                                               WEBKIT_DOM_NODE (selection_end_marker))),
+                               parent,
+                               webkit_dom_node_get_next_sibling (
+                                       webkit_dom_node_get_parent_node (
+                                               WEBKIT_DOM_NODE (selection_end_marker))),
+                               NULL);
+                       node = parent;
+               } else {
+                       node = webkit_dom_node_get_next_sibling (parent);
+                       if (!node) {
+                               fix_structure_after_pasting_multiline_content (parent);
+                               if (!webkit_dom_node_get_first_child (parent))
+                                       remove_node (parent);
+                       }
+               }
+
+               if (node) {
+                       /* Restore caret on the end of pasted text */
+                       webkit_dom_node_insert_before (
+                               node,
+                               WEBKIT_DOM_NODE (selection_end_marker),
+                               webkit_dom_node_get_first_child (node),
+                               NULL);
+
+                       selection_start_marker = webkit_dom_document_get_element_by_id (
+                               document, "-x-evo-selection-start-marker");
+                       webkit_dom_node_insert_before (
+                               node,
+                               WEBKIT_DOM_NODE (selection_start_marker),
+                               webkit_dom_node_get_first_child (node),
+                               NULL);
+               }
+
+               if (element)
+                       webkit_dom_element_remove_attribute (element, "class");
+
+               if (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)) && !has_selection)
+                       remove_node (parent);
+       } else {
+               /* When pasting the content that was copied from the composer, WebKit
+                * restores the selection wrongly, thus is saved wrongly and we have
+                * to fix it */
+               WebKitDOMNode *block, *parent, *clone1, *clone2;
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               selection_end_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               parent = webkit_dom_node_get_parent_node (block);
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (parent), "id");
+
+               /* Check if WebKit created wrong structure */
+               clone1 = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (block), FALSE, NULL);
+               clone2 = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (parent), FALSE, NULL);
+               if (webkit_dom_node_is_equal_node (clone1, clone2) ||
+                   (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (clone1) && WEBKIT_DOM_IS_HTML_DIV_ELEMENT (clone2))) {
+                       fix_structure_after_pasting_multiline_content (block);
+                       if (g_strcmp0 (html, "\n") == 0) {
+                               WebKitDOMElement *br;
+
+                               br = webkit_dom_document_create_element (document, "br", NULL);
+                               webkit_dom_node_append_child (
+                                       parent, WEBKIT_DOM_NODE (br), NULL);
+
+                               webkit_dom_node_insert_before (
+                                       parent,
+                                       WEBKIT_DOM_NODE (selection_start_marker),
+                                       webkit_dom_node_get_last_child (parent),
+                                       NULL);
+                       } else if (!webkit_dom_node_get_first_child (parent))
+                               remove_node (parent);
+               }
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (
+                               WEBKIT_DOM_NODE (selection_start_marker)),
+                       WEBKIT_DOM_NODE (selection_end_marker),
+                       webkit_dom_node_get_next_sibling (
+                               WEBKIT_DOM_NODE (selection_start_marker)),
+                       NULL);
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+ out:
+       e_editor_dom_check_magic_links (editor_page, FALSE);
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+       e_editor_dom_scroll_to_caret (editor_page);
+
+       e_editor_dom_register_input_event_listener_on_body (editor_page);
+
+       e_editor_page_emit_content_changed (editor_page);
+}
+
+static gint
+get_indentation_level (WebKitDOMElement *element)
+{
+       WebKitDOMElement *parent;
+       gint level = 0;
+
+       if (element_has_class (element, "-x-evo-indented"))
+               level++;
+
+       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (element));
+       /* Count level of indentation */
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               if (element_has_class (parent, "-x-evo-indented"))
+                       level++;
+
+               parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (parent));
+       }
+
+       return level;
+}
+
+static void
+process_blockquote (WebKitDOMElement *blockquote,
+                    gboolean replace_indentation_with_spaces)
+{
+       WebKitDOMNodeList *list;
+       int jj, length;
+
+       /* First replace wrappers */
+       list = webkit_dom_element_query_selector_all (
+               blockquote, "span.-x-evo-temp-text-wrapper", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (jj = 0; jj < length; jj++) {
+               WebKitDOMNode *quoted_node;
+               gchar *text_content;
+
+               quoted_node = webkit_dom_node_list_item (list, jj);
+               text_content = webkit_dom_node_get_text_content (quoted_node);
+               webkit_dom_element_set_outer_html (
+                       WEBKIT_DOM_ELEMENT (quoted_node), text_content, NULL);
+
+               g_free (text_content);
+               g_object_unref (quoted_node);
+       }
+       g_object_unref (list);
+
+       /* Afterwards replace quote nodes with symbols */
+       list = webkit_dom_element_query_selector_all (
+               blockquote, "span.-x-evo-quoted", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (jj = 0; jj < length; jj++) {
+               WebKitDOMNode *quoted_node;
+               gchar *text_content;
+
+               quoted_node = webkit_dom_node_list_item (list, jj);
+               text_content = webkit_dom_node_get_text_content (quoted_node);
+               webkit_dom_element_set_outer_html (
+                       WEBKIT_DOM_ELEMENT (quoted_node), text_content, NULL);
+
+               g_free (text_content);
+               g_object_unref (quoted_node);
+       }
+       g_object_unref (list);
+
+       if (element_has_class (blockquote, "-x-evo-indented") && replace_indentation_with_spaces) {
+               WebKitDOMNode *child;
+               gchar *spaces;
+
+               spaces = g_strnfill (4 * get_indentation_level (blockquote), ' ');
+
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (blockquote));
+               while (child) {
+                       /* If next sibling is indented blockqoute skip it,
+                        * it will be processed afterwards */
+                       if (WEBKIT_DOM_IS_ELEMENT (child) &&
+                           element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-indented"))
+                               child = webkit_dom_node_get_next_sibling (child);
+
+                       if (WEBKIT_DOM_IS_TEXT (child)) {
+                               gchar *text_content;
+                               gchar *indented_text;
+
+                               text_content = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (child));
+                               indented_text = g_strconcat (spaces, text_content, NULL);
+
+                               webkit_dom_text_replace_whole_text (
+                                       WEBKIT_DOM_TEXT (child),
+                                       indented_text,
+                                       NULL);
+
+                               g_free (text_content);
+                               g_free (indented_text);
+                       }
+
+                       if (!child)
+                               break;
+
+                       /* Move to next node */
+                       if (webkit_dom_node_has_child_nodes (child))
+                               child = webkit_dom_node_get_first_child (child);
+                       else if (webkit_dom_node_get_next_sibling (child))
+                               child = webkit_dom_node_get_next_sibling (child);
+                       else {
+                               if (webkit_dom_node_is_equal_node (WEBKIT_DOM_NODE (blockquote), child))
+                                       break;
+
+                               child = webkit_dom_node_get_parent_node (child);
+                               if (child)
+                                       child = webkit_dom_node_get_next_sibling (child);
+                       }
+               }
+               g_free (spaces);
+
+               webkit_dom_element_remove_attribute (blockquote, "style");
+       }
+}
+
+/* Taken from GtkHTML */
+static gchar *
+get_alpha_value (gint value,
+                 gboolean lower)
+{
+       GString *str;
+       gchar *rv;
+       gint add = lower ? 'a' : 'A';
+
+       str = g_string_new (". ");
+
+       do {
+               g_string_prepend_c (str, ((value - 1) % 26) + add);
+               value = (value - 1) / 26;
+       } while (value);
+
+       rv = str->str;
+       g_string_free (str, FALSE);
+
+       return rv;
+}
+
+/* Taken from GtkHTML */
+static gchar *
+get_roman_value (gint value,
+                 gboolean lower)
+{
+       GString *str;
+       const gchar *base = "IVXLCDM";
+       gchar *rv;
+       gint b, r, add = lower ? 'a' - 'A' : 0;
+
+       if (value > 3999)
+               return g_strdup ("?. ");
+
+       str = g_string_new (". ");
+
+       for (b = 0; value > 0 && b < 7 - 1; b += 2, value /= 10) {
+               r = value % 10;
+               if (r != 0) {
+                       if (r < 4) {
+                               for (; r; r--)
+                                       g_string_prepend_c (str, base[b] + add);
+                       } else if (r == 4) {
+                               g_string_prepend_c (str, base[b + 1] + add);
+                               g_string_prepend_c (str, base[b] + add);
+                       } else if (r == 5) {
+                               g_string_prepend_c (str, base[b + 1] + add);
+                       } else if (r < 9) {
+                               for (; r > 5; r--)
+                                       g_string_prepend_c (str, base[b] + add);
+                               g_string_prepend_c (str, base[b + 1] + add);
+                       } else if (r == 9) {
+                               g_string_prepend_c (str, base[b + 2] + add);
+                               g_string_prepend_c (str, base[b] + add);
+                       }
+               }
+       }
+
+       rv = str->str;
+       g_string_free (str, FALSE);
+
+       return rv;
+}
+
+static void
+process_list_to_plain_text (EEditorPage *editor_page,
+                            WebKitDOMElement *element,
+                            gint level,
+                            GString *output)
+{
+       EContentEditorBlockFormat format;
+       EContentEditorAlignment alignment;
+       gint counter = 1;
+       gchar *indent_per_level;
+       WebKitDOMNode *item;
+       gint word_wrap_length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       indent_per_level = g_strnfill (SPACES_PER_LIST_LEVEL, ' ');
+       word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+       format = dom_get_list_format_from_node (
+               WEBKIT_DOM_NODE (element));
+
+       /* Process list items to plain text */
+       item = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element));
+       while (item) {
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (item))
+                       g_string_append (output, "\n");
+
+               if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+                       gchar *space, *item_str = NULL;
+                       gint ii = 0;
+                       WebKitDOMElement *wrapped;
+                       GString *item_value = g_string_new ("");
+
+                       alignment = e_editor_dom_get_list_alignment_from_node (
+                               WEBKIT_DOM_NODE (item));
+
+                       wrapped = webkit_dom_element_query_selector (
+                               WEBKIT_DOM_ELEMENT (item), ".-x-evo-wrap-br", NULL);
+                       /* Wrapped text */
+                       if (wrapped) {
+                               WebKitDOMNode *node = webkit_dom_node_get_first_child (item);
+                               GString *line = g_string_new ("");
+                               while (node) {
+                                       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node) &&
+                                           element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br")) {
+                                               g_string_append (line, "\n");
+                                               /* put spaces before line characters -> wordwraplength - 
indentation */
+                                               for (ii = 0; ii < level; ii++)
+                                                       g_string_append (line, indent_per_level);
+                                               if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (element))
+                                                       g_string_append (line, indent_per_level);
+                                               g_string_append (item_value, line->str);
+                                               g_string_erase (line, 0, -1);
+                                       } else {
+                                               /* append text from node to line */
+                                               gchar *text_content;
+                                               text_content = webkit_dom_node_get_text_content (node);
+                                               g_string_append (line, text_content);
+                                               g_free (text_content);
+                                       }
+                                       node = webkit_dom_node_get_next_sibling (node);
+                               }
+
+                               if (alignment == E_CONTENT_EDITOR_ALIGNMENT_LEFT)
+                                       g_string_append (item_value, line->str);
+
+                               if (alignment == E_CONTENT_EDITOR_ALIGNMENT_CENTER) {
+                                       gchar *fill = NULL;
+                                       gint fill_length;
+
+                                       fill_length = word_wrap_length - g_utf8_strlen (line->str, -1);
+                                       fill_length -= ii * SPACES_PER_LIST_LEVEL;
+                                       if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (element))
+                                               fill_length += SPACES_PER_LIST_LEVEL;
+                                       fill_length /= 2;
+
+                                       if (fill_length < 0)
+                                               fill_length = 0;
+
+                                       fill = g_strnfill (fill_length, ' ');
+
+                                       g_string_append (item_value, fill);
+                                       g_string_append (item_value, line->str);
+                                       g_free (fill);
+                               }
+
+                               if (alignment == E_CONTENT_EDITOR_ALIGNMENT_RIGHT) {
+                                       gchar *fill = NULL;
+                                       gint fill_length;
+
+                                       fill_length = word_wrap_length - g_utf8_strlen (line->str, -1);
+                                       fill_length -= ii * SPACES_PER_LIST_LEVEL;
+
+                                       if (fill_length < 0)
+                                               fill_length = 0;
+
+                                       fill = g_strnfill (fill_length, ' ');
+
+                                       g_string_append (item_value, fill);
+                                       g_string_append (item_value, line->str);
+                                       g_free (fill);
+                               }
+                               g_string_free (line, TRUE);
+                               /* that same here */
+                       } else {
+                               gchar *text_content =
+                                       webkit_dom_node_get_text_content (item);
+                               g_string_append (item_value, text_content);
+                               g_free (text_content);
+                       }
+
+                       if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST) {
+                               space = g_strnfill (SPACES_PER_LIST_LEVEL - 2, ' ');
+                               item_str = g_strdup_printf (
+                                       "%s* %s", space, item_value->str);
+                               g_free (space);
+                       }
+
+                       if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST) {
+                               gint length = 1, tmp = counter;
+
+                               while ((tmp = tmp / 10) > 1)
+                                       length++;
+
+                               if (tmp == 1)
+                                       length++;
+
+                               space = g_strnfill (SPACES_ORDERED_LIST_FIRST_LEVEL - 2 - length, ' ');
+                               item_str = g_strdup_printf (
+                                       "%s%d. %s", space, counter, item_value->str);
+                               g_free (space);
+                       }
+
+                       if (format > E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST) {
+                               gchar *value;
+
+                               if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA)
+                                       value = get_alpha_value (counter, FALSE);
+                               else
+                                       value = get_roman_value (counter, FALSE);
+
+                               space = g_strnfill (SPACES_ORDERED_LIST_FIRST_LEVEL - strlen (value), ' ');
+                               item_str = g_strdup_printf (
+                                       "%s%s%s", space, value, item_value->str);
+                               g_free (space);
+                               g_free (value);
+                       }
+
+                       if (alignment == E_CONTENT_EDITOR_ALIGNMENT_LEFT) {
+                               for (ii = 0; ii < level - 1; ii++) {
+                                       g_string_append (output, indent_per_level);
+                               }
+                               if (WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (element))
+                                       if (dom_node_find_parent_element (item, "OL"))
+                                               g_string_append (output, indent_per_level);
+                               g_string_append (output, item_str);
+                       }
+
+                       if (alignment == E_CONTENT_EDITOR_ALIGNMENT_RIGHT) {
+                               if (!wrapped) {
+                                       gchar *fill = NULL;
+                                       gint fill_length;
+
+                                       fill_length = word_wrap_length - g_utf8_strlen (item_str, -1);
+                                       fill_length -= ii * SPACES_PER_LIST_LEVEL;
+
+                                       if (fill_length < 0)
+                                               fill_length = 0;
+
+                                       if (g_str_has_suffix (item_str, " "))
+                                               fill_length++;
+
+                                       fill = g_strnfill (fill_length, ' ');
+
+                                       g_string_append (output, fill);
+                                       g_free (fill);
+                               }
+                               if (g_str_has_suffix (item_str, " "))
+                                       g_string_append_len (output, item_str, g_utf8_strlen (item_str, -1) - 
1);
+                               else
+                                       g_string_append (output, item_str);
+                       }
+
+                       if (alignment == E_CONTENT_EDITOR_ALIGNMENT_CENTER) {
+                               if (!wrapped) {
+                                       gchar *fill = NULL;
+                                       gint fill_length = 0;
+
+                                       for (ii = 0; ii < level - 1; ii++)
+                                               g_string_append (output, indent_per_level);
+
+                                       fill_length = word_wrap_length - g_utf8_strlen (item_str, -1);
+                                       fill_length -= ii * SPACES_PER_LIST_LEVEL;
+                                       if (WEBKIT_DOM_IS_HTML_O_LIST_ELEMENT (element))
+                                               fill_length += SPACES_PER_LIST_LEVEL;
+                                       fill_length /= 2;
+
+                                       if (fill_length < 0)
+                                               fill_length = 0;
+
+                                       if (g_str_has_suffix (item_str, " "))
+                                               fill_length++;
+
+                                       fill = g_strnfill (fill_length, ' ');
+
+                                       g_string_append (output, fill);
+                                       g_free (fill);
+                               }
+                               if (g_str_has_suffix (item_str, " "))
+                                       g_string_append_len (output, item_str, g_utf8_strlen (item_str, -1) - 
1);
+                               else
+                                       g_string_append (output, item_str);
+                       }
+
+                       counter++;
+                       item = webkit_dom_node_get_next_sibling (item);
+                       if (item)
+                               g_string_append (output, "\n");
+
+                       g_free (item_str);
+                       g_string_free (item_value, TRUE);
+               } else if (node_is_list (item)) {
+                       process_list_to_plain_text (
+                               editor_page, WEBKIT_DOM_ELEMENT (item), level + 1, output);
+                       item = webkit_dom_node_get_next_sibling (item);
+               } else {
+                       item = webkit_dom_node_get_next_sibling (item);
+               }
+       }
+
+       if (webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element)))
+               g_string_append (output, "\n");
+
+       g_free (indent_per_level);
+}
+
+static void
+remove_base_attributes (WebKitDOMElement *element)
+{
+       webkit_dom_element_remove_attribute (element, "class");
+       webkit_dom_element_remove_attribute (element, "id");
+       webkit_dom_element_remove_attribute (element, "name");
+}
+
+static void
+remove_evolution_attributes (WebKitDOMElement *element)
+{
+       webkit_dom_element_remove_attribute (element, "data-converted");
+       webkit_dom_element_remove_attribute (element, "data-edit-as-new");
+       webkit_dom_element_remove_attribute (element, "data-evo-draft");
+       webkit_dom_element_remove_attribute (element, "data-inline");
+       webkit_dom_element_remove_attribute (element, "data-uri");
+       webkit_dom_element_remove_attribute (element, "data-message");
+       webkit_dom_element_remove_attribute (element, "data-name");
+       webkit_dom_element_remove_attribute (element, "data-new-message");
+       webkit_dom_element_remove_attribute (element, "data-user-wrapped");
+       webkit_dom_element_remove_attribute (element, "data-evo-plain-text");
+       webkit_dom_element_remove_attribute (element, "data-style");
+       webkit_dom_element_remove_attribute (element, "spellcheck");
+}
+
+static void
+convert_element_from_html_to_plain_text (EEditorPage *editor_page,
+                                         WebKitDOMElement *element,
+                                         gboolean *wrap,
+                                         gboolean *quote)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *top_signature, *signature, *blockquote, *main_blockquote;
+       WebKitDOMNode *signature_clone, *from;
+       WebKitDOMNodeList *list;
+       gint blockquotes_count, ii, length;
+       gchar *inner_text, *inner_html;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       top_signature = webkit_dom_element_query_selector (
+               element, ".-x-evo-top-signature", NULL);
+       signature = webkit_dom_element_query_selector (
+               element, "span.-x-evo-signature", NULL);
+       main_blockquote = webkit_dom_element_query_selector (
+               element, "#-x-evo-main-cite", NULL);
+
+       blockquote = webkit_dom_document_create_element (
+               document, "blockquote", NULL);
+
+       if (main_blockquote) {
+               webkit_dom_element_set_attribute (
+                       blockquote, "type", "cite", NULL);
+               from = WEBKIT_DOM_NODE (main_blockquote);
+       } else {
+               if (signature) {
+                       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (
+                               WEBKIT_DOM_NODE (signature));
+                       signature_clone = webkit_dom_node_clone_node_with_error (parent, TRUE, NULL);
+                       remove_node (parent);
+               }
+               from = WEBKIT_DOM_NODE (element);
+       }
+
+       /* Add the missing BR elements on the end of all DIV elements to correctly
+        * preserve the line breaks. */
+       list = webkit_dom_element_query_selector_all (WEBKIT_DOM_ELEMENT (from), "div", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (list, ii);
+               if (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (node))) {
+                       webkit_dom_node_append_child (
+                               node,
+                               WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)),
+                               NULL);
+               }
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       blockquotes_count = create_text_markers_for_citations_in_element (WEBKIT_DOM_ELEMENT (from));
+       create_text_markers_for_selection_in_element (WEBKIT_DOM_ELEMENT (from));
+
+       inner_text = webkit_dom_html_element_get_inner_text (
+               WEBKIT_DOM_HTML_ELEMENT (from));
+
+       webkit_dom_html_element_set_inner_text (
+               WEBKIT_DOM_HTML_ELEMENT (blockquote), inner_text, NULL);
+
+       inner_html = webkit_dom_element_get_inner_html (blockquote);
+
+       parse_html_into_blocks (editor_page,
+               main_blockquote ? blockquote : WEBKIT_DOM_ELEMENT (element),
+               NULL,
+               inner_html);
+
+       if (main_blockquote) {
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (
+                               WEBKIT_DOM_NODE (main_blockquote)),
+                       WEBKIT_DOM_NODE (blockquote),
+                       WEBKIT_DOM_NODE (main_blockquote),
+                       NULL);
+
+               remove_evolution_attributes (WEBKIT_DOM_ELEMENT (element));
+       } else {
+               WebKitDOMNode *first_child;
+
+               if (signature) {
+                       if (!top_signature) {
+                               signature_clone = webkit_dom_node_append_child (
+                                       WEBKIT_DOM_NODE (element),
+                                       signature_clone,
+                                       NULL);
+                       } else {
+                               webkit_dom_node_insert_before (
+                                       WEBKIT_DOM_NODE (element),
+                                       signature_clone,
+                                       webkit_dom_node_get_first_child (
+                                               WEBKIT_DOM_NODE (element)),
+                                       NULL);
+                       }
+               }
+
+               first_child = webkit_dom_node_get_first_child (
+                       WEBKIT_DOM_NODE (element));
+               if (first_child) {
+                       if (!webkit_dom_node_has_child_nodes (first_child)) {
+                               webkit_dom_element_set_inner_html (
+                                       WEBKIT_DOM_ELEMENT (first_child),
+                                       "<br>",
+                                       NULL);
+                       }
+                       dom_add_selection_markers_into_element_start (
+                               document, WEBKIT_DOM_ELEMENT (first_child), NULL, NULL);
+               }
+       }
+
+       if (wrap)
+               *wrap = TRUE;
+       if (quote)
+               *quote = main_blockquote || blockquotes_count > 0;
+
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (element), "data-converted", "", NULL);
+
+       g_free (inner_text);
+       g_free (inner_html);
+}
+
+void
+e_editor_dom_convert_element_from_html_to_plain_text (EEditorPage *editor_page,
+                                                     WebKitDOMElement *element)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       convert_element_from_html_to_plain_text (editor_page, element, NULL, NULL);
+}
+
+static void
+process_elements (EEditorPage *editor_page,
+                  WebKitDOMNode *node,
+                  gboolean changing_mode,
+                  gboolean to_plain_text,
+                  GString *buffer)
+{
+       WebKitDOMNodeList *nodes;
+       gulong ii, length;
+       gchar *content = NULL;
+       gboolean skip_nl = FALSE;
+       gboolean html_mode;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (to_plain_text && !buffer)
+               return;
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node)) {
+               if (changing_mode && to_plain_text) {
+                       WebKitDOMNamedNodeMap *attributes;
+                       gulong attributes_length;
+
+                       /* Copy attributes */
+                       g_string_append (buffer, "<html><head></head><body ");
+                       attributes = webkit_dom_element_get_attributes (
+                               WEBKIT_DOM_ELEMENT (node));
+                       attributes_length =
+                               webkit_dom_named_node_map_get_length (attributes);
+
+                       for (ii = 0; ii < attributes_length; ii++) {
+                               gchar *name;
+                               WebKitDOMNode *node =
+                                       webkit_dom_named_node_map_item (
+                                               attributes, ii);
+
+                               name = webkit_dom_node_get_local_name (node);
+                               if (g_strcmp0 (name, "bgcolor") != 0 &&
+                                   g_strcmp0 (name, "text") != 0 &&
+                                   g_strcmp0 (name, "vlink") != 0 &&
+                                   g_strcmp0 (name, "link") != 0) {
+                                       gchar *value;
+
+                                       value = webkit_dom_node_get_node_value (node);
+
+                                       g_string_append (buffer, name);
+                                       g_string_append (buffer, "=\"");
+                                       g_string_append (buffer, value);
+                                       g_string_append (buffer, "\" ");
+
+                                       g_free (value);
+                               }
+                               g_free (name);
+                               g_object_unref (node);
+                       }
+                       g_string_append (buffer, ">");
+                       g_object_unref (attributes);
+               }
+               if (!to_plain_text)
+                       remove_evolution_attributes (WEBKIT_DOM_ELEMENT (node));
+       }
+
+       nodes = webkit_dom_node_get_child_nodes (node);
+       length = webkit_dom_node_list_get_length (nodes);
+
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *child;
+               gboolean skip_node = FALSE;
+
+               child = webkit_dom_node_list_item (nodes, ii);
+
+               if (WEBKIT_DOM_IS_TEXT (child)) {
+                       GRegex *regex;
+
+                       content = webkit_dom_node_get_text_content (child);
+                       if (strstr (content, UNICODE_ZERO_WIDTH_SPACE)) {
+                               gchar *tmp;
+
+                               regex = g_regex_new (UNICODE_ZERO_WIDTH_SPACE, 0, 0, NULL);
+                               tmp = g_regex_replace (
+                                       regex, content, -1, 0, "", 0, NULL);
+                               g_free (content);
+                               if (changing_mode) {
+                                       webkit_dom_node_set_text_content (child, tmp, NULL);
+                                       g_free (tmp);
+                                       content = webkit_dom_node_get_text_content (child);
+                               } else
+                                       content = tmp;
+                               g_regex_unref (regex);
+                       }
+
+                       if (to_plain_text && !changing_mode) {
+                               gchar *class;
+                               const gchar *css_align = NULL;
+
+                               class = webkit_dom_element_get_class_name (WEBKIT_DOM_ELEMENT (node));
+                               if (class && (css_align = strstr (class, "-x-evo-align-"))) {
+                                       gchar *align;
+                                       gchar *content_with_align;
+                                       gint length;
+                                       gint word_wrap_length = e_editor_page_get_word_wrap_length 
(editor_page);
+
+                                       if (!g_str_has_prefix (css_align + 13, "left")) {
+                                               if (g_str_has_prefix (css_align + 13, "center"))
+                                                       length = (word_wrap_length - g_utf8_strlen (content, 
-1)) / 2;
+                                               else
+                                                       length = word_wrap_length - g_utf8_strlen (content, 
-1);
+
+                                               if (length < 0)
+                                                       length = 0;
+
+                                               if (g_str_has_suffix (content, " ")) {
+                                                       char *tmp;
+
+                                                       length++;
+                                                       align = g_strnfill (length, ' ');
+
+                                                       tmp = g_strndup (content, g_utf8_strlen (content, -1) 
-1);
+
+                                                       content_with_align = g_strconcat (
+                                                               align, tmp, NULL);
+                                                       g_free (tmp);
+                                               } else {
+                                                       align = g_strnfill (length, ' ');
+
+                                                       content_with_align = g_strconcat (
+                                                               align, content, NULL);
+                                               }
+
+                                               g_free (content);
+                                               g_free (align);
+                                               content = content_with_align;
+                                       }
+                               }
+
+                               g_free (class);
+                       }
+
+                       if (to_plain_text || changing_mode)
+                               g_string_append (buffer, content);
+
+                       g_free (content);
+
+                       goto next;
+               }
+
+               if (WEBKIT_DOM_IS_COMMENT (child) || !WEBKIT_DOM_IS_ELEMENT (child))
+                       goto next;
+
+               if (element_has_class (WEBKIT_DOM_ELEMENT (child), "Apple-tab-span")) {
+                       if (!changing_mode) {
+                               if (to_plain_text) {
+                                       content = webkit_dom_node_get_text_content (child);
+                                       g_string_append (buffer, content);
+                                       g_free (content);
+                               } else
+                                       element_remove_class (
+                                               WEBKIT_DOM_ELEMENT (child),
+                                               "Applet-tab-span");
+                       }
+                       skip_node = TRUE;
+                       goto next;
+               }
+
+               /* Leave blockquotes as they are */
+               if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (child)) {
+                       if (changing_mode && to_plain_text) {
+                               content = webkit_dom_element_get_outer_html (
+                                       WEBKIT_DOM_ELEMENT (child));
+                               g_string_append (buffer, content);
+                               g_free (content);
+                               skip_node = TRUE;
+                               goto next;
+                       } else {
+                               process_blockquote (WEBKIT_DOM_ELEMENT (child), FALSE);
+                               if (!to_plain_text)
+                                       remove_base_attributes (WEBKIT_DOM_ELEMENT (child));
+                       }
+               }
+
+               if (!to_plain_text && !changing_mode) {
+                       gchar *class;
+                       const gchar *css_align;
+
+                       class = webkit_dom_element_get_class_name (WEBKIT_DOM_ELEMENT (child));
+                       if (class && (css_align = strstr (class, "-x-evo-align-"))) {
+                               if (!g_str_has_prefix (css_align + 13, "left")) {
+                                       if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (child))
+                                               webkit_dom_element_set_attribute (
+                                                       WEBKIT_DOM_ELEMENT (child),
+                                                       "style",
+                                                       g_str_has_prefix (css_align + 13, "center") ?
+                                                               "list-style-position: inside; text-align: 
center" :
+                                                               "list-style-position: inside; text-align: 
right",
+                                                       NULL);
+                                       else
+                                               webkit_dom_element_set_attribute (
+                                                       WEBKIT_DOM_ELEMENT (child),
+                                                       "style",
+                                                       g_str_has_prefix (css_align + 13, "center") ?
+                                                               "text-align: center" :
+                                                               "text-align: right",
+                                                       NULL);
+                               }
+                       }
+                       element_remove_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-align-left");
+                       element_remove_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-align-center");
+                       element_remove_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-align-right");
+                       g_free (class);
+               }
+
+               if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (child) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-indented")) {
+                       if (!to_plain_text && !changing_mode) {
+                               process_blockquote (WEBKIT_DOM_ELEMENT (child), FALSE);
+                               element_remove_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-indented");
+                       } else
+                               process_blockquote (WEBKIT_DOM_ELEMENT (child), TRUE);
+
+               }
+
+               if (node_is_list (child)) {
+                       if (to_plain_text) {
+                               if (changing_mode) {
+                                       content = webkit_dom_element_get_outer_html (
+                                               WEBKIT_DOM_ELEMENT (child));
+                                       g_string_append (buffer, content);
+                                       g_free (content);
+                               } else {
+                                       process_list_to_plain_text (editor_page, WEBKIT_DOM_ELEMENT (child), 
1, buffer);
+                               }
+                               skip_node = TRUE;
+                               goto next;
+                       }
+               }
+
+               if (element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-resizable-wrapper") &&
+                   !element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-smiley-wrapper")) {
+                       WebKitDOMNode *image =
+                               webkit_dom_node_get_first_child (child);
+
+                       if (!to_plain_text && WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (image)) {
+                               remove_evolution_attributes (
+                                       WEBKIT_DOM_ELEMENT (image));
+
+                               webkit_dom_node_replace_child (
+                                       node, image, child, NULL);
+                       }
+
+                       skip_node = TRUE;
+                       goto next;
+               }
+
+               /* Leave paragraphs as they are */
+               if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (child), "data-evo-paragraph")) {
+                       if (changing_mode && to_plain_text) {
+                               content = webkit_dom_element_get_outer_html (
+                                       WEBKIT_DOM_ELEMENT (child));
+                               g_string_append (buffer, content);
+                               g_free (content);
+                               skip_node = TRUE;
+                               goto next;
+                       }
+                       if (!to_plain_text) {
+                               remove_base_attributes (WEBKIT_DOM_ELEMENT (child));
+                               remove_evolution_attributes (WEBKIT_DOM_ELEMENT (child));
+                       }
+               }
+
+               /* Signature */
+               if (WEBKIT_DOM_IS_HTML_DIV_ELEMENT (child) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-signature-wrapper")) {
+                       WebKitDOMNode *first_child;
+
+                       first_child = webkit_dom_node_get_first_child (child);
+
+                       skip_node = TRUE;
+                       /* Don't generate any text if the signature is set to None. */
+                       if (!changing_mode) {
+                               gchar *id;
+
+                               id = webkit_dom_element_get_id (WEBKIT_DOM_ELEMENT (first_child));
+                               if (g_strcmp0 (id, "none") == 0) {
+                                       g_free (id);
+
+                                       remove_node (child);
+                                       goto next;
+                               }
+                               g_free (id);
+                       }
+
+                       if (!to_plain_text) {
+                               remove_base_attributes (
+                                       WEBKIT_DOM_ELEMENT (child));
+                               remove_base_attributes (
+                                       WEBKIT_DOM_ELEMENT (first_child));
+                               remove_evolution_attributes (
+                                       WEBKIT_DOM_ELEMENT (first_child));
+                               if (!changing_mode)
+                                       skip_node = FALSE;
+                       } else if (changing_mode) {
+                               content = webkit_dom_element_get_outer_html (
+                                       WEBKIT_DOM_ELEMENT (child));
+                               g_string_append (buffer, content);
+                               g_free (content);
+                       } else {
+                               g_string_append (buffer, "\n");
+
+                               if (html_mode) {
+                                       convert_element_from_html_to_plain_text (
+                                               editor_page, WEBKIT_DOM_ELEMENT (first_child), NULL, NULL);
+                               } else {
+                                       WebKitDOMNode *signature_node;
+
+                                       signature_node = webkit_dom_node_get_last_child (first_child);
+                                       if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (signature_node)) {
+                                               WebKitDOMNode *last_child;
+
+                                               /* Remove a line break on the end of the last
+                                                * PRE element. It is not showed by the WebKit,
+                                                * but it is still there are will be added to
+                                                * the output. */
+                                               last_child = webkit_dom_node_get_last_child (signature_node);
+                                               if (WEBKIT_DOM_IS_CHARACTER_DATA (last_child)) {
+                                                       WebKitDOMCharacterData *data;
+                                                       glong length;
+
+                                                       data = WEBKIT_DOM_CHARACTER_DATA (last_child);
+                                                       length = webkit_dom_character_data_get_length (data);
+                                                       if (length > 0) {
+                                                               gchar *last_char;
+
+                                                               last_char = 
webkit_dom_character_data_substring_data (
+                                                                               data, length - 1, 1, NULL);
+
+                                                               if (last_char && *last_char == '\n')
+                                                                       webkit_dom_character_data_delete_data 
(
+                                                                                       data, length -1, 1, 
NULL);
+
+                                                               g_free (last_char);
+                                                       }
+                                               }
+                                       }
+                               }
+                               skip_node = FALSE;
+                               skip_nl = TRUE;
+                       }
+
+                       goto next;
+               }
+
+               /* Replace smileys with their text representation */
+               if (element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-smiley-wrapper")) {
+                       if (to_plain_text && !changing_mode) {
+                               WebKitDOMNode *text_version;
+
+                               text_version = webkit_dom_node_get_last_child (child);
+                               content = webkit_dom_html_element_get_inner_text (
+                                       WEBKIT_DOM_HTML_ELEMENT (text_version));
+                               g_string_append (buffer, content);
+                               g_free (content);
+                               skip_node = TRUE;
+                               goto next;
+                       }
+                       if (!to_plain_text) {
+                               WebKitDOMElement *img;
+
+                               img = WEBKIT_DOM_ELEMENT (
+                                       webkit_dom_node_get_first_child (child)),
+
+                               remove_evolution_attributes (img);
+                               remove_base_attributes (img);
+
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (child),
+                                       WEBKIT_DOM_NODE (img),
+                                       child,
+                                       NULL);
+                               remove_node (child);
+                               skip_node = TRUE;
+                               goto next;
+                       }
+               }
+
+               /* Leave PRE elements untouched */
+               if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (child)) {
+                       if (!to_plain_text) {
+                               remove_evolution_attributes (WEBKIT_DOM_ELEMENT (child));
+                       } else if (changing_mode) {
+                               content = webkit_dom_element_get_outer_html (
+                                       WEBKIT_DOM_ELEMENT (child));
+                               g_string_append (buffer, content);
+                               g_free (content);
+                               skip_node = TRUE;
+                       }
+               }
+
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child)) {
+                       if (to_plain_text) {
+                               if (element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-wrap-br")) {
+                                       g_string_append (buffer, changing_mode ? "<br>" : "\n");
+                                       goto next;
+                               }
+
+                               /* Insert new line when we hit the BR element that is
+                                * not the last element in the block */
+                               if (!webkit_dom_node_is_same_node (
+                                       child, webkit_dom_node_get_last_child (node))) {
+                                       g_string_append (buffer, changing_mode ? "<br>" : "\n");
+                               } else {
+                                       /* In citations in the empty lines the BR element
+                                        * is on the end and we have to put NL there */
+                                       WebKitDOMNode *parent;
+
+                                       parent = webkit_dom_node_get_parent_node (child);
+                                       if (webkit_dom_node_get_next_sibling (parent)) {
+                                               parent = webkit_dom_node_get_parent_node (parent);
+
+                                               if (e_editor_dom_node_is_citation_node (parent))
+                                                       g_string_append (buffer, changing_mode ? "<br>" : 
"\n");
+                                       }
+                               }
+                       }
+               }
+
+               if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (child)) {
+                       if (changing_mode && to_plain_text) {
+                               content = webkit_dom_element_get_outer_html (
+                                       WEBKIT_DOM_ELEMENT (child));
+                               g_string_append (buffer, content);
+                               g_free (content);
+                               skip_node = TRUE;
+                       }
+                       if (!changing_mode) {
+                               if (to_plain_text) {
+                                       content = webkit_dom_html_element_get_inner_text (
+                                               WEBKIT_DOM_HTML_ELEMENT (child));
+                                       g_string_append (buffer, content);
+                                       g_free (content);
+                                       skip_node = TRUE;
+                               } else
+                                       remove_base_attributes (WEBKIT_DOM_ELEMENT (child));
+                       }
+               }
+ next:
+               if (webkit_dom_node_has_child_nodes (child) && !skip_node)
+                       process_elements (
+                               editor_page, child, changing_mode, to_plain_text, buffer);
+               g_object_unref (child);
+       }
+
+       if (to_plain_text && (
+           WEBKIT_DOM_IS_HTML_DIV_ELEMENT (node) ||
+           WEBKIT_DOM_IS_HTML_PARAGRAPH_ELEMENT (node) ||
+           WEBKIT_DOM_IS_HTML_PRE_ELEMENT (node) ||
+           WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node))) {
+
+               gboolean add_br = TRUE;
+               WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (node);
+               WebKitDOMNode *last_child = webkit_dom_node_get_last_child (node);
+
+               if (last_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (last_child))
+                       if (webkit_dom_node_get_previous_sibling (last_child))
+                               add_br = FALSE;
+
+               /* If we don't have next sibling (last element in body) or next element is
+                * signature we are not adding the BR element */
+               if (!next_sibling)
+                       add_br = FALSE;
+               else if (next_sibling && WEBKIT_DOM_IS_HTML_DIV_ELEMENT (next_sibling)) {
+                       if (webkit_dom_element_query_selector (
+                               WEBKIT_DOM_ELEMENT (next_sibling),
+                               "span.-x-evo-signature", NULL)) {
+
+                               add_br = FALSE;
+                       }
+               }
+
+               if (add_br && !skip_nl)
+                       g_string_append (buffer, changing_mode ? "<br>" : "\n");
+       }
+
+       g_object_unref (nodes);
+}
+
+static void
+remove_image_attributes_from_element (WebKitDOMElement *element)
+{
+       webkit_dom_element_remove_attribute (element, "background");
+       webkit_dom_element_remove_attribute (element, "data-uri");
+       webkit_dom_element_remove_attribute (element, "data-inline");
+       webkit_dom_element_remove_attribute (element, "data-name");
+}
+
+static void
+remove_background_images_in_element (WebKitDOMElement *element)
+{
+       gint length, ii;
+       WebKitDOMNodeList *images;
+
+       images = webkit_dom_element_query_selector_all (
+               element, "[background][data-inline]", NULL);
+
+       length = webkit_dom_node_list_get_length (images);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *image = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_list_item (images, ii));
+
+               remove_image_attributes_from_element (image);
+               g_object_unref (image);
+       }
+
+       remove_image_attributes_from_element (element);
+       g_object_unref (element);
+}
+
+static void
+remove_images_in_element (WebKitDOMElement *element)
+{
+       gint length, ii;
+       WebKitDOMNodeList *images;
+
+       images = webkit_dom_element_query_selector_all (
+               element, "img:not(.-x-evo-smiley-img)", NULL);
+
+       length = webkit_dom_node_list_get_length (images);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (images, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+
+       g_object_unref (images);
+}
+
+static void
+remove_images (WebKitDOMDocument *document)
+{
+       remove_images_in_element (
+               WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document)));
+}
+
+static void
+toggle_smileys (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *smileys;
+       gboolean html_mode;
+       gint length;
+       gint ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       smileys = webkit_dom_document_query_selector_all (
+               document, "img.-x-evo-smiley-img", NULL);
+
+       length = webkit_dom_node_list_get_length (smileys);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *img = webkit_dom_node_list_item (smileys, ii);
+               WebKitDOMNode *text = webkit_dom_node_get_next_sibling (img);
+               WebKitDOMElement *parent = webkit_dom_node_get_parent_element (img);
+
+               webkit_dom_element_set_attribute (
+                       WEBKIT_DOM_ELEMENT (html_mode ? text : img),
+                       "style",
+                       "display: none",
+                       NULL);
+
+               webkit_dom_element_remove_attribute (
+                       WEBKIT_DOM_ELEMENT (html_mode ? img : text), "style");
+
+               if (html_mode)
+                       element_add_class (parent, "-x-evo-resizable-wrapper");
+               else
+                       element_remove_class (parent, "-x-evo-resizable-wrapper");
+               g_object_unref (img);
+       }
+
+       g_object_unref (smileys);
+}
+
+static void
+toggle_paragraphs_style_in_element (EEditorPage *editor_page,
+                                    WebKitDOMElement *element,
+                                    gboolean html_mode)
+{
+       gint ii, length;
+       WebKitDOMNodeList *paragraphs;
+
+       paragraphs = webkit_dom_element_query_selector_all (
+               element, ":not(td) > [data-evo-paragraph]", NULL);
+
+       length = webkit_dom_node_list_get_length (paragraphs);
+
+       for (ii = 0; ii < length; ii++) {
+               gchar *style;
+               const gchar *css_align;
+               WebKitDOMNode *node = webkit_dom_node_list_item (paragraphs, ii);
+
+               if (html_mode) {
+                       style = webkit_dom_element_get_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "style");
+
+                       if (style && (css_align = strstr (style, "text-align: "))) {
+                               webkit_dom_element_set_attribute (
+                                       WEBKIT_DOM_ELEMENT (node),
+                                       "style",
+                                       g_str_has_prefix (css_align + 12, "center") ?
+                                               "text-align: center" :
+                                               "text-align: right",
+                                       NULL);
+                       } else {
+                               /* In HTML mode the paragraphs don't have width limit */
+                               webkit_dom_element_remove_attribute (
+                                       WEBKIT_DOM_ELEMENT (node), "style");
+                       }
+                       g_free (style);
+               } else {
+                       WebKitDOMNode *parent;
+
+                       parent = webkit_dom_node_get_parent_node (node);
+                       /* If the paragraph is inside indented paragraph don't set
+                        * the style as it will be inherited */
+                       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent) && node_is_list (node)) {
+                               gint offset;
+
+                               offset = WEBKIT_DOM_IS_HTML_U_LIST_ELEMENT (node) ?
+                                       SPACES_PER_LIST_LEVEL : SPACES_ORDERED_LIST_FIRST_LEVEL;
+                               /* In plain text mode the paragraphs have width limit */
+                               e_editor_dom_set_paragraph_style (
+                                       editor_page, WEBKIT_DOM_ELEMENT (node), -1, -offset, "");
+                       } else if (!element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-indented")) {
+                               const gchar *style_to_add = "";
+                               style = webkit_dom_element_get_attribute (
+                                       WEBKIT_DOM_ELEMENT (node), "style");
+
+                               if (style && (css_align = strstr (style, "text-align: "))) {
+                                       style_to_add = g_str_has_prefix (
+                                               css_align + 12, "center") ?
+                                                       "text-align: center;" :
+                                                       "text-align: right;";
+                               }
+
+                               /* In plain text mode the paragraphs have width limit */
+                               e_editor_dom_set_paragraph_style (
+                                       editor_page, WEBKIT_DOM_ELEMENT (node), -1, 0, style_to_add);
+
+                               g_free (style);
+                       }
+               }
+               g_object_unref (node);
+       }
+       g_object_unref (paragraphs);
+}
+
+static void
+toggle_paragraphs_style (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       toggle_paragraphs_style_in_element (
+               editor_page,
+               WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document)),
+               e_editor_page_get_html_mode (editor_page));
+}
+
+gchar *
+e_editor_dom_process_content_for_draft (EEditorPage *editor_page,
+                                       gboolean only_inner_body)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMElement *document_element;
+       WebKitDOMNodeList *list;
+       WebKitDOMNode *document_element_clone;
+       gboolean selection_saved = FALSE;
+       gchar *content;
+       gint ii, length;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       body = webkit_dom_document_get_body (document);
+
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-evo-draft", "", NULL);
+
+       if (webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker"))
+               selection_saved = TRUE;
+
+       if (!selection_saved)
+               e_editor_dom_selection_save (editor_page);
+
+       document_element = webkit_dom_document_get_document_element (document);
+
+       document_element_clone = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (document_element), TRUE, NULL);
+
+       list = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (document_element_clone), "a.-x-evo-visited-link", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *anchor;
+
+               anchor = webkit_dom_node_list_item (list, ii);
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (anchor), "class");
+               g_object_unref (anchor);
+       }
+       g_object_unref (list);
+
+       list = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (document_element_clone), "#-x-evo-input-start", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_list_item (list, ii);
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "id");
+               g_object_unref (node);
+       }
+
+       g_object_unref (list);
+
+       if (only_inner_body) {
+               WebKitDOMElement *body;
+               WebKitDOMNode *first_child;
+
+               body = webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (document_element_clone), "body", NULL);
+
+               first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               if (!e_editor_page_get_html_mode (editor_page))
+                       webkit_dom_element_set_attribute (
+                               WEBKIT_DOM_ELEMENT (first_child),
+                               "data-evo-signature-plain-text-mode",
+                               "",
+                               NULL);
+
+               content = webkit_dom_element_get_inner_html (body);
+
+               if (!e_editor_page_get_html_mode (editor_page))
+                       webkit_dom_element_remove_attribute (
+                               WEBKIT_DOM_ELEMENT (first_child),
+                               "data-evo-signature-plain-text-mode");
+       } else
+               content = webkit_dom_element_get_outer_html (
+                       WEBKIT_DOM_ELEMENT (document_element_clone));
+
+       webkit_dom_element_remove_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-evo-draft");
+
+       e_editor_dom_selection_restore (editor_page);
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+       if (selection_saved)
+               e_editor_dom_selection_save (editor_page);
+
+       return content;
+}
+
+static gchar *
+process_content_for_mode_change (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *body;
+       GString *plain_text;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document));
+
+       plain_text = g_string_sized_new (1024);
+
+       webkit_dom_element_remove_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-user-colors");
+
+       process_elements (editor_page, body, TRUE, TRUE, plain_text);
+
+       g_string_append (plain_text, "</body></html>");
+
+       return g_string_free (plain_text, FALSE);
+}
+
+gchar *
+e_editor_dom_process_content_for_plain_text (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *body, *source;
+       WebKitDOMNodeList *paragraphs;
+       gboolean wrap = FALSE, quote = FALSE, clean = FALSE;
+       gboolean converted, is_from_new_message;
+       gint length, ii;
+       GString *plain_text;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       plain_text = g_string_sized_new (1024);
+
+       body = WEBKIT_DOM_NODE (webkit_dom_document_get_body (document));
+       converted = webkit_dom_element_has_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-converted");
+       is_from_new_message = webkit_dom_element_has_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-new-message");
+       source = webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (body), TRUE, NULL);
+
+       e_editor_dom_selection_save (editor_page);
+
+       /* If composer is in HTML mode we have to move the content to plain version */
+       if (e_editor_page_get_html_mode (editor_page)) {
+               if (converted || is_from_new_message) {
+                       toggle_paragraphs_style_in_element (
+                               editor_page, WEBKIT_DOM_ELEMENT (source), FALSE);
+                       remove_images_in_element (
+                               WEBKIT_DOM_ELEMENT (source));
+                       remove_background_images_in_element (
+                               WEBKIT_DOM_ELEMENT (source));
+               } else {
+                       gchar *inner_html;
+                       WebKitDOMElement *div;
+
+                       inner_html = webkit_dom_element_get_inner_html (
+                               WEBKIT_DOM_ELEMENT (body));
+
+                       div = webkit_dom_document_create_element (
+                               document, "div", NULL);
+
+                       webkit_dom_element_set_inner_html (div, inner_html, NULL);
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (body),
+                               WEBKIT_DOM_NODE (div),
+                               NULL);
+
+                       paragraphs = webkit_dom_element_query_selector_all (
+                               div, "#-x-evo-input-start", NULL);
+
+                       length = webkit_dom_node_list_get_length (paragraphs);
+                       for (ii = 0; ii < length; ii++) {
+                               WebKitDOMNode *paragraph;
+
+                               paragraph = webkit_dom_node_list_item (paragraphs, ii);
+
+                               webkit_dom_element_remove_attribute (
+                                       WEBKIT_DOM_ELEMENT (paragraph), "id");
+                       }
+                       g_object_unref (paragraphs);
+
+                       convert_element_from_html_to_plain_text (
+                               editor_page, div, &wrap, &quote);
+
+                       g_object_unref (source);
+
+                       source = WEBKIT_DOM_NODE (div);
+
+                       clean = TRUE;
+               }
+       }
+
+       paragraphs = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (source), "[data-evo-paragraph]", NULL);
+
+       length = webkit_dom_node_list_get_length (paragraphs);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *paragraph;
+
+               paragraph = webkit_dom_node_list_item (paragraphs, ii);
+
+               if (node_is_list (paragraph)) {
+                       WebKitDOMNode *item = webkit_dom_node_get_first_child (paragraph);
+
+                       while (item) {
+                               WebKitDOMNode *next_item =
+                                       webkit_dom_node_get_next_sibling (item);
+
+                               if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+                                       e_editor_dom_wrap_paragraph (editor_page, WEBKIT_DOM_ELEMENT (item));
+                               }
+                               item = next_item;
+                       }
+               } else if (!webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (paragraph), 
".-x-evo-wrap-br,.-x-evo-quoted", NULL)) {
+                       /* Dont't try to wrap the already wrapped content. */
+                       e_editor_dom_wrap_paragraph (editor_page, WEBKIT_DOM_ELEMENT (paragraph));
+               }
+               g_object_unref (paragraph);
+       }
+       g_object_unref (paragraphs);
+
+       paragraphs = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (source), "span[id^=\"-x-evo-selection-\"]", NULL);
+
+       length = webkit_dom_node_list_get_length (paragraphs);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (paragraphs, ii);
+               WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+               remove_node (node);
+               g_object_unref (node);
+               webkit_dom_node_normalize (parent);
+       }
+       g_object_unref (paragraphs);
+
+       if (quote)
+               quote_plain_text_recursive (document, source, source, 0);
+       else if (e_editor_page_get_html_mode (editor_page)) {
+               WebKitDOMElement *citation;
+
+               citation = webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (source), "blockquote[type=cite]", NULL);
+               if (citation)
+                       quote_plain_text_recursive (document, source, source, 0);
+       }
+
+       process_elements (editor_page, source, FALSE, TRUE, plain_text);
+
+       if (clean)
+               remove_node (source);
+       else
+               g_object_unref (source);
+
+       e_editor_dom_selection_restore (editor_page);
+
+       /* Return text content between <body> and </body> */
+       return g_string_free (plain_text, FALSE);
+}
+
+static void
+restore_image (WebKitDOMDocument *document,
+               const gchar *id,
+               const gchar *element_src)
+{
+       gchar *selector;
+       gint length, ii;
+       WebKitDOMNodeList *list;
+
+       selector = g_strconcat ("[data-inline][background=\"cid:", id, "\"]", NULL);
+       list = webkit_dom_document_query_selector_all (document, selector, NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *element = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_list_item (list, ii));
+
+               webkit_dom_element_set_attribute (element, "background", element_src, NULL);
+               g_object_unref (element);
+       }
+       g_free (selector);
+       g_object_unref (list);
+
+       selector = g_strconcat ("[data-inline][src=\"cid:", id, "\"]", NULL);
+       list = webkit_dom_document_query_selector_all (document, selector, NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *element = WEBKIT_DOM_ELEMENT (
+                       webkit_dom_node_list_item (list, ii));
+
+               webkit_dom_element_set_attribute (element, "src", element_src, NULL);
+               g_object_unref (element);
+       }
+       g_free (selector);
+       g_object_unref (list);
+}
+
+void
+e_editor_dom_restore_images (EEditorPage *editor_page,
+                            GVariant *inline_images_to_restore)
+{
+       WebKitDOMDocument *document;
+       const gchar *element_src, *name, *id;
+       GVariantIter *iter;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       g_variant_get (inline_images_to_restore, "asss", &iter);
+       while (g_variant_iter_loop (iter, "&s&s&s", &element_src, &name, &id))
+               restore_image (document, id, element_src);
+}
+
+gchar *
+e_editor_dom_process_content_for_html (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node, *document_clone;
+       WebKitDOMNodeList *list;
+       GSettings *settings;
+       gint ii, length;
+       gchar *html_content;
+       gboolean send_editor_colors = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       document_clone = webkit_dom_node_clone_node_with_error (
+               WEBKIT_DOM_NODE (webkit_dom_document_get_document_element (document)), TRUE, NULL);
+       element = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-quote-style", NULL);
+       if (element)
+               remove_node (WEBKIT_DOM_NODE (element));
+       element = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-a-color-style", NULL);
+       if (element)
+               remove_node (WEBKIT_DOM_NODE (element));
+       element = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-a-color-style-visited", NULL);
+       if (element)
+               remove_node (WEBKIT_DOM_NODE (element));
+       /* When the Ctrl + Enter is pressed for sending, the links are activated. */
+       element = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (document_clone), "style#-x-evo-style-a", NULL);
+       if (element)
+               remove_node (WEBKIT_DOM_NODE (element));
+       node = WEBKIT_DOM_NODE (webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (document_clone), "body", NULL));
+       element = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (node), "#-x-evo-selection-start-marker", NULL);
+       if (element)
+               remove_node (WEBKIT_DOM_NODE (element));
+       element = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (node), "#-x-evo-selection-end-marker", NULL);
+       if (element)
+               remove_node (WEBKIT_DOM_NODE (element));
+
+       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+       send_editor_colors = g_settings_get_boolean (settings, "composer-inherit-theme-colors");
+       g_object_unref (settings);
+
+       if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), "data-user-colors")) {
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "data-user-colors");
+       } else if (!send_editor_colors) {
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "bgcolor");
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "text");
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "link");
+               webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (node), "vlink");
+       }
+
+       list = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (node), "span[data-hidden-space]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *hidden_space_node;
+
+               hidden_space_node = webkit_dom_node_list_item (list, ii);
+               remove_node (hidden_space_node);
+               g_object_unref (hidden_space_node);
+       }
+       g_object_unref (list);
+
+       list = webkit_dom_element_query_selector_all (
+               WEBKIT_DOM_ELEMENT (node), "[data-style]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *data_style_node;
+
+               data_style_node = webkit_dom_node_list_item (list, ii);
+
+               element_rename_attribute (WEBKIT_DOM_ELEMENT (data_style_node), "data-style", "style");
+               g_object_unref (data_style_node);
+       }
+       g_object_unref (list);
+
+       process_elements (editor_page, node, FALSE, FALSE, NULL);
+
+       html_content = webkit_dom_element_get_outer_html (
+               WEBKIT_DOM_ELEMENT (document_clone));
+
+       g_object_unref (document_clone);
+
+       return html_content;
+}
+
+void
+e_editor_dom_convert_when_changing_composer_mode (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+       gboolean quote = FALSE, wrap = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       body = webkit_dom_document_get_body (document);
+
+       convert_element_from_html_to_plain_text (
+               editor_page, WEBKIT_DOM_ELEMENT (body), &wrap, &quote);
+
+       if (wrap)
+               e_editor_dom_wrap_paragraphs_in_document (editor_page);
+
+       if (quote) {
+               e_editor_dom_selection_save (editor_page);
+               if (wrap)
+                       quote_plain_text_elements_after_wrapping_in_document (editor_page);
+               else
+                       body = WEBKIT_DOM_HTML_ELEMENT (dom_quote_plain_text (document));
+               e_editor_dom_selection_restore (editor_page);
+       }
+
+       toggle_paragraphs_style (editor_page);
+       toggle_smileys (editor_page);
+       remove_images (document);
+       remove_background_images_in_element (WEBKIT_DOM_ELEMENT (body));
+
+       clear_attributes (editor_page);
+
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-converted", "", NULL);
+
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+       e_editor_dom_scroll_to_caret (editor_page);
+}
+
+static void
+wrap_paragraphs_in_quoted_content (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *paragraphs;
+       gint ii, length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       paragraphs = webkit_dom_document_query_selector_all (
+               document, "blockquote[type=cite] > [data-evo-paragraph]", NULL);
+
+       length = webkit_dom_node_list_get_length (paragraphs);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *paragraph;
+
+               paragraph = webkit_dom_node_list_item (paragraphs, ii);
+
+               e_editor_dom_wrap_paragraph (editor_page, WEBKIT_DOM_ELEMENT (paragraph));
+
+               g_object_unref (paragraph);
+       }
+       g_object_unref (paragraphs);
+}
+
+static void
+set_base64_to_element_attribute (GHashTable *inline_images,
+                                 WebKitDOMElement *element,
+                                 const gchar *attribute)
+{
+       gchar *attribute_value;
+       const gchar *base64_src;
+
+       attribute_value = webkit_dom_element_get_attribute (element, attribute);
+
+       if (attribute_value && (base64_src = g_hash_table_lookup (inline_images, attribute_value)) != NULL) {
+               const gchar *base64_data = strstr (base64_src, ";") + 1;
+               gchar *name;
+               glong name_length;
+
+               name_length =
+                       g_utf8_strlen (base64_src, -1) -
+                       g_utf8_strlen (base64_data, -1) - 1;
+               name = g_strndup (base64_src, name_length);
+
+               webkit_dom_element_set_attribute (element, "data-inline", "", NULL);
+               webkit_dom_element_set_attribute (element, "data-name", name, NULL);
+               webkit_dom_element_set_attribute (element, attribute, base64_data, NULL);
+
+               g_free (name);
+       }
+       g_free (attribute_value);
+}
+
+static void
+change_cid_images_src_to_base64 (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *document_element;
+       WebKitDOMNamedNodeMap *attributes;
+       WebKitDOMNodeList *list;
+       GHashTable *inline_images;
+       gint ii, length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       inline_images = e_editor_page_get_inline_images (editor_page);
+
+       document_element = webkit_dom_document_get_document_element (document);
+
+       list = webkit_dom_document_query_selector_all (document, "img[src^=\"cid:\"]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               set_base64_to_element_attribute (inline_images, WEBKIT_DOM_ELEMENT (node), "src");
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       /* Namespaces */
+       attributes = webkit_dom_element_get_attributes (document_element);
+       length = webkit_dom_named_node_map_get_length (attributes);
+       for (ii = 0; ii < length; ii++) {
+               gchar *name;
+               WebKitDOMNode *node = webkit_dom_named_node_map_item (attributes, ii);
+
+               name = webkit_dom_node_get_local_name (node);
+
+               if (g_str_has_prefix (name, "xmlns:")) {
+                       const gchar *ns = name + 6;
+                       gchar *attribute_ns = g_strconcat (ns, ":src", NULL);
+                       gchar *selector = g_strconcat ("img[", ns, "\\:src^=\"cid:\"]", NULL);
+                       gint ns_length, jj;
+
+                       list = webkit_dom_document_query_selector_all (
+                               document, selector, NULL);
+                       ns_length = webkit_dom_node_list_get_length (list);
+                       for (jj = 0; jj < ns_length; jj++) {
+                               WebKitDOMNode *node = webkit_dom_node_list_item (list, jj);
+
+                               set_base64_to_element_attribute (
+                                       inline_images, WEBKIT_DOM_ELEMENT (node), attribute_ns);
+                               g_object_unref (node);
+                       }
+
+                       g_object_unref (list);
+                       g_free (attribute_ns);
+                       g_free (selector);
+               }
+               g_object_unref (node);
+               g_free (name);
+       }
+       g_object_unref (attributes);
+
+       list = webkit_dom_document_query_selector_all (
+               document, "[background^=\"cid:\"]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               set_base64_to_element_attribute (
+                       inline_images, WEBKIT_DOM_ELEMENT (node), "background");
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+       g_hash_table_remove_all (inline_images);
+}
+
+static void
+adapt_to_editor_dom_changes (WebKitDOMDocument *document)
+{
+       WebKitDOMHTMLCollection *collection;
+       gint ii, length;
+
+       /* Normal block code div.-x-evo-paragraph replaced by p[data-evo-paragraph] */
+       collection = webkit_dom_document_get_elements_by_class_name_as_html_collection (document, 
"-x-evo-paragraph");
+       length = webkit_dom_html_collection_get_length (collection);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node, *child;
+               WebKitDOMElement *element;
+               gchar *style;
+
+               node = webkit_dom_html_collection_item (collection, ii);
+               element = webkit_dom_document_create_element (document, "p", NULL);
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (node),
+                       WEBKIT_DOM_NODE (element),
+                       node,
+                       NULL);
+
+               while ((child = webkit_dom_node_get_first_child (node)))
+                       webkit_dom_node_append_child (WEBKIT_DOM_NODE (element), child, NULL);
+
+               style = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "style");
+               if (style)
+                       webkit_dom_element_set_attribute (element, "style", style, NULL);
+
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (collection);
+}
+
+void
+e_editor_dom_process_content_after_load (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMDOMWindow *dom_window;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* Don't use CSS when possible to preserve compatibility with older
+        * versions of Evolution or other MUAs */
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_STYLE_WITH_CSS, "false");
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DEFAULT_PARAGRAPH_SEPARATOR, "p");
+
+       body = webkit_dom_document_get_body (document);
+
+       webkit_dom_element_remove_attribute (WEBKIT_DOM_ELEMENT (body), "style");
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-message", "", NULL);
+
+       if (e_editor_page_get_convert_in_situ (editor_page)) {
+               e_editor_dom_convert_content (editor_page, NULL);
+               /* Make the quote marks non-selectable. */
+               e_editor_dom_disable_quote_marks_select (editor_page);
+               dom_set_links_active (document, FALSE);
+               e_editor_page_set_convert_in_situ (editor_page, FALSE);
+
+               e_editor_dom_register_input_event_listener_on_body (editor_page);
+               register_html_events_handlers (editor_page, body);
+
+               return;
+       }
+
+       adapt_to_editor_dom_changes (document);
+
+       /* Make the quote marks non-selectable. */
+       e_editor_dom_disable_quote_marks_select (editor_page);
+       dom_set_links_active (document, FALSE);
+       put_body_in_citation (document);
+       move_elements_to_body (editor_page);
+       repair_gmail_blockquotes (document);
+       remove_thunderbird_signature (document);
+
+       if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (body), "data-evo-draft")) {
+               /* Restore the selection how it was when the draft was saved */
+               e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT (body), FALSE);
+               e_editor_dom_selection_restore (editor_page);
+               e_editor_dom_remove_embedded_style_sheet (editor_page);
+       }
+
+       /* The composer body could be empty in some case (loading an empty string
+        * or empty HTML. In that case create the initial paragraph. */
+       if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) {
+               WebKitDOMElement *paragraph;
+
+               paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+               webkit_dom_element_set_id (paragraph, "-x-evo-input-start");
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (paragraph), NULL);
+               e_editor_dom_selection_restore (editor_page);
+       }
+
+       /* Register on input event that is called when the content (body) is modified */
+       e_editor_dom_register_input_event_listener_on_body (editor_page);
+       register_html_events_handlers (editor_page, body);
+
+       if (e_editor_page_get_html_mode (editor_page))
+               change_cid_images_src_to_base64 (editor_page);
+
+       if (e_editor_page_get_inline_spelling_enabled (editor_page))
+               e_editor_dom_force_spell_check (editor_page);
+       else
+               e_editor_dom_turn_spell_check_off (editor_page);
+
+       set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (body), e_editor_page_get_html_mode 
(editor_page));
+
+       dom_window = webkit_dom_document_get_default_view (document);
+
+       webkit_dom_event_target_add_event_listener (
+               WEBKIT_DOM_EVENT_TARGET (dom_window),
+               "scroll",
+               G_CALLBACK (body_scroll_event_cb),
+               FALSE,
+               editor_page);
+}
+
+GVariant *
+e_editor_dom_get_inline_images_data (EEditorPage *editor_page,
+                                    const gchar *uid_domain)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       GVariant *result;
+       GVariantBuilder *builder = NULL;
+       GHashTable *added = NULL;
+       gint length, ii;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       list = webkit_dom_document_query_selector_all (document, "img[data-inline]", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+       if (length == 0) {
+               g_object_unref (list);
+               goto background;
+       }
+
+       builder = g_variant_builder_new (G_VARIANT_TYPE ("asss"));
+
+       added = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+       for (ii = 0; ii < length; ii++) {
+               const gchar *id;
+               gchar *cid = NULL;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               gchar *src = webkit_dom_element_get_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "src");
+
+               if (!src)
+                       continue;
+
+               if ((id = g_hash_table_lookup (added, src)) != NULL) {
+                       cid = g_strdup_printf ("cid:%s", id);
+                       g_free (src);
+               } else {
+                       gchar *data_name = webkit_dom_element_get_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "data-name");
+
+                       if (data_name) {
+                               gchar *new_id;
+
+                               new_id = camel_header_msgid_generate (uid_domain);
+                               g_variant_builder_add (
+                                       builder, "sss", src, data_name, new_id);
+                               cid = g_strdup_printf ("cid:%s", new_id);
+
+                               g_hash_table_insert (added, src, new_id);
+                               g_free (new_id);
+                       }
+                       g_free (data_name);
+               }
+               webkit_dom_element_set_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "src", cid, NULL);
+               g_object_unref (node);
+               g_free (cid);
+       }
+       g_object_unref (list);
+
+ background:
+       list = webkit_dom_document_query_selector_all (
+               document, "[data-inline][background]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       if (length == 0)
+               goto out;
+       if (!builder)
+               builder = g_variant_builder_new (G_VARIANT_TYPE ("asss"));
+
+       for (ii = 0; ii < length; ii++) {
+               const gchar *id;
+               gchar *cid = NULL;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               gchar *src = webkit_dom_element_get_attribute (
+                       WEBKIT_DOM_ELEMENT (node), "background");
+
+               if (!src)
+                       continue;
+
+               if ((id = g_hash_table_lookup (added, src)) != NULL) {
+                       cid = g_strdup_printf ("cid:%s", id);
+                       webkit_dom_element_set_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
+                       g_free (src);
+               } else {
+                       gchar *data_name = webkit_dom_element_get_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "data-name");
+
+                       if (data_name) {
+                               gchar *new_id;
+
+                               new_id = camel_header_msgid_generate (uid_domain);
+                               g_variant_builder_add (
+                                       builder, "sss", src, data_name, new_id);
+                               cid = g_strdup_printf ("cid:%s", new_id);
+
+                               g_hash_table_insert (added, src, new_id);
+                               g_free (new_id);
+
+                               webkit_dom_element_set_attribute (
+                                       WEBKIT_DOM_ELEMENT (node), "background", cid, NULL);
+                       }
+                       g_free (data_name);
+               }
+               g_free (cid);
+               g_object_unref (node);
+       }
+ out:
+       g_object_unref (list);
+       if (added)
+               g_hash_table_destroy (added);
+
+       result = g_variant_new ("asss", builder);
+       g_variant_builder_unref (builder);
+
+       return result;
+}
+
+static gboolean
+pasting_quoted_content (const gchar *content)
+{
+       /* Check if the content we are pasting is a quoted content from composer.
+        * If it is, we can't use WebKit to paste it as it would leave the formatting
+        * on the content. */
+       return g_str_has_prefix (
+               content,
+               "<meta http-equiv=\"content-type\" content=\"text/html; "
+               "charset=utf-8\"><blockquote type=\"cite\"") &&
+               strstr (content, "\"-x-evo-");
+}
+
+/*
+ * e_editor_dom_insert_html:
+ * @selection: an #EEditorSelection
+ * @html_text: an HTML code to insert
+ *
+ * Insert @html_text into document at current cursor position. When a text range
+ * is selected, it will be replaced by @html_text.
+ */
+void
+e_editor_dom_insert_html (EEditorPage *editor_page,
+                         const gchar *html_text)
+{
+       WebKitDOMDocument *document;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean html_mode;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (html_text != NULL);
+
+       document = e_editor_page_get_document (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               gboolean collapsed;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INSERT_HTML;
+
+               collapsed = e_editor_dom_selection_is_collapsed (editor_page);
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               if (!collapsed) {
+                       ev->before.end.x = ev->before.start.x;
+                       ev->before.end.y = ev->before.start.y;
+               }
+
+               ev->data.string.from = NULL;
+               ev->data.string.to = g_strdup (html_text);
+       }
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+       if (html_mode ||
+           (e_editor_page_is_pasting_content_from_itself (editor_page) &&
+           !pasting_quoted_content (html_text))) {
+               if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+                       EEditorHistoryEvent *event;
+                       WebKitDOMDocumentFragment *fragment;
+                       WebKitDOMRange *range;
+
+                       event = g_new0 (EEditorHistoryEvent, 1);
+                       event->type = HISTORY_DELETE;
+
+                       range = e_editor_dom_get_current_range (editor_page);
+                       fragment = webkit_dom_range_clone_contents (range, NULL);
+                       g_object_unref (range);
+                       event->data.fragment = fragment;
+
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &event->before.start.x,
+                               &event->before.start.y,
+                               &event->before.end.x,
+                               &event->before.end.y);
+
+                       event->after.start.x = event->before.start.x;
+                       event->after.start.y = event->before.start.y;
+                       event->after.end.x = event->before.start.x;
+                       event->after.end.y = event->before.start.y;
+
+                       e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+                       event = g_new0 (EEditorHistoryEvent, 1);
+                       event->type = HISTORY_AND;
+
+                       e_editor_undo_redo_manager_insert_history_event (manager, event);
+               }
+
+               e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_HTML, html_text);
+               /* FIXME WK2 - e_editor_dom_fix_file_uri_images
+               e_html_editor_view_fix_file_uri_images (view);*/
+               if (strstr (html_text, "id=\"-x-evo-selection-start-marker\""))
+                       e_editor_dom_selection_restore (editor_page);
+
+               if (!html_mode) {
+                       WebKitDOMNodeList *list;
+                       gint ii, length;
+
+                       list = webkit_dom_document_query_selector_all (
+                               document, "span[style^=font-family]", NULL);
+                       length = webkit_dom_node_list_get_length (list);
+                       if (length > 0)
+                               e_editor_dom_selection_save (editor_page);
+
+                       for (ii = 0; ii < length; ii++) {
+                               WebKitDOMNode *span, *child;
+
+                               span = webkit_dom_node_list_item (list, ii);
+                               while ((child = webkit_dom_node_get_first_child (span)))
+                                       webkit_dom_node_insert_before (
+                                               webkit_dom_node_get_parent_node (span),
+                                               child,
+                                               span,
+                                               NULL);
+
+                               remove_node (span);
+                               g_object_unref (span);
+                       }
+                       g_object_unref (list);
+
+                       if (length > 0)
+                               e_editor_dom_selection_restore (editor_page);
+               }
+
+               e_editor_dom_check_magic_links (editor_page, FALSE);
+               e_editor_dom_force_spell_check (editor_page);
+               e_editor_dom_scroll_to_caret (editor_page);
+       } else
+               e_editor_dom_convert_and_insert_html_into_selection (editor_page, html_text, TRUE);
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
+static void
+save_history_for_delete_or_backspace (EEditorPage *editor_page,
+                                      gboolean delete_key,
+                                      gboolean control_key)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment = NULL;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection)) {
+               g_object_unref (dom_selection);
+               return;
+       }
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       /* Check if we can delete something */
+       if (webkit_dom_range_get_collapsed (range, NULL)) {
+               WebKitDOMRange *tmp_range;
+
+               webkit_dom_dom_selection_modify (
+                       dom_selection, "move", delete_key ? "right" : "left", "character");
+
+               tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+               if (webkit_dom_range_compare_boundary_points (tmp_range, WEBKIT_DOM_RANGE_END_TO_END, range, 
NULL) == 0) {
+                       g_object_unref (dom_selection);
+                       g_object_unref (range);
+                       g_object_unref (tmp_range);
+
+                       return;
+               }
+
+               webkit_dom_dom_selection_modify (
+                       dom_selection, "move", delete_key ? "left" : "right", "character");
+       }
+
+       if (save_history_before_event_in_table (editor_page, range)) {
+               g_object_unref (range);
+               g_object_unref (dom_selection);
+               return;
+       }
+
+       ev = g_new0 (EEditorHistoryEvent, 1);
+       ev->type = HISTORY_DELETE;
+
+       e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, &ev->before.start.y, 
&ev->before.end.x, &ev->before.end.y);
+       g_object_unref (range);
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       if (webkit_dom_range_get_collapsed (range, NULL)) {
+               gboolean removing_from_anchor = FALSE;
+               WebKitDOMRange *range_clone;
+               WebKitDOMNode *node, *next_block = NULL;
+
+               e_editor_page_block_selection_changed (editor_page);
+
+               range_clone = webkit_dom_range_clone_range (range, NULL);
+               if (control_key) {
+                       WebKitDOMRange *tmp_range;
+
+                       /* Control + Delete/Backspace deletes previous/next word. */
+                       webkit_dom_dom_selection_modify (
+                               dom_selection, "move", delete_key ? "right" : "left", "word");
+                       tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+                       if (delete_key)
+                               webkit_dom_range_set_end (
+                                       range_clone,
+                                       webkit_dom_range_get_end_container (tmp_range, NULL),
+                                       webkit_dom_range_get_end_offset (tmp_range, NULL),
+                                       NULL);
+                       else
+                               webkit_dom_range_set_start (
+                                       range_clone,
+                                       webkit_dom_range_get_start_container (tmp_range, NULL),
+                                       webkit_dom_range_get_start_offset (tmp_range, NULL),
+                                       NULL);
+                       g_object_unref (tmp_range);
+               } else {
+                       typedef WebKitDOMNode * (*GetSibling)(WebKitDOMNode *node);
+                       WebKitDOMNode *container, *sibling;
+                       WebKitDOMElement *selection_marker;
+
+                       GetSibling get_sibling = delete_key ?
+                               webkit_dom_node_get_next_sibling :
+                               webkit_dom_node_get_previous_sibling;
+
+                       container = webkit_dom_range_get_end_container (range_clone, NULL);
+                       sibling = get_sibling (container);
+
+                       selection_marker = webkit_dom_document_get_element_by_id (
+                               document,
+                               delete_key ?
+                                       "-x-evo-selection-end-marker" :
+                                       "-x-evo-selection-start-marker");
+
+                       if (selection_marker) {
+                               WebKitDOMNode *tmp_sibling;
+
+                               tmp_sibling = get_sibling (WEBKIT_DOM_NODE (selection_marker));
+                               if (!tmp_sibling || (WEBKIT_DOM_IS_HTML_BR_ELEMENT (tmp_sibling) &&
+                                   !element_has_class (WEBKIT_DOM_ELEMENT (tmp_sibling), "-x-evo-wrap-br")))
+                                       sibling = WEBKIT_DOM_NODE (selection_marker);
+                       }
+
+                       if (e_editor_dom_is_selection_position_node (sibling)) {
+                               if ((node = get_sibling (sibling)))
+                                       node = get_sibling (node);
+                               if (node) {
+                                       if (WEBKIT_DOM_IS_ELEMENT (node) &&
+                                           webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node), 
"data-hidden-space")) {
+                                               fragment = webkit_dom_document_create_document_fragment 
(document);
+                                               webkit_dom_node_append_child (
+                                                       WEBKIT_DOM_NODE (fragment),
+                                                       WEBKIT_DOM_NODE (
+                                                               webkit_dom_document_create_text_node 
(document, " ")),
+                                                       NULL);
+                                       } else if (delete_key) {
+                                               webkit_dom_range_set_start (
+                                                       range_clone, node, 0, NULL);
+                                               webkit_dom_range_set_end (
+                                                       range_clone, node, 1, NULL);
+                                       }
+                               } else {
+                                       WebKitDOMRange *tmp_range, *actual_range;
+
+                                       actual_range = webkit_dom_dom_selection_get_range_at (dom_selection, 
0, NULL);
+
+                                       webkit_dom_dom_selection_modify (
+                                               dom_selection, "move", delete_key ? "right" : "left", 
"character");
+
+                                       tmp_range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, 
NULL);
+                                       if (webkit_dom_range_compare_boundary_points (tmp_range, 
WEBKIT_DOM_RANGE_END_TO_END, actual_range, NULL) != 0) {
+                                               WebKitDOMNode *actual_block;
+                                               WebKitDOMNode *tmp_block;
+
+                                               actual_block = e_editor_dom_get_parent_block_node_from_child 
(container);
+
+                                               tmp_block = delete_key ?
+                                                       webkit_dom_range_get_end_container (tmp_range, NULL) :
+                                                       webkit_dom_range_get_start_container (tmp_range, 
NULL);
+                                               tmp_block = e_editor_dom_get_parent_block_node_from_child 
(tmp_block);
+
+                                               webkit_dom_dom_selection_modify (
+                                                       dom_selection, "move", delete_key ? "left" : "right", 
"character");
+
+                                               if (tmp_block) {
+                                                       fragment = 
webkit_dom_document_create_document_fragment (document);
+                                                       if (delete_key) {
+                                                               webkit_dom_node_append_child (
+                                                                       WEBKIT_DOM_NODE (fragment),
+                                                                       webkit_dom_node_clone_node_with_error 
(actual_block, TRUE, NULL),
+                                                                       NULL);
+                                                               webkit_dom_node_append_child (
+                                                                       WEBKIT_DOM_NODE (fragment),
+                                                                       webkit_dom_node_clone_node_with_error 
(tmp_block, TRUE, NULL),
+                                                                       NULL);
+                                                               if (delete_key)
+                                                                       next_block = tmp_block;
+                                                       } else {
+                                                               webkit_dom_node_append_child (
+                                                                       WEBKIT_DOM_NODE (fragment),
+                                                                       webkit_dom_node_clone_node_with_error 
(tmp_block, TRUE, NULL),
+                                                                       NULL);
+                                                               webkit_dom_node_append_child (
+                                                                       WEBKIT_DOM_NODE (fragment),
+                                                                       webkit_dom_node_clone_node_with_error 
(actual_block, TRUE, NULL),
+                                                                       NULL);
+                                                       }
+                                                       g_object_set_data (
+                                                               G_OBJECT (fragment),
+                                                               "history-concatenating-blocks",
+                                                               GINT_TO_POINTER (1));
+                                               }
+                                       }
+                                       g_object_unref (tmp_range);
+                                       g_object_unref (actual_range);
+                               }
+                       } else {
+                               glong offset;
+
+                               /* FIXME This code is wrong for unicode smileys. */
+                               offset = webkit_dom_range_get_start_offset (range_clone, NULL);
+
+                               if (delete_key)
+                                       webkit_dom_range_set_end (
+                                               range_clone, container, offset + 1, NULL);
+                               else
+                                       webkit_dom_range_set_start (
+                                               range_clone, container, offset - 1, NULL);
+
+                               removing_from_anchor = WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (
+                                       webkit_dom_node_get_parent_node (container));
+                       }
+               }
+
+
+               if (!fragment)
+                       fragment = webkit_dom_range_clone_contents (range_clone, NULL);
+               if (removing_from_anchor)
+                       g_object_set_data (
+                               G_OBJECT (fragment),
+                               "history-removing-from-anchor",
+                               GINT_TO_POINTER (1));
+               node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+               if (!node) {
+                       g_free (ev);
+                       e_editor_page_unblock_selection_changed (editor_page);
+                       g_object_unref (range);
+                       g_object_unref (range_clone);
+                       g_object_unref (dom_selection);
+                       g_warning ("History event was not saved for %s key", delete_key ? "Delete" : 
"Backspace");
+                       return;
+               }
+
+               if (control_key) {
+                       if (delete_key) {
+                               ev->after.start.x = ev->before.start.x;
+                               ev->after.start.y = ev->before.start.y;
+                               ev->after.end.x = ev->before.end.x;
+                               ev->after.end.y = ev->before.end.y;
+
+                               webkit_dom_range_collapse (range_clone, TRUE, NULL);
+                               webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+                               webkit_dom_dom_selection_add_range (dom_selection, range_clone);
+                       } else {
+                               gboolean selection_saved = FALSE;
+                               WebKitDOMRange *tmp_range;
+
+                               if (webkit_dom_document_get_element_by_id (document, 
"-x-evo-selection-start-marker"))
+                                       selection_saved = TRUE;
+
+                               if (selection_saved)
+                                       e_editor_dom_selection_restore (editor_page);
+
+                               tmp_range = webkit_dom_range_clone_range (range_clone, NULL);
+                               /* Prepare the selection to the right position after
+                                * delete and save it. */
+                               webkit_dom_range_collapse (range_clone, TRUE, NULL);
+                               webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+                               webkit_dom_dom_selection_add_range (dom_selection, range_clone);
+                               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, 
&ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+                               /* Restore the selection where it was before the
+                                * history event was saved. */
+                               webkit_dom_range_collapse (tmp_range, FALSE, NULL);
+                               webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+                               webkit_dom_dom_selection_add_range (dom_selection, tmp_range);
+                               g_object_unref (tmp_range);
+
+                               if (selection_saved)
+                                       e_editor_dom_selection_save (editor_page);
+                       }
+               } else {
+                       gboolean selection_saved = FALSE;
+
+                       if (webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker"))
+                               selection_saved = TRUE;
+
+                       if (selection_saved)
+                               e_editor_dom_selection_restore (editor_page);
+
+                       if (delete_key) {
+                               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, 
&ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+                       } else {
+                               webkit_dom_dom_selection_modify (dom_selection, "move", "left", "character");
+                               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, 
&ev->after.start.y, &ev->after.end.x, &ev->after.end.y);
+                               webkit_dom_dom_selection_modify (dom_selection, "move", "right", "character");
+
+                               ev->after.end.x = ev->after.start.x;
+                               ev->after.end.y = ev->after.start.y;
+                       }
+
+                       if (selection_saved)
+                               e_editor_dom_selection_save (editor_page);
+               }
+
+               g_object_unref (range_clone);
+
+               if (delete_key) {
+                       if (!WEBKIT_DOM_IS_ELEMENT (node)) {
+                               webkit_dom_node_insert_before (
+                                       WEBKIT_DOM_NODE (fragment),
+                                       WEBKIT_DOM_NODE (
+                                               dom_create_selection_marker (document, FALSE)),
+                                       webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+                                       NULL);
+                               webkit_dom_node_insert_before (
+                                       WEBKIT_DOM_NODE (fragment),
+                                       WEBKIT_DOM_NODE (
+                                               dom_create_selection_marker (document, TRUE)),
+                                       webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+                                       NULL);
+                       }
+               } else {
+                       if (!WEBKIT_DOM_IS_ELEMENT (node)) {
+                               webkit_dom_node_append_child (
+                                       WEBKIT_DOM_NODE (fragment),
+                                       WEBKIT_DOM_NODE (
+                                               dom_create_selection_marker (document, TRUE)),
+                                       NULL);
+                               webkit_dom_node_append_child (
+                                       WEBKIT_DOM_NODE (fragment),
+                                       WEBKIT_DOM_NODE (
+                                               dom_create_selection_marker (document, FALSE)),
+                                       NULL);
+                       }
+               }
+
+               /* If concatenating two blocks with pressing Delete on the end
+                * of the previous one and the next node contain content that
+                * is wrapped on multiple lines, the last line will by separated
+                * by WebKit to the separate block. To avoid it let's remove
+                * all quoting and wrapping from the next paragraph. */
+               if (next_block) {
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (next_block));
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (next_block));
+               }
+
+               e_editor_page_unblock_selection_changed (editor_page);
+       } else {
+               WebKitDOMElement *tmp_element;
+               WebKitDOMNode *sibling;
+
+               ev->after.start.x = ev->before.start.x;
+               ev->after.start.y = ev->before.start.y;
+               ev->after.end.x = ev->before.start.x;
+               ev->after.end.y = ev->before.start.y;
+
+               fragment = webkit_dom_range_clone_contents (range, NULL);
+
+               tmp_element = webkit_dom_document_fragment_query_selector (
+                       fragment, "#-x-evo-selection-start-marker", NULL);
+               if (tmp_element)
+                       remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+               tmp_element = webkit_dom_document_fragment_query_selector (
+                       fragment, "#-x-evo-selection-end-marker", NULL);
+               if (tmp_element)
+                       remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+               /* If any empty blockquote is presented, remove it. */
+               tmp_element = webkit_dom_document_query_selector (
+                       document, "blockquote[type=cite]:empty", NULL);
+               if (tmp_element)
+                       remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+               /* Selection starts in the beginning of blockquote. */
+               tmp_element = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (tmp_element));
+               if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-quoted")) {
+                       WebKitDOMNode *child;
+
+                       tmp_element = webkit_dom_document_get_element_by_id (
+                               document, "-x-evo-selection-end-marker");
+
+                       /* If there is no text after the selection end it means that
+                        * the block will be replaced with block that is body's descendant
+                        * and not the blockquote's one. Also if the selection started
+                        * in the beginning of blockquote we have to insert the quote
+                        * characters into the deleted content to correctly restore
+                        * them during undo/redo operations. */
+                       if (!(tmp_element && webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE 
(tmp_element)))) {
+                               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+                               while (child && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (child))
+                                       child = webkit_dom_node_get_first_child (child);
+
+                               child = webkit_dom_node_get_first_child (child);
+                               if (child && (WEBKIT_DOM_IS_TEXT (child) ||
+                                   (WEBKIT_DOM_IS_ELEMENT (child) &&
+                                    !element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-quoted")))) {
+                                       webkit_dom_node_insert_before (
+                                               webkit_dom_node_get_parent_node (child),
+                                               webkit_dom_node_clone_node_with_error (sibling, TRUE, NULL),
+                                               child,
+                                               NULL);
+                               }
+                       }
+               }
+
+               /* When we were cloning the range above and the range contained
+                * quoted content there will still be blockquote missing in the
+                * final range. Let's modify the fragment and add it there. */
+               tmp_element = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+               if (tmp_element) {
+                       WebKitDOMNode *node;
+
+                       node = WEBKIT_DOM_NODE (tmp_element);
+                       while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (node)))
+                               node = webkit_dom_node_get_parent_node (node);
+
+                       if (node && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) {
+                               WebKitDOMNode *last_child;
+
+                               last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+
+                               if (last_child && !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (last_child)) {
+                                       WebKitDOMDocumentFragment *tmp_fragment;
+                                       WebKitDOMNode *clone;
+
+                                       tmp_fragment = webkit_dom_document_create_document_fragment 
(document);
+                                       clone = webkit_dom_node_clone_node_with_error (node, FALSE, NULL);
+                                       clone = webkit_dom_node_append_child (
+                                               WEBKIT_DOM_NODE (tmp_fragment), clone, NULL);
+                                       webkit_dom_node_append_child (clone, WEBKIT_DOM_NODE (fragment), 
NULL);
+                                       fragment = tmp_fragment;
+                               }
+                       }
+               }
+
+               /* FIXME Ugly hack */
+               /* If the deleted selection contained the signature (or at least its
+                * part) replace it with the unchanged signature to correctly perform
+                * undo operation. */
+               tmp_element = webkit_dom_document_fragment_query_selector (fragment, 
".-x-evo-signature-wrapper", NULL);
+               if (tmp_element) {
+                       WebKitDOMElement *signature;
+
+                       signature = webkit_dom_document_query_selector (document, 
".-x-evo-signature-wrapper", NULL);
+                       if (signature) {
+                               webkit_dom_node_replace_child (
+                                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp_element)),
+                                       webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (signature), 
TRUE, NULL),
+                                       WEBKIT_DOM_NODE (tmp_element),
+                                       NULL);
+                       }
+               }
+       }
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+
+       g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (delete_key));
+       g_object_set_data (G_OBJECT (fragment), "history-control-key", GINT_TO_POINTER (control_key));
+
+       ev->data.fragment = fragment;
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+}
+
+gboolean
+e_editor_dom_fix_structure_after_delete_before_quoted_content (EEditorPage *editor_page,
+                                                              glong key_code,
+                                                              gboolean control_key,
+                                                              gboolean delete_key)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block, *node;
+       gboolean collapsed = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       collapsed = e_editor_dom_selection_is_collapsed (editor_page);
+
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker || !selection_end_marker)
+               return FALSE;
+
+       if (collapsed) {
+               WebKitDOMNode *next_block;
+
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               /* Next block is quoted content */
+               if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (next_block))
+                       goto restore;
+
+               /* Delete was pressed in block without any content */
+               if (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)))
+                       goto restore;
+
+               /* If there is just BR element go ahead */
+               node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+               if (node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node))
+                       goto restore;
+               else {
+                       if (key_code != ~0)
+                               save_history_for_delete_or_backspace (
+                                       editor_page, key_code == HTML_KEY_CODE_DELETE, control_key);
+
+                       /* Remove the empty block and move caret to the right place. */
+                       remove_node (block);
+
+                       if (delete_key) {
+                               /* To the beginning of the next block. */
+                               e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT 
(next_block), TRUE);
+                       } else {
+                               WebKitDOMNode *prev_block;
+
+                               /* On the end of previous block. */
+                               prev_block = webkit_dom_node_get_previous_sibling (next_block);
+                               while (prev_block && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (prev_block))
+                                       prev_block = webkit_dom_node_get_last_child (prev_block);
+
+                               if (prev_block)
+                                       e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT 
(prev_block), FALSE);
+                       }
+
+                       return TRUE;
+               }
+       } else {
+               WebKitDOMNode *end_block, *parent;
+
+               /* Let the quote marks be selectable to nearly correctly remove the
+                * selection. Corrections after are done in body_keyup_event_cb. */
+               enable_quote_marks_select (document);
+
+               parent = webkit_dom_node_get_parent_node (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) ||
+                   element_has_tag (WEBKIT_DOM_ELEMENT (parent), "b") ||
+                   element_has_tag (WEBKIT_DOM_ELEMENT (parent), "i") ||
+                   element_has_tag (WEBKIT_DOM_ELEMENT (parent), "u"))
+                       node = webkit_dom_node_get_previous_sibling (parent);
+               else
+                       node = webkit_dom_node_get_previous_sibling (
+                               WEBKIT_DOM_NODE (selection_start_marker));
+
+               if (!node || !WEBKIT_DOM_IS_ELEMENT (node))
+                       goto restore;
+
+               if (!element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted"))
+                       goto restore;
+
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               end_block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_end_marker));
+
+               /* Situation where the start of the selection is in the beginning
+               + * of the block in quoted content and the end in the beginning of
+               + * content that is after the citation or the selection end is in
+               + * the end of the quoted content (showed by ^). We have to
+               + * mark the start block to correctly restore the structure
+               + * afterwards.
+               *
+               * > |xxx
+               * > xxx^
+               * |xxx
+               */
+               if (e_editor_dom_get_citation_level (end_block, FALSE) > 0) {
+                       WebKitDOMNode *parent;
+
+                       if (webkit_dom_node_get_next_sibling (end_block))
+                               goto restore;
+
+                       parent = webkit_dom_node_get_parent_node (end_block);
+                       while (parent && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent)) {
+                               WebKitDOMNode *next_parent = webkit_dom_node_get_parent_node (parent);
+
+                               if (webkit_dom_node_get_next_sibling (parent) &&
+                                   !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (next_parent))
+                                       goto restore;
+
+                               parent = next_parent;
+                       }
+               }
+       }
+
+ restore:
+       if (key_code != ~0)
+               save_history_for_delete_or_backspace (
+                       editor_page, key_code == HTML_KEY_CODE_DELETE, control_key);
+
+       e_editor_dom_selection_restore (editor_page);
+
+       return FALSE;
+}
+
+static gboolean
+split_citation (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               WebKitDOMElement *selection_end;
+               WebKitDOMNode *sibling;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_CITATION_SPLIT;
+
+               e_editor_dom_selection_save (editor_page);
+
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->before.start.x, 
&ev->before.start.y, &ev->before.end.x, &ev->before.end.y);
+
+               if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+                       WebKitDOMRange *range;
+
+                       range = e_editor_dom_get_current_range (editor_page);
+                       insert_delete_event (editor_page, range);
+
+                       g_object_unref (range);
+
+                       ev->before.end.x = ev->before.start.x;
+                       ev->before.end.y = ev->before.start.y;
+               }
+
+               selection_end = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+
+               sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end));
+               if (!sibling || (WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) &&
+                   !element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-wrap-br"))) {
+                       WebKitDOMDocumentFragment *fragment;
+
+                       fragment = webkit_dom_document_create_document_fragment (document);
+                       ev->data.fragment = fragment;
+               } else
+                       ev->data.fragment = NULL;
+
+               e_editor_dom_selection_restore (editor_page);
+       }
+
+       element = e_editor_dom_insert_new_line_into_citation (editor_page, "");
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page, &ev->after.start.x, &ev->after.start.y, 
&ev->after.end.x, &ev->after.end.y);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       return element != NULL;
+}
+
+static gboolean
+delete_last_character_from_previous_line_in_quoted_block (EEditorPage *editor_page,
+                                                          glong key_code,
+                                                          guint state)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment = NULL;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node, *beginning, *prev_sibling;
+       EEditorHistoryEvent *ev = NULL;
+       gboolean hidden_space = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       /* We have to be in quoted content. */
+       if (!e_editor_dom_selection_is_citation (editor_page))
+               return FALSE;
+
+       /* Selection is just caret. */
+       if (!e_editor_dom_selection_is_collapsed (editor_page))
+               return FALSE;
+
+       document = e_editor_page_get_document (editor_page);
+
+       e_editor_dom_selection_save (editor_page);
+
+       element = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+
+       /* Before the caret are just quote characters */
+       beginning = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+       if (!(beginning && WEBKIT_DOM_IS_ELEMENT (beginning))) {
+               WebKitDOMNode *parent;
+
+               parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+               if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+                       beginning = webkit_dom_node_get_previous_sibling (parent);
+               else
+                       goto out;
+       }
+
+       /* Before the text is the beginning of line. */
+       if (!(element_has_class (WEBKIT_DOM_ELEMENT (beginning), "-x-evo-quoted")))
+               goto out;
+
+       /* If we are just on the beginning of the line and not on the beginning of
+        * the block we need to remove the last character ourselves as well, otherwise
+        * WebKit will put the caret to wrong position. */
+       if (!(prev_sibling = webkit_dom_node_get_previous_sibling (beginning)))
+               goto out;
+
+       if (key_code != ~0) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_DELETE;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               fragment = webkit_dom_document_create_document_fragment (document);
+       }
+
+       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling)) {
+               if (key_code != ~0)
+                       webkit_dom_node_append_child (WEBKIT_DOM_NODE (fragment), prev_sibling, NULL);
+               else
+                       remove_node (prev_sibling);
+       }
+
+       prev_sibling = webkit_dom_node_get_previous_sibling (beginning);
+       if (WEBKIT_DOM_IS_ELEMENT (prev_sibling) &&
+           webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (prev_sibling), "data-hidden-space")) {
+               hidden_space = TRUE;
+               if (key_code != ~0)
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (fragment),
+                               prev_sibling,
+                               webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment)),
+                               NULL);
+               else
+                       remove_node (prev_sibling);
+       }
+
+       node = webkit_dom_node_get_previous_sibling (beginning);
+
+       if (key_code != ~0)
+               webkit_dom_node_append_child (WEBKIT_DOM_NODE (fragment), beginning, NULL);
+       else
+               remove_node (beginning);
+
+       if (!hidden_space) {
+               if (key_code != ~0) {
+                       gchar *data;
+
+                       data = webkit_dom_character_data_substring_data (
+                               WEBKIT_DOM_CHARACTER_DATA (node),
+                               webkit_dom_character_data_get_length (
+                                       WEBKIT_DOM_CHARACTER_DATA (node)) -1,
+                               1,
+                               NULL);
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               WEBKIT_DOM_NODE (
+                                       webkit_dom_document_create_text_node (document, data)),
+                               NULL);
+
+                       g_free (data);
+               }
+
+               webkit_dom_character_data_delete_data (
+                       WEBKIT_DOM_CHARACTER_DATA (node),
+                       webkit_dom_character_data_get_length (
+                               WEBKIT_DOM_CHARACTER_DATA (node)) -1,
+                       1,
+                       NULL);
+       }
+
+       if (key_code != ~0) {
+               EEditorUndoRedoManager *manager;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+
+               ev->data.fragment = fragment;
+
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       return TRUE;
+ out:
+       e_editor_dom_selection_restore (editor_page);
+
+       return FALSE;
+}
+
+gboolean
+e_editor_dom_delete_last_character_on_line_in_quoted_block (EEditorPage *editor_page,
+                                                           glong key_code,
+                                                           gboolean control_key)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node, *beginning, *next_sibling;
+       gboolean success = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* We have to be in quoted content. */
+       if (!e_editor_dom_selection_is_citation (editor_page))
+               return FALSE;
+
+       /* Selection is just caret. */
+       if (!e_editor_dom_selection_is_collapsed (editor_page))
+               return FALSE;
+
+       e_editor_dom_selection_save (editor_page);
+
+       element = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+
+       /* selection end marker */
+       node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+       /* We have to be on the end of line. */
+       next_sibling = webkit_dom_node_get_next_sibling (node);
+       if (next_sibling &&
+           (!WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling) ||
+            webkit_dom_node_get_next_sibling (next_sibling)))
+               goto out;
+
+       /* Before the caret is just text. */
+       node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+       if (!(node && WEBKIT_DOM_IS_TEXT (node)))
+               goto out;
+
+       /* There is just one character. */
+       if (webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)) != 1)
+               goto out;
+
+       beginning = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (node));
+       if (!(beginning && WEBKIT_DOM_IS_ELEMENT (beginning)))
+               goto out;
+
+       /* Before the text is the beginning of line. */
+       if (!(element_has_class (WEBKIT_DOM_ELEMENT (beginning), "-x-evo-quoted")))
+               goto out;
+
+       if (!webkit_dom_node_get_previous_sibling (beginning))
+               goto out;
+
+       if (key_code != ~0)
+               save_history_for_delete_or_backspace (
+                       editor_page, key_code == HTML_KEY_CODE_DELETE, control_key);
+
+       element = webkit_dom_node_get_parent_element (beginning);
+       remove_node (WEBKIT_DOM_NODE (element));
+
+       success = TRUE;
+ out:
+       e_editor_dom_selection_restore (editor_page);
+
+       if (success)
+               e_editor_dom_insert_new_line_into_citation (editor_page, NULL);
+
+       return success;
+}
+
+static gboolean
+selection_is_in_empty_list_item (WebKitDOMNode *selection_start_marker)
+{
+       gchar *text;
+       WebKitDOMNode *sibling;
+
+       /* Selection needs to be collapsed. */
+       sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+       if (!e_editor_dom_is_selection_position_node (sibling))
+               return FALSE;
+
+       /* After the selection end there could be just the BR element. */
+       sibling = webkit_dom_node_get_next_sibling (sibling);
+       if (sibling && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling))
+              return FALSE;
+
+       if (sibling && webkit_dom_node_get_next_sibling (sibling))
+               return FALSE;
+
+       sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+
+       /* Only text node with the zero width space character is allowed. */
+       if (!WEBKIT_DOM_IS_TEXT (sibling))
+               return FALSE;
+
+       if (webkit_dom_node_get_previous_sibling (sibling))
+               return FALSE;
+
+       if (webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (sibling)) != 1)
+               return FALSE;
+
+       text = webkit_dom_character_data_get_data (WEBKIT_DOM_CHARACTER_DATA (sibling));
+       if (!(text && g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0)) {
+               g_free (text);
+               return FALSE;
+       }
+
+       g_free (text);
+
+       return TRUE;
+}
+
+static gboolean
+return_pressed_in_image_wrapper (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment;
+       WebKitDOMElement *selection_start_marker;
+       WebKitDOMNode *parent, *block, *clone;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       if (!e_editor_dom_selection_is_collapsed (editor_page))
+               return FALSE;
+
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+       if (!element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper")) {
+               e_editor_dom_selection_restore (editor_page);
+               return FALSE;
+       }
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INPUT;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               fragment = webkit_dom_document_create_document_fragment (document);
+
+               g_object_set_data (
+                       G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+       }
+
+       block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       clone = webkit_dom_node_clone_node_with_error (block, FALSE, NULL);
+       webkit_dom_node_append_child (
+               clone, WEBKIT_DOM_NODE (webkit_dom_document_create_element (document, "br", NULL)), NULL);
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (block),
+               clone,
+               block,
+               NULL);
+
+       if (ev) {
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       webkit_dom_node_clone_node_with_error (clone, TRUE, NULL),
+                       NULL);
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+
+               ev->data.fragment = fragment;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_page_emit_content_changed (editor_page);
+
+       e_editor_dom_selection_restore (editor_page);
+
+       return TRUE;
+}
+
+gboolean
+e_editor_dom_return_pressed_in_empty_list_item (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker;
+       WebKitDOMNode *parent;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       if (!e_editor_dom_selection_is_collapsed (editor_page))
+               return FALSE;
+
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+       if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent)) {
+               e_editor_dom_selection_restore (editor_page);
+               return FALSE;
+       }
+
+       if (selection_is_in_empty_list_item (WEBKIT_DOM_NODE (selection_start_marker))) {
+               EEditorHistoryEvent *ev = NULL;
+               EEditorUndoRedoManager *manager;
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMElement *paragraph;
+               WebKitDOMNode *list;
+
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+               if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+                       ev = g_new0 (EEditorHistoryEvent, 1);
+                       ev->type = HISTORY_INPUT;
+
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->before.start.x,
+                               &ev->before.start.y,
+                               &ev->before.end.x,
+                               &ev->before.end.y);
+
+                       fragment = webkit_dom_document_create_document_fragment (document);
+
+                       g_object_set_data (
+                               G_OBJECT (fragment), "history-return-key", GINT_TO_POINTER (1));
+               }
+
+               list = split_list_into_two (parent, -1);
+
+               if (ev) {
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               parent,
+                               NULL);
+               } else {
+                       remove_node (parent);
+               }
+
+               paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (list),
+                       WEBKIT_DOM_NODE (paragraph),
+                       list,
+                       NULL);
+
+               if (ev) {
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->after.start.x,
+                               &ev->after.start.y,
+                               &ev->after.end.x,
+                               &ev->after.end.y);
+
+                       ev->data.fragment = fragment;
+
+                       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+               }
+
+               e_editor_dom_selection_restore (editor_page);
+
+               e_editor_page_emit_content_changed (editor_page);
+
+               return TRUE;
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       return FALSE;
+}
+
+static void
+process_smiley_on_delete_or_backspace (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+       WebKitDOMNode *parent;
+       gboolean in_smiley = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+       element = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+       if (WEBKIT_DOM_IS_ELEMENT (parent) &&
+           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text"))
+               in_smiley = TRUE;
+       else {
+               if (e_editor_dom_selection_is_collapsed (editor_page)) {
+                       WebKitDOMNode *prev_sibling;
+
+                       prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+                       if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling)) {
+                               gchar *text = webkit_dom_character_data_get_data (
+                                       WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+
+                               if (g_strcmp0 (text, UNICODE_ZERO_WIDTH_SPACE) == 0) {
+                                       WebKitDOMNode *prev_prev_sibling;
+
+                                       prev_prev_sibling = webkit_dom_node_get_previous_sibling 
(prev_sibling);
+                                       if (WEBKIT_DOM_IS_ELEMENT (prev_prev_sibling) &&
+                                           element_has_class (WEBKIT_DOM_ELEMENT (prev_prev_sibling), 
"-x-evo-smiley-wrapper")) {
+                                               remove_node (prev_sibling);
+                                               in_smiley = TRUE;
+                                               parent = webkit_dom_node_get_last_child (prev_prev_sibling);
+                                       }
+                               }
+
+                               g_free (text);
+                       }
+               } else {
+                       element = webkit_dom_document_get_element_by_id (
+                               document, "-x-evo-selection-end-marker");
+
+                       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+                       if (WEBKIT_DOM_IS_ELEMENT (parent) &&
+                           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-text"))
+                               in_smiley = TRUE;
+               }
+       }
+
+       if (in_smiley) {
+               WebKitDOMNode *wrapper;
+
+               wrapper = webkit_dom_node_get_parent_node (parent);
+               if (!e_editor_page_get_html_mode (editor_page)) {
+                       WebKitDOMNode *child;
+
+                       while ((child = webkit_dom_node_get_first_child (parent)))
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (wrapper),
+                                       child,
+                                       wrapper,
+                                       NULL);
+               }
+               /* In the HTML mode the whole smiley will be removed. */
+               remove_node (wrapper);
+               /* FIXME history will be probably broken here */
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+}
+
+gboolean
+e_editor_dom_key_press_event_process_return_key (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *table = NULL;
+       gboolean first_cell = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       /* Return pressed in the beginning of the first cell will insert
+        * new block before the table (and move the caret there) if none
+        * is already there, otherwise it will act as normal return. */
+       if (selection_is_in_table (document, &first_cell, &table) && first_cell) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_get_previous_sibling (table);
+               if (!node) {
+                       node = webkit_dom_node_get_next_sibling (table);
+                       node = webkit_dom_node_clone_node_with_error (node, FALSE, NULL);
+                       webkit_dom_node_append_child (
+                               node,
+                               WEBKIT_DOM_NODE (webkit_dom_document_create_element (
+                                       document, "br", NULL)),
+                               NULL);
+                       dom_add_selection_markers_into_element_start (
+                               document, WEBKIT_DOM_ELEMENT (node), NULL, NULL);
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (table),
+                               node,
+                               table,
+                               NULL);
+                       e_editor_dom_selection_restore (editor_page);
+                       e_editor_page_emit_content_changed (editor_page);
+                       return TRUE;
+               }
+       }
+
+       /* When user presses ENTER in a citation block, WebKit does
+        * not break the citation automatically, so we need to use
+        * the special command to do it. */
+       if (e_editor_dom_selection_is_citation (editor_page)) {
+               e_editor_dom_remove_input_event_listener_from_body (editor_page);
+               if (split_citation (editor_page)) {
+                       e_editor_page_set_return_key_pressed (editor_page, TRUE);
+                       e_editor_dom_check_magic_links (editor_page, FALSE);
+                       e_editor_page_set_return_key_pressed (editor_page, FALSE);
+                       e_editor_page_emit_content_changed (editor_page);
+
+                       return TRUE;
+               }
+               return FALSE;
+       }
+
+       /* If the ENTER key is pressed inside an empty list item then the list
+        * is broken into two and empty paragraph is inserted between lists. */
+       if (e_editor_dom_return_pressed_in_empty_list_item (editor_page))
+               return TRUE;
+
+       if (return_pressed_in_image_wrapper (editor_page))
+               return TRUE;
+
+       return FALSE;
+}
+
+static gboolean
+remove_empty_bulleted_list_item (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start;
+       WebKitDOMNode *parent;
+       EEditorUndoRedoManager *manager;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start));
+       while (parent && !node_is_list_or_item (parent))
+               parent = webkit_dom_node_get_parent_node (parent);
+
+       if (!parent)
+               goto out;
+
+       if (selection_is_in_empty_list_item (WEBKIT_DOM_NODE (selection_start))) {
+               EEditorHistoryEvent *ev = NULL;
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMNode *prev_item;
+
+               prev_item = webkit_dom_node_get_previous_sibling (parent);
+
+               if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+                       /* Insert new history event for Return to have the right coordinates.
+                        * The fragment will be added later. */
+                       ev = g_new0 (EEditorHistoryEvent, 1);
+                       ev->type = HISTORY_DELETE;
+
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->before.start.x,
+                               &ev->before.start.y,
+                               &ev->before.end.x,
+                               &ev->before.end.y);
+
+                       fragment = webkit_dom_document_create_document_fragment (document);
+               }
+
+               if (ev) {
+                       if (prev_item)
+                               webkit_dom_node_append_child (
+                                       WEBKIT_DOM_NODE (fragment),
+                                       webkit_dom_node_clone_node_with_error (prev_item, TRUE, NULL),
+                                       NULL);
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (fragment),
+                               parent,
+                               NULL);
+               } else
+                       remove_node (parent);
+
+               if (prev_item)
+                       dom_add_selection_markers_into_element_end (
+                               document, WEBKIT_DOM_ELEMENT (prev_item), NULL, NULL);
+
+               if (ev) {
+                       e_editor_dom_selection_get_coordinates (editor_page,
+                               &ev->after.start.x,
+                               &ev->after.start.y,
+                               &ev->after.end.x,
+                               &ev->after.end.y);
+
+                       ev->data.fragment = fragment;
+
+                       e_editor_undo_redo_manager_insert_history_event (manager, ev);
+               }
+
+               e_editor_page_emit_content_changed (editor_page);
+               e_editor_dom_selection_restore (editor_page);
+
+               return TRUE;
+       }
+ out:
+       e_editor_dom_selection_restore (editor_page);
+
+       return FALSE;
+}
+
+gboolean
+e_editor_dom_key_press_event_process_backspace_key (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       /* BackSpace pressed in the beginning of quoted content changes
+        * format to normal and inserts text into body */
+       if (e_editor_dom_selection_is_collapsed (editor_page)) {
+               e_editor_dom_selection_save (editor_page);
+               if (e_editor_dom_move_quoted_block_level_up (editor_page) || delete_hidden_space 
(editor_page)) {
+                       e_editor_dom_selection_restore (editor_page);
+                       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+                       e_editor_page_emit_content_changed (editor_page);
+                       return TRUE;
+               }
+               e_editor_dom_selection_restore (editor_page);
+       }
+
+       /* BackSpace in indented block decrease indent level by one */
+       if (e_editor_dom_selection_is_indented (editor_page) &&
+           e_editor_dom_selection_is_collapsed (editor_page)) {
+               WebKitDOMDocument *document;
+               WebKitDOMElement *selection_start;
+               WebKitDOMNode *prev_sibling;
+
+               document = e_editor_page_get_document (editor_page);
+
+               e_editor_dom_selection_save (editor_page);
+               selection_start = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+
+               /* Empty text node before caret */
+               prev_sibling = webkit_dom_node_get_previous_sibling (
+                       WEBKIT_DOM_NODE (selection_start));
+               if (prev_sibling && WEBKIT_DOM_IS_TEXT (prev_sibling))
+                       if (webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (prev_sibling)) 
== 0)
+                               prev_sibling = webkit_dom_node_get_previous_sibling (prev_sibling);
+
+               e_editor_dom_selection_restore (editor_page);
+               if (!prev_sibling) {
+                       e_editor_dom_selection_unindent (editor_page);
+                       e_editor_page_emit_content_changed (editor_page);
+                       return TRUE;
+               }
+       }
+
+       /* BackSpace pressed in an empty item in the bulleted list removes it. */
+       if (!e_editor_page_get_html_mode (editor_page) && e_editor_dom_selection_is_collapsed (editor_page) &&
+           remove_empty_bulleted_list_item (editor_page))
+               return TRUE;
+
+
+       if (prevent_from_deleting_last_element_in_body (e_editor_page_get_document (editor_page)))
+               return TRUE;
+
+       return FALSE;
+}
+
+gboolean
+e_editor_dom_key_press_event_process_delete_or_backspace_key (EEditorPage *editor_page,
+                                                             glong key_code,
+                                                             gboolean control_key,
+                                                             gboolean delete)
+{
+       WebKitDOMDocument *document;
+       gboolean html_mode;
+       gboolean local_delete;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       html_mode = e_editor_page_get_html_mode (editor_page);
+       local_delete = (key_code == HTML_KEY_CODE_DELETE) || delete;
+
+       if (e_editor_page_get_magic_smileys_enabled (editor_page)) {
+               /* If deleting something in a smiley it won't be a smiley
+                * anymore (at least from Evolution' POV), so remove all
+                * the elements that are hidden in the wrapper and leave
+                * just the text. Also this ensures that when a smiley is
+                * recognized and we press the BackSpace key we won't delete
+                * the UNICODE_HIDDEN_SPACE, but we will correctly delete
+                * the last character of smiley. */
+               process_smiley_on_delete_or_backspace (editor_page);
+       }
+
+       if (!local_delete && !html_mode &&
+           e_editor_dom_delete_last_character_on_line_in_quoted_block (editor_page, key_code, control_key))
+               goto out;
+
+       if (!local_delete && !html_mode &&
+           delete_last_character_from_previous_line_in_quoted_block (editor_page, key_code, control_key))
+               goto out;
+
+       if (e_editor_dom_fix_structure_after_delete_before_quoted_content (editor_page, key_code, 
control_key, FALSE))
+               goto out;
+
+       if (local_delete) {
+               WebKitDOMElement *selection_start_marker;
+               WebKitDOMNode *sibling, *block, *next_block;
+
+               /* This needs to be performed just in plain text mode
+                * and when the selection is collapsed. */
+               if (html_mode || !e_editor_dom_selection_is_collapsed (editor_page))
+                       return FALSE;
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               sibling = webkit_dom_node_get_previous_sibling (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               /* Check if the key was pressed in the beginning of block. */
+               if (!(sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+                     element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-quoted"))) {
+                       e_editor_dom_selection_restore (editor_page);
+                       return FALSE;
+               }
+
+               sibling = webkit_dom_node_get_next_sibling (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               sibling = webkit_dom_node_get_next_sibling (sibling);
+
+               /* And also the current block was empty. */
+               if (!(!sibling || (sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) &&
+                     !element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-wrap-br")))) {
+                       e_editor_dom_selection_restore (editor_page);
+                       return FALSE;
+               }
+
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               remove_node (block);
+
+               e_editor_dom_move_caret_into_element (editor_page, WEBKIT_DOM_ELEMENT (next_block), TRUE);
+
+               goto out;
+       } else {
+               /* Concatenating a non-quoted block with Backspace key to the
+                * previous block that is inside a quoted content. */
+               WebKitDOMElement *selection_start_marker;
+               WebKitDOMNode *node, *block, *prev_block, *last_child, *child;
+
+               if (html_mode || !e_editor_dom_selection_is_collapsed (editor_page) ||
+                   e_editor_dom_selection_is_citation (editor_page))
+                       return FALSE;
+
+               e_editor_dom_selection_save (editor_page);
+
+               selection_start_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+
+               node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker));
+               if (node) {
+                       e_editor_dom_selection_restore (editor_page);
+                       return FALSE;
+               }
+
+               remove_empty_blocks (document);
+
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+               prev_block = webkit_dom_node_get_previous_sibling (block);
+               if (!prev_block || !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (prev_block)) {
+                       e_editor_dom_selection_restore (editor_page);
+                       return FALSE;
+               }
+
+               last_child = webkit_dom_node_get_last_child (prev_block);
+               while (last_child && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (last_child))
+                       last_child = webkit_dom_node_get_last_child (last_child);
+
+               if (!last_child) {
+                       e_editor_dom_selection_restore (editor_page);
+                       return FALSE;
+               }
+
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
+               e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
+
+               node = webkit_dom_node_get_last_child (last_child);
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (node))
+                       remove_node (node);
+
+               while ((child = webkit_dom_node_get_first_child (block)))
+                       webkit_dom_node_append_child (last_child, child, NULL);
+
+               remove_node (block);
+
+               if (WEBKIT_DOM_IS_ELEMENT (last_child))
+                       e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_child));
+
+               e_editor_dom_selection_restore (editor_page);
+
+               goto out;
+       }
+
+       return FALSE;
+ out:
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+       e_editor_page_emit_content_changed (editor_page);
+
+       return TRUE;
+}
+
+gboolean
+e_editor_dom_check_if_conversion_needed (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+       gboolean is_from_new_message, converted, edit_as_new, message, convert;
+       gboolean reply, hide;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       body = webkit_dom_document_get_body (document);
+
+       is_from_new_message = webkit_dom_element_has_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-new-message");
+       converted = webkit_dom_element_has_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-converted");
+       edit_as_new = webkit_dom_element_has_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-edit-as-new");
+       message = webkit_dom_element_has_attribute (
+               WEBKIT_DOM_ELEMENT (body), "data-message");
+
+       reply = !is_from_new_message && !edit_as_new && message;
+       hide = !reply && !converted;
+
+       convert = message && ((!hide && reply && !converted) || (edit_as_new && !converted));
+       convert = convert && !is_from_new_message;
+
+       return convert;
+}
+
+static void
+toggle_tables (WebKitDOMDocument *document,
+               gboolean html_mode)
+{
+       WebKitDOMNodeList *list;
+       gint ii, length;
+
+       list = webkit_dom_document_query_selector_all (document, "table", NULL);
+       length = webkit_dom_node_list_get_length (list);
+
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *table = webkit_dom_node_list_item (list, ii);
+
+               if (html_mode) {
+                       element_remove_class (WEBKIT_DOM_ELEMENT (table), "-x-evo-plaintext-table");
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "data-width", "width");
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "data-cellspacing", 
"cellspacing");
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "data-cellpadding", 
"cellpadding");
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "data-border", "border");
+               } else {
+                       element_add_class (WEBKIT_DOM_ELEMENT (table), "-x-evo-plaintext-table");
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "width", "data-width");
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "cellspacing", 
"data-cellspacing");
+                       webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (table), "cellspacing", "0", 
NULL);
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "cellpadding", 
"data-cellpadding");
+                       webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (table), "cellpadding", "0", 
NULL);
+                       element_rename_attribute (WEBKIT_DOM_ELEMENT (table), "border", "data-border");
+                       webkit_dom_element_set_attribute (WEBKIT_DOM_ELEMENT (table), "border", "0", NULL);
+               }
+               g_object_unref (table);
+       }
+       g_object_unref (list);
+}
+
+static void
+toggle_unordered_lists (WebKitDOMDocument *document,
+                        gboolean html_mode)
+{
+       WebKitDOMNodeList *list;
+       gint ii, length;
+
+       list = webkit_dom_document_query_selector_all (document, "ul", NULL);
+       length = webkit_dom_node_list_get_length (list);
+
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               if (html_mode) {
+                       webkit_dom_element_remove_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "data-evo-plain-text");
+               } else {
+                       webkit_dom_element_set_attribute (
+                               WEBKIT_DOM_ELEMENT (node), "data-evo-plain-text", "", NULL);
+               }
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+}
+
+void
+e_editor_dom_process_content_after_mode_change (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *blockquote;
+       EEditorUndoRedoManager *manager;
+       gboolean html_mode;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       blockquote = webkit_dom_document_query_selector (
+               document, "blockquote[type|=cite]", NULL);
+
+       if (html_mode) {
+               WebKitDOMHTMLElement *body;
+
+               if (blockquote)
+                       dom_dequote_plain_text (document);
+
+               toggle_paragraphs_style (editor_page);
+               toggle_smileys (editor_page);
+               toggle_tables (document, html_mode);
+               toggle_unordered_lists (document, html_mode);
+
+               body = webkit_dom_document_get_body (document);
+
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (body));
+       } else {
+               gchar *plain;
+               WebKitDOMHTMLElement *body;
+
+               e_editor_dom_selection_save (editor_page);
+
+               if (blockquote) {
+                       wrap_paragraphs_in_quoted_content (editor_page);
+                       quote_plain_text_elements_after_wrapping_in_document (editor_page);
+               }
+
+               toggle_paragraphs_style (editor_page);
+               toggle_smileys (editor_page);
+               toggle_tables (document, html_mode);
+               toggle_unordered_lists (document, html_mode);
+               remove_images (document);
+               body = webkit_dom_document_get_body (document);
+               remove_background_images_in_element (WEBKIT_DOM_ELEMENT (body));
+
+               plain = process_content_for_mode_change (editor_page);
+
+               if (*plain) {
+                       webkit_dom_element_set_outer_html (
+                               WEBKIT_DOM_ELEMENT (
+                                       webkit_dom_document_get_document_element (document)),
+                               plain,
+                               NULL);
+                       e_editor_dom_selection_restore (editor_page);
+                       e_editor_dom_force_spell_check_in_viewport (editor_page);
+               }
+
+               g_free (plain);
+       }
+
+       set_monospace_font_family_on_body (WEBKIT_DOM_ELEMENT (webkit_dom_document_get_body (document)), 
html_mode);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       e_editor_undo_redo_manager_clean_history (manager);
+}
+
+guint
+e_editor_dom_get_caret_offset (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMNode *anchor;
+       WebKitDOMRange *range;
+       guint ret_val;
+       gchar *text;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+               g_object_unref (dom_selection);
+               return 0;
+       }
+
+       webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
+       /* Select the text from the current caret position to the beginning of the line. */
+       webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "lineBoundary");
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+       text = webkit_dom_range_to_string (range, NULL);
+       ret_val = strlen (text);
+       g_free (text);
+
+       webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+
+       /* In the plain text mode we need to increase the return value by 2 per
+        * citation level because of "> ". */
+       if (!e_editor_page_get_html_mode (editor_page)) {
+               WebKitDOMNode *parent = anchor;
+
+               while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+                       if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+                           element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-plaintext-quoted"))
+                               ret_val += 2;
+
+                       parent = webkit_dom_node_get_parent_node (parent);
+               }
+       }
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+
+       return ret_val;
+}
+
+guint
+e_editor_dom_get_caret_position (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLElement *body;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range, *range_clone;
+       guint ret_val;
+       gchar *text;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       g_object_unref (dom_window);
+
+       if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+               g_object_unref (dom_selection);
+               return 0;
+       }
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       range_clone = webkit_dom_range_clone_range (range, NULL);
+
+       body = webkit_dom_document_get_body (document);
+       /* Select the text from the beginning of the body to the current caret. */
+       webkit_dom_range_set_start_before (
+               range_clone, webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body)), NULL);
+
+       /* This is returning a text without new lines! */
+       text = webkit_dom_range_to_string (range_clone, NULL);
+       ret_val = strlen (text);
+       g_free (text);
+
+       g_object_unref (range_clone);
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+
+       return ret_val;
+}
+
+void
+e_editor_dom_save_history_for_drop (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMNodeList *list;
+       WebKitDOMRange *range;
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *event;
+       gint ii, length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       /* When the image is DnD inside the view WebKit removes the wrapper that
+        * is used for resizing the image, so we have to recreate it again. */
+       list = webkit_dom_document_query_selector_all (document, ":not(span) > img[data-inline]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMElement *element;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               element = webkit_dom_document_create_element (document, "span", NULL);
+               webkit_dom_element_set_class_name (element, "-x-evo-resizable-wrapper");
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (node),
+                       WEBKIT_DOM_NODE (element),
+                       node,
+                       NULL);
+
+               webkit_dom_node_append_child (WEBKIT_DOM_NODE (element), node, NULL);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       /* When the image is moved the new selection is created after after it, so
+        * lets collapse the selection to have the caret right after the image. */
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       /* Remove the last inserted history event as this one was inserted in
+        * body_input_event_cb and is wrong as its type is HISTORY_INPUT. */
+       /* FIXME we could probably disable the HTML input event callback while
+        * doing DnD within the view */
+       /* FIXME WK2 - what if e_editor_undo_redo_manager_get_current_history_event() returns NULL? */
+       if (((EEditorHistoryEvent *) (e_editor_undo_redo_manager_get_current_history_event (manager)))->type 
== HISTORY_INPUT)
+               e_editor_undo_redo_manager_remove_current_history_event (manager);
+
+       event = g_new0 (EEditorHistoryEvent, 1);
+       event->type = HISTORY_INSERT_HTML;
+
+       /* Get the dropped content. It's easy as it is selected by WebKit. */
+       fragment = webkit_dom_range_clone_contents (range, NULL);
+       event->data.string.from = NULL;
+       /* Get the HTML content of the dropped content. */
+       event->data.string.to = dom_get_node_inner_html (WEBKIT_DOM_NODE (fragment));
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &event->before.start.x,
+               &event->before.start.y,
+               &event->before.end.x,
+               &event->before.end.y);
+
+       event->before.end.x = event->before.start.x;
+       event->before.end.y = event->before.start.y;
+
+       if (length > 0)
+               webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
+       else
+               webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+
+       e_editor_dom_selection_get_coordinates (editor_page,
+               &event->after.start.x,
+               &event->after.start.y,
+               &event->after.end.x,
+               &event->after.end.y);
+
+       e_editor_undo_redo_manager_insert_history_event (manager, event);
+
+       if (!e_editor_page_get_html_mode (editor_page)) {
+               WebKitDOMNodeList *list;
+               gint ii, length;
+
+               list = webkit_dom_document_query_selector_all (
+                       document, "span[style^=font-family]", NULL);
+               length = webkit_dom_node_list_get_length (list);
+               if (length > 0)
+                       e_editor_dom_selection_save (editor_page);
+
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *span, *child;
+
+                       span = webkit_dom_node_list_item (list, ii);
+                       while ((child = webkit_dom_node_get_first_child (span)))
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (span),
+                                       child,
+                                       span,
+                                       NULL);
+
+                       remove_node (span);
+                       g_object_unref (span);
+               }
+               g_object_unref (list);
+
+               if (length > 0)
+                       e_editor_dom_selection_restore (editor_page);
+       }
+
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+}
+
+void
+e_editor_dom_drag_and_drop_end (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_dom_save_history_for_drop (editor_page);
+}
+
+static void
+dom_set_link_color_in_document (EEditorPage *editor_page,
+                                const gchar *color,
+                                gboolean visited)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMHTMLHeadElement *head;
+       WebKitDOMElement *style_element;
+       WebKitDOMHTMLElement *body;
+       gchar *color_str = NULL;
+       const gchar *style_id;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (color != NULL);
+
+       style_id = visited ? "-x-evo-a-color-style-visited" : "-x-evo-a-color-style";
+
+       document = e_editor_page_get_document (editor_page);
+       head = webkit_dom_document_get_head (document);
+       body = webkit_dom_document_get_body (document);
+
+       style_element = webkit_dom_document_get_element_by_id (document, style_id);
+       if (!style_element) {
+               style_element = webkit_dom_document_create_element (document, "style", NULL);
+               webkit_dom_element_set_id (style_element, style_id);
+               webkit_dom_element_set_attribute (style_element, "type", "text/css", NULL);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (head), WEBKIT_DOM_NODE (style_element), NULL);
+       }
+
+       color_str = g_strdup_printf (
+               visited ? "a.-x-evo-visited-link { color: %s; }" : "a { color: %s; }", color);
+       webkit_dom_element_set_inner_html (style_element, color_str, NULL);
+       g_free (color_str);
+
+       if (visited)
+               webkit_dom_html_body_element_set_v_link (
+                       WEBKIT_DOM_HTML_BODY_ELEMENT (body), color);
+       else
+               webkit_dom_html_body_element_set_link (
+                       WEBKIT_DOM_HTML_BODY_ELEMENT (body), color);
+}
+
+void
+e_editor_dom_set_link_color (EEditorPage *editor_page,
+                            const gchar *color)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       dom_set_link_color_in_document (editor_page, color, FALSE);
+}
+
+void
+e_editor_dom_set_visited_link_color (EEditorPage *editor_page,
+                                    const gchar *color)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       dom_set_link_color_in_document (editor_page, color, TRUE);
+}
+
+void
+e_editor_dom_fix_file_uri_images (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       gint ii, length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       list = webkit_dom_document_query_selector_all (
+               document, "img[src^=\"file://\"]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node;
+               gchar *uri;
+
+               node = webkit_dom_node_list_item (list, ii);
+               uri = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "src");
+               g_free (uri);
+       }
+
+       g_object_unref (list);
+}
+
+/* ******************** Selection ******************** */
+
+void
+e_editor_dom_replace_base64_image_src (EEditorPage *editor_page,
+                                      const gchar *selector,
+                                      const gchar *base64_content,
+                                      const gchar *filename,
+                                      const gchar *uri)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       element = webkit_dom_document_query_selector (document, selector, NULL);
+
+       if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (element))
+               webkit_dom_html_image_element_set_src (
+                       WEBKIT_DOM_HTML_IMAGE_ELEMENT (element),
+                       base64_content);
+       else
+               webkit_dom_element_set_attribute (
+                       element, "background", base64_content, NULL);
+
+       webkit_dom_element_set_attribute (element, "data-uri", uri, NULL);
+       webkit_dom_element_set_attribute (element, "data-inline", "", NULL);
+       webkit_dom_element_set_attribute (
+               element, "data-name", filename ? filename : "", NULL);
+}
+
+WebKitDOMRange *
+e_editor_dom_get_current_range (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range = NULL;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       if (!dom_window)
+               return NULL;
+
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       if (!WEBKIT_DOM_IS_DOM_SELECTION (dom_selection)) {
+               g_object_unref (dom_window);
+               return NULL;
+       }
+
+       if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1)
+               goto exit;
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+ exit:
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+
+       return range;
+}
+
+void
+e_editor_dom_move_caret_into_element (EEditorPage *editor_page,
+                                     WebKitDOMElement *element,
+                                     gboolean to_start)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!element)
+               return;
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       range = webkit_dom_document_create_range (document);
+
+       webkit_dom_range_select_node_contents (
+               range, WEBKIT_DOM_NODE (element), NULL);
+       webkit_dom_range_collapse (range, to_start, NULL);
+       webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+       webkit_dom_dom_selection_add_range (dom_selection, range);
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+}
+
+void
+e_editor_dom_insert_base64_image (EEditorPage *editor_page,
+                                 const gchar *filename,
+                                 const gchar *uri,
+                                 const gchar *base64_content)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *selection_start_marker, *resizable_wrapper;
+       WebKitDOMText *text;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (!e_editor_dom_selection_is_collapsed (editor_page)) {
+               EEditorHistoryEvent *ev;
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMRange *range;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_DELETE;
+
+               range = e_editor_dom_get_current_range (editor_page);
+               fragment = webkit_dom_range_clone_contents (range, NULL);
+               g_object_unref (range);
+               ev->data.fragment = fragment;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->after.start.x = ev->before.start.x;
+               ev->after.start.y = ev->before.start.y;
+               ev->after.end.x = ev->before.start.x;
+               ev->after.end.y = ev->before.start.y;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_AND;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+               e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+       }
+
+       e_editor_dom_selection_save (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_IMAGE;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+       }
+
+       resizable_wrapper =
+               webkit_dom_document_create_element (document, "span", NULL);
+       webkit_dom_element_set_attribute (
+               resizable_wrapper, "class", "-x-evo-resizable-wrapper", NULL);
+
+       element = webkit_dom_document_create_element (document, "img", NULL);
+       webkit_dom_html_image_element_set_src (
+               WEBKIT_DOM_HTML_IMAGE_ELEMENT (element),
+               base64_content);
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (element), "data-uri", uri, NULL);
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (element), "data-inline", "", NULL);
+       webkit_dom_element_set_attribute (
+               WEBKIT_DOM_ELEMENT (element), "data-name",
+               filename ? filename : "", NULL);
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (resizable_wrapper),
+               WEBKIT_DOM_NODE (element),
+               NULL);
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (
+                       WEBKIT_DOM_NODE (selection_start_marker)),
+               WEBKIT_DOM_NODE (resizable_wrapper),
+               WEBKIT_DOM_NODE (selection_start_marker),
+               NULL);
+
+       /* We have to again use UNICODE_ZERO_WIDTH_SPACE character to restore
+        * caret on right position */
+       text = webkit_dom_document_create_text_node (
+               document, UNICODE_ZERO_WIDTH_SPACE);
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (
+                       WEBKIT_DOM_NODE (selection_start_marker)),
+               WEBKIT_DOM_NODE (text),
+               WEBKIT_DOM_NODE (selection_start_marker),
+               NULL);
+
+       if (ev) {
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMNode *node;
+
+               fragment = webkit_dom_document_create_document_fragment (document);
+               node = webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (resizable_wrapper), TRUE, 
NULL),
+                       NULL);
+
+               webkit_dom_html_element_insert_adjacent_html (
+                       WEBKIT_DOM_HTML_ELEMENT (node), "afterend", "&#8203;", NULL);
+               ev->data.fragment = fragment;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+       e_editor_dom_scroll_to_caret (editor_page);
+}
+
+/* ************************ image_load_and_insert_async() ************************ */
+
+typedef struct _ImageLoadContext {
+       EEditorPage *editor_page;
+       GInputStream *input_stream;
+       GOutputStream *output_stream;
+       GFile *file;
+       GFileInfo *file_info;
+       goffset total_num_bytes;
+       gssize bytes_read;
+       const gchar *content_type;
+       const gchar *filename;
+       const gchar *selector;
+       gchar buffer[4096];
+} ImageLoadContext;
+
+/* Forward Declaration */
+static void
+image_load_stream_read_cb (GInputStream *input_stream,
+                           GAsyncResult *result,
+                           ImageLoadContext *load_context);
+
+static ImageLoadContext *
+image_load_context_new (EEditorPage *editor_page)
+{
+       ImageLoadContext *load_context;
+
+       load_context = g_slice_new0 (ImageLoadContext);
+       load_context->editor_page = editor_page;
+
+       return load_context;
+}
+
+static void
+image_load_context_free (ImageLoadContext *load_context)
+{
+       if (load_context->input_stream != NULL)
+               g_object_unref (load_context->input_stream);
+
+       if (load_context->output_stream != NULL)
+               g_object_unref (load_context->output_stream);
+
+       if (load_context->file_info != NULL)
+               g_object_unref (load_context->file_info);
+
+       if (load_context->file != NULL)
+               g_object_unref (load_context->file);
+
+       g_slice_free (ImageLoadContext, load_context);
+}
+
+static void
+image_load_finish (ImageLoadContext *load_context)
+{
+       EEditorPage *editor_page;
+       GMemoryOutputStream *output_stream;
+       const gchar *selector;
+       gchar *base64_encoded, *mime_type, *output, *uri;
+       gsize size;
+       gpointer data;
+
+       output_stream = G_MEMORY_OUTPUT_STREAM (load_context->output_stream);
+       editor_page = load_context->editor_page;
+       mime_type = g_content_type_get_mime_type (load_context->content_type);
+
+       data = g_memory_output_stream_get_data (output_stream);
+       size = g_memory_output_stream_get_data_size (output_stream);
+       uri = g_file_get_uri (load_context->file);
+
+       base64_encoded = g_base64_encode ((const guchar *) data, size);
+       output = g_strconcat ("data:", mime_type, ";base64,", base64_encoded, NULL);
+       selector = load_context->selector;
+       if (selector && *selector)
+               e_editor_dom_replace_base64_image_src (editor_page, selector, output, load_context->filename, 
uri);
+       else
+               e_editor_dom_insert_base64_image (editor_page, output, load_context->filename, uri);
+
+       g_free (base64_encoded);
+       g_free (output);
+       g_free (mime_type);
+       g_free (uri);
+
+       image_load_context_free (load_context);
+}
+
+static void
+image_load_write_cb (GOutputStream *output_stream,
+                     GAsyncResult *result,
+                     ImageLoadContext *load_context)
+{
+       GInputStream *input_stream;
+       gssize bytes_written;
+       GError *error = NULL;
+
+       bytes_written = g_output_stream_write_finish (
+               output_stream, result, &error);
+
+       if (error) {
+               image_load_context_free (load_context);
+               return;
+       }
+
+       input_stream = load_context->input_stream;
+
+       if (bytes_written < load_context->bytes_read) {
+               g_memmove (
+                       load_context->buffer,
+                       load_context->buffer + bytes_written,
+                       load_context->bytes_read - bytes_written);
+               load_context->bytes_read -= bytes_written;
+
+               g_output_stream_write_async (
+                       output_stream,
+                       load_context->buffer,
+                       load_context->bytes_read,
+                       G_PRIORITY_DEFAULT, NULL,
+                       (GAsyncReadyCallback) image_load_write_cb,
+                       load_context);
+       } else
+               g_input_stream_read_async (
+                       input_stream,
+                       load_context->buffer,
+                       sizeof (load_context->buffer),
+                       G_PRIORITY_DEFAULT, NULL,
+                       (GAsyncReadyCallback) image_load_stream_read_cb,
+                       load_context);
+}
+
+static void
+image_load_stream_read_cb (GInputStream *input_stream,
+                           GAsyncResult *result,
+                           ImageLoadContext *load_context)
+{
+       GOutputStream *output_stream;
+       gssize bytes_read;
+       GError *error = NULL;
+
+       bytes_read = g_input_stream_read_finish (
+               input_stream, result, &error);
+
+       if (error) {
+               image_load_context_free (load_context);
+               return;
+       }
+
+       if (bytes_read == 0) {
+               image_load_finish (load_context);
+               return;
+       }
+
+       output_stream = load_context->output_stream;
+       load_context->bytes_read = bytes_read;
+
+       g_output_stream_write_async (
+               output_stream,
+               load_context->buffer,
+               load_context->bytes_read,
+               G_PRIORITY_DEFAULT, NULL,
+               (GAsyncReadyCallback) image_load_write_cb,
+               load_context);
+}
+
+static void
+image_load_file_read_cb (GFile *file,
+                         GAsyncResult *result,
+                         ImageLoadContext *load_context)
+{
+       GFileInputStream *input_stream;
+       GOutputStream *output_stream;
+       GError *error = NULL;
+
+       /* Input stream might be NULL, so don't use cast macro. */
+       input_stream = g_file_read_finish (file, result, &error);
+       load_context->input_stream = (GInputStream *) input_stream;
+
+       if (error) {
+               image_load_context_free (load_context);
+               return;
+       }
+
+       /* Load the contents into a GMemoryOutputStream. */
+       output_stream = g_memory_output_stream_new (
+               NULL, 0, g_realloc, g_free);
+
+       load_context->output_stream = output_stream;
+
+       g_input_stream_read_async (
+               load_context->input_stream,
+               load_context->buffer,
+               sizeof (load_context->buffer),
+               G_PRIORITY_DEFAULT, NULL,
+               (GAsyncReadyCallback) image_load_stream_read_cb,
+               load_context);
+}
+
+static void
+image_load_query_info_cb (GFile *file,
+                          GAsyncResult *result,
+                          ImageLoadContext *load_context)
+{
+       GFileInfo *file_info;
+       GError *error = NULL;
+
+       file_info = g_file_query_info_finish (file, result, &error);
+       if (error) {
+               image_load_context_free (load_context);
+               return;
+       }
+
+       load_context->content_type = g_file_info_get_content_type (file_info);
+       load_context->total_num_bytes = g_file_info_get_size (file_info);
+       load_context->filename = g_file_info_get_name (file_info);
+
+       g_file_read_async (
+               file, G_PRIORITY_DEFAULT,
+               NULL, (GAsyncReadyCallback)
+               image_load_file_read_cb, load_context);
+}
+
+static void
+image_load_and_insert_async (EEditorPage *editor_page,
+                             const gchar *selector,
+                             const gchar *uri)
+{
+       ImageLoadContext *load_context;
+       GFile *file;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (uri && *uri);
+
+       file = g_file_new_for_uri (uri);
+       g_return_if_fail (file != NULL);
+
+       load_context = image_load_context_new (editor_page);
+       load_context->file = file;
+       if (selector && *selector)
+               load_context->selector = g_strdup (selector);
+
+       g_file_query_info_async (
+               file, "standard::*",
+               G_FILE_QUERY_INFO_NONE,G_PRIORITY_DEFAULT,
+               NULL, (GAsyncReadyCallback)
+               image_load_query_info_cb, load_context);
+}
+
+void
+e_editor_dom_insert_image (EEditorPage *editor_page,
+                          const gchar *uri)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!e_editor_page_get_html_mode (editor_page))
+               return;
+
+       if (strstr (uri, ";base64,")) {
+               if (g_str_has_prefix (uri, "data:"))
+                       e_editor_dom_insert_base64_image (editor_page, uri, "", "");
+               if (strstr (uri, ";data")) {
+                       const gchar *base64_data = strstr (uri, ";") + 1;
+                       gchar *filename;
+                       glong filename_length;
+
+                       filename_length =
+                               g_utf8_strlen (uri, -1) -
+                               g_utf8_strlen (base64_data, -1) - 1;
+                       filename = g_strndup (uri, filename_length);
+
+                       e_editor_dom_insert_base64_image (editor_page, base64_data, filename, "");
+                       g_free (filename);
+               }
+       } else
+               image_load_and_insert_async (editor_page, NULL, uri);
+}
+
+void
+e_editor_dom_replace_image_src (EEditorPage *editor_page,
+                               const gchar *selector,
+                               const gchar *uri)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (strstr (uri, ";base64,")) {
+               if (g_str_has_prefix (uri, "data:"))
+                       e_editor_dom_replace_base64_image_src (
+                               editor_page, selector, uri, "", "");
+               if (strstr (uri, ";data")) {
+                       const gchar *base64_data = strstr (uri, ";") + 1;
+                       gchar *filename;
+                       glong filename_length;
+
+                       filename_length =
+                               g_utf8_strlen (uri, -1) -
+                               g_utf8_strlen (base64_data, -1) - 1;
+                       filename = g_strndup (uri, filename_length);
+
+                       e_editor_dom_replace_base64_image_src (
+                               editor_page, selector, base64_data, filename, "");
+                       g_free (filename);
+               }
+       } else
+               image_load_and_insert_async (editor_page, selector, uri);
+}
+
+/*
+ * e_html_editor_selection_unlink:
+ * @selection: an #EEditorSelection
+ *
+ * Removes any links (&lt;A&gt; elements) from current selection or at current
+ * cursor position.
+ */
+void
+e_editor_dom_selection_unlink (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range;
+       WebKitDOMElement *link;
+       EEditorUndoRedoManager *manager;
+       gchar *text;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       link = dom_node_find_parent_element (
+               webkit_dom_range_get_start_container (range, NULL), "A");
+
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+
+       if (!link) {
+               WebKitDOMNode *node;
+
+               /* get element that was clicked on */
+               node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+               if (node && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+                       link = dom_node_find_parent_element (node, "A");
+                       if (link && !WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (link)) {
+                               g_object_unref (range);
+                               return;
+                       } else
+                               link = WEBKIT_DOM_ELEMENT (node);
+               }
+       } else {
+               e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_UNLINK, NULL);
+       }
+
+       g_object_unref (range);
+
+       if (!link)
+               return;
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               EEditorHistoryEvent *ev;
+               WebKitDOMDocumentFragment *fragment;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_REMOVE_LINK;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               fragment = webkit_dom_document_create_document_fragment (document);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (fragment),
+                       webkit_dom_node_clone_node_with_error (WEBKIT_DOM_NODE (link), TRUE, NULL),
+                       NULL);
+               ev->data.fragment = fragment;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       text = webkit_dom_html_element_get_inner_text (
+               WEBKIT_DOM_HTML_ELEMENT (link));
+       webkit_dom_element_set_outer_html (link, text, NULL);
+       g_free (text);
+}
+
+/*
+ * e_html_editor_selection_create_link:
+ * @document: a @WebKitDOMDocument
+ * @uri: destination of the new link
+ *
+ * Converts current selection into a link pointing to @url.
+ */
+void
+e_editor_dom_create_link (EEditorPage *editor_page,
+                         const gchar *uri)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (uri != NULL && *uri != '\0');
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_CREATE_LINK, uri);
+}
+
+static gint
+get_list_level (WebKitDOMNode *node)
+{
+       gint level = 0;
+
+       while (node && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node)) {
+               if (node_is_list (node))
+                       level++;
+               node = webkit_dom_node_get_parent_node (node);
+       }
+
+       return level;
+}
+
+static void
+set_ordered_list_type_to_element (WebKitDOMElement *list,
+                                  EContentEditorBlockFormat format)
+{
+       if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST)
+               webkit_dom_element_remove_attribute (list, "type");
+       else if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA)
+               webkit_dom_element_set_attribute (list, "type", "A", NULL);
+       else if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN)
+               webkit_dom_element_set_attribute (list, "type", "I", NULL);
+}
+
+static const gchar *
+get_css_alignment_value_class (EContentEditorAlignment alignment)
+{
+       if (alignment == E_CONTENT_EDITOR_ALIGNMENT_LEFT)
+               return ""; /* Left is by default on ltr */
+
+       if (alignment == E_CONTENT_EDITOR_ALIGNMENT_CENTER)
+               return "-x-evo-align-center";
+
+       if (alignment == E_CONTENT_EDITOR_ALIGNMENT_RIGHT)
+               return "-x-evo-align-right";
+
+       return "";
+}
+
+/*
+ * e_html_editor_selection_get_alignment:
+ * @selection: #an EEditorSelection
+ *
+ * Returns alignment of current paragraph
+ *
+ * Returns: #EContentEditorAlignment
+ */
+static EContentEditorAlignment
+dom_get_alignment (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMCSSStyleDeclaration *style;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       EContentEditorAlignment alignment;
+       gchar *value;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+       document = e_editor_page_get_document (editor_page);
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+       g_object_unref (range);
+       if (!node)
+               return E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+       if (WEBKIT_DOM_IS_ELEMENT (node))
+               element = WEBKIT_DOM_ELEMENT (node);
+       else
+               element = webkit_dom_node_get_parent_element (node);
+
+       if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (element)) {
+               if (element_has_class (element, "-x-evo-align-right"))
+                       alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+               else if (element_has_class (element, "-x-evo-align-center"))
+                       alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+               else
+                       alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+
+               return alignment;
+       }
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       style = webkit_dom_dom_window_get_computed_style (dom_window, element, NULL);
+       value = webkit_dom_css_style_declaration_get_property_value (style, "text-align");
+
+       if (!value || !*value ||
+           (g_ascii_strncasecmp (value, "left", 4) == 0)) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       } else if (g_ascii_strncasecmp (value, "center", 6) == 0) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+       } else if (g_ascii_strncasecmp (value, "right", 5) == 0) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+       } else {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       }
+
+       g_object_unref (dom_window);
+       g_object_unref (style);
+       g_free (value);
+
+       return alignment;
+}
+
+static gint
+set_word_wrap_length (EEditorPage *editor_page,
+                      gint user_word_wrap_length)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       /* user_word_wrap_length < 0, set block width to word_wrap_length
+        * user_word_wrap_length ==  0, no width limit set,
+        * user_word_wrap_length > 0, set width limit to given value */
+       return (user_word_wrap_length < 0) ?
+               e_editor_page_get_word_wrap_length (editor_page) : user_word_wrap_length;
+}
+
+void
+e_editor_dom_set_paragraph_style (EEditorPage *editor_page,
+                                 WebKitDOMElement *element,
+                                 gint width,
+                                 gint offset,
+                                 const gchar *style_to_add)
+{
+       WebKitDOMNode *parent;
+       gchar *style = NULL;
+       gint word_wrap_length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       word_wrap_length = set_word_wrap_length (editor_page, width);
+       webkit_dom_element_set_attribute (element, "data-evo-paragraph", "", NULL);
+
+       /* Don't set the alignment for nodes as they are handled separately. */
+       if (!node_is_list (WEBKIT_DOM_NODE (element))) {
+               EContentEditorAlignment alignment;
+
+               alignment = dom_get_alignment (editor_page);
+               element_add_class (element, get_css_alignment_value_class (alignment));
+       }
+
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+       /* Don't set the width limit to sub-blocks as the width limit is inhered
+        * from its parents. */
+       if (!e_editor_page_get_html_mode (editor_page) &&
+           (!parent || WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent))) {
+               style = g_strdup_printf (
+                       "width: %dch; "
+                       "word-wrap: break-word; "
+                       "word-break: break-word; %s",
+                       (word_wrap_length + offset), style_to_add);
+       } else {
+               if (*style_to_add)
+                       style = g_strdup_printf ("%s", style_to_add);
+       }
+       if (style) {
+               webkit_dom_element_set_attribute (element, "style", style, NULL);
+               g_free (style);
+       }
+}
+
+static WebKitDOMElement *
+create_list_element (EEditorPage *editor_page,
+                     EContentEditorBlockFormat format,
+                    gint level,
+                     gboolean html_mode)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *list;
+       gboolean inserting_unordered_list;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       inserting_unordered_list = format == E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+
+       list = webkit_dom_document_create_element (
+               document, inserting_unordered_list  ? "UL" : "OL", NULL);
+
+       if (!inserting_unordered_list)
+               set_ordered_list_type_to_element (list, format);
+
+       if (level >= 0 && !html_mode) {
+               gint offset;
+
+               offset = (level + 1) * SPACES_PER_LIST_LEVEL;
+
+               offset += !inserting_unordered_list ?
+                       SPACES_ORDERED_LIST_FIRST_LEVEL - SPACES_PER_LIST_LEVEL: 0;
+
+               e_editor_dom_set_paragraph_style (editor_page, list, -1, -offset, "");
+
+               if (inserting_unordered_list)
+                       webkit_dom_element_set_attribute (list, "data-evo-plain-text", "", NULL);
+       }
+
+       return list;
+}
+
+static gboolean
+indent_list (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *item, *next_item;
+       gboolean after_selection_end = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       item = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+               gboolean html_mode = e_editor_page_get_html_mode (editor_page);
+               WebKitDOMElement *list;
+               WebKitDOMNode *source_list = webkit_dom_node_get_parent_node (item);
+               EContentEditorBlockFormat format;
+
+               format = dom_get_list_format_from_node (source_list);
+
+               list = create_list_element (
+                       editor_page, format, get_list_level (item), html_mode);
+
+               element_add_class (list, "-x-evo-indented");
+
+               webkit_dom_node_insert_before (
+                       source_list, WEBKIT_DOM_NODE (list), item, NULL);
+
+               while (item && !after_selection_end) {
+                       after_selection_end = webkit_dom_node_contains (
+                               item, WEBKIT_DOM_NODE (selection_end_marker));
+
+                       next_item = webkit_dom_node_get_next_sibling (item);
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (list), item, NULL);
+
+                       item = next_item;
+               }
+
+               merge_lists_if_possible (WEBKIT_DOM_NODE (list));
+       }
+
+       return after_selection_end;
+}
+
+static void
+dom_set_indented_style (EEditorPage *editor_page,
+                        WebKitDOMElement *element,
+                        gint width)
+{
+       gchar *style;
+       gint word_wrap_length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       word_wrap_length = set_word_wrap_length (editor_page, width);
+       webkit_dom_element_set_class_name (element, "-x-evo-indented");
+
+       if (e_editor_page_get_html_mode (editor_page) || word_wrap_length == 0)
+               style = g_strdup_printf ("margin-left: %dch;", SPACES_PER_INDENTATION);
+       else
+               style = g_strdup_printf (
+                       "margin-left: %dch; word-wrap: normal; width: %dch;",
+                       SPACES_PER_INDENTATION, word_wrap_length);
+
+       webkit_dom_element_set_attribute (element, "style", style, NULL);
+       g_free (style);
+}
+
+static WebKitDOMElement *
+dom_get_indented_element (EEditorPage *editor_page,
+                          gint width)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       element = webkit_dom_document_create_element (document, "DIV", NULL);
+       dom_set_indented_style (editor_page, element, width);
+
+       return element;
+}
+
+static WebKitDOMNode *
+indent_block (EEditorPage *editor_page,
+              WebKitDOMNode *block,
+              gint width)
+{
+       WebKitDOMElement *element;
+       WebKitDOMNode *sibling, *tmp;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       sibling = webkit_dom_node_get_previous_sibling (block);
+       if (WEBKIT_DOM_IS_ELEMENT (sibling) &&
+           element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-indented")) {
+               element = WEBKIT_DOM_ELEMENT (sibling);
+       } else {
+               element = dom_get_indented_element (editor_page, width);
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (block),
+                       WEBKIT_DOM_NODE (element),
+                       block,
+                       NULL);
+       }
+
+       /* Remove style and let the paragraph inherit it from parent */
+       if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), "data-evo-paragraph"))
+               webkit_dom_element_remove_attribute (
+                       WEBKIT_DOM_ELEMENT (block), "style");
+
+       tmp = webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (element),
+               block,
+               NULL);
+
+       sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+       while (WEBKIT_DOM_IS_ELEMENT (sibling) &&
+              element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-indented")) {
+               WebKitDOMNode *next_sibling;
+               WebKitDOMNode *child;
+
+               next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (sibling));
+
+               while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (sibling)))) {
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (element),
+                               child,
+                               NULL);
+               }
+               remove_node (sibling);
+               sibling = next_sibling;
+       }
+
+       return tmp;
+}
+
+static WebKitDOMNode *
+get_list_item_node_from_child (WebKitDOMNode *child)
+{
+       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (child);
+
+       while (parent && !WEBKIT_DOM_IS_HTML_LI_ELEMENT (parent))
+               parent = webkit_dom_node_get_parent_node (parent);
+
+       return parent;
+}
+
+static WebKitDOMNode *
+get_list_node_from_child (WebKitDOMNode *child)
+{
+       WebKitDOMNode *parent = get_list_item_node_from_child (child);
+
+       return webkit_dom_node_get_parent_node (parent);
+}
+
+static gboolean
+do_format_change_list_to_block (EEditorPage *editor_page,
+                                EContentEditorBlockFormat format,
+                                WebKitDOMNode *item,
+                                const gchar *value)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *selection_end;
+       WebKitDOMNode *node, *source_list;
+       gboolean after_end = FALSE;
+       gint level;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       selection_end = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       source_list = webkit_dom_node_get_parent_node (item);
+       while (source_list) {
+               WebKitDOMNode *parent;
+
+               parent = webkit_dom_node_get_parent_node (source_list);
+               if (node_is_list (parent))
+                       source_list = parent;
+               else
+                       break;
+       }
+
+       if (webkit_dom_node_contains (source_list, WEBKIT_DOM_NODE (selection_end)))
+               source_list = split_list_into_two (item, -1);
+       else {
+               source_list = webkit_dom_node_get_next_sibling (source_list);
+       }
+
+       /* Process all nodes that are in selection one by one */
+       while (item && WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+               WebKitDOMNode *next_item;
+
+               next_item = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (item));
+               if (!next_item) {
+                       WebKitDOMNode *parent;
+                       WebKitDOMNode *tmp = item;
+
+                       while (tmp) {
+                               parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp));
+                               if (!node_is_list (parent))
+                                       break;
+
+                               next_item = webkit_dom_node_get_next_sibling (parent);
+                               if (node_is_list (next_item)) {
+                                       next_item = webkit_dom_node_get_first_child (next_item);
+                                       break;
+                               } else if (next_item && !WEBKIT_DOM_IS_HTML_LI_ELEMENT (next_item)) {
+                                       next_item = webkit_dom_node_get_next_sibling (next_item);
+                                       break;
+                               } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (next_item)) {
+                                       break;
+                               }
+                               tmp = parent;
+                       }
+               } else if (node_is_list (next_item)) {
+                       next_item = webkit_dom_node_get_first_child (next_item);
+               } else if (!WEBKIT_DOM_IS_HTML_LI_ELEMENT (next_item)) {
+                       next_item = webkit_dom_node_get_next_sibling (item);
+                       continue;
+               }
+
+               if (!after_end) {
+                       after_end = webkit_dom_node_contains (item, WEBKIT_DOM_NODE (selection_end));
+
+                       level = get_indentation_level (WEBKIT_DOM_ELEMENT (item));
+
+                       if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH) {
+                               element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+                       } else
+                               element = webkit_dom_document_create_element (
+                                       document, value, NULL);
+
+                       while ((node = webkit_dom_node_get_first_child (item)))
+                               webkit_dom_node_append_child (
+                                       WEBKIT_DOM_NODE (element), node, NULL);
+
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (source_list),
+                               WEBKIT_DOM_NODE (element),
+                               source_list,
+                               NULL);
+
+                       if (level > 0) {
+                               gint final_width = 0;
+
+                               node = WEBKIT_DOM_NODE (element);
+
+                               if (webkit_dom_element_has_attribute (element, "data-evo-paragraph"))
+                                       final_width = e_editor_page_get_word_wrap_length (editor_page) -
+                                               SPACES_PER_INDENTATION * level;
+
+                               while (level--)
+                                       node = indent_block (editor_page, node, final_width);
+                       }
+
+                       e_editor_dom_remove_node_and_parents_if_empty (item);
+               } else
+                       break;
+
+               item = next_item;
+       }
+
+       remove_node_if_empty (source_list);
+
+       return after_end;
+}
+
+static void
+format_change_list_to_block (EEditorPage *editor_page,
+                             EContentEditorBlockFormat format,
+                             const gchar *value)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start;
+       WebKitDOMNode *item;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       selection_start = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+
+       item = get_list_item_node_from_child (WEBKIT_DOM_NODE (selection_start));
+
+       do_format_change_list_to_block (editor_page, format, item, value);
+}
+
+static WebKitDOMNode *
+get_parent_indented_block (WebKitDOMNode *node)
+{
+       WebKitDOMNode *parent, *block = NULL;
+
+       parent = webkit_dom_node_get_parent_node (node);
+       if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-indented"))
+               block = parent;
+
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-indented"))
+                       block = parent;
+               parent = webkit_dom_node_get_parent_node (parent);
+       }
+
+       return block;
+}
+
+static WebKitDOMElement*
+get_element_for_inspection (WebKitDOMRange *range)
+{
+       WebKitDOMNode *node;
+
+       node = webkit_dom_range_get_end_container (range, NULL);
+       /* No selection or whole body selected */
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node))
+               return NULL;
+
+       return WEBKIT_DOM_ELEMENT (get_parent_indented_block (node));
+}
+
+static EContentEditorAlignment
+dom_get_alignment_from_node (WebKitDOMNode *node)
+{
+       EContentEditorAlignment alignment;
+       gchar *value;
+       WebKitDOMCSSStyleDeclaration *style;
+
+       style = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (node));
+       value = webkit_dom_css_style_declaration_get_property_value (style, "text-align");
+
+       if (!value || !*value ||
+           (g_ascii_strncasecmp (value, "left", 4) == 0)) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       } else if (g_ascii_strncasecmp (value, "center", 6) == 0) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+       } else if (g_ascii_strncasecmp (value, "right", 5) == 0) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+       } else {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       }
+
+       g_object_unref (style);
+       g_free (value);
+
+       return alignment;
+}
+
+/*
+ * e_html_editor_selection_indent:
+ * @selection: an #EEditorSelection
+ *
+ * Indents current paragraph by one level.
+ */
+void
+e_editor_dom_selection_indent (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean after_selection_start = FALSE, after_selection_end = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       /* If the selection was not saved, move it into the first child of body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMHTMLElement *body;
+               WebKitDOMNode *child;
+
+               body = webkit_dom_document_get_body (document);
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+       }
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INDENT;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.style.from = 1;
+               ev->data.style.to = 1;
+       }
+
+       block = get_parent_indented_block (
+               WEBKIT_DOM_NODE (selection_start_marker));
+       if (!block)
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+       while (block && !after_selection_end) {
+               gint ii, length, level, word_wrap_length, final_width = 0;
+               WebKitDOMNode *next_block;
+               WebKitDOMNodeList *list;
+
+               word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               list = webkit_dom_element_query_selector_all (
+                       WEBKIT_DOM_ELEMENT (block),
+                       ".-x-evo-indented > *:not(.-x-evo-indented):not(li)",
+                       NULL);
+
+               after_selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               length = webkit_dom_node_list_get_length (list);
+               if (length == 0 && node_is_list_or_item (block)) {
+                       after_selection_end = indent_list (editor_page);
+                       goto next;
+               }
+
+               if (length == 0) {
+                       if (!after_selection_start) {
+                               after_selection_start = webkit_dom_node_contains (
+                                       block, WEBKIT_DOM_NODE (selection_start_marker));
+                               if (!after_selection_start)
+                                       goto next;
+                       }
+
+                       if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), 
"data-evo-paragraph")) {
+                               level = get_indentation_level (WEBKIT_DOM_ELEMENT (block));
+
+                               final_width = word_wrap_length - SPACES_PER_INDENTATION * (level + 1);
+                               if (final_width < MINIMAL_PARAGRAPH_WIDTH &&
+                               !e_editor_page_get_html_mode (editor_page))
+                                       goto next;
+                       }
+
+                       indent_block (editor_page, block, final_width);
+
+                       if (after_selection_end)
+                               goto next;
+               }
+
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *block_to_process;
+
+                       block_to_process = webkit_dom_node_list_item (list, ii);
+
+                       after_selection_end = webkit_dom_node_contains (
+                               block_to_process, WEBKIT_DOM_NODE (selection_end_marker));
+
+                       if (!after_selection_start) {
+                               after_selection_start = webkit_dom_node_contains (
+                                       block_to_process,
+                                       WEBKIT_DOM_NODE (selection_start_marker));
+                               if (!after_selection_start) {
+                                       g_object_unref (block_to_process);
+                                       continue;
+                               }
+                       }
+
+                       if (webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), 
"data-evo-paragraph")) {
+                               level = get_indentation_level (
+                                       WEBKIT_DOM_ELEMENT (block_to_process));
+
+                               final_width = word_wrap_length - SPACES_PER_INDENTATION * (level + 1);
+                               if (final_width < MINIMAL_PARAGRAPH_WIDTH &&
+                                   !e_editor_page_get_html_mode (editor_page)) {
+                                       g_object_unref (block_to_process);
+                                       continue;
+                               }
+                       }
+
+                       indent_block (editor_page, block_to_process, final_width);
+
+                       g_object_unref (block_to_process);
+                       if (after_selection_end)
+                               break;
+               }
+
+ next:
+               g_object_unref (list);
+
+               if (!after_selection_end)
+                       block = next_block;
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+static void
+unindent_list (WebKitDOMDocument *document)
+{
+       gboolean after = FALSE;
+       WebKitDOMElement *new_list;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *source_list, *source_list_clone, *current_list, *item;
+       WebKitDOMNode *prev_item;
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker || !selection_end_marker)
+               return;
+
+       /* Copy elements from previous block to list */
+       item = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+       source_list = webkit_dom_node_get_parent_node (item);
+       new_list = WEBKIT_DOM_ELEMENT (
+               webkit_dom_node_clone_node_with_error (source_list, FALSE, NULL));
+       current_list = source_list;
+       source_list_clone = webkit_dom_node_clone_node_with_error (source_list, FALSE, NULL);
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (source_list),
+               WEBKIT_DOM_NODE (source_list_clone),
+               webkit_dom_node_get_next_sibling (source_list),
+               NULL);
+
+       if (element_has_class (WEBKIT_DOM_ELEMENT (source_list), "-x-evo-indented"))
+               element_add_class (WEBKIT_DOM_ELEMENT (new_list), "-x-evo-indented");
+
+       prev_item = source_list;
+
+       while (item) {
+               WebKitDOMNode *next_item = webkit_dom_node_get_next_sibling (item);
+
+               if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+                       if (after)
+                               prev_item = webkit_dom_node_append_child (
+                                       source_list_clone, WEBKIT_DOM_NODE (item), NULL);
+                       else
+                               prev_item = webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (prev_item),
+                                       item,
+                                       webkit_dom_node_get_next_sibling (prev_item),
+                                       NULL);
+               }
+
+               if (webkit_dom_node_contains (item, WEBKIT_DOM_NODE (selection_end_marker)))
+                       after = TRUE;
+
+               if (!next_item) {
+                       if (after)
+                               break;
+
+                       current_list = webkit_dom_node_get_next_sibling (current_list);
+                       next_item = webkit_dom_node_get_first_child (current_list);
+               }
+               item = next_item;
+       }
+
+       remove_node_if_empty (source_list_clone);
+       remove_node_if_empty (source_list);
+}
+
+static void
+unindent_block (EEditorPage *editor_page,
+                WebKitDOMNode *block)
+{
+       WebKitDOMElement *element;
+       WebKitDOMElement *prev_blockquote = NULL, *next_blockquote = NULL;
+       WebKitDOMNode *block_to_process, *node_clone = NULL, *child;
+       EContentEditorAlignment alignment;
+       gboolean before_node = TRUE;
+       gint word_wrap_length, level, width;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       block_to_process = block;
+
+       alignment = dom_get_alignment_from_node (block_to_process);
+       element = webkit_dom_node_get_parent_element (block_to_process);
+
+       if (!WEBKIT_DOM_IS_HTML_DIV_ELEMENT (element) &&
+           !element_has_class (element, "-x-evo-indented"))
+               return;
+
+       element_add_class (WEBKIT_DOM_ELEMENT (block_to_process), "-x-evo-to-unindent");
+
+       level = get_indentation_level (element);
+       word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+       width = word_wrap_length - SPACES_PER_INDENTATION * level;
+
+       /* Look if we have previous siblings, if so, we have to
+        * create new blockquote that will include them */
+       if (webkit_dom_node_get_previous_sibling (block_to_process))
+               prev_blockquote = dom_get_indented_element (editor_page, width);
+
+       /* Look if we have next siblings, if so, we have to
+        * create new blockquote that will include them */
+       if (webkit_dom_node_get_next_sibling (block_to_process))
+               next_blockquote = dom_get_indented_element (editor_page, width);
+
+       /* Copy nodes that are before / after the element that we want to unindent */
+       while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element)))) {
+               if (webkit_dom_node_is_equal_node (child, block_to_process)) {
+                       before_node = FALSE;
+                       node_clone = webkit_dom_node_clone_node_with_error (child, TRUE, NULL);
+                       remove_node (child);
+                       continue;
+               }
+
+               webkit_dom_node_append_child (
+                       before_node ?
+                               WEBKIT_DOM_NODE (prev_blockquote) :
+                               WEBKIT_DOM_NODE (next_blockquote),
+                       child,
+                       NULL);
+       }
+
+       if (node_clone) {
+               element_remove_class (WEBKIT_DOM_ELEMENT (node_clone), "-x-evo-to-unindent");
+
+               /* Insert blockqoute with nodes that were before the element that we want to unindent */
+               if (prev_blockquote) {
+                       if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (prev_blockquote))) {
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                                       WEBKIT_DOM_NODE (prev_blockquote),
+                                       WEBKIT_DOM_NODE (element),
+                                       NULL);
+                       }
+               }
+
+               if (level == 1 && webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (node_clone), 
"data-evo-paragraph")) {
+                       e_editor_dom_set_paragraph_style (
+                               editor_page, WEBKIT_DOM_ELEMENT (node_clone), word_wrap_length, 0, "");
+                       element_add_class (
+                               WEBKIT_DOM_ELEMENT (node_clone),
+                               get_css_alignment_value_class (alignment));
+               }
+
+               /* Insert the unindented element */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       node_clone,
+                       WEBKIT_DOM_NODE (element),
+                       NULL);
+       } else {
+               g_warn_if_reached ();
+       }
+
+       /* Insert blockqoute with nodes that were after the element that we want to unindent */
+       if (next_blockquote) {
+               if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (next_blockquote))) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                               WEBKIT_DOM_NODE (next_blockquote),
+                               WEBKIT_DOM_NODE (element),
+                               NULL);
+               }
+       }
+
+       /* Remove old blockquote */
+       remove_node (WEBKIT_DOM_NODE (element));
+}
+
+/*
+ * dom_unindent:
+ * @selection: an #EEditorSelection
+ *
+ * Unindents current paragraph by one level.
+ */
+void
+e_editor_dom_selection_unindent (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean after_selection_start = FALSE, after_selection_end = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       /* If the selection was not saved, move it into the first child of body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMHTMLElement *body;
+               WebKitDOMNode *child;
+
+               body = webkit_dom_document_get_body (document);
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+       }
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_INDENT;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+       }
+
+       block = get_parent_indented_block (
+               WEBKIT_DOM_NODE (selection_start_marker));
+       if (!block)
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+       while (block && !after_selection_end) {
+               gint ii, length;
+               WebKitDOMNode *next_block;
+               WebKitDOMNodeList *list;
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               list = webkit_dom_element_query_selector_all (
+                       WEBKIT_DOM_ELEMENT (block),
+                       ".-x-evo-indented > *:not(.-x-evo-indented):not(li)",
+                       NULL);
+
+               after_selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               length = webkit_dom_node_list_get_length (list);
+               if (length == 0 && node_is_list_or_item (block)) {
+                       unindent_list (document);
+                       goto next;
+               }
+
+               if (length == 0) {
+                       if (!after_selection_start) {
+                               after_selection_start = webkit_dom_node_contains (
+                                       block, WEBKIT_DOM_NODE (selection_start_marker));
+                               if (!after_selection_start)
+                                       goto next;
+                       }
+
+                       unindent_block (editor_page, block);
+
+                       if (after_selection_end)
+                               goto next;
+               }
+
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *block_to_process;
+
+                       block_to_process = webkit_dom_node_list_item (list, ii);
+
+                       after_selection_end = webkit_dom_node_contains (
+                               block_to_process,
+                               WEBKIT_DOM_NODE (selection_end_marker));
+
+                       if (!after_selection_start) {
+                               after_selection_start = webkit_dom_node_contains (
+                                       block_to_process,
+                                       WEBKIT_DOM_NODE (selection_start_marker));
+                               if (!after_selection_start) {
+                                       g_object_unref (block_to_process);
+                                       continue;
+                               }
+                       }
+
+                       unindent_block (editor_page, block_to_process);
+
+                       g_object_unref (block_to_process);
+                       if (after_selection_end)
+                               break;
+               }
+ next:
+               g_object_unref (list);
+               block = next_block;
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+static WebKitDOMNode *
+in_empty_block_in_quoted_content (WebKitDOMNode *element)
+{
+       WebKitDOMNode *first_child, *next_sibling;
+
+       first_child = webkit_dom_node_get_first_child (element);
+       if (!WEBKIT_DOM_IS_ELEMENT (first_child))
+               return NULL;
+
+       if (!element_has_class (WEBKIT_DOM_ELEMENT (first_child), "-x-evo-quoted"))
+               return NULL;
+
+       next_sibling = webkit_dom_node_get_next_sibling (first_child);
+       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+               return next_sibling;
+
+       if (!WEBKIT_DOM_IS_ELEMENT (next_sibling))
+               return NULL;
+
+       if (!element_has_id (WEBKIT_DOM_ELEMENT (next_sibling), "-x-evo-selection-start-marker"))
+               return NULL;
+
+       next_sibling = webkit_dom_node_get_next_sibling (next_sibling);
+       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
+               return next_sibling;
+
+       return NULL;
+}
+
+/*
+ * e_html_editor_selection_save:
+ * @selection: an #EEditorSelection
+ *
+ * Saves current cursor position or current selection range. The selection can
+ * be later restored by calling e_html_editor_selection_restore().
+ *
+ * Note that calling e_html_editor_selection_save() overwrites previously saved
+ * position.
+ *
+ * Note that this method inserts special markings into the HTML code that are
+ * used to later restore the selection. It can happen that by deleting some
+ * segments of the document some of the markings are deleted too. In that case
+ * restoring the selection by e_html_editor_selection_restore() can fail. Also by
+ * moving text segments (Cut & Paste) can result in moving the markings
+ * elsewhere, thus e_html_editor_selection_restore() will restore the selection
+ * incorrectly.
+ *
+ * It is recommended to use this method only when you are not planning to make
+ * bigger changes to content or structure of the document (formatting changes
+ * are usually OK).
+ */
+void
+e_editor_dom_selection_save (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMRange *range;
+       WebKitDOMNode *container, *next_sibling, *marker_node;
+       WebKitDOMNode *split_node, *parent_node, *anchor;
+       WebKitDOMElement *start_marker = NULL, *end_marker = NULL;
+       gboolean collapsed = FALSE;
+       glong offset, anchor_offset;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+
+       /* First remove all markers (if present) */
+       dom_remove_selection_markers (document);
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
+               g_object_unref (dom_selection);
+               g_object_unref (dom_window);
+               return;
+       }
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       if (!range) {
+               g_object_unref (dom_selection);
+               g_object_unref (dom_window);
+               return;
+       }
+
+       anchor = webkit_dom_dom_selection_get_anchor_node (dom_selection);
+       anchor_offset = webkit_dom_dom_selection_get_anchor_offset (dom_selection);
+
+       collapsed = webkit_dom_range_get_collapsed (range, NULL);
+       start_marker = dom_create_selection_marker (document, TRUE);
+
+       container = webkit_dom_range_get_start_container (range, NULL);
+       offset = webkit_dom_range_get_start_offset (range, NULL);
+       parent_node = webkit_dom_node_get_parent_node (container);
+
+       if (webkit_dom_node_is_same_node (anchor, container) && offset == anchor_offset)
+               webkit_dom_element_set_attribute (start_marker, "data-anchor", "", NULL);
+
+       if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "-x-evo-quote-character")) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_get_parent_node (
+               webkit_dom_node_get_parent_node (parent_node));
+
+               if ((next_sibling = in_empty_block_in_quoted_content (node))) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (next_sibling),
+                               WEBKIT_DOM_NODE (start_marker),
+                               next_sibling,
+                               NULL);
+               } else {
+                       webkit_dom_node_insert_before (
+                               node,
+                               WEBKIT_DOM_NODE (start_marker),
+                               webkit_dom_node_get_next_sibling (
+                                       webkit_dom_node_get_parent_node (parent_node)),
+                               NULL);
+               }
+               goto insert_end_marker;
+       } else if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "-x-evo-smiley-text")) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_get_parent_node (parent_node);
+               if (offset == 0) {
+                       marker_node = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (node),
+                               WEBKIT_DOM_NODE (start_marker),
+                               webkit_dom_node_get_next_sibling (node),
+                               NULL);
+                       goto insert_end_marker;
+               }
+       } else if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "Apple-tab-span") && offset == 1) {
+                       marker_node = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent_node),
+                               WEBKIT_DOM_NODE (start_marker),
+                               webkit_dom_node_get_next_sibling (parent_node),
+                               NULL);
+                       goto insert_end_marker;
+       }
+
+       if (WEBKIT_DOM_IS_TEXT (container)) {
+               if (offset != 0) {
+                       WebKitDOMText *split_text;
+
+                       split_text = webkit_dom_text_split_text (
+                               WEBKIT_DOM_TEXT (container), offset, NULL);
+                       split_node = WEBKIT_DOM_NODE (split_text);
+               } else {
+                       marker_node = webkit_dom_node_insert_before (
+                               parent_node,
+                               WEBKIT_DOM_NODE (start_marker),
+                               container,
+                               NULL);
+                       goto insert_end_marker;
+               }
+       } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (container)) {
+               marker_node = webkit_dom_node_insert_before (
+                       container,
+                       WEBKIT_DOM_NODE (start_marker),
+                       webkit_dom_node_get_first_child (container),
+                       NULL);
+               goto insert_end_marker;
+       } else if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (container)) {
+               marker_node = webkit_dom_node_insert_before (
+                       container,
+                       WEBKIT_DOM_NODE (start_marker),
+                       webkit_dom_node_get_first_child (container),
+                       NULL);
+               goto insert_end_marker;
+       } else {
+               /* Insert the selection marker on the right position in
+                * an empty paragraph in the quoted content */
+               if ((next_sibling = in_empty_block_in_quoted_content (container))) {
+                       marker_node = webkit_dom_node_insert_before (
+                               container,
+                               WEBKIT_DOM_NODE (start_marker),
+                               next_sibling,
+                               NULL);
+                       goto insert_end_marker;
+               }
+               if (!webkit_dom_node_get_previous_sibling (container)) {
+                       marker_node = webkit_dom_node_insert_before (
+                               container,
+                               WEBKIT_DOM_NODE (start_marker),
+                               webkit_dom_node_get_first_child (container),
+                               NULL);
+                       goto insert_end_marker;
+               } else if (!webkit_dom_node_get_next_sibling (container)) {
+                       WebKitDOMNode *tmp;
+
+                       tmp = webkit_dom_node_get_last_child (container);
+                       if (tmp && WEBKIT_DOM_IS_HTML_BR_ELEMENT (tmp))
+                               marker_node = webkit_dom_node_insert_before (
+                                       container,
+                                       WEBKIT_DOM_NODE (start_marker),
+                                       tmp,
+                                       NULL);
+                       else
+                               marker_node = webkit_dom_node_append_child (
+                                       container,
+                                       WEBKIT_DOM_NODE (start_marker),
+                                       NULL);
+                       goto insert_end_marker;
+               } else {
+                       if (webkit_dom_node_get_first_child (container)) {
+                               marker_node = webkit_dom_node_insert_before (
+                                       container,
+                                       WEBKIT_DOM_NODE (start_marker),
+                                       webkit_dom_node_get_first_child (container),
+                                       NULL);
+                               goto insert_end_marker;
+                       }
+                       split_node = container;
+               }
+       }
+
+       /* Don't save selection straight into body */
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (split_node)) {
+               g_object_unref (range);
+               g_object_unref (dom_selection);
+               g_object_unref (dom_window);
+               return;
+       }
+
+       if (!split_node) {
+               marker_node = webkit_dom_node_insert_before (
+                       container,
+                       WEBKIT_DOM_NODE (start_marker),
+                       webkit_dom_node_get_first_child (
+                               WEBKIT_DOM_NODE (container)),
+                       NULL);
+       } else {
+               marker_node = WEBKIT_DOM_NODE (start_marker);
+               parent_node = webkit_dom_node_get_parent_node (split_node);
+
+               webkit_dom_node_insert_before (
+                       parent_node, marker_node, split_node, NULL);
+       }
+
+       webkit_dom_node_normalize (parent_node);
+
+ insert_end_marker:
+       end_marker = dom_create_selection_marker (document, FALSE);
+
+       if (collapsed) {
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (start_marker)),
+                       WEBKIT_DOM_NODE (end_marker),
+                       webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (start_marker)),
+                       NULL);
+               goto out;
+       }
+
+       container = webkit_dom_range_get_end_container (range, NULL);
+       offset = webkit_dom_range_get_end_offset (range, NULL);
+       parent_node = webkit_dom_node_get_parent_node (container);
+
+       if (webkit_dom_node_is_same_node (anchor, container) && offset == anchor_offset)
+               webkit_dom_element_set_attribute (end_marker, "data-anchor", "", NULL);
+
+       if (element_has_class (WEBKIT_DOM_ELEMENT (parent_node), "-x-evo-quote-character")) {
+               WebKitDOMNode *node;
+
+               node = webkit_dom_node_get_parent_node (
+               webkit_dom_node_get_parent_node (parent_node));
+
+               if ((next_sibling = in_empty_block_in_quoted_content (node))) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (next_sibling),
+                               WEBKIT_DOM_NODE (end_marker),
+                               next_sibling,
+                               NULL);
+               } else {
+                       webkit_dom_node_insert_before (
+                               node,
+                               WEBKIT_DOM_NODE (end_marker),
+                               webkit_dom_node_get_next_sibling (
+                                       webkit_dom_node_get_parent_node (parent_node)),
+                               NULL);
+               }
+               goto out;
+       }
+
+       if (WEBKIT_DOM_IS_TEXT (container)) {
+               if (offset != 0) {
+                       WebKitDOMText *split_text;
+
+                       split_text = webkit_dom_text_split_text (
+                               WEBKIT_DOM_TEXT (container), offset, NULL);
+                       split_node = WEBKIT_DOM_NODE (split_text);
+               } else {
+                       marker_node = webkit_dom_node_insert_before (
+                               parent_node, WEBKIT_DOM_NODE (end_marker), container, NULL);
+                       goto check;
+
+               }
+       } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (container)) {
+               webkit_dom_node_append_child (
+                       container, WEBKIT_DOM_NODE (end_marker), NULL);
+               goto out;
+       } else {
+               /* Insert the selection marker on the right position in
+                * an empty paragraph in the quoted content */
+               if ((next_sibling = in_empty_block_in_quoted_content (container))) {
+                       webkit_dom_node_insert_before (
+                               container,
+                               WEBKIT_DOM_NODE (end_marker),
+                               next_sibling,
+                               NULL);
+                       goto out;
+               }
+               if (!webkit_dom_node_get_previous_sibling (container)) {
+                       split_node = parent_node;
+               } else if (!webkit_dom_node_get_next_sibling (container) &&
+                          !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_node)) {
+                       split_node = parent_node;
+                       split_node = webkit_dom_node_get_next_sibling (split_node);
+               } else
+                       split_node = container;
+       }
+
+       /* Don't save selection straight into body */
+       if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (split_node)) {
+               remove_node (WEBKIT_DOM_NODE (start_marker));
+               return;
+       }
+
+       marker_node = WEBKIT_DOM_NODE (end_marker);
+
+       if (split_node) {
+               parent_node = webkit_dom_node_get_parent_node (split_node);
+
+               if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_node)) {
+                       if (offset == 0)
+                               webkit_dom_node_insert_before (
+                                       split_node,
+                                       marker_node,
+                                       webkit_dom_node_get_first_child (split_node),
+                                       NULL);
+                       else
+                               webkit_dom_node_append_child (
+                                       webkit_dom_node_get_previous_sibling (split_node),
+                                       marker_node,
+                                       NULL);
+               } else
+                       webkit_dom_node_insert_before (
+                               parent_node, marker_node, split_node, NULL);
+       } else {
+                WebKitDOMNode *first_child;
+
+               first_child = webkit_dom_node_get_first_child (container);
+               if (offset == 0 && WEBKIT_DOM_IS_TEXT (first_child))
+                       webkit_dom_node_insert_before (
+                               WEBKIT_DOM_NODE (container), marker_node, webkit_dom_node_get_first_child 
(container), NULL);
+               else
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (container), marker_node, NULL);
+       }
+
+        webkit_dom_node_normalize (parent_node);
+
+ check:
+       if ((next_sibling = webkit_dom_node_get_next_sibling (marker_node))) {
+               if (!WEBKIT_DOM_IS_ELEMENT (next_sibling))
+                       next_sibling = webkit_dom_node_get_next_sibling (next_sibling);
+               /* If the selection is collapsed ensure that the selection start marker
+                * is before the end marker */
+               if (next_sibling && webkit_dom_node_is_same_node (next_sibling, WEBKIT_DOM_NODE 
(start_marker))) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (marker_node),
+                               next_sibling,
+                               marker_node,
+                               NULL);
+               }
+       }
+ out:
+       if (!collapsed) {
+               if (start_marker && end_marker) {
+                       webkit_dom_range_set_start_after (range, WEBKIT_DOM_NODE (start_marker), NULL);
+                       webkit_dom_range_set_end_before (range, WEBKIT_DOM_NODE (end_marker), NULL);
+               } else {
+                       g_warn_if_reached ();
+               }
+
+               webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+               webkit_dom_dom_selection_add_range (dom_selection, range);
+       }
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+}
+
+gboolean
+e_editor_dom_is_selection_position_node (WebKitDOMNode *node)
+{
+       WebKitDOMElement *element;
+
+       if (!node || !WEBKIT_DOM_IS_ELEMENT (node))
+               return FALSE;
+
+       element = WEBKIT_DOM_ELEMENT (node);
+
+       return element_has_id (element, "-x-evo-selection-start-marker") ||
+              element_has_id (element, "-x-evo-selection-end-marker");
+}
+
+/*
+ * e_html_editor_selection_restore:
+ * @selection: an #EEditorSelection
+ *
+ * Restores cursor position or selection range that was saved by
+ * e_html_editor_selection_save().
+ *
+ * Note that calling this function without calling e_html_editor_selection_save()
+ * before is a programming error and the behavior is undefined.
+ */
+void
+e_editor_dom_selection_restore (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *marker;
+       WebKitDOMNode *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *parent_start, *parent_end, *anchor;
+       WebKitDOMRange *range;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDOMWindow *dom_window;
+       gboolean start_is_anchor = FALSE;
+       glong offset;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       g_object_unref (dom_window);
+       if (!range) {
+               WebKitDOMHTMLElement *body;
+
+               range = webkit_dom_document_create_range (document);
+               body = webkit_dom_document_get_body (document);
+
+               webkit_dom_range_select_node_contents (range, WEBKIT_DOM_NODE (body), NULL);
+               webkit_dom_range_collapse (range, TRUE, NULL);
+               webkit_dom_dom_selection_add_range (dom_selection, range);
+       }
+
+       selection_start_marker = webkit_dom_range_get_start_container (range, NULL);
+       if (selection_start_marker) {
+               gboolean ok = FALSE;
+               selection_start_marker =
+                       webkit_dom_node_get_next_sibling (selection_start_marker);
+
+               ok = e_editor_dom_is_selection_position_node (selection_start_marker);
+
+               if (ok) {
+                       ok = FALSE;
+                       if (webkit_dom_range_get_collapsed (range, NULL)) {
+                               selection_end_marker = webkit_dom_node_get_next_sibling (
+                                       selection_start_marker);
+
+                               ok = e_editor_dom_is_selection_position_node (selection_end_marker);
+                               if (ok) {
+                                       WebKitDOMNode *next_sibling;
+
+                                       next_sibling = webkit_dom_node_get_next_sibling 
(selection_end_marker);
+
+                                       if (next_sibling && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling)) {
+                                               parent_start = webkit_dom_node_get_parent_node 
(selection_end_marker);
+
+                                               remove_node (selection_start_marker);
+                                               remove_node (selection_end_marker);
+
+                                               webkit_dom_node_normalize (parent_start);
+                                               g_object_unref (range);
+                                               g_object_unref (dom_selection);
+                                               return;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       g_object_unref (range);
+       range = webkit_dom_document_create_range (document);
+       if (!range) {
+               g_object_unref (dom_selection);
+               return;
+       }
+
+       marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       if (!marker) {
+               marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+               if (marker)
+                       remove_node (WEBKIT_DOM_NODE (marker));
+               g_object_unref (dom_selection);
+               g_object_unref (range);
+               return;
+       }
+
+       start_is_anchor = webkit_dom_element_has_attribute (marker, "data-anchor");
+       parent_start = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (marker));
+
+       webkit_dom_range_set_start_after (range, WEBKIT_DOM_NODE (marker), NULL);
+       remove_node (WEBKIT_DOM_NODE (marker));
+
+       marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+       if (!marker) {
+               marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               if (marker)
+                       remove_node (WEBKIT_DOM_NODE (marker));
+               g_object_unref (dom_selection);
+               g_object_unref (range);
+               return;
+       }
+
+       parent_end = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (marker));
+
+       webkit_dom_range_set_end_before (range, WEBKIT_DOM_NODE (marker), NULL);
+       remove_node (WEBKIT_DOM_NODE (marker));
+
+       webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+       if (webkit_dom_node_is_same_node (parent_start, parent_end))
+               webkit_dom_node_normalize (parent_start);
+       else {
+               webkit_dom_node_normalize (parent_start);
+               webkit_dom_node_normalize (parent_end);
+       }
+
+       if (start_is_anchor) {
+               anchor = webkit_dom_range_get_end_container (range, NULL);
+               offset = webkit_dom_range_get_end_offset (range, NULL);
+
+               webkit_dom_range_collapse (range, TRUE, NULL);
+       } else {
+               anchor = webkit_dom_range_get_start_container (range, NULL);
+               offset = webkit_dom_range_get_start_offset (range, NULL);
+
+               webkit_dom_range_collapse (range, FALSE, NULL);
+       }
+       webkit_dom_dom_selection_add_range (dom_selection, range);
+       webkit_dom_dom_selection_extend (dom_selection, anchor, offset, NULL);
+
+       g_object_unref (dom_selection);
+       g_object_unref (range);
+}
+
+static gint
+find_where_to_break_line (WebKitDOMCharacterData *node,
+                          gint max_length)
+{
+       gboolean last_break_position_is_dash = FALSE;
+       gchar *str, *text_start;
+       gunichar uc;
+       gint pos = 1, last_break_position = 0, ret_val = 0;
+
+       text_start = webkit_dom_character_data_get_data (node);
+
+       str = text_start;
+       do {
+               uc = g_utf8_get_char (str);
+               if (!uc) {
+                       ret_val = pos <= max_length ? pos : last_break_position > 0 ? last_break_position - 1 
: 0;
+                       goto out;
+               }
+
+               if ((g_unichar_isspace (uc) && !(g_unichar_break_type (uc) == 
G_UNICODE_BREAK_NON_BREAKING_GLUE)) ||
+                    *str == '-') {
+                       if ((last_break_position_is_dash = *str == '-')) {
+                               /* There was no space before the dash */
+                               if (pos - 1 != last_break_position) {
+                                       gchar *rest;
+
+                                       rest = g_utf8_next_char (str);
+                                       if (rest && *rest) {
+                                               gunichar next_char;
+
+                                               /* There is no space after the dash */
+                                               next_char = g_utf8_get_char (rest);
+                                               if (g_unichar_isspace (next_char))
+                                                       last_break_position_is_dash = FALSE;
+                                               else
+                                                       last_break_position = pos;
+                                       } else
+                                               last_break_position_is_dash = FALSE;
+                               } else
+                                       last_break_position_is_dash = FALSE;
+                       } else
+                               last_break_position = pos;
+               }
+
+               if ((pos == max_length)) {
+                       /* Look one character after the limit to check if there
+                        * is a space (skip dash) that we are allowed to break at, if so
+                        * break it there. */
+                       if (*str) {
+                               str = g_utf8_next_char (str);
+                               uc = g_utf8_get_char (str);
+
+                               if ((g_unichar_isspace (uc) &&
+                                   !(g_unichar_break_type (uc) == G_UNICODE_BREAK_NON_BREAKING_GLUE)))
+                                       last_break_position = ++pos;
+                       }
+                       break;
+               }
+
+               pos++;
+               str = g_utf8_next_char (str);
+       } while (*str);
+
+       if (last_break_position != 0)
+               ret_val = last_break_position - 1;
+ out:
+       g_free (text_start);
+
+       /* Always break after the dash character. */
+       if (last_break_position_is_dash)
+               ret_val++;
+
+       /* No character to break at is found. We should split at max_length, but
+        * we will leave the decision on caller as it depends on context. */
+       if (ret_val == 0 && last_break_position == 0)
+               ret_val = -1;
+
+       return ret_val;
+}
+
+/*
+ * e_html_editor_selection_is_collapsed:
+ * @selection: an #EEditorSelection
+ *
+ * Returns if selection is collapsed.
+ *
+ * Returns: Whether the selection is collapsed (just caret) or not (someting is selected).
+ */
+gboolean
+e_editor_dom_selection_is_collapsed (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       gboolean collapsed;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+       if (!(dom_window = webkit_dom_document_get_default_view (document)))
+               return FALSE;
+
+       if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
+               g_object_unref (dom_window);
+               return FALSE;
+       }
+
+       collapsed = webkit_dom_dom_selection_get_is_collapsed (dom_selection);
+
+       g_object_unref (dom_selection);
+
+       return collapsed;
+}
+
+void
+e_editor_dom_scroll_to_caret (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMElement *selection_start_marker;
+       glong element_top, element_left;
+       glong window_top, window_left, window_right, window_bottom;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       if (!selection_start_marker)
+               return;
+
+       dom_window = webkit_dom_document_get_default_view (document);
+
+       window_top = webkit_dom_dom_window_get_scroll_y (dom_window);
+       window_left = webkit_dom_dom_window_get_scroll_x (dom_window);
+       window_bottom = window_top + webkit_dom_dom_window_get_inner_height (dom_window);
+       window_right = window_left + webkit_dom_dom_window_get_inner_width (dom_window);
+
+       element_left = webkit_dom_element_get_offset_left (selection_start_marker);
+       element_top = webkit_dom_element_get_offset_top (selection_start_marker);
+
+       /* Check if caret is inside viewport, if not move to it */
+       if (!(element_top >= window_top && element_top <= window_bottom &&
+            element_left >= window_left && element_left <= window_right)) {
+               webkit_dom_element_scroll_into_view (selection_start_marker, TRUE);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       g_object_unref (dom_window);
+}
+
+static void
+mark_and_remove_trailing_space (WebKitDOMDocument *document,
+                                WebKitDOMNode *node)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_create_element (document, "SPAN", NULL);
+       webkit_dom_element_set_attribute (element, "data-hidden-space", "", NULL);
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (node),
+               WEBKIT_DOM_NODE (element),
+               webkit_dom_node_get_next_sibling (node),
+               NULL);
+       webkit_dom_character_data_replace_data (
+               WEBKIT_DOM_CHARACTER_DATA (node),
+               webkit_dom_character_data_get_length (WEBKIT_DOM_CHARACTER_DATA (node)),
+               1,
+               "",
+               NULL);
+}
+
+static void
+mark_and_remove_leading_space (WebKitDOMDocument *document,
+                               WebKitDOMNode *node)
+{
+       WebKitDOMElement *element;
+
+       element = webkit_dom_document_create_element (document, "SPAN", NULL);
+       webkit_dom_element_set_attribute (element, "data-hidden-space", "", NULL);
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (node),
+               WEBKIT_DOM_NODE (element),
+               node,
+               NULL);
+       webkit_dom_character_data_replace_data (
+               WEBKIT_DOM_CHARACTER_DATA (node), 0, 1, "", NULL);
+}
+
+static WebKitDOMElement *
+wrap_lines (EEditorPage *editor_page,
+            WebKitDOMNode *block,
+           gboolean remove_all_br,
+           gint length_to_wrap,
+           gint word_wrap_length)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *node, *start_node, *block_clone = NULL;
+       gboolean has_selection;
+       guint line_length;
+       gulong length_left;
+       gchar *text_content;
+       gboolean compensated = FALSE;
+       gboolean check_next_node = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       has_selection = !e_editor_dom_selection_is_collapsed (editor_page);
+
+       if (has_selection) {
+               gint ii, length;
+               WebKitDOMDocumentFragment *fragment;
+               WebKitDOMNodeList *list;
+               WebKitDOMRange *range;
+
+               range = e_editor_dom_get_current_range (editor_page);
+               fragment = webkit_dom_range_clone_contents (range, NULL);
+               g_object_unref (range);
+
+               /* Select all BR elements or just ours that are used for wrapping.
+                * We are not removing user BR elements when this function is activated
+                * from Format->Wrap Lines action */
+               list = webkit_dom_document_fragment_query_selector_all (
+                       fragment,
+                       remove_all_br ? "br" : "br.-x-evo-wrap-br",
+                       NULL);
+               length = webkit_dom_node_list_get_length (list);
+               /* And remove them */
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *node = webkit_dom_node_list_item (list, length);
+                       remove_node (node);
+                       g_object_unref (node);
+               }
+               g_object_unref (list);
+
+               list = webkit_dom_document_fragment_query_selector_all (
+                       fragment, "span[data-hidden-space]", NULL);
+               length = webkit_dom_node_list_get_length (list);
+               for (ii = 0; ii < length; ii++) {
+                       WebKitDOMNode *hidden_space_node;
+
+                       hidden_space_node = webkit_dom_node_list_item (list, ii);
+                       webkit_dom_html_element_set_outer_text (
+                               WEBKIT_DOM_HTML_ELEMENT (hidden_space_node), " ", NULL);
+                       g_object_unref (hidden_space_node);
+               }
+               g_object_unref (list);
+
+               node = WEBKIT_DOM_NODE (fragment);
+               start_node = node;
+       } else {
+               WebKitDOMElement *selection_start_marker, *selection_end_marker;
+               WebKitDOMNode *start_point = NULL, *first_child;
+
+               if (!webkit_dom_node_has_child_nodes (block))
+                       return WEBKIT_DOM_ELEMENT (block);
+
+               /* Avoid wrapping when the block contains just the BR element alone
+                * or with selection markers. */
+               if ((first_child = webkit_dom_node_get_first_child (block)) &&
+                    WEBKIT_DOM_IS_HTML_BR_ELEMENT (first_child)) {
+                       WebKitDOMNode *next_sibling;
+
+                       if ((next_sibling = webkit_dom_node_get_next_sibling (first_child))) {
+                              if (e_editor_dom_is_selection_position_node (next_sibling) &&
+                                  (next_sibling = webkit_dom_node_get_next_sibling (next_sibling)) &&
+                                  e_editor_dom_is_selection_position_node (next_sibling) &&
+                                  !webkit_dom_node_get_next_sibling (next_sibling))
+                                       return WEBKIT_DOM_ELEMENT (block);
+                       } else
+                               return WEBKIT_DOM_ELEMENT (block);
+               }
+
+               block_clone = webkit_dom_node_clone_node_with_error (block, TRUE, NULL);
+
+               /* When we wrap, we are wrapping just the text after caret, text
+                * before the caret is already wrapped, so unwrap the text after
+                * the caret position */
+               selection_end_marker = webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block_clone),
+                       "span#-x-evo-selection-end-marker",
+                       NULL);
+
+               if (selection_end_marker) {
+                       WebKitDOMNode *nd = WEBKIT_DOM_NODE (selection_end_marker);
+
+                       while (nd) {
+                               WebKitDOMNode *parent_node;
+                               WebKitDOMNode *next_nd = webkit_dom_node_get_next_sibling (nd);
+
+                               parent_node = webkit_dom_node_get_parent_node (nd);
+                               if (!next_nd && parent_node && !webkit_dom_node_is_same_node (parent_node, 
block_clone))
+                                       next_nd = webkit_dom_node_get_next_sibling (parent_node);
+
+                               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (nd)) {
+                                       if (remove_all_br)
+                                               remove_node (nd);
+                                       else if (element_has_class (WEBKIT_DOM_ELEMENT (nd), 
"-x-evo-wrap-br"))
+                                               remove_node (nd);
+                               } else if (WEBKIT_DOM_IS_ELEMENT (nd) &&
+                                          webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (nd), 
"data-hidden-space"))
+                                       webkit_dom_html_element_set_outer_text (
+                                               WEBKIT_DOM_HTML_ELEMENT (nd), " ", NULL);
+
+                               nd = next_nd;
+                       }
+               } else {
+                       gint ii, length;
+                       WebKitDOMNodeList *list;
+
+                       list = webkit_dom_element_query_selector_all (
+                               WEBKIT_DOM_ELEMENT (block_clone), "span[data-hidden-space]", NULL);
+                       length = webkit_dom_node_list_get_length (list);
+                       for (ii = 0; ii < length; ii++) {
+                               WebKitDOMNode *hidden_space_node;
+
+                               hidden_space_node = webkit_dom_node_list_item (list, ii);
+                               webkit_dom_html_element_set_outer_text (
+                                       WEBKIT_DOM_HTML_ELEMENT (hidden_space_node), " ", NULL);
+                               g_object_unref (hidden_space_node);
+                       }
+                       g_object_unref (list);
+               }
+
+               /* We have to start from the end of the last wrapped line */
+               selection_start_marker = webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block_clone),
+                       "span#-x-evo-selection-start-marker",
+                       NULL);
+
+               if (selection_start_marker) {
+                       gboolean first_removed = FALSE;
+                       WebKitDOMNode *nd;
+
+                       nd = webkit_dom_node_get_previous_sibling (
+                               WEBKIT_DOM_NODE (selection_start_marker));
+                       while (nd) {
+                               WebKitDOMNode *prev_nd = webkit_dom_node_get_previous_sibling (nd);
+
+                               if (!prev_nd && !webkit_dom_node_is_same_node 
(webkit_dom_node_get_parent_node (nd), block_clone))
+                                       prev_nd = webkit_dom_node_get_previous_sibling 
(webkit_dom_node_get_parent_node (nd));
+
+                               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (nd)) {
+                                       if (first_removed) {
+                                               start_point = nd;
+                                               break;
+                                       } else {
+                                               remove_node (nd);
+                                               first_removed = TRUE;
+                                       }
+                               } else if (WEBKIT_DOM_IS_ELEMENT (nd) &&
+                                          webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (nd), 
"data-hidden-space")) {
+                                       webkit_dom_html_element_set_outer_text (
+                                               WEBKIT_DOM_HTML_ELEMENT (nd), " ", NULL);
+                               } else if (!prev_nd) {
+                                       WebKitDOMNode *parent;
+
+                                       parent = webkit_dom_node_get_parent_node (nd);
+                                       if (!WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent))
+                                               start_point = nd;
+                               }
+
+                               nd = prev_nd;
+                       }
+               }
+
+               webkit_dom_node_normalize (block_clone);
+               node = webkit_dom_node_get_first_child (block_clone);
+               if (node) {
+                       text_content = webkit_dom_node_get_text_content (node);
+                       if (g_strcmp0 ("\n", text_content) == 0)
+                               node = webkit_dom_node_get_next_sibling (node);
+                       g_free (text_content);
+               }
+
+               if (start_point) {
+                       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (start_point))
+                               node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (start_point));
+                       else
+                               node = start_point;
+                       start_node = block_clone;
+               } else
+                       start_node = node;
+       }
+
+       line_length = 0;
+       while (node) {
+               gint offset = 0;
+               WebKitDOMElement *element;
+
+               if (WEBKIT_DOM_IS_TEXT (node)) {
+                       const gchar *newline;
+                       WebKitDOMNode *next_sibling;
+
+                       /* If there is temporary hidden space we remove it */
+                       text_content = webkit_dom_node_get_text_content (node);
+                       if (strstr (text_content, UNICODE_ZERO_WIDTH_SPACE)) {
+                               if (g_str_has_prefix (text_content, UNICODE_ZERO_WIDTH_SPACE))
+                                       webkit_dom_character_data_delete_data (
+                                               WEBKIT_DOM_CHARACTER_DATA (node),
+                                               0,
+                                               1,
+                                               NULL);
+                               if (g_str_has_suffix (text_content, UNICODE_ZERO_WIDTH_SPACE))
+                                       webkit_dom_character_data_delete_data (
+                                               WEBKIT_DOM_CHARACTER_DATA (node),
+                                               g_utf8_strlen (text_content, -1) - 1,
+                                               1,
+                                               NULL);
+                               g_free (text_content);
+                               text_content = webkit_dom_node_get_text_content (node);
+                       }
+                       newline = strstr (text_content, "\n");
+
+                       next_sibling = node;
+                       while (newline) {
+                               next_sibling = WEBKIT_DOM_NODE (webkit_dom_text_split_text (
+                                       WEBKIT_DOM_TEXT (next_sibling),
+                                       g_utf8_pointer_to_offset (text_content, newline),
+                                       NULL));
+
+                               if (!next_sibling)
+                                       break;
+
+                               element = webkit_dom_document_create_element (
+                                       document, "BR", NULL);
+                               element_add_class (element, "-x-evo-temp-wrap-text-br");
+
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (next_sibling),
+                                       WEBKIT_DOM_NODE (element),
+                                       next_sibling,
+                                       NULL);
+
+                               g_free (text_content);
+
+                               text_content = webkit_dom_node_get_text_content (next_sibling);
+                               if (g_str_has_prefix (text_content, "\n")) {
+                                       webkit_dom_character_data_delete_data (
+                                               WEBKIT_DOM_CHARACTER_DATA (next_sibling), 0, 1, NULL);
+                                       g_free (text_content);
+                                       text_content =
+                                               webkit_dom_node_get_text_content (next_sibling);
+                               }
+                               newline = strstr (text_content, "\n");
+                       }
+                       g_free (text_content);
+               } else {
+                       if (e_editor_dom_is_selection_position_node (node)) {
+                               if (line_length == 0) {
+                                       WebKitDOMNode *tmp_node;
+
+                                       tmp_node = webkit_dom_node_get_previous_sibling (node);
+                                       /* Only check if there is some node before the selection marker. */
+                                       if (tmp_node && !e_editor_dom_is_selection_position_node (tmp_node))
+                                               check_next_node = TRUE;
+                               }
+                               node = webkit_dom_node_get_next_sibling (node);
+                               continue;
+                       }
+
+                       check_next_node = FALSE;
+                       /* If element is ANCHOR we wrap it separately */
+                       if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
+                               glong anchor_length;
+                               WebKitDOMNode *next_sibling;
+
+                               text_content = webkit_dom_node_get_text_content (node);
+                               anchor_length = g_utf8_strlen (text_content, -1);
+                               g_free (text_content);
+
+                               next_sibling = webkit_dom_node_get_next_sibling (node);
+                               /* If the anchor doesn't fit on the line move the inner
+                                * nodes out of it and start to wrap them. */
+                               if ((line_length + anchor_length) > length_to_wrap) {
+                                       WebKitDOMNode *inner_node;
+
+                                       while ((inner_node = webkit_dom_node_get_first_child (node))) {
+                                               g_object_set_data (
+                                                       G_OBJECT (inner_node),
+                                                       "-x-evo-anchor-text",
+                                                       GINT_TO_POINTER (1));
+                                               webkit_dom_node_insert_before (
+                                                       webkit_dom_node_get_parent_node (node),
+                                                       inner_node,
+                                                       next_sibling,
+                                                       NULL);
+                                       }
+                                       next_sibling = webkit_dom_node_get_next_sibling (node);
+
+                                       remove_node (node);
+                                       node = next_sibling;
+                                       continue;
+                               }
+
+                               line_length += anchor_length;
+                               node = next_sibling;
+                               continue;
+                       }
+
+                       if (element_has_class (WEBKIT_DOM_ELEMENT (node), "Apple-tab-span")) {
+                               WebKitDOMNode *sibling;
+                               gint tab_length;
+
+                               sibling = webkit_dom_node_get_previous_sibling (node);
+                               if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+                                   element_has_class (WEBKIT_DOM_ELEMENT (sibling), "Apple-tab-span"))
+                                       tab_length = TAB_LENGTH;
+                               else {
+                                       tab_length = TAB_LENGTH - (line_length + compensated ? 0 : 
(word_wrap_length - length_to_wrap)) % TAB_LENGTH;
+                                       compensated = TRUE;
+                               }
+
+                               if (line_length + tab_length > length_to_wrap) {
+                                       if (webkit_dom_node_get_next_sibling (node)) {
+                                               element = webkit_dom_document_create_element (
+                                                       document, "BR", NULL);
+                                               element_add_class (element, "-x-evo-wrap-br");
+                                               node = webkit_dom_node_insert_before (
+                                                       webkit_dom_node_get_parent_node (node),
+                                                       WEBKIT_DOM_NODE (element),
+                                                       webkit_dom_node_get_next_sibling (node),
+                                                       NULL);
+                                       }
+                                       line_length = 0;
+                                       compensated = FALSE;
+                               } else
+                                       line_length += tab_length;
+
+                               sibling = webkit_dom_node_get_next_sibling (node);
+                               node = sibling;
+                               continue;
+                       }
+                       /* When we are not removing user-entered BR elements (lines wrapped by user),
+                        * we need to skip those elements */
+                       if (!remove_all_br && WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+                               if (!element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-wrap-br")) {
+                                       line_length = 0;
+                                       compensated = FALSE;
+                                       node = webkit_dom_node_get_next_sibling (node);
+                                       continue;
+                               }
+                       }
+                       goto next_node;
+               }
+
+               /* If length of this node + what we already have is still less
+                * then length_to_wrap characters, then just concatenate it and
+                * continue to next node */
+               length_left = webkit_dom_character_data_get_length (
+                       WEBKIT_DOM_CHARACTER_DATA (node));
+
+               if ((length_left + line_length) <= length_to_wrap) {
+                       if (check_next_node)
+                               goto check_node;
+                       line_length += length_left;
+                       if (line_length == length_to_wrap) {
+                               line_length = 0;
+
+                               element = webkit_dom_document_create_element (document, "BR", NULL);
+                               element_add_class (element, "-x-evo-wrap-br");
+
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (node),
+                                       WEBKIT_DOM_NODE (element),
+                                       webkit_dom_node_get_next_sibling (node),
+                                       NULL);
+                       }
+                       goto next_node;
+               }
+
+               /* wrap until we have something */
+               while (node && (length_left + line_length) > length_to_wrap) {
+                       gboolean insert_and_continue;
+                       gint max_length;
+
+ check_node:
+                       insert_and_continue = FALSE;
+
+                       if (!WEBKIT_DOM_IS_CHARACTER_DATA (node))
+                               goto next_node;
+
+                       element = webkit_dom_document_create_element (document, "BR", NULL);
+                       element_add_class (element, "-x-evo-wrap-br");
+
+                       max_length = length_to_wrap - line_length;
+                       if (max_length < 0)
+                               max_length = length_to_wrap;
+                       else if (max_length == 0) {
+                               if (check_next_node) {
+                                       insert_and_continue = TRUE;
+                                       goto check;
+                               }
+
+                               /* Break before the current node and continue. */
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (node),
+                                       WEBKIT_DOM_NODE (element),
+                                       node,
+                                       NULL);
+                               line_length = 0;
+                               continue;
+                       }
+
+                       /* Allow anchors to break on any character. */
+                       if (g_object_steal_data (G_OBJECT (node), "-x-evo-anchor-text"))
+                               offset = max_length;
+                       else {
+                               /* Find where we can line-break the node so that it
+                                * effectively fills the rest of current row. */
+                               offset = find_where_to_break_line (
+                                       WEBKIT_DOM_CHARACTER_DATA (node), max_length);
+
+                               /* When pressing delete on the end of line to concatenate
+                                * the last word from the line and first word from the
+                                * next line we will end with the second word split
+                                * somewhere in the middle (to be precise it will be
+                                * split after the last character that will fit on the
+                                * previous line. To avoid that we need to put the
+                                * concatenated word on the next line. */
+                               if (offset == -1 || check_next_node) {
+                                       WebKitDOMNode *prev_sibling;
+
+ check:
+                                       check_next_node = FALSE;
+                                       prev_sibling = webkit_dom_node_get_previous_sibling (node);
+                                       if (prev_sibling && e_editor_dom_is_selection_position_node 
(prev_sibling)) {
+                                               WebKitDOMNode *prev_br = NULL;
+
+                                               prev_sibling = webkit_dom_node_get_previous_sibling 
(prev_sibling);
+
+                                               /* Collapsed selection */
+                                               if (prev_sibling && e_editor_dom_is_selection_position_node 
(prev_sibling))
+                                                       prev_sibling = webkit_dom_node_get_previous_sibling 
(prev_sibling);
+
+                                               if (prev_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT 
(prev_sibling) &&
+                                                   element_has_class (WEBKIT_DOM_ELEMENT (prev_sibling), 
"-x-evo-wrap-br")) {
+                                                       prev_br = prev_sibling;
+                                                       prev_sibling = webkit_dom_node_get_previous_sibling 
(prev_sibling);
+                                               }
+
+                                               if (prev_sibling && WEBKIT_DOM_IS_CHARACTER_DATA 
(prev_sibling)) {
+                                                       gchar *data;
+                                                       glong text_length, length = 0;
+
+                                                       data = webkit_dom_character_data_get_data (
+                                                               WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+                                                       text_length = webkit_dom_character_data_get_length (
+                                                               WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+
+                                                       /* Find the last character where we can break. */
+                                                       while (text_length - length > 0) {
+                                                               if (strchr (" ", data[text_length - length - 
1])) {
+                                                                       length++;
+                                                                       break;
+                                                               } else if (data[text_length - length - 1] == 
'-' &&
+                                                                          text_length - length > 1 &&
+                                                                          !strchr (" ", data[text_length - 
length - 2]))
+                                                                       break;
+                                                               length++;
+                                                       }
+
+                                                       if (text_length != length) {
+                                                               WebKitDOMNode *nd;
+
+                                                               webkit_dom_text_split_text (
+                                                                       WEBKIT_DOM_TEXT (prev_sibling),
+                                                                       text_length - length,
+                                                                       NULL);
+
+                                                               if ((nd = webkit_dom_node_get_next_sibling 
(prev_sibling))) {
+                                                                       gchar *nd_content;
+
+                                                                       nd_content = 
webkit_dom_node_get_text_content (nd);
+                                                                       if (nd_content && *nd_content) {
+                                                                               if (*nd_content == ' ')
+                                                                                       
mark_and_remove_leading_space (document, nd);
+
+                                                                               if 
(!webkit_dom_node_get_next_sibling (nd) &&
+                                                                                   g_str_has_suffix 
(nd_content, " "))
+                                                                                       
mark_and_remove_trailing_space (document, nd);
+
+                                                                               g_free (nd_content);
+                                                                       }
+
+                                                                       if (nd) {
+                                                                               if (prev_br)
+                                                                                       remove_node (prev_br);
+                                                                                
webkit_dom_node_insert_before (
+                                                                                       
webkit_dom_node_get_parent_node (nd),
+                                                                                       WEBKIT_DOM_NODE 
(element),
+                                                                                       nd,
+                                                                                       NULL);
+
+                                                                               offset = 0;
+                                                                               line_length = length;
+                                                                               continue;
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       if (insert_and_continue) {
+                                               webkit_dom_node_insert_before (
+                                                       webkit_dom_node_get_parent_node (node),
+                                                       WEBKIT_DOM_NODE (element),
+                                                       node,
+                                                       NULL);
+
+                                               offset = 0;
+                                               line_length = 0;
+                                               insert_and_continue = FALSE;
+                                               continue;
+                                       }
+
+                                       offset = offset != -1 ? offset : max_length;
+                               }
+                       }
+
+                       if (offset >= 0) {
+                               WebKitDOMNode *nd;
+
+                               if (offset != length_left && offset != 0) {
+                                       webkit_dom_text_split_text (
+                                               WEBKIT_DOM_TEXT (node), offset, NULL);
+
+                                       nd = webkit_dom_node_get_next_sibling (node);
+                               } else
+                                       nd = node;
+
+                               if (nd) {
+                                       gboolean no_sibling = FALSE;
+                                       gchar *nd_content;
+
+                                       nd_content = webkit_dom_node_get_text_content (nd);
+                                       if (nd_content && *nd_content) {
+                                               if (*nd_content == ' ')
+                                                       mark_and_remove_leading_space (document, nd);
+
+                                               if (!webkit_dom_node_get_next_sibling (nd) &&
+                                                   length_left <= length_to_wrap &&
+                                                   g_str_has_suffix (nd_content, " ")) {
+                                                       mark_and_remove_trailing_space (document, nd);
+                                                       no_sibling = TRUE;
+                                               }
+
+                                               g_free (nd_content);
+                                       }
+
+                                       if (!no_sibling)
+                                               webkit_dom_node_insert_before (
+                                                       webkit_dom_node_get_parent_node (node),
+                                                       WEBKIT_DOM_NODE (element),
+                                                       nd,
+                                                       NULL);
+
+                                       offset = 0;
+
+                                       nd_content = webkit_dom_node_get_text_content (nd);
+                                       if (!*nd_content)
+                                               remove_node (nd);
+                                       g_free (nd_content);
+
+                                       if (no_sibling)
+                                               node = NULL;
+                                       else
+                                               node = webkit_dom_node_get_next_sibling (
+                                                       WEBKIT_DOM_NODE (element));
+                               } else {
+                                       webkit_dom_node_append_child (
+                                               webkit_dom_node_get_parent_node (node),
+                                               WEBKIT_DOM_NODE (element),
+                                               NULL);
+                               }
+                       }
+                       if (node && WEBKIT_DOM_IS_CHARACTER_DATA (node))
+                               length_left = webkit_dom_character_data_get_length (
+                                       WEBKIT_DOM_CHARACTER_DATA (node));
+
+                       line_length = 0;
+                       compensated = FALSE;
+               }
+               line_length += length_left - offset;
+ next_node:
+               if (!node)
+                       break;
+
+               if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (node)) {
+                       line_length = 0;
+                       compensated = FALSE;
+               }
+
+               /* Move to next node */
+               if (webkit_dom_node_has_child_nodes (node)) {
+                       node = webkit_dom_node_get_first_child (node);
+               } else if (webkit_dom_node_get_next_sibling (node)) {
+                       node = webkit_dom_node_get_next_sibling (node);
+               } else {
+                       WebKitDOMNode *tmp_parent;
+
+                       if (webkit_dom_node_is_equal_node (node, start_node))
+                               break;
+
+                       /* Find a next node that we can process. */
+                       tmp_parent = webkit_dom_node_get_parent_node (node);
+                       if (tmp_parent && webkit_dom_node_get_next_sibling (tmp_parent))
+                               node = webkit_dom_node_get_next_sibling (tmp_parent);
+                       else {
+                               WebKitDOMNode *tmp;
+
+                               tmp = tmp_parent;
+                               /* Find a node that is not a start node (that would mean
+                                * that we already processed the whole block) and it has
+                                * a sibling that we can process. */
+                               while (tmp && !webkit_dom_node_is_equal_node (tmp, start_node) &&
+                                      !webkit_dom_node_get_next_sibling (tmp)) {
+                                       tmp = webkit_dom_node_get_parent_node (tmp);
+                               }
+
+                               /* If we found a node to process, let's process its
+                                * sibling, otherwise give up. */
+                               if (tmp)
+                                       node = webkit_dom_node_get_next_sibling (tmp);
+                               else
+                                       break;
+                       }
+               }
+       }
+
+       if (has_selection) {
+               gchar *html;
+               WebKitDOMElement *element;
+
+               /* Create a wrapper DIV and put the processed content into it */
+               element = webkit_dom_document_create_element (document, "p", NULL);
+               webkit_dom_element_set_attribute (
+                       element, "data-evo-paragraph", "", NULL);
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (element),
+                       WEBKIT_DOM_NODE (start_node),
+                       NULL);
+
+               webkit_dom_node_normalize (WEBKIT_DOM_NODE (element));
+               /* Get HTML code of the processed content */
+               html = webkit_dom_element_get_inner_html (element);
+
+               /* Overwrite the current selection by the processed content */
+               e_editor_dom_insert_html (editor_page, html);
+
+               g_free (html);
+
+               return NULL;
+       } else {
+               WebKitDOMNode *last_child;
+
+               last_child = webkit_dom_node_get_last_child (block_clone);
+               if (last_child && WEBKIT_DOM_IS_HTML_BR_ELEMENT (last_child) &&
+                   element_has_class (WEBKIT_DOM_ELEMENT (last_child), "-x-evo-wrap-br"))
+                       remove_node (last_child);
+
+               webkit_dom_node_normalize (block_clone);
+
+               node = webkit_dom_node_get_parent_node (block);
+               if (node) {
+                       /* Replace block with wrapped one */
+                       webkit_dom_node_replace_child (
+                               node, block_clone, block, NULL);
+               }
+
+               return WEBKIT_DOM_ELEMENT (block_clone);
+       }
+}
+
+void
+e_editor_dom_remove_wrapping_from_element (WebKitDOMElement *element)
+{
+       WebKitDOMNodeList *list;
+       gint ii, length;
+
+       g_return_if_fail (element != NULL);
+
+       list = webkit_dom_element_query_selector_all (
+               element, "br.-x-evo-wrap-br", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               WebKitDOMNode *parent;
+
+               parent = e_editor_dom_get_parent_block_node_from_child (node);
+               if (!webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-user-wrapped"))
+                       remove_node (node);
+               g_object_unref (node);
+       }
+
+       g_object_unref (list);
+
+       list = webkit_dom_element_query_selector_all (
+               element, "span[data-hidden-space]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *hidden_space_node;
+               WebKitDOMNode *parent;
+
+               hidden_space_node = webkit_dom_node_list_item (list, ii);
+               parent = e_editor_dom_get_parent_block_node_from_child (hidden_space_node);
+               if (!webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "data-user-wrapped")) {
+                       webkit_dom_html_element_set_outer_text (
+                               WEBKIT_DOM_HTML_ELEMENT (hidden_space_node), " ", NULL);
+               }
+               g_object_unref (hidden_space_node);
+       }
+       g_object_unref (list);
+
+       webkit_dom_node_normalize (WEBKIT_DOM_NODE (element));
+}
+
+void
+e_editor_dom_remove_quoting_from_element (WebKitDOMElement *element)
+{
+       gint ii, length;
+       WebKitDOMNodeList *list;
+
+       g_return_if_fail (element != NULL);
+
+       list = webkit_dom_element_query_selector_all (
+               element, "span.-x-evo-quoted", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       list = webkit_dom_element_query_selector_all (
+               element, "span.-x-evo-temp-text-wrapper", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+
+               while (webkit_dom_node_get_first_child (node))
+                       webkit_dom_node_insert_before (
+                               parent,
+                               webkit_dom_node_get_first_child (node),
+                               node,
+                               NULL);
+
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       list = webkit_dom_element_query_selector_all (
+               element, "br.-x-evo-temp-br", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+               remove_node (node);
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+
+       webkit_dom_node_normalize (WEBKIT_DOM_NODE (element));
+}
+
+WebKitDOMElement *
+e_editor_dom_get_paragraph_element (EEditorPage *editor_page,
+                                   gint width,
+                                   gint offset)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       element = webkit_dom_document_create_element (document, "p", NULL);
+       e_editor_dom_set_paragraph_style (editor_page, element, width, offset, "");
+
+       return element;
+}
+
+WebKitDOMElement *
+e_editor_dom_put_node_into_paragraph (EEditorPage *editor_page,
+                                     WebKitDOMNode *node,
+                                     gboolean with_input)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMRange *range;
+       WebKitDOMElement *container;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       range = webkit_dom_document_create_range (document);
+       container = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+       webkit_dom_range_select_node (range, node, NULL);
+       webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (container), NULL);
+       /* We have to move caret position inside this container */
+       if (with_input)
+               dom_add_selection_markers_into_element_end (document, container, NULL, NULL);
+
+       g_object_unref (range);
+
+       return container;
+}
+
+static gint
+selection_get_citation_level (WebKitDOMNode *node)
+{
+       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
+       gint level = 0;
+
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               if (WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent) &&
+                   webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (parent), "type"))
+                       level++;
+
+               parent = webkit_dom_node_get_parent_node (parent);
+       }
+
+       return level;
+}
+
+WebKitDOMElement *
+e_editor_dom_wrap_paragraph_length (EEditorPage *editor_page,
+                                   WebKitDOMElement *paragraph,
+                                   gint length)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+       g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (paragraph), NULL);
+       g_return_val_if_fail (length >= MINIMAL_PARAGRAPH_WIDTH, NULL);
+
+       return wrap_lines (editor_page, WEBKIT_DOM_NODE (paragraph), FALSE, length,
+               e_editor_page_get_word_wrap_length (editor_page));
+}
+
+/*
+ * e_html_editor_selection_wrap_lines:
+ * @selection: an #EEditorSelection
+ *
+ * Wraps all lines in current selection to be 71 characters long.
+ */
+
+void
+e_editor_dom_selection_wrap (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block, *next_block;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       gboolean after_selection_end = FALSE, html_mode;
+       gint word_wrap_length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+       e_editor_dom_selection_save (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       /* If the selection was not saved, move it into the first child of body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMHTMLElement *body;
+               WebKitDOMNode *child;
+
+               body = webkit_dom_document_get_body (document);
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+       }
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_WRAP;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.style.from = 1;
+               ev->data.style.to = 1;
+       }
+
+       block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       /* Process all blocks that are in the selection one by one */
+       while (block && !after_selection_end) {
+               gboolean quoted = FALSE;
+               gint citation_level, quote;
+               WebKitDOMElement *wrapped_paragraph;
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               /* Don't try to wrap the 'Normal' blocks as they are already wrapped and*/
+               /* also skip blocks that we already wrapped with this function. */
+               if ((!html_mode && webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), 
"data-evo-paragraph")) ||
+                   webkit_dom_element_has_attribute (WEBKIT_DOM_ELEMENT (block), "data-user-wrapped")) {
+                       block = next_block;
+                       continue;
+               }
+
+               if (webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block), "span.-x-evo-quoted", NULL)) {
+                       quoted = TRUE;
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+               }
+
+               if (!html_mode)
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+
+               after_selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               citation_level = selection_get_citation_level (block);
+               quote = citation_level ? citation_level * 2 : 0;
+
+               wrapped_paragraph = e_editor_dom_wrap_paragraph_length (
+                       editor_page, WEBKIT_DOM_ELEMENT (block), word_wrap_length - quote);
+
+               webkit_dom_element_set_attribute (
+                       wrapped_paragraph, "data-user-wrapped", "", NULL);
+
+               if (quoted && !html_mode)
+                       e_editor_dom_quote_plain_text_element (editor_page, wrapped_paragraph);
+
+               block = next_block;
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_dom_force_spell_check_in_viewport (editor_page);
+}
+
+void
+e_editor_dom_wrap_paragraphs_in_document (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNodeList *list;
+       gint ii, length;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       list = webkit_dom_document_query_selector_all (
+               document, "[data-evo-paragraph]:not(#-x-evo-input-start)", NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+
+       for (ii = 0; ii < length; ii++) {
+               gint word_wrap_length, quote, citation_level;
+               WebKitDOMNode *node = webkit_dom_node_list_item (list, ii);
+
+               citation_level = selection_get_citation_level (node);
+               quote = citation_level ? citation_level * 2 : 0;
+               word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+
+               if (node_is_list (node)) {
+                       WebKitDOMNode *item = webkit_dom_node_get_first_child (node);
+
+                       while (item && WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+                               e_editor_dom_wrap_paragraph_length (
+                                       editor_page, WEBKIT_DOM_ELEMENT (item), word_wrap_length - quote);
+                               item = webkit_dom_node_get_next_sibling (item);
+                       }
+               } else {
+                       e_editor_dom_wrap_paragraph_length (
+                               editor_page, WEBKIT_DOM_ELEMENT (node), word_wrap_length - quote);
+               }
+               g_object_unref (node);
+       }
+       g_object_unref (list);
+}
+
+WebKitDOMElement *
+e_editor_dom_wrap_paragraph (EEditorPage *editor_page,
+                            WebKitDOMElement *paragraph)
+{
+       gint indentation_level, citation_level, quote;
+       gint word_wrap_length, final_width, offset = 0;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+       g_return_val_if_fail (WEBKIT_DOM_IS_ELEMENT (paragraph), NULL);
+
+       indentation_level = get_indentation_level (paragraph);
+       citation_level = selection_get_citation_level (WEBKIT_DOM_NODE (paragraph));
+
+       if (node_is_list_or_item (WEBKIT_DOM_NODE (paragraph))) {
+               gint list_level = get_list_level (WEBKIT_DOM_NODE (paragraph));
+               indentation_level = 0;
+
+               if (list_level > 0)
+                       offset = list_level * -SPACES_PER_LIST_LEVEL;
+               else
+                       offset = -SPACES_PER_LIST_LEVEL;
+       }
+
+       quote = citation_level ? citation_level * 2 : 0;
+
+       word_wrap_length = e_editor_page_get_word_wrap_length (editor_page);
+       final_width = word_wrap_length - quote + offset;
+       final_width -= SPACES_PER_INDENTATION * indentation_level;
+
+       return e_editor_dom_wrap_paragraph_length (
+               editor_page, WEBKIT_DOM_ELEMENT (paragraph), final_width);
+}
+
+static gboolean
+get_has_style (EEditorPage *editor_page,
+               const gchar *style_tag)
+{
+       WebKitDOMNode *node;
+       WebKitDOMElement *element;
+       WebKitDOMRange *range;
+       gboolean result;
+       gint tag_len;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return FALSE;
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (WEBKIT_DOM_IS_ELEMENT (node))
+               element = WEBKIT_DOM_ELEMENT (node);
+       else
+               element = webkit_dom_node_get_parent_element (node);
+       g_object_unref (range);
+
+       tag_len = strlen (style_tag);
+       result = FALSE;
+       while (!result && element) {
+               gchar *element_tag;
+               gboolean accept_citation = FALSE;
+
+               element_tag = webkit_dom_element_get_tag_name (element);
+
+               if (g_ascii_strncasecmp (style_tag, "citation", 8) == 0) {
+                       accept_citation = TRUE;
+                       result = WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (element);
+                       if (element_has_class (element, "-x-evo-indented"))
+                               result = FALSE;
+               } else {
+                       result = ((tag_len == strlen (element_tag)) &&
+                               (g_ascii_strncasecmp (element_tag, style_tag, tag_len) == 0));
+               }
+
+               /* Special case: <blockquote type=cite> marks quotation, while
+                * just <blockquote> is used for indentation. If the <blockquote>
+                * has type=cite, then ignore it unless style_tag is "citation" */
+               if (result && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (element)) {
+                       if (webkit_dom_element_has_attribute (element, "type")) {
+                               gchar *type = webkit_dom_element_get_attribute (element, "type");
+                               if (!accept_citation && (type && g_ascii_strncasecmp (type, "cite", 4) == 0)) 
{
+                                       result = FALSE;
+                               }
+                               g_free (type);
+                       } else {
+                               if (accept_citation)
+                                       result = FALSE;
+                       }
+               }
+
+               g_free (element_tag);
+
+               if (result)
+                       break;
+
+               element = webkit_dom_node_get_parent_element (
+                       WEBKIT_DOM_NODE (element));
+       }
+
+       return result;
+}
+
+typedef gboolean (*IsRightFormatNodeFunc) (WebKitDOMElement *element);
+
+static gboolean
+dom_selection_is_font_format (EEditorPage *editor_page,
+                              IsRightFormatNodeFunc func,
+                              gboolean *previous_value)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window = NULL;
+       WebKitDOMDOMSelection *dom_selection = NULL;
+       WebKitDOMNode *start, *end, *sibling;
+       WebKitDOMRange *range = NULL;
+       gboolean ret_val = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       if (!e_editor_page_get_html_mode (editor_page))
+               goto out;
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection))
+               goto out;
+
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+       if (!range)
+               goto out;
+
+       if (webkit_dom_range_get_collapsed (range, NULL) && previous_value) {
+               WebKitDOMNode *node;
+               gchar* text_content;
+
+               node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+               /* If we are changing the format of block we have to re-set the
+                * format property, otherwise it will be turned off because of no
+                * text in block. */
+               text_content = webkit_dom_node_get_text_content (node);
+               if (g_strcmp0 (text_content, "") == 0) {
+                       g_free (text_content);
+                       ret_val = *previous_value;
+                       goto out;
+               }
+               g_free (text_content);
+       }
+
+       /* Range without start or end point is a wrong range. */
+       start = webkit_dom_range_get_start_container (range, NULL);
+       end = webkit_dom_range_get_end_container (range, NULL);
+       if (!start || !end)
+               goto out;
+
+       if (WEBKIT_DOM_IS_TEXT (start))
+               start = webkit_dom_node_get_parent_node (start);
+       while (start && WEBKIT_DOM_IS_ELEMENT (start) && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (start)) {
+               /* Find the start point's parent node with given formatting. */
+               if (func (WEBKIT_DOM_ELEMENT (start))) {
+                       ret_val = TRUE;
+                       break;
+               }
+               start = webkit_dom_node_get_parent_node (start);
+       }
+
+       /* Start point doesn't have the given formatting. */
+       if (!ret_val)
+               goto out;
+
+       /* If the selection is collapsed, we can return early. */
+       if (webkit_dom_range_get_collapsed (range, NULL))
+               goto out;
+
+       /* The selection is in the same node and that node is supposed to have
+        * the same formatting (otherwise it is split up with formatting element. */
+       if (webkit_dom_node_is_same_node (
+               webkit_dom_range_get_start_container (range, NULL),
+               webkit_dom_range_get_end_container (range, NULL)))
+               goto out;
+
+       ret_val = FALSE;
+
+       if (WEBKIT_DOM_IS_TEXT (end))
+               end = webkit_dom_node_get_parent_node (end);
+       while (end && WEBKIT_DOM_IS_ELEMENT (end) && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (end)) {
+               /* Find the end point's parent node with given formatting. */
+               if (func (WEBKIT_DOM_ELEMENT (end))) {
+                       ret_val = TRUE;
+                       break;
+               }
+               end = webkit_dom_node_get_parent_node (end);
+       }
+
+       if (!ret_val)
+               goto out;
+
+       ret_val = FALSE;
+
+       /* Now go between the end points and check the inner nodes for format validity. */
+       sibling = start;
+       while ((sibling = webkit_dom_node_get_next_sibling (sibling))) {
+               if (webkit_dom_node_is_same_node (sibling, end)) {
+                       ret_val = TRUE;
+                       goto out;
+               }
+
+               if (WEBKIT_DOM_IS_TEXT (sibling))
+                       goto out;
+               else if (func (WEBKIT_DOM_ELEMENT (sibling)))
+                       continue;
+               else if (webkit_dom_node_get_first_child (sibling)) {
+                       WebKitDOMNode *first_child;
+
+                       first_child = webkit_dom_node_get_first_child (sibling);
+                       if (!webkit_dom_node_get_next_sibling (first_child))
+                               if (WEBKIT_DOM_IS_ELEMENT (first_child) && func (WEBKIT_DOM_ELEMENT 
(first_child)))
+                                       continue;
+                               else
+                                       goto out;
+                       else
+                               goto out;
+               } else
+                       goto out;
+       }
+
+       sibling = end;
+       while ((sibling = webkit_dom_node_get_previous_sibling (sibling))) {
+               if (webkit_dom_node_is_same_node (sibling, start))
+                       break;
+
+               if (WEBKIT_DOM_IS_TEXT (sibling))
+                       goto out;
+               else if (func (WEBKIT_DOM_ELEMENT (sibling)))
+                       continue;
+               else if (webkit_dom_node_get_first_child (sibling)) {
+                       WebKitDOMNode *first_child;
+
+                       first_child = webkit_dom_node_get_first_child (sibling);
+                       if (!webkit_dom_node_get_next_sibling (first_child))
+                               if (WEBKIT_DOM_IS_ELEMENT (first_child) && func (WEBKIT_DOM_ELEMENT 
(first_child)))
+                                       continue;
+                               else
+                                       goto out;
+                       else
+                               goto out;
+               } else
+                       goto out;
+       }
+
+       ret_val = TRUE;
+ out:
+       g_clear_object (&range);
+       g_clear_object (&dom_window);
+       g_clear_object (&dom_selection);
+
+       return ret_val;
+}
+
+static gboolean
+is_underline_element (WebKitDOMElement *element)
+{
+       if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       return element_has_tag (element, "u");
+}
+
+/*
+ * e_html_editor_selection_is_underline:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is underlined.
+ *
+ * Returns @TRUE when selection is underlined, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_underline (EEditorPage *editor_page)
+{
+       gboolean is_underline;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       is_underline = e_editor_page_get_underline (editor_page);
+       is_underline = dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_underline_element, &is_underline);
+
+       return is_underline;
+}
+
+static WebKitDOMElement *
+set_font_style (WebKitDOMDocument *document,
+                const gchar *element_name,
+                gboolean value)
+{
+       WebKitDOMElement *element;
+       WebKitDOMNode *parent;
+
+       element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-end-marker");
+       parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+       if (value) {
+               WebKitDOMNode *node;
+               WebKitDOMElement *el;
+               gchar *name;
+
+               el = webkit_dom_document_create_element (document, element_name, NULL);
+               webkit_dom_html_element_set_inner_text (
+                       WEBKIT_DOM_HTML_ELEMENT (el), UNICODE_ZERO_WIDTH_SPACE, NULL);
+
+               node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (el), node, NULL);
+               name = webkit_dom_node_get_local_name (parent);
+               if (g_strcmp0 (name, element_name) == 0 && g_strcmp0 (name, "font") != 0)
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               WEBKIT_DOM_NODE (el),
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+               else
+                       webkit_dom_node_insert_before (
+                               parent,
+                               WEBKIT_DOM_NODE (el),
+                               WEBKIT_DOM_NODE (element),
+                               NULL);
+               g_free (name);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (el), WEBKIT_DOM_NODE (element), NULL);
+
+               return el;
+       } else {
+               gboolean no_sibling;
+               WebKitDOMNode *node, *sibling;
+
+               node = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
+
+               /* Turning the formatting in the middle of element. */
+               sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+               no_sibling = sibling &&
+                       !WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) &&
+                       !webkit_dom_node_get_next_sibling (sibling);
+
+               if (no_sibling) {
+                       WebKitDOMNode *clone;
+                       WebKitDOMNode *sibling;
+
+                       clone = webkit_dom_node_clone_node_with_error (
+                               WEBKIT_DOM_NODE (parent), FALSE, NULL);
+
+                       while ((sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element))))
+                               webkit_dom_node_insert_before (
+                                       clone,
+                                       sibling,
+                                       webkit_dom_node_get_first_child (clone),
+                                       NULL);
+
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               clone,
+                               webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
+                               NULL);
+               }
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (parent),
+                       WEBKIT_DOM_NODE (element),
+                       webkit_dom_node_get_next_sibling (parent),
+                       NULL);
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (parent),
+                       node,
+                       webkit_dom_node_get_next_sibling (parent),
+                       NULL);
+
+               if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (sibling) && !no_sibling) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (parent),
+                               node,
+                               webkit_dom_node_get_next_sibling (parent),
+                               NULL);
+               }
+
+               webkit_dom_html_element_insert_adjacent_text (
+                       WEBKIT_DOM_HTML_ELEMENT (parent),
+                       "afterend",
+                       UNICODE_ZERO_WIDTH_SPACE,
+                       NULL);
+
+               remove_node_if_empty (parent);
+       }
+
+       return NULL;
+}
+
+static void
+selection_set_font_style (EEditorPage *editor_page,
+                          EContentEditorCommand command,
+                          gboolean value)
+{
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_dom_selection_save (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               if (command == E_CONTENT_EDITOR_COMMAND_BOLD)
+                       ev->type = HISTORY_BOLD;
+               else if (command == E_CONTENT_EDITOR_COMMAND_ITALIC)
+                       ev->type = HISTORY_ITALIC;
+               else if (command == E_CONTENT_EDITOR_COMMAND_UNDERLINE)
+                       ev->type = HISTORY_UNDERLINE;
+               else if (command == E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH)
+                       ev->type = HISTORY_STRIKETHROUGH;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.style.from = !value;
+               ev->data.style.to = value;
+       }
+
+       if (e_editor_dom_selection_is_collapsed (editor_page)) {
+               const gchar *element_name = NULL;
+
+               if (command == E_CONTENT_EDITOR_COMMAND_BOLD)
+                       element_name = "b";
+               else if (command == E_CONTENT_EDITOR_COMMAND_ITALIC)
+                       element_name = "i";
+               else if (command == E_CONTENT_EDITOR_COMMAND_UNDERLINE)
+                       element_name = "u";
+               else if (command == E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH)
+                       element_name = "strike";
+
+               if (element_name)
+                       set_font_style (e_editor_page_get_document (editor_page), element_name, value);
+               e_editor_dom_selection_restore (editor_page);
+
+               goto exit;
+       }
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_dom_exec_command (editor_page, command, NULL);
+exit:
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+/*
+ * e_html_editor_selection_set_underline:
+ * @selection: an #EEditorSelection
+ * @underline: @TRUE to enable underline, @FALSE to disable
+ *
+ * Toggles underline formatting of current selection or letter at current
+ * cursor position, depending on whether @underline is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_underline (EEditorPage *editor_page,
+                                     gboolean underline)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_dom_selection_is_underline (editor_page) == underline)
+               return;
+
+       selection_set_font_style (
+               editor_page, E_CONTENT_EDITOR_COMMAND_UNDERLINE, underline);
+}
+
+static gboolean
+is_subscript_element (WebKitDOMElement *element)
+{
+       if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       return element_has_tag (element, "sub");
+}
+
+/*
+ * e_html_editor_selection_is_subscript:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is in subscript.
+ *
+ * Returns @TRUE when selection is in subscript, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_subscript (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_subscript_element, NULL);
+}
+
+/*
+ * e_html_editor_selection_set_subscript:
+ * @selection: an #EEditorSelection
+ * @subscript: @TRUE to enable subscript, @FALSE to disable
+ *
+ * Toggles subscript of current selection or letter at current cursor position,
+ * depending on whether @subscript is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_subscript (EEditorPage *editor_page,
+                                     gboolean subscript)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_dom_selection_is_subscript (editor_page) == subscript)
+               return;
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_SUBSCRIPT, NULL);
+}
+
+static gboolean
+is_superscript_element (WebKitDOMElement *element)
+{
+       if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       return element_has_tag (element, "sup");
+}
+
+/*
+ * e_html_editor_selection_is_superscript:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is in superscript.
+ *
+ * Returns @TRUE when selection is in superscript, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_superscript (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_superscript_element, NULL);
+}
+
+/*
+ * e_html_editor_selection_set_superscript:
+ * @selection: an #EEditorSelection
+ * @superscript: @TRUE to enable superscript, @FALSE to disable
+ *
+ * Toggles superscript of current selection or letter at current cursor position,
+ * depending on whether @superscript is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_superscript (EEditorPage *editor_page,
+                                       gboolean superscript)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_dom_selection_is_superscript (editor_page) == superscript)
+               return;
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_SUPERSCRIPT, NULL);
+}
+
+static gboolean
+is_strikethrough_element (WebKitDOMElement *element)
+{
+       if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       return element_has_tag (element, "strike");
+}
+
+/*
+ * e_html_editor_selection_is_strikethrough:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is striked through.
+ *
+ * Returns @TRUE when selection is striked through, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_strikethrough (EEditorPage *editor_page)
+{
+       gboolean is_strikethrough;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       is_strikethrough = e_editor_page_get_strikethrough (editor_page);
+       is_strikethrough = dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_strikethrough_element, &is_strikethrough);
+
+       return is_strikethrough;
+}
+
+/*
+ * e_html_editor_selection_set_strikethrough:
+ * @selection: an #EEditorSelection
+ * @strikethrough: @TRUE to enable strikethrough, @FALSE to disable
+ *
+ * Toggles strike through formatting of current selection or letter at current
+ * cursor position, depending on whether @strikethrough is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_strikethrough (EEditorPage *editor_page,
+                                         gboolean strikethrough)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_dom_selection_is_strikethrough (editor_page) == strikethrough)
+               return;
+
+       selection_set_font_style (
+               editor_page, E_CONTENT_EDITOR_COMMAND_STRIKETHROUGH, strikethrough);
+}
+
+static gboolean
+is_monospace_element (WebKitDOMElement *element)
+{
+       gchar *value;
+       gboolean ret_val = FALSE;
+
+       if (!element)
+               return FALSE;
+
+       if (!WEBKIT_DOM_IS_HTML_FONT_ELEMENT (element))
+               return FALSE;
+
+       value = webkit_dom_element_get_attribute (element, "face");
+       if (value && g_strcmp0 (value, "monospace") == 0)
+               ret_val = TRUE;
+
+       g_free (value);
+
+       return ret_val;
+}
+
+/*
+ * e_html_editor_selection_is_monospaced:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is monospaced.
+ *
+ * Returns @TRUE when selection is monospaced, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_monospace (EEditorPage *editor_page)
+{
+       gboolean is_monospace;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       is_monospace = e_editor_page_get_monospace (editor_page);
+       is_monospace = dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_monospace_element, &is_monospace);
+
+       return is_monospace;
+}
+
+static void
+monospace_selection (EEditorPage *editor_page,
+                     WebKitDOMElement *monospace_element)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *sibling, *node, *monospace, *block;
+       WebKitDOMNodeList *list;
+       gboolean selection_end = FALSE;
+       gboolean first = TRUE;
+       gint length, ii;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       selection_end_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+
+       block = WEBKIT_DOM_NODE (get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker)));
+
+       monospace = WEBKIT_DOM_NODE (monospace_element);
+       node = WEBKIT_DOM_NODE (selection_start_marker);
+       /* Go through first block in selection. */
+       while (block && node && !webkit_dom_node_is_same_node (block, node)) {
+               if (webkit_dom_node_get_next_sibling (node)) {
+                       /* Prepare the monospaced element. */
+                       monospace = webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (node),
+                               first ? monospace : webkit_dom_node_clone_node_with_error (monospace, FALSE, 
NULL),
+                               first ? node : webkit_dom_node_get_next_sibling (node),
+                               NULL);
+               } else
+                       break;
+
+               /* Move the nodes into monospaced element. */
+               while (((sibling = webkit_dom_node_get_next_sibling (monospace)))) {
+                       webkit_dom_node_append_child (monospace, sibling, NULL);
+                       if (webkit_dom_node_is_same_node (WEBKIT_DOM_NODE (selection_end_marker), sibling)) {
+                               selection_end = TRUE;
+                               break;
+                       }
+               }
+
+               node = webkit_dom_node_get_parent_node (monospace);
+               first = FALSE;
+       }
+
+       /* Just one block was selected. */
+       if (selection_end)
+               goto out;
+
+       /* Middle blocks (blocks not containing the end of the selection. */
+       block = webkit_dom_node_get_next_sibling (block);
+       while (block && !selection_end) {
+               WebKitDOMNode *next_block;
+
+               selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               if (selection_end)
+                       break;
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               monospace = webkit_dom_node_insert_before (
+                       block,
+                       webkit_dom_node_clone_node_with_error (monospace, FALSE, NULL),
+                       webkit_dom_node_get_first_child (block),
+                       NULL);
+
+               while (((sibling = webkit_dom_node_get_next_sibling (monospace))))
+                       webkit_dom_node_append_child (monospace, sibling, NULL);
+
+               block = next_block;
+       }
+
+       /* Block containing the end of selection. */
+       node = WEBKIT_DOM_NODE (selection_end_marker);
+       while (block && node && !webkit_dom_node_is_same_node (block, node)) {
+               monospace = webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (node),
+                       webkit_dom_node_clone_node_with_error (monospace, FALSE, NULL),
+                       webkit_dom_node_get_next_sibling (node),
+                       NULL);
+
+               while (((sibling = webkit_dom_node_get_previous_sibling (monospace)))) {
+                       webkit_dom_node_insert_before (
+                               monospace,
+                               sibling,
+                               webkit_dom_node_get_first_child (monospace),
+                               NULL);
+               }
+
+               node = webkit_dom_node_get_parent_node (monospace);
+       }
+ out:
+       /* Merge all the monospace elements inside other monospace elements. */
+       list = webkit_dom_document_query_selector_all (
+               document, "font[face=monospace] > font[face=monospace]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *item;
+               WebKitDOMNode *child;
+
+               item = webkit_dom_node_list_item (list, ii);
+               while ((child = webkit_dom_node_get_first_child (item))) {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (item),
+                               child,
+                               item,
+                               NULL);
+               }
+               remove_node (item);
+               g_object_unref (item);
+       }
+       g_object_unref (list);
+
+       /* Merge all the adjacent monospace elements. */
+       list = webkit_dom_document_query_selector_all (
+               document, "font[face=monospace] + font[face=monospace]", NULL);
+       length = webkit_dom_node_list_get_length (list);
+       for (ii = 0; ii < length; ii++) {
+               WebKitDOMNode *item;
+               WebKitDOMNode *child;
+
+               item = webkit_dom_node_list_item (list, ii);
+               /* The + CSS selector will return some false positives as it doesn't
+                * take text between elements into account so it will return this:
+                * <font face="monospace">xx</font>yy<font face="monospace">zz</font>
+                * as valid, but it isn't so we have to check if previous node
+                * is indeed element or not. */
+               if (WEBKIT_DOM_IS_ELEMENT (webkit_dom_node_get_previous_sibling (item))) {
+                       while ((child = webkit_dom_node_get_first_child (item))) {
+                               webkit_dom_node_append_child (
+                                       webkit_dom_node_get_previous_sibling (item), child, NULL);
+                       }
+                       remove_node (item);
+               }
+               g_object_unref (item);
+       }
+       g_object_unref (list);
+
+       e_editor_dom_selection_restore (editor_page);
+}
+
+static void
+unmonospace_selection (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker;
+       WebKitDOMElement *selection_end_marker;
+       WebKitDOMElement *selection_start_clone;
+       WebKitDOMElement *selection_end_clone;
+       WebKitDOMNode *sibling, *node;
+       WebKitDOMNode *block, *clone, *monospace;
+       gboolean selection_end = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       selection_end_marker = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+
+       block = WEBKIT_DOM_NODE (get_parent_block_element (WEBKIT_DOM_NODE (selection_start_marker)));
+
+       node = WEBKIT_DOM_NODE (selection_start_marker);
+       monospace = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
+       while (monospace && !is_monospace_element (WEBKIT_DOM_ELEMENT (monospace)))
+               monospace = webkit_dom_node_get_parent_node (monospace);
+
+       /* No monospaced element was found as a parent of selection start node. */
+       if (!monospace)
+               goto out;
+
+       /* Make a clone of current monospaced element. */
+       clone = webkit_dom_node_clone_node_with_error (monospace, TRUE, NULL);
+
+       /* First block */
+       /* Remove all the nodes that are after the selection start point as they
+        * will be in the cloned node. */
+       while (monospace && node && !webkit_dom_node_is_same_node (monospace, node)) {
+               WebKitDOMNode *tmp;
+               while (((sibling = webkit_dom_node_get_next_sibling (node))))
+                       remove_node (sibling);
+
+               tmp = webkit_dom_node_get_parent_node (node);
+               if (webkit_dom_node_get_next_sibling (node))
+                       remove_node (node);
+               node = tmp;
+       }
+
+       selection_start_clone = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (clone), "#-x-evo-selection-start-marker", NULL);
+       selection_end_clone = webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (clone), "#-x-evo-selection-end-marker", NULL);
+
+       /* No selection start node in the block where it is supposed to be, return. */
+       if (!selection_start_clone)
+               goto out;
+
+       /* Remove all the nodes until we hit the selection start point as these
+        * nodes will stay monospaced and they are already in original element. */
+       node = webkit_dom_node_get_first_child (clone);
+       while (node) {
+               WebKitDOMNode *next_sibling;
+
+               next_sibling = webkit_dom_node_get_next_sibling (node);
+               if (webkit_dom_node_get_first_child (node)) {
+                       if (webkit_dom_node_contains (node, WEBKIT_DOM_NODE (selection_start_clone))) {
+                               node = webkit_dom_node_get_first_child (node);
+                               continue;
+                       } else
+                               remove_node (node);
+               } else if (webkit_dom_node_is_same_node (node, WEBKIT_DOM_NODE (selection_start_clone)))
+                       break;
+               else
+                       remove_node (node);
+
+               node = next_sibling;
+       }
+
+       /* Insert the clone into the tree. Do it after the previous clean up. If
+        * we would do it the other way the line would contain duplicated text nodes
+        * and the block would be expading and shrinking while we would modify it. */
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (monospace),
+               clone,
+               webkit_dom_node_get_next_sibling (monospace),
+               NULL);
+
+       /* Move selection start point the right place. */
+       remove_node (WEBKIT_DOM_NODE (selection_start_marker));
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (clone),
+               WEBKIT_DOM_NODE (selection_start_clone),
+               clone,
+               NULL);
+
+       /* Move all the nodes the are supposed to lose the monospace formatting
+        * out of monospaced element. */
+       node = webkit_dom_node_get_first_child (clone);
+       while (node) {
+               WebKitDOMNode *next_sibling;
+
+               next_sibling = webkit_dom_node_get_next_sibling (node);
+               if (webkit_dom_node_get_first_child (node)) {
+                       if (selection_end_clone &&
+                           webkit_dom_node_contains (node, WEBKIT_DOM_NODE (selection_end_clone))) {
+                               node = webkit_dom_node_get_first_child (node);
+                               continue;
+                       } else
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (clone),
+                                       node,
+                                       clone,
+                                       NULL);
+               } else if (selection_end_clone &&
+                          webkit_dom_node_is_same_node (node, WEBKIT_DOM_NODE (selection_end_clone))) {
+                       selection_end = TRUE;
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (clone),
+                               node,
+                               clone,
+                               NULL);
+                       break;
+               } else
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (clone),
+                               node,
+                               clone,
+                               NULL);
+
+               node = next_sibling;
+       }
+
+       if (!webkit_dom_node_get_first_child (clone))
+               remove_node (clone);
+
+       /* Just one block was selected and we hit the selection end point. */
+       if (selection_end)
+               goto out;
+
+       /* Middle blocks */
+       block = webkit_dom_node_get_next_sibling (block);
+       while (block && !selection_end) {
+               WebKitDOMNode *next_block, *child, *parent;
+               WebKitDOMElement *monospace_element;
+
+               selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               if (selection_end)
+                       break;
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               /* Find the monospaced element and move all the nodes from it and
+                * finally remove it. */
+               monospace_element = webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block), "font[face=monospace]", NULL);
+               if (!monospace_element)
+                       break;
+
+               parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (monospace_element));
+               while  ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (monospace_element)))) {
+                       webkit_dom_node_insert_before (
+                               parent, child, WEBKIT_DOM_NODE (monospace_element), NULL);
+               }
+
+               remove_node (WEBKIT_DOM_NODE (monospace_element));
+
+               block = next_block;
+       }
+
+       /* End block */
+       node = WEBKIT_DOM_NODE (selection_end_marker);
+       monospace = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_end_marker));
+       while (monospace && !is_monospace_element (WEBKIT_DOM_ELEMENT (monospace)))
+               monospace = webkit_dom_node_get_parent_node (monospace);
+
+       /* No monospaced element was found as a parent of selection end node. */
+       if (!monospace)
+               return;
+
+       clone = WEBKIT_DOM_NODE (monospace);
+       node = webkit_dom_node_get_first_child (clone);
+       /* Move all the nodes that are supposed to lose the monospaced formatting
+        * out of the monospaced element. */
+       while (node) {
+               WebKitDOMNode *next_sibling;
+
+               next_sibling = webkit_dom_node_get_next_sibling (node);
+               if (webkit_dom_node_get_first_child (node)) {
+                       if (webkit_dom_node_contains (node, WEBKIT_DOM_NODE (selection_end_marker))) {
+                               node = webkit_dom_node_get_first_child (node);
+                               continue;
+                       } else
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (clone),
+                                       node,
+                                       clone,
+                                       NULL);
+               } else if (webkit_dom_node_is_same_node (node, WEBKIT_DOM_NODE (selection_end_marker))) {
+                       selection_end = TRUE;
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (clone),
+                               node,
+                               clone,
+                               NULL);
+                       break;
+               } else {
+                       webkit_dom_node_insert_before (
+                               webkit_dom_node_get_parent_node (clone),
+                               node,
+                               clone,
+                               NULL);
+               }
+
+               node = next_sibling;
+       }
+
+       if (!webkit_dom_node_get_first_child (clone))
+               remove_node (clone);
+ out:
+       e_editor_dom_selection_restore (editor_page);
+}
+
+/*
+ * e_html_editor_selection_set_monospaced:
+ * @selection: an #EEditorSelection
+ * @monospaced: @TRUE to enable monospaced, @FALSE to disable
+ *
+ * Toggles monospaced formatting of current selection or letter at current cursor
+ * position, depending on whether @monospaced is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_monospace (EEditorPage *editor_page,
+                                     gboolean value)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMRange *range;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+       guint font_size = 0;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if ((e_editor_dom_selection_is_monospace (editor_page) ? 1 : 0) == (value ? 1 : 0))
+               return;
+
+       document = e_editor_page_get_document (editor_page);
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return;
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_MONOSPACE;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.style.from = !value;
+               ev->data.style.to = value;
+       }
+
+       font_size = e_editor_page_get_font_size (editor_page);
+       if (font_size == 0)
+               font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       if (value) {
+               WebKitDOMElement *monospace;
+
+               monospace = webkit_dom_document_create_element (
+                       document, "font", NULL);
+               webkit_dom_element_set_attribute (
+                       monospace, "face", "monospace", NULL);
+               if (font_size != 0) {
+                       gchar *font_size_str;
+
+                       font_size_str = g_strdup_printf ("%d", font_size);
+                       webkit_dom_element_set_attribute (
+                               monospace, "size", font_size_str, NULL);
+                       g_free (font_size_str);
+               }
+
+               if (!webkit_dom_range_get_collapsed (range, NULL))
+                       monospace_selection (editor_page, monospace);
+               else {
+                       /* https://bugs.webkit.org/show_bug.cgi?id=15256 */
+                       webkit_dom_element_set_inner_html (
+                               monospace,
+                               UNICODE_ZERO_WIDTH_SPACE,
+                               NULL);
+                       webkit_dom_range_insert_node (
+                               range, WEBKIT_DOM_NODE (monospace), NULL);
+
+                       e_editor_dom_move_caret_into_element (editor_page, monospace, FALSE);
+               }
+       } else {
+               gboolean is_bold = FALSE, is_italic = FALSE;
+               gboolean is_underline = FALSE, is_strikethrough = FALSE;
+               guint font_size = 0;
+               WebKitDOMElement *tt_element;
+               WebKitDOMNode *node;
+
+               node = webkit_dom_range_get_end_container (range, NULL);
+               if (WEBKIT_DOM_IS_ELEMENT (node) &&
+                   is_monospace_element (WEBKIT_DOM_ELEMENT (node))) {
+                       tt_element = WEBKIT_DOM_ELEMENT (node);
+               } else {
+                       tt_element = dom_node_find_parent_element (node, "FONT");
+
+                       if (!is_monospace_element (tt_element)) {
+                               g_object_unref (range);
+                               g_object_unref (dom_selection);
+                               g_object_unref (dom_window);
+                               g_free (ev);
+                               return;
+                       }
+               }
+
+               /* Save current formatting */
+               is_bold = e_editor_page_get_bold (editor_page);
+               is_italic = e_editor_page_get_italic (editor_page);
+               is_underline = e_editor_page_get_underline (editor_page);
+               is_strikethrough = e_editor_page_get_strikethrough (editor_page);
+
+               if (!e_editor_dom_selection_is_collapsed (editor_page))
+                       unmonospace_selection (editor_page);
+               else {
+                       e_editor_dom_selection_save (editor_page);
+                       set_font_style (document, "", FALSE);
+                       e_editor_dom_selection_restore (editor_page);
+               }
+
+               /* Re-set formatting */
+               if (is_bold)
+                       e_editor_dom_selection_set_bold (editor_page, TRUE);
+               if (is_italic)
+                       e_editor_dom_selection_set_italic (editor_page, TRUE);
+               if (is_underline)
+                       e_editor_dom_selection_set_underline (editor_page, TRUE);
+               if (is_strikethrough)
+                       e_editor_dom_selection_set_strikethrough (editor_page, TRUE);
+
+               if (font_size)
+                       e_editor_dom_selection_set_font_size (editor_page, font_size);
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+}
+
+static gboolean
+is_bold_element (WebKitDOMElement *element)
+{
+       if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       if (element_has_tag (element, "b"))
+               return TRUE;
+
+       /* Headings are bold by default */
+       return WEBKIT_DOM_IS_HTML_HEADING_ELEMENT (element);
+}
+
+/*
+ * e_html_editor_selection_is_bold:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is bold.
+ *
+ * Returns @TRUE when selection is bold, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_bold (EEditorPage *editor_page)
+{
+       gboolean is_bold;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       is_bold = e_editor_page_get_bold (editor_page);
+
+       is_bold = dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_bold_element, &is_bold);
+
+       return is_bold;
+}
+
+/*
+ * e_html_editor_selection_set_bold:
+ * @selection: an #EEditorSelection
+ * @bold: @TRUE to enable bold, @FALSE to disable
+ *
+ * Toggles bold formatting of current selection or letter at current cursor
+ * position, depending on whether @bold is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_bold (EEditorPage *editor_page,
+                                gboolean bold)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_dom_selection_is_bold (editor_page) == bold)
+               return;
+
+       selection_set_font_style (
+               editor_page, E_CONTENT_EDITOR_COMMAND_BOLD, bold);
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+static gboolean
+is_italic_element (WebKitDOMElement *element)
+{
+       if (!element || !WEBKIT_DOM_IS_ELEMENT (element))
+               return FALSE;
+
+       return element_has_tag (element, "i") || element_has_tag (element, "address");
+}
+
+/*
+ * e_html_editor_selection_is_italic:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current selection or letter at current cursor position
+ * is italic.
+ *
+ * Returns @TRUE when selection is italic, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_italic (EEditorPage *editor_page)
+{
+       gboolean is_italic;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       is_italic = e_editor_page_get_italic (editor_page);
+       is_italic = dom_selection_is_font_format (
+               editor_page, (IsRightFormatNodeFunc) is_italic_element, &is_italic);
+
+       return is_italic;
+}
+
+/*
+ * e_html_editor_selection_set_italic:
+ * @selection: an #EEditorSelection
+ * @italic: @TRUE to enable italic, @FALSE to disable
+ *
+ * Toggles italic formatting of current selection or letter at current cursor
+ * position, depending on whether @italic is @TRUE or @FALSE.
+ */
+void
+e_editor_dom_selection_set_italic (EEditorPage *editor_page,
+                                  gboolean italic)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_dom_selection_is_italic (editor_page) == italic)
+               return;
+
+       selection_set_font_style (
+               editor_page, E_CONTENT_EDITOR_COMMAND_ITALIC, italic);
+}
+
+/*
+ * e_html_editor_selection_is_indented:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current paragraph is indented. This does not include
+ * citations.  To check, whether paragraph is a citation, use
+ * e_html_editor_selection_is_citation().
+ *
+ * Returns: @TRUE when current paragraph is indented, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_indented (EEditorPage *editor_page)
+{
+       WebKitDOMElement *element;
+       WebKitDOMRange *range;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return FALSE;
+
+       if (webkit_dom_range_get_collapsed (range, NULL)) {
+               element = get_element_for_inspection (range);
+               g_object_unref (range);
+               return element_has_class (element, "-x-evo-indented");
+       } else {
+               WebKitDOMNode *node;
+               gboolean ret_val;
+
+               node = webkit_dom_range_get_end_container (range, NULL);
+               /* No selection or whole body selected */
+               if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node))
+                       goto out;
+
+               element = WEBKIT_DOM_ELEMENT (get_parent_indented_block (node));
+               ret_val = element_has_class (element, "-x-evo-indented");
+               if (!ret_val)
+                       goto out;
+
+               node = webkit_dom_range_get_start_container (range, NULL);
+               /* No selection or whole body selected */
+               if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (node))
+                       goto out;
+
+               element = WEBKIT_DOM_ELEMENT (get_parent_indented_block (node));
+               ret_val = element_has_class (element, "-x-evo-indented");
+
+               g_object_unref (range);
+
+               return ret_val;
+       }
+
+ out:
+       g_object_unref (range);
+
+       return FALSE;
+}
+
+/*
+ * e_html_editor_selection_is_citation:
+ * @selection: an #EEditorSelection
+ *
+ * Returns whether current paragraph is a citation.
+ *
+ * Returns: @TRUE when current paragraph is a citation, @FALSE otherwise.
+ */
+gboolean
+e_editor_dom_selection_is_citation (EEditorPage *editor_page)
+{
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       gboolean ret_val;
+       gchar *value, *text_content;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return FALSE;
+
+       node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+       g_object_unref (range);
+
+       if (WEBKIT_DOM_IS_TEXT (node))
+               return get_has_style (editor_page, "citation");
+
+       text_content = webkit_dom_node_get_text_content (node);
+       if (g_strcmp0 (text_content, "") == 0) {
+               g_free (text_content);
+               return FALSE;
+       }
+       g_free (text_content);
+
+       value = webkit_dom_element_get_attribute (WEBKIT_DOM_ELEMENT (node), "type");
+       /* citation == <blockquote type='cite'> */
+       if (value && strstr (value, "cite"))
+               ret_val = TRUE;
+       else
+               ret_val = get_has_style (editor_page, "citation");
+
+       g_free (value);
+       return ret_val;
+}
+
+static gchar *
+get_font_property (EEditorPage *editor_page,
+                   const gchar *font_property)
+{
+       WebKitDOMRange *range;
+       WebKitDOMNode *node;
+       WebKitDOMElement *element;
+       gchar *value;
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return NULL;
+
+       node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+       g_object_unref (range);
+       element = dom_node_find_parent_element (node, "FONT");
+       while (element && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (element) &&
+              !webkit_dom_element_has_attribute (element, font_property)) {
+               element = dom_node_find_parent_element (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)), "FONT");
+       }
+
+       if (!element)
+               return NULL;
+
+       g_object_get (G_OBJECT (element), font_property, &value, NULL);
+
+       return value;
+}
+
+/*
+ * e_editor_dom_selection_get_font_size:
+ * @selection: an #EEditorSelection
+ *
+ * Returns point size of current selection or of letter at current cursor position.
+ */
+guint
+e_editor_dom_selection_get_font_size (EEditorPage *editor_page)
+{
+       gchar *size;
+       guint size_int;
+       gboolean increment;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       size = get_font_property (editor_page, "size");
+       if (!(size && *size)) {
+               g_free (size);
+               return E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+       }
+
+       /* We don't support increments, but when going through a content that
+        * was not written in Evolution we can find it. In this case just report
+        * the normal size. */
+       /* FIXME: go through all parent and get the right value. */
+       increment = size[0] == '+' || size[0] == '-';
+       size_int = atoi (size);
+       g_free (size);
+
+       if (increment || size_int == 0)
+               return E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+
+       return size_int;
+}
+
+/*
+ * e_html_editor_selection_set_font_size:
+ * @selection: an #EEditorSelection
+ * @font_size: point size to apply
+ *
+ * Sets font size of current selection or of letter at current cursor position
+ * to @font_size.
+ */
+void
+e_editor_dom_selection_set_font_size (EEditorPage *editor_page,
+                                     EContentEditorFontSize font_size)
+{
+       WebKitDOMDocument *document;
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       gchar *size_str;
+       guint current_font_size;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       current_font_size = e_editor_dom_selection_get_font_size (editor_page);
+       if (current_font_size == font_size)
+               return;
+
+       e_editor_dom_selection_save (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_FONT_SIZE;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.style.from = current_font_size;
+               ev->data.style.to = font_size;
+       }
+
+       size_str = g_strdup_printf ("%d", font_size);
+
+       if (e_editor_dom_selection_is_collapsed (editor_page)) {
+               WebKitDOMElement *font;
+
+               font = set_font_style (document, "font", font_size != 3);
+               if (font)
+                       webkit_dom_element_set_attribute (font, "size", size_str, NULL);
+               e_editor_dom_selection_restore (editor_page);
+               goto exit;
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_FONT_SIZE, size_str);
+
+       /* Text in <font size="3"></font> (size 3 is our default size) is a little
+        * bit smaller than font outsize it. So move it outside of it. */
+       if (font_size == E_CONTENT_EDITOR_FONT_SIZE_NORMAL) {
+               WebKitDOMElement *element;
+
+               element = webkit_dom_document_query_selector (document, "font[size=\"3\"]", NULL);
+               if (element) {
+                       WebKitDOMNode *child;
+
+                       while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                                       child,
+                                       WEBKIT_DOM_NODE (element),
+                                       NULL);
+
+                       remove_node (WEBKIT_DOM_NODE (element));
+               }
+       }
+
+ exit:
+       g_free (size_str);
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
+/*
+ * e_html_editor_selection_set_font_name:
+ * @selection: an #EEditorSelection
+ * @font_name: a font name to apply
+ *
+ * Sets font name of current selection or of letter at current cursor position
+ * to @font_name.
+ */
+void
+e_editor_dom_selection_set_font_name (EEditorPage *editor_page,
+                                     const gchar *font_name)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_FONT_NAME, font_name);
+}
+
+/*
+ * e_html_editor_selection_get_font_name:
+ * @selection: an #EEditorSelection
+ *
+ * Returns name of font used in current selection or at letter at current cursor
+ * position.
+ *
+ * Returns: A string with font name. [transfer-none]
+ */
+gchar *
+e_editor_dom_selection_get_font_name (EEditorPage *editor_page)
+{
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       WebKitDOMCSSStyleDeclaration *css;
+       gchar *value;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       node = webkit_dom_range_get_common_ancestor_container (range, NULL);
+       g_object_unref (range);
+
+       css = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (node));
+       value = webkit_dom_css_style_declaration_get_property_value (css, "fontFamily");
+       g_object_unref (css);
+
+       return value;
+}
+
+/*
+ * e_html_editor_selection_set_font_color:
+ * @selection: an #EEditorSelection
+ * @rgba: a #GdkRGBA
+ *
+ * Sets font color of current selection or letter at current cursor position to
+ * color defined in @rgba.
+ */
+void
+e_editor_dom_selection_set_font_color (EEditorPage *editor_page,
+                                      const gchar *color)
+{
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_FONT_COLOR;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.string.from = g_strdup (e_editor_page_get_font_color (editor_page));
+               ev->data.string.to = g_strdup (color);
+       }
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_FORE_COLOR, color);
+
+       if (ev) {
+               ev->after.start.x = ev->before.start.x;
+               ev->after.start.y = ev->before.start.y;
+               ev->after.end.x = ev->before.end.x;
+               ev->after.end.y = ev->before.end.y;
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
+/*
+ * e_html_editor_selection_get_font_color:
+ * @selection: an #EEditorSelection
+ * @rgba: a #GdkRGBA object to be set to current font color
+ *
+ * Sets @rgba to contain color of current text selection or letter at current
+ * cursor position.
+ */
+gchar *
+e_editor_dom_selection_get_font_color (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       gchar *color;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       color = get_font_property (editor_page, "color");
+       if (!(color && *color)) {
+               WebKitDOMHTMLElement *body;
+
+               body = webkit_dom_document_get_body (document);
+               g_free (color);
+               color = webkit_dom_html_body_element_get_text (WEBKIT_DOM_HTML_BODY_ELEMENT (body));
+               if (!(color && *color)) {
+                       g_free (color);
+                       return g_strdup ("#000000");
+               }
+       }
+
+       return color;
+}
+
+/*
+ * e_html_editor_selection_get_block_format:
+ * @selection: an #EEditorSelection
+ *
+ * Returns block format of current paragraph.
+ *
+ * Returns: #EContentEditorBlockFormat
+ */
+EContentEditorBlockFormat
+e_editor_dom_selection_get_block_format (EEditorPage *editor_page)
+{
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       WebKitDOMElement *element;
+       EContentEditorBlockFormat result;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_BLOCK_FORMAT_NONE);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+
+       if ((element = dom_node_find_parent_element (node, "UL"))) {
+               WebKitDOMElement *tmp_element;
+
+               tmp_element = dom_node_find_parent_element (node, "OL");
+               if (tmp_element) {
+                       if (webkit_dom_node_contains (WEBKIT_DOM_NODE (tmp_element), WEBKIT_DOM_NODE 
(element)))
+                               result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (element));
+                       else
+                               result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (tmp_element));
+               } else
+                       result = E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+       } else if ((element = dom_node_find_parent_element (node, "OL")) != NULL) {
+               WebKitDOMElement *tmp_element;
+
+               tmp_element = dom_node_find_parent_element (node, "UL");
+               if (tmp_element) {
+                       if (webkit_dom_node_contains (WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE 
(tmp_element)))
+                               result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (element));
+                       else
+                               result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (tmp_element));
+               } else
+                       result = dom_get_list_format_from_node (WEBKIT_DOM_NODE (element));
+       } else if (dom_node_find_parent_element (node, "PRE")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_PRE;
+       } else if (dom_node_find_parent_element (node, "ADDRESS")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS;
+       } else if (dom_node_find_parent_element (node, "H1")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_H1;
+       } else if (dom_node_find_parent_element (node, "H2")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_H2;
+       } else if (dom_node_find_parent_element (node, "H3")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_H3;
+       } else if (dom_node_find_parent_element (node, "H4")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_H4;
+       } else if (dom_node_find_parent_element (node, "H5")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_H5;
+       } else if (dom_node_find_parent_element (node, "H6")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_H6;
+       } else if ((element = dom_node_find_parent_element (node, "BLOCKQUOTE")) != NULL) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+       } else if (dom_node_find_parent_element (node, "P")) {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+       } else {
+               result = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+       }
+
+       g_object_unref (range);
+
+       return result;
+}
+
+static void
+change_leading_space_to_nbsp (WebKitDOMNode *block)
+{
+       WebKitDOMNode *child;
+
+       if (!WEBKIT_DOM_IS_HTML_PRE_ELEMENT (block))
+               return;
+
+       if ((child = webkit_dom_node_get_first_child (block)) &&
+            WEBKIT_DOM_IS_CHARACTER_DATA (child)) {
+               gchar *data;
+
+               data = webkit_dom_character_data_substring_data (
+                       WEBKIT_DOM_CHARACTER_DATA (child), 0, 1, NULL);
+
+               if (data && *data == ' ')
+                       webkit_dom_character_data_replace_data (
+                               WEBKIT_DOM_CHARACTER_DATA (child), 0, 1, UNICODE_NBSP, NULL);
+               g_free (data);
+       }
+}
+
+static void
+change_trailing_space_in_block_to_nbsp (WebKitDOMNode *block)
+{
+       WebKitDOMNode *child;
+
+       if ((child = webkit_dom_node_get_last_child (block)) &&
+           WEBKIT_DOM_IS_CHARACTER_DATA (child)) {
+               gchar *tmp;
+               gulong length;
+
+               length = webkit_dom_character_data_get_length (
+                       WEBKIT_DOM_CHARACTER_DATA (child));
+
+               tmp = webkit_dom_character_data_substring_data (
+                       WEBKIT_DOM_CHARACTER_DATA (child), length - 1, 1, NULL);
+               if (tmp && *tmp == ' ') {
+                       webkit_dom_character_data_replace_data (
+                               WEBKIT_DOM_CHARACTER_DATA (child),
+                               length - 1,
+                               1,
+                               UNICODE_NBSP,
+                               NULL);
+               }
+               g_free (tmp);
+       }
+}
+
+static void
+change_space_before_selection_to_nbsp (WebKitDOMNode *node)
+{
+       WebKitDOMNode *prev_sibling;
+
+       if ((prev_sibling = webkit_dom_node_get_previous_sibling (node))) {
+               if (WEBKIT_DOM_IS_CHARACTER_DATA (prev_sibling)) {
+                       gchar *tmp;
+                       gulong length;
+
+                       length = webkit_dom_character_data_get_length (
+                               WEBKIT_DOM_CHARACTER_DATA (prev_sibling));
+
+                       tmp = webkit_dom_character_data_substring_data (
+                               WEBKIT_DOM_CHARACTER_DATA (prev_sibling), length - 1, 1, NULL);
+                       if (tmp && *tmp == ' ') {
+                               webkit_dom_character_data_replace_data (
+                                       WEBKIT_DOM_CHARACTER_DATA (prev_sibling),
+                                       length - 1,
+                                       1,
+                                       UNICODE_NBSP,
+                                       NULL);
+                       }
+                       g_free (tmp);
+               }
+       }
+}
+
+static gboolean
+process_block_to_block (EEditorPage *editor_page,
+                        EContentEditorBlockFormat format,
+                        const gchar *value,
+                        WebKitDOMNode *block,
+                        WebKitDOMNode *end_block,
+                        WebKitDOMNode *blockquote,
+                        gboolean html_mode)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMNode *next_block;
+       gboolean after_selection_end = FALSE;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       document = e_editor_page_get_document (editor_page);
+
+       while (!after_selection_end && block) {
+               gboolean quoted = FALSE;
+               gboolean empty = FALSE;
+               gchar *content;
+               WebKitDOMNode *child;
+               WebKitDOMElement *element;
+
+               if (e_editor_dom_node_is_citation_node (block)) {
+                       gboolean finished;
+
+                       next_block = webkit_dom_node_get_next_sibling (block);
+                       finished = process_block_to_block (
+                               editor_page,
+                               format,
+                               value,
+                               webkit_dom_node_get_first_child (block),
+                               end_block,
+                               blockquote,
+                               html_mode);
+
+                       if (finished)
+                               return TRUE;
+
+                       block = next_block;
+
+                       continue;
+               }
+
+               if (webkit_dom_element_query_selector (
+                       WEBKIT_DOM_ELEMENT (block), "span.-x-evo-quoted", NULL)) {
+                       quoted = TRUE;
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+               }
+
+               if (!html_mode)
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+
+               after_selection_end = webkit_dom_node_is_same_node (block, end_block);
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               if (node_is_list (block)) {
+                       WebKitDOMNode *item;
+
+                       item = webkit_dom_node_get_first_child (block);
+                       while (item && !WEBKIT_DOM_IS_HTML_LI_ELEMENT (item))
+                               item = webkit_dom_node_get_first_child (item);
+
+                       if (item && do_format_change_list_to_block (editor_page, format, item, value))
+                               return TRUE;
+
+                       block = next_block;
+
+                       continue;
+               }
+
+               if (format == E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH)
+                       element = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+               else
+                       element = webkit_dom_document_create_element (
+                               document, value, NULL);
+
+               content = webkit_dom_node_get_text_content (block);
+
+               empty = !*content || (g_strcmp0 (content, UNICODE_ZERO_WIDTH_SPACE) == 0);
+               g_free (content);
+
+               change_leading_space_to_nbsp (block);
+               change_trailing_space_in_block_to_nbsp (block);
+
+               while ((child = webkit_dom_node_get_first_child (block))) {
+                       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+                               empty = FALSE;
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (element), child, NULL);
+               }
+
+               if (empty) {
+                       WebKitDOMElement *br;
+
+                       br = webkit_dom_document_create_element (
+                               document, "BR", NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (br), NULL);
+               }
+
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (block),
+                       WEBKIT_DOM_NODE (element),
+                       block,
+                       NULL);
+
+               remove_node (block);
+
+               if (!next_block && !after_selection_end) {
+                       gint citation_level;
+
+                       citation_level = selection_get_citation_level (WEBKIT_DOM_NODE (element));
+
+                       if (citation_level > 0) {
+                               next_block = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element));
+                               next_block = webkit_dom_node_get_next_sibling (next_block);
+                       }
+               }
+
+               block = next_block;
+
+               if (!html_mode && format == E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH) {
+                       gint citation_level;
+
+                       citation_level = selection_get_citation_level (WEBKIT_DOM_NODE (element));
+
+                       if (citation_level > 0) {
+                               gint quote, word_wrap_length;
+
+                               word_wrap_length =
+                                       e_editor_page_get_word_wrap_length (editor_page);
+                               quote = citation_level ? citation_level * 2 : 0;
+
+                               element = e_editor_dom_wrap_paragraph_length (
+                                       editor_page, element, word_wrap_length - quote);
+
+                       }
+               }
+
+               if (!html_mode && quoted)
+                       e_editor_dom_quote_plain_text_element (editor_page, element);
+       }
+
+       return after_selection_end;
+}
+
+static void
+format_change_block_to_block (EEditorPage *editor_page,
+                              EContentEditorBlockFormat format,
+                              const gchar *value)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block, *end_block, *blockquote = NULL;
+       gboolean html_mode = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       /* If the selection was not saved, move it into the first child of body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMHTMLElement *body;
+               WebKitDOMNode *child;
+
+               body = webkit_dom_document_get_body (document);
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+       }
+
+       block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       end_block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_end_marker));
+
+       /* Process all blocks that are in the selection one by one */
+       process_block_to_block (
+               editor_page, format, value, block, end_block, blockquote, html_mode);
+}
+
+static void
+format_change_block_to_list (EEditorPage *editor_page,
+                             EContentEditorBlockFormat format)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker, *item, *list;
+       WebKitDOMNode *block, *next_block;
+       gboolean after_selection_end = FALSE, in_quote = FALSE;
+       gboolean html_mode = e_editor_page_get_html_mode (editor_page);
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       /* If the selection was not saved, move it into the first child of body */
+       if (!selection_start_marker || !selection_end_marker) {
+               WebKitDOMHTMLElement *body;
+               WebKitDOMNode *child;
+
+               body = webkit_dom_document_get_body (document);
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body));
+
+               dom_add_selection_markers_into_element_start (
+                       document,
+                       WEBKIT_DOM_ELEMENT (child),
+                       &selection_start_marker,
+                       &selection_end_marker);
+       }
+
+       block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       list = create_list_element (editor_page, format, 0, html_mode);
+
+       if (webkit_dom_element_query_selector (
+               WEBKIT_DOM_ELEMENT (block), "span.-x-evo-quoted", NULL)) {
+               WebKitDOMElement *element;
+               WebKitDOMDOMWindow *dom_window;
+               WebKitDOMDOMSelection *dom_selection;
+               WebKitDOMRange *range;
+
+               in_quote = TRUE;
+
+               dom_window = webkit_dom_document_get_default_view (document);
+               dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+               range = webkit_dom_document_create_range (document);
+
+               webkit_dom_range_select_node (range, block, NULL);
+               webkit_dom_range_collapse (range, TRUE, NULL);
+               webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+               webkit_dom_dom_selection_add_range (dom_selection, range);
+
+               g_object_unref (range);
+               g_object_unref (dom_selection);
+               g_object_unref (dom_window);
+
+               e_editor_dom_remove_input_event_listener_from_body (editor_page);
+               e_editor_page_block_selection_changed (editor_page);
+
+               e_editor_dom_exec_command (
+                       editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_NEW_LINE_IN_QUOTED_CONTENT, NULL);
+
+               e_editor_dom_register_input_event_listener_on_body (editor_page);
+               e_editor_page_unblock_selection_changed (editor_page);
+
+               element = webkit_dom_document_query_selector (
+                       document, "body>br", NULL);
+
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       WEBKIT_DOM_NODE (list),
+                       WEBKIT_DOM_NODE (element),
+                       NULL);
+
+               block = e_editor_dom_get_parent_block_node_from_child (
+                       WEBKIT_DOM_NODE (selection_start_marker));
+       } else
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (block),
+                       WEBKIT_DOM_NODE (list),
+                       block,
+                       NULL);
+
+       /* Process all blocks that are in the selection one by one */
+       while (block && !after_selection_end) {
+               gboolean empty = FALSE;
+               gchar *content;
+               WebKitDOMNode *child, *parent;
+
+               after_selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               next_block = webkit_dom_node_get_next_sibling (
+                       WEBKIT_DOM_NODE (block));
+
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (block));
+               e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (block));
+
+               item = webkit_dom_document_create_element (document, "LI", NULL);
+               content = webkit_dom_node_get_text_content (block);
+
+               empty = !*content || (g_strcmp0 (content, UNICODE_ZERO_WIDTH_SPACE) == 0);
+               g_free (content);
+
+               change_leading_space_to_nbsp (block);
+               change_trailing_space_in_block_to_nbsp (block);
+
+               while ((child = webkit_dom_node_get_first_child (block))) {
+                       if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (child))
+                               empty = FALSE;
+
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (item), child, NULL);
+               }
+
+               /* We have to use again the hidden space to move caret into newly inserted list */
+               if (empty) {
+                       WebKitDOMElement *br;
+
+                       br = webkit_dom_document_create_element (
+                               document, "BR", NULL);
+                       webkit_dom_node_append_child (
+                               WEBKIT_DOM_NODE (item), WEBKIT_DOM_NODE (br), NULL);
+               }
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (list), WEBKIT_DOM_NODE (item), NULL);
+
+               parent = webkit_dom_node_get_parent_node (block);
+               remove_node (block);
+
+               if (in_quote) {
+                       /* Remove all parents if previously removed node was the
+                        * only one with text content */
+                       content = webkit_dom_node_get_text_content (parent);
+                       while (parent && content && !*content) {
+                               WebKitDOMNode *tmp = webkit_dom_node_get_parent_node (parent);
+
+                               remove_node (parent);
+                               parent = tmp;
+
+                               g_free (content);
+                               content = webkit_dom_node_get_text_content (parent);
+                       }
+                       g_free (content);
+               }
+
+               block = next_block;
+       }
+
+       merge_lists_if_possible (WEBKIT_DOM_NODE (list));
+}
+
+static WebKitDOMElement *
+do_format_change_list_to_list (WebKitDOMElement *list_to_process,
+                               WebKitDOMElement *new_list_template,
+                               EContentEditorBlockFormat to)
+{
+       EContentEditorBlockFormat current_format;
+
+       current_format = dom_get_list_format_from_node (
+               WEBKIT_DOM_NODE (list_to_process));
+       if (to == current_format) {
+               /* Same format, skip it. */
+               return list_to_process;
+       } else if (current_format >= E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST &&
+                  to >= E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST) {
+               /* Changing from ordered list type to another ordered list type. */
+               set_ordered_list_type_to_element (list_to_process, to);
+               return list_to_process;
+       } else {
+               WebKitDOMNode *clone, *child;
+
+               /* Create new list from template. */
+               clone = webkit_dom_node_clone_node_with_error (
+                       WEBKIT_DOM_NODE (new_list_template), FALSE, NULL);
+
+               /* Insert it before the list that we are processing. */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (
+                               WEBKIT_DOM_NODE (list_to_process)),
+                       clone,
+                       WEBKIT_DOM_NODE (list_to_process),
+                       NULL);
+
+               /* Move all it children to the new one. */
+               while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (list_to_process))))
+                       webkit_dom_node_append_child (clone, child, NULL);
+
+               remove_node (WEBKIT_DOM_NODE (list_to_process));
+
+               return WEBKIT_DOM_ELEMENT (clone);
+       }
+
+       return NULL;
+}
+
+static void
+format_change_list_from_list (EEditorPage *editor_page,
+                              EContentEditorBlockFormat to,
+                              gboolean html_mode)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker, *new_list;
+       WebKitDOMNode *source_list, *source_list_clone, *current_list, *item;
+       gboolean after_selection_end = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker || !selection_end_marker)
+               return;
+
+       /* Copy elements from previous block to list */
+       item = get_list_item_node_from_child (WEBKIT_DOM_NODE (selection_start_marker));
+       source_list = webkit_dom_node_get_parent_node (item);
+       current_list = source_list;
+       source_list_clone = webkit_dom_node_clone_node_with_error (source_list, FALSE, NULL);
+
+       new_list = create_list_element (editor_page, to, 0, html_mode);
+
+       if (element_has_class (WEBKIT_DOM_ELEMENT (source_list), "-x-evo-indented"))
+               element_add_class (WEBKIT_DOM_ELEMENT (new_list), "-x-evo-indented");
+
+       while (item) {
+               gboolean selection_end;
+               WebKitDOMNode *next_item = webkit_dom_node_get_next_sibling (item);
+
+               selection_end = webkit_dom_node_contains (
+                       item, WEBKIT_DOM_NODE (selection_end_marker));
+
+               if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (item)) {
+                       /* Actual node is an item, just copy it. */
+                       webkit_dom_node_append_child (
+                               after_selection_end ?
+                                       source_list_clone : WEBKIT_DOM_NODE (new_list),
+                               item,
+                               NULL);
+               } else if (node_is_list (item) && !selection_end && !after_selection_end) {
+                       /* Node is a list and it doesn't contain the selection end
+                        * marker, we can process the whole list. */
+                       gint ii;
+                       WebKitDOMNodeList *list;
+                       WebKitDOMElement *processed_list;
+
+                       list = webkit_dom_element_query_selector_all (
+                               WEBKIT_DOM_ELEMENT (item), "ol,ul", NULL);
+                       ii = webkit_dom_node_list_get_length (list);
+                       g_object_unref (list);
+
+                       /* Process every sublist separately. */
+                       while (ii) {
+                               WebKitDOMElement *list_to_process;
+
+                               list_to_process = webkit_dom_element_query_selector (
+                                       WEBKIT_DOM_ELEMENT (item), "ol,ul", NULL);
+                               if (list_to_process)
+                                       do_format_change_list_to_list (list_to_process, new_list, to);
+                               ii--;
+                       }
+
+                       /* Process the current list. */
+                       processed_list = do_format_change_list_to_list (
+                               WEBKIT_DOM_ELEMENT (item), new_list, to);
+
+                       webkit_dom_node_append_child (
+                               after_selection_end ?
+                                       source_list_clone : WEBKIT_DOM_NODE (new_list),
+                               WEBKIT_DOM_NODE (processed_list),
+                               NULL);
+               } else if (node_is_list (item) && !after_selection_end) {
+                       /* Node is a list and it contains the selection end marker,
+                        * thus we have to process it until we find the marker. */
+                       gint ii;
+                       WebKitDOMNodeList *list;
+
+                       list = webkit_dom_element_query_selector_all (
+                               WEBKIT_DOM_ELEMENT (item), "ol,ul", NULL);
+                       ii = webkit_dom_node_list_get_length (list);
+                       g_object_unref (list);
+
+                       /* No nested lists - process the items. */
+                       if (ii == 0) {
+                               WebKitDOMNode *clone, *child;
+
+                               clone = webkit_dom_node_clone_node_with_error (
+                                       WEBKIT_DOM_NODE (new_list), FALSE, NULL);
+
+                               webkit_dom_node_append_child (
+                                       after_selection_end ?
+                                               source_list_clone : WEBKIT_DOM_NODE (new_list),
+                                       clone,
+                                       NULL);
+
+                               while ((child = webkit_dom_node_get_first_child (item))) {
+                                       webkit_dom_node_append_child (clone, child, NULL);
+                                       if (webkit_dom_node_contains (child, WEBKIT_DOM_NODE 
(selection_end_marker)))
+                                               break;
+                               }
+
+                               if (webkit_dom_node_get_first_child (item))
+                                       webkit_dom_node_append_child (
+                                               after_selection_end ?
+                                                       source_list_clone : WEBKIT_DOM_NODE (new_list),
+                                               item,
+                                               NULL);
+                               else
+                                       remove_node (item);
+                       } else {
+                               gboolean done = FALSE;
+                               WebKitDOMNode *tmp_parent = WEBKIT_DOM_NODE (new_list);
+                               WebKitDOMNode *tmp_item = WEBKIT_DOM_NODE (item);
+
+                               while (!done) {
+                                       WebKitDOMNode *clone, *child;
+
+                                       clone = webkit_dom_node_clone_node_with_error (
+                                               WEBKIT_DOM_NODE (new_list), FALSE, NULL);
+
+                                       webkit_dom_node_append_child (
+                                               tmp_parent, clone, NULL);
+
+                                       while ((child = webkit_dom_node_get_first_child (tmp_item))) {
+                                               if (!webkit_dom_node_contains (child, WEBKIT_DOM_NODE 
(selection_end_marker))) {
+                                                       webkit_dom_node_append_child (clone, child, NULL);
+                                               } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (child)) {
+                                                       webkit_dom_node_append_child (clone, child, NULL);
+                                                       done = TRUE;
+                                                       break;
+                                               } else {
+                                                       tmp_parent = clone;
+                                                       tmp_item = child;
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       webkit_dom_node_append_child (
+                               after_selection_end ?
+                                       source_list_clone : WEBKIT_DOM_NODE (new_list),
+                               item,
+                               NULL);
+               }
+
+               if (selection_end) {
+                       source_list_clone = webkit_dom_node_clone_node_with_error (current_list, FALSE, NULL);
+                       after_selection_end = TRUE;
+               }
+
+               if (!next_item) {
+                       if (after_selection_end)
+                               break;
+
+                       current_list = webkit_dom_node_get_next_sibling (current_list);
+                       if (!node_is_list_or_item (current_list))
+                               break;
+                       if (node_is_list (current_list)) {
+                               next_item = webkit_dom_node_get_first_child (current_list);
+                               if (!node_is_list_or_item (next_item))
+                                       break;
+                       } else if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (current_list)) {
+                               next_item = current_list;
+                               current_list = webkit_dom_node_get_parent_node (next_item);
+                       }
+               }
+
+               item = next_item;
+       }
+
+       webkit_dom_node_insert_before (
+               webkit_dom_node_get_parent_node (source_list),
+               WEBKIT_DOM_NODE (source_list_clone),
+               webkit_dom_node_get_next_sibling (source_list),
+               NULL);
+
+       if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (new_list)))
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (source_list_clone),
+                       WEBKIT_DOM_NODE (new_list),
+                       source_list_clone, NULL);
+
+       if (!webkit_dom_node_has_child_nodes (source_list))
+               remove_node (source_list);
+
+       if (!webkit_dom_node_has_child_nodes (source_list_clone))
+               remove_node (source_list_clone);
+
+       merge_lists_if_possible (WEBKIT_DOM_NODE (new_list));
+}
+
+static void
+format_change_list_to_list (EEditorPage *editor_page,
+                            EContentEditorBlockFormat format,
+                            gboolean html_mode)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *prev_list, *current_list, *next_list;
+       EContentEditorBlockFormat prev = 0, next = 0;
+       gboolean done = FALSE, indented = FALSE;
+       gboolean selection_starts_in_first_child, selection_ends_in_last_child;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       current_list = get_list_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       prev_list = get_list_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       next_list = get_list_node_from_child (
+               WEBKIT_DOM_NODE (selection_end_marker));
+
+       selection_starts_in_first_child =
+               webkit_dom_node_contains (
+                       webkit_dom_node_get_first_child (current_list),
+                       WEBKIT_DOM_NODE (selection_start_marker));
+
+       selection_ends_in_last_child =
+               webkit_dom_node_contains (
+                       webkit_dom_node_get_last_child (current_list),
+                       WEBKIT_DOM_NODE (selection_end_marker));
+
+       indented = element_has_class (WEBKIT_DOM_ELEMENT (current_list), "-x-evo-indented");
+
+       if (!prev_list || !next_list || indented) {
+               format_change_list_from_list (editor_page, format, html_mode);
+               return;
+       }
+
+       if (webkit_dom_node_is_same_node (prev_list, next_list)) {
+               prev_list = webkit_dom_node_get_previous_sibling (
+                       webkit_dom_node_get_parent_node (
+                               webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (selection_start_marker))));
+               next_list = webkit_dom_node_get_next_sibling (
+                       webkit_dom_node_get_parent_node (
+                               webkit_dom_node_get_parent_node (
+                                       WEBKIT_DOM_NODE (selection_end_marker))));
+               if (!prev_list || !next_list) {
+                       format_change_list_from_list (editor_page, format, html_mode);
+                       return;
+               }
+       }
+
+       prev = dom_get_list_format_from_node (prev_list);
+       next = dom_get_list_format_from_node (next_list);
+
+       if (format != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+               if (format == prev && prev != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+                       if (selection_starts_in_first_child && selection_ends_in_last_child) {
+                               done = TRUE;
+                               merge_list_into_list (current_list, prev_list, FALSE);
+                       }
+               }
+               if (format == next && next != E_CONTENT_EDITOR_BLOCK_FORMAT_NONE) {
+                       if (selection_starts_in_first_child && selection_ends_in_last_child) {
+                               done = TRUE;
+                               merge_list_into_list (next_list, prev_list, FALSE);
+                       }
+               }
+       }
+
+       if (done)
+               return;
+
+       format_change_list_from_list (editor_page, format, html_mode);
+}
+
+/*
+ * e_html_editor_selection_set_block_format:
+ * @selection: an #EEditorSelection
+ * @format: an #EContentEditorBlockFormat value
+ *
+ * Changes block format of current paragraph to @format.
+ */
+void
+e_editor_dom_selection_set_block_format (EEditorPage *editor_page,
+                                        EContentEditorBlockFormat format)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMRange *range;
+       EContentEditorBlockFormat current_format;
+       EContentEditorAlignment current_alignment;
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       const gchar *value;
+       gboolean from_list = FALSE, to_list = FALSE, html_mode = FALSE;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       current_format = e_editor_dom_selection_get_block_format (editor_page);
+       if (current_format == format)
+               return;
+
+       switch (format) {
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_H1:
+                       value = "H1";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_H2:
+                       value = "H2";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_H3:
+                       value = "H3";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_H4:
+                       value = "H4";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_H5:
+                       value = "H5";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_H6:
+                       value = "H6";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH:
+                       value = "P";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_PRE:
+                       value = "PRE";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_ADDRESS:
+                       value = "ADDRESS";
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST:
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ALPHA:
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_ORDERED_LIST_ROMAN:
+                       to_list = TRUE;
+                       value = NULL;
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST:
+                       to_list = TRUE;
+                       value = NULL;
+                       break;
+               case E_CONTENT_EDITOR_BLOCK_FORMAT_NONE:
+               default:
+                       value = NULL;
+                       break;
+       }
+
+       html_mode = e_editor_page_get_html_mode (editor_page);
+
+       from_list =
+               current_format >= E_CONTENT_EDITOR_BLOCK_FORMAT_UNORDERED_LIST;
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return;
+
+       current_alignment = e_editor_page_get_alignment (editor_page);
+
+       e_editor_dom_selection_save (editor_page);
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_BLOCK_FORMAT;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               ev->data.style.from = current_format;
+               ev->data.style.to = format;
+       }
+
+       g_object_unref (range);
+
+       if (current_format == E_CONTENT_EDITOR_BLOCK_FORMAT_PRE) {
+               WebKitDOMElement *selection_marker;
+
+               selection_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               if (selection_marker)
+                       change_space_before_selection_to_nbsp (WEBKIT_DOM_NODE (selection_marker));
+               selection_marker = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-end-marker");
+               if (selection_marker)
+                       change_space_before_selection_to_nbsp (WEBKIT_DOM_NODE (selection_marker));
+       }
+
+       if (from_list && to_list)
+               format_change_list_to_list (editor_page, format, html_mode);
+
+       if (!from_list && !to_list)
+               format_change_block_to_block (editor_page, format, value);
+
+       if (from_list && !to_list)
+               format_change_list_to_block (editor_page, format, value);
+
+       if (!from_list && to_list)
+               format_change_block_to_list (editor_page, format);
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+       /* When changing the format we need to re-set the alignment */
+       e_editor_dom_selection_set_alignment (editor_page, current_alignment);
+
+       e_editor_page_emit_content_changed (editor_page);
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+}
+
+/*
+ * e_html_editor_selection_get_background_color:
+ * @selection: an #EEditorSelection
+ *
+ * Returns background color of currently selected text or letter at current
+ * cursor position.
+ *
+ * Returns: A string with code of current background color.
+ */
+gchar *
+e_editor_dom_selection_get_background_color (EEditorPage *editor_page)
+{
+       WebKitDOMNode *ancestor;
+       WebKitDOMRange *range;
+       WebKitDOMCSSStyleDeclaration *css;
+       gchar *value;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       ancestor = webkit_dom_range_get_common_ancestor_container (range, NULL);
+       css = webkit_dom_element_get_style (WEBKIT_DOM_ELEMENT (ancestor));
+/* FIXME WK2
+       g_free (selection->priv->background_color);
+       selection->priv->background_color =
+               webkit_dom_css_style_declaration_get_property_value (
+                       css, "background-color");*/
+
+       value = webkit_dom_css_style_declaration_get_property_value (css, "background-color");
+
+       g_object_unref (css);
+       g_object_unref (range);
+
+       return value;
+}
+
+/*
+ * e_html_editor_selection_set_background_color:
+ * @selection: an #EEditorSelection
+ * @color: code of new background color to set
+ *
+ * Changes background color of current selection or letter at current cursor
+ * position to @color.
+ */
+void
+e_editor_dom_selection_set_background_color (EEditorPage *editor_page,
+                                            const gchar *color)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_BACKGROUND_COLOR, color);
+}
+
+/*
+ * e_html_editor_selection_get_alignment:
+ * @selection: #an EEditorSelection
+ *
+ * Returns alignment of current paragraph
+ *
+ * Returns: #EContentEditorAlignment
+ */
+EContentEditorAlignment
+e_editor_dom_selection_get_alignment (EEditorPage *editor_page)
+{
+       WebKitDOMCSSStyleDeclaration *style;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+       EContentEditorAlignment alignment;
+       gchar *value;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+               goto out;
+       }
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+       g_object_unref (range);
+       if (!node) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+               goto out;
+       }
+
+       if (WEBKIT_DOM_IS_ELEMENT (node))
+               element = WEBKIT_DOM_ELEMENT (node);
+       else
+               element = webkit_dom_node_get_parent_element (node);
+
+       if (element_has_class (element, "-x-evo-align-right")) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+               goto out;
+       } else if (element_has_class (element, "-x-evo-align-center")) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+               goto out;
+       }
+
+       style = webkit_dom_element_get_style (element);
+       value = webkit_dom_css_style_declaration_get_property_value (style, "text-align");
+
+       if (!value || !*value ||
+           (g_ascii_strncasecmp (value, "left", 4) == 0)) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       } else if (g_ascii_strncasecmp (value, "center", 6) == 0) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+       } else if (g_ascii_strncasecmp (value, "right", 5) == 0) {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+       } else {
+               alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       }
+
+       g_object_unref (style);
+       g_free (value);
+
+ out:
+       return alignment;
+}
+
+static void
+set_block_alignment (WebKitDOMElement *element,
+                     const gchar *class)
+{
+       WebKitDOMElement *parent;
+
+       element_remove_class (element, "-x-evo-align-center");
+       element_remove_class (element, "-x-evo-align-right");
+       element_add_class (element, class);
+       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (element));
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               element_remove_class (parent, "-x-evo-align-center");
+               element_remove_class (parent, "-x-evo-align-right");
+               parent = webkit_dom_node_get_parent_element (
+                       WEBKIT_DOM_NODE (parent));
+       }
+}
+
+/*
+ * e_html_editor_selection_set_alignment:
+ * @selection: an #EEditorSelection
+ * @alignment: an #EContentEditorAlignment value to apply
+ *
+ * Sets alignment of current paragraph to give @alignment.
+ */
+void
+e_editor_dom_selection_set_alignment (EEditorPage *editor_page,
+                                     EContentEditorAlignment alignment)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *selection_start_marker, *selection_end_marker;
+       WebKitDOMNode *block;
+       EContentEditorAlignment current_alignment;
+       EEditorUndoRedoManager *manager;
+       EEditorHistoryEvent *ev = NULL;
+       gboolean after_selection_end = FALSE;
+       const gchar *class = "";
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       current_alignment = e_editor_page_get_alignment (editor_page);
+
+       if (current_alignment == alignment)
+               return;
+
+       switch (alignment) {
+               case E_CONTENT_EDITOR_ALIGNMENT_CENTER:
+                       class = "-x-evo-align-center";
+                       break;
+
+               case E_CONTENT_EDITOR_ALIGNMENT_LEFT:
+                       break;
+
+               case E_CONTENT_EDITOR_ALIGNMENT_RIGHT:
+                       class = "-x-evo-align-right";
+                       break;
+       }
+
+       e_editor_dom_selection_save (editor_page);
+
+       selection_start_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-start-marker", NULL);
+       selection_end_marker = webkit_dom_document_query_selector (
+               document, "span#-x-evo-selection-end-marker", NULL);
+
+       if (!selection_start_marker)
+               return;
+
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_ALIGNMENT;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+               ev->data.style.from = current_alignment;
+               ev->data.style.to = alignment;
+       }
+
+       block = e_editor_dom_get_parent_block_node_from_child (
+               WEBKIT_DOM_NODE (selection_start_marker));
+
+       while (block && !after_selection_end) {
+               WebKitDOMNode *next_block;
+
+               next_block = webkit_dom_node_get_next_sibling (block);
+
+               after_selection_end = webkit_dom_node_contains (
+                       block, WEBKIT_DOM_NODE (selection_end_marker));
+
+               if (element_has_class (WEBKIT_DOM_ELEMENT (block), "-x-evo-indented")) {
+                       gint ii, length;
+                       WebKitDOMNodeList *list;
+
+                       list = webkit_dom_element_query_selector_all (
+                               WEBKIT_DOM_ELEMENT (block),
+                               ".-x-evo-indented > *:not(.-x-evo-indented):not(li)",
+                               NULL);
+                       length = webkit_dom_node_list_get_length (list);
+
+                       for (ii = 0; ii < length; ii++) {
+                               WebKitDOMNode *item = webkit_dom_node_list_item (list, ii);
+
+                               set_block_alignment (WEBKIT_DOM_ELEMENT (item), class);
+
+                               after_selection_end = webkit_dom_node_contains (
+                                       item, WEBKIT_DOM_NODE (selection_end_marker));
+                               g_object_unref (item);
+                               if (after_selection_end)
+                                       break;
+                       }
+
+                       g_object_unref (list);
+               } else {
+                       set_block_alignment (WEBKIT_DOM_ELEMENT (block), class);
+               }
+
+               block = next_block;
+       }
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_selection_restore (editor_page);
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+}
+
+/*
+ * e_html_editor_selection_replace:
+ * @selection: an #EEditorSelection
+ * @replacement: a string to replace current selection with
+ *
+ * Replaces currently selected text with @replacement.
+ */
+void
+e_editor_dom_selection_replace (EEditorPage *editor_page,
+                               const gchar *replacement)
+{
+       WebKitDOMDocument *document;
+       EEditorHistoryEvent *ev = NULL;
+       EEditorUndoRedoManager *manager;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+
+       if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
+               WebKitDOMDOMWindow *dom_window;
+               WebKitDOMDOMSelection *dom_selection;
+               WebKitDOMRange *range;
+
+               ev = g_new0 (EEditorHistoryEvent, 1);
+               ev->type = HISTORY_REPLACE;
+
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               dom_window = webkit_dom_document_get_default_view (document);
+               dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+               range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+               ev->data.string.from = webkit_dom_range_get_text (range);
+               ev->data.string.to = g_strdup (replacement);
+
+               g_object_unref (range);
+               g_object_unref (dom_selection);
+               g_object_unref (dom_window);
+       }
+
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, replacement);
+
+       if (ev) {
+               e_editor_dom_selection_get_coordinates (editor_page,
+                       &ev->after.start.x,
+                       &ev->after.start.y,
+                       &ev->after.end.x,
+                       &ev->after.end.y);
+
+               e_editor_undo_redo_manager_insert_history_event (manager, ev);
+       }
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+       e_editor_page_emit_content_changed (editor_page);
+}
+
+/*
+ * e_html_editor_selection_replace_caret_word:
+ * @selection: an #EEditorSelection
+ * @replacement: a string to replace current caret word with
+ *
+ * Replaces current word under cursor with @replacement.
+ */
+void
+e_editor_dom_replace_caret_word (EEditorPage *editor_page,
+                                const gchar *replacement)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMDocumentFragment *fragment;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       e_editor_page_emit_content_changed (editor_page);
+       range = e_editor_dom_get_current_range (editor_page);
+       webkit_dom_range_expand (range, "word", NULL);
+       webkit_dom_dom_selection_add_range (dom_selection, range);
+
+       fragment = webkit_dom_range_extract_contents (range, NULL);
+
+       /* Get the text node to replace and leave other formatting nodes
+        * untouched (font color, boldness, ...). */
+       webkit_dom_node_normalize (WEBKIT_DOM_NODE (fragment));
+       node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+       if (!WEBKIT_DOM_IS_TEXT (node)) {
+               while (node && WEBKIT_DOM_IS_ELEMENT (node))
+                       node = webkit_dom_node_get_first_child (node);
+       }
+
+       if (node && WEBKIT_DOM_IS_TEXT (node)) {
+               WebKitDOMText *text;
+
+               /* Replace the word */
+               text = webkit_dom_document_create_text_node (document, replacement);
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (node),
+                       WEBKIT_DOM_NODE (text),
+                       node,
+                       NULL);
+
+               /* Insert the word on current location. */
+               webkit_dom_range_insert_node (range, WEBKIT_DOM_NODE (fragment), NULL);
+
+               webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
+       }
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+}
+
+/*
+ * e_html_editor_selection_get_caret_word:
+ * @selection: an #EEditorSelection
+ *
+ * Returns word under cursor.
+ *
+ * Returns: A newly allocated string with current caret word or @NULL when there
+ * is no text under cursor or when selection is active. [transfer-full].
+ */
+gchar *
+e_editor_dom_get_caret_word (EEditorPage *editor_page)
+{
+       gchar *word;
+       WebKitDOMRange *range;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       range = e_editor_dom_get_current_range (editor_page);
+
+       /* Don't operate on the visible selection */
+       range = webkit_dom_range_clone_range (range, NULL);
+       webkit_dom_range_expand (range, "word", NULL);
+       word = webkit_dom_range_to_string (range, NULL);
+
+       g_object_unref (range);
+
+       return word;
+}
+
+/*
+ * e_html_editor_selection_get_list_alignment_from_node:
+ * @node: #an WebKitDOMNode
+ *
+ * Returns alignment of given list.
+ *
+ * Returns: #EContentEditorAlignment
+ */
+EContentEditorAlignment
+e_editor_dom_get_list_alignment_from_node (WebKitDOMNode *node)
+{
+       if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-center"))
+               return E_CONTENT_EDITOR_ALIGNMENT_CENTER;
+       if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-align-right"))
+               return E_CONTENT_EDITOR_ALIGNMENT_RIGHT;
+       else
+               return E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+}
+
+WebKitDOMElement *
+e_editor_dom_prepare_paragraph (EEditorPage *editor_page,
+                               gboolean with_selection)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *paragraph;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       paragraph = e_editor_dom_get_paragraph_element (editor_page, -1, 0);
+
+       if (with_selection)
+               dom_add_selection_markers_into_element_start (
+                       document, paragraph, NULL, NULL);
+
+       element = webkit_dom_document_create_element (document, "BR", NULL);
+
+       webkit_dom_node_append_child (
+               WEBKIT_DOM_NODE (paragraph), WEBKIT_DOM_NODE (element), NULL);
+
+       return paragraph;
+}
+
+void
+e_editor_dom_selection_set_on_point (EEditorPage *editor_page,
+                                    guint x,
+                                    guint y)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMRange *range;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       range = webkit_dom_document_caret_range_from_point (document, x, y);
+       webkit_dom_dom_selection_remove_all_ranges (dom_selection);
+       webkit_dom_dom_selection_add_range (dom_selection, range);
+
+       g_object_unref (range);
+       g_object_unref (dom_selection);
+       g_object_unref (dom_window);
+}
+
+void
+e_editor_dom_selection_get_coordinates (EEditorPage *editor_page,
+                                       guint *start_x,
+                                       guint *start_y,
+                                       guint *end_x,
+                                       guint *end_y)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMElement *element, *parent;
+       gboolean created_selection_markers = FALSE;
+       guint local_x = 0, local_y = 0;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (start_x != NULL);
+       g_return_if_fail (start_y != NULL);
+       g_return_if_fail (end_x != NULL);
+       g_return_if_fail (end_y != NULL);
+
+       document = e_editor_page_get_document (editor_page);
+       element = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-start-marker");
+       if (!element) {
+               created_selection_markers = TRUE;
+               e_editor_dom_selection_save (editor_page);
+               element = webkit_dom_document_get_element_by_id (
+                       document, "-x-evo-selection-start-marker");
+               if (!element)
+                       return;
+       }
+
+       parent = element;
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               local_x += (guint) webkit_dom_element_get_offset_left (parent);
+               local_y += (guint) webkit_dom_element_get_offset_top (parent);
+               parent = webkit_dom_element_get_offset_parent (parent);
+       }
+
+       if (start_x)
+               *start_x = local_x;
+       if (start_y)
+               *start_y = local_y;
+
+       if (e_editor_dom_selection_is_collapsed (editor_page)) {
+               *end_x = local_x;
+               *end_y = local_y;
+
+               if (created_selection_markers)
+                       e_editor_dom_selection_restore (editor_page);
+
+               goto workaroud;
+       }
+
+       element = webkit_dom_document_get_element_by_id (
+               document, "-x-evo-selection-end-marker");
+
+       local_x = 0;
+       local_y = 0;
+
+       parent = element;
+       while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+               local_x += (guint) webkit_dom_element_get_offset_left (parent);
+               local_y += (guint) webkit_dom_element_get_offset_top (parent);
+               parent = webkit_dom_element_get_offset_parent (parent);
+       }
+
+       if (end_x)
+               *end_x = local_x;
+       if (end_y)
+               *end_y = local_y;
+
+       if (created_selection_markers)
+               e_editor_dom_selection_restore (editor_page);
+
+ workaroud:
+       /* Workaround for bug 749712 on the Evolution side. The cause of the bug
+        * is that WebKit is having problems determining the right line height
+        * for some fonts and font sizes (the right and wrong value differ by 1).
+        * To fix this we will add an extra one to the final top offset. This is
+        * safe to do even for fonts and font sizes that don't behave badly as we
+        * will still get the right element as we use fonts bigger than 1 pixel. */
+       *start_y += 1;
+       *end_y += 1;
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-dom-functions.h 
b/modules/webkit-editor/web-extension/e-editor-dom-functions.h
new file mode 100644
index 0000000..4aeacb5
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-dom-functions.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (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/>.
+ */
+
+#ifndef E_EDITOR_DOM_FUNCTIONS_H
+#define E_EDITOR_DOM_FUNCTIONS_H
+
+#include <webkitdom/webkitdom.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+#include "e-editor-page.h"
+
+#define UNICODE_ZERO_WIDTH_SPACE "\xe2\x80\x8b"
+#define UNICODE_NBSP "\xc2\xa0"
+
+/* stephenhay from https://mathiasbynens.be/demo/url-regex */
+#define URL_PROTOCOLS "news|telnet|nntp|file|https?|s?ftp|webcal|localhost|ssh"
+#define URL_PATTERN_BASE "(?=((?:(?:(?:" URL_PROTOCOLS 
")\\:\\/\\/)|(?:www\\.|ftp\\.))[^\\s\\/\\$\\.\\?#].[^\\s]*)"
+#define URL_PATTERN_NO_NBSP ")((?:(?!&nbsp;).)*)"
+#define URL_PATTERN URL_PATTERN_BASE URL_PATTERN_NO_NBSP
+#define URL_PATTERN_SPACE URL_PATTERN_BASE "\\s$" URL_PATTERN_NO_NBSP
+/* Taken from camel-url-scanner.c */
+#define URL_INVALID_TRAILING_CHARS ",.:;?!-|}])\""
+
+/* http://www.w3.org/TR/html5/forms.html#valid-e-mail-address */
+#define E_MAIL_PATTERN \
+       "[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+ [a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}"\
+       "[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*"
+
+#define E_MAIL_PATTERN_SPACE E_MAIL_PATTERN "\\s"
+
+#define QUOTE_SYMBOL ">"
+
+#define SPACES_PER_INDENTATION 3
+#define SPACES_PER_LIST_LEVEL 3
+#define SPACES_ORDERED_LIST_FIRST_LEVEL 6
+#define TAB_LENGTH 8
+#define MINIMAL_PARAGRAPH_WIDTH 5
+
+G_BEGIN_DECLS
+
+/* ******************** Tests ******************** */
+
+gboolean       e_editor_dom_test_html_equal    (WebKitDOMDocument *document,
+                                                const gchar *html1,
+                                                const gchar *html2);
+
+/* ******************** Actions ******************** */
+
+void           e_editor_dom_delete_cell_contents
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_delete_column      (EEditorPage *editor_page);
+void           e_editor_dom_delete_row         (EEditorPage *editor_page);
+void           e_editor_dom_delete_table       (EEditorPage *editor_page);
+void           e_editor_dom_insert_column_after
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_insert_column_before
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_insert_row_above   (EEditorPage *editor_page);
+void           e_editor_dom_insert_row_below   (EEditorPage *editor_page);
+void           e_editor_dom_save_history_for_cut
+                                               (EEditorPage *editor_page);
+
+/* ******************** View ******************** */
+
+gboolean       e_editor_dom_exec_command       (EEditorPage *editor_page,
+                                                EContentEditorCommand command,
+                                                const gchar *value);
+void           e_editor_dom_force_spell_check_for_current_paragraph
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_force_spell_check_in_viewport
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_force_spell_check  (EEditorPage *editor_page);
+void           e_editor_dom_turn_spell_check_off
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_embed_style_sheet  (EEditorPage *editor_page,
+                                                const gchar *style_sheet_content);
+void           e_editor_dom_remove_embedded_style_sheet
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_register_input_event_listener_on_body
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_remove_input_event_listener_from_body
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_quote_and_insert_text_into_selection
+                                               (EEditorPage *editor_page,
+                                                const gchar *text);
+void           e_editor_dom_check_magic_links  (EEditorPage *editor_page,
+                                                gboolean include_space_by_user);
+void           e_editor_dom_insert_smiley      (EEditorPage *editor_page,
+                                                 EEmoticon *emoticon);
+void           e_editor_dom_insert_smiley_by_name
+                                               (EEditorPage *editor_page,
+                                                const gchar *name);
+void           e_editor_dom_check_magic_smileys
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_convert_content    (EEditorPage *editor_page,
+                                                const gchar *preferred_text);
+void           e_editor_dom_convert_and_insert_html_into_selection
+                                               (EEditorPage *editor_page,
+                                                const gchar *html,
+                                                gboolean is_html);
+gboolean       e_editor_dom_node_is_citation_node
+                                               (WebKitDOMNode *node);
+void           e_editor_dom_quote_plain_text_element_after_wrapping
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *element,
+                                                gint quote_level);
+WebKitDOMNode * e_editor_dom_get_parent_block_node_from_child
+                                               (WebKitDOMNode *node);
+WebKitDOMElement *
+               e_editor_dom_insert_new_line_into_citation
+                                               (EEditorPage *editor_page,
+                                                const gchar *html_to_insert);
+WebKitDOMElement *
+               e_editor_dom_quote_plain_text_element
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *element);
+void           e_editor_dom_convert_when_changing_composer_mode
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_process_content_after_load
+                                               (EEditorPage *editor_page);
+GVariant *     e_editor_dom_get_inline_images_data
+                                               (EEditorPage *editor_page,
+                                                const gchar *uid_domain);
+void           e_editor_dom_insert_html        (EEditorPage *editor_page,
+                                                const gchar *html_text);
+void           e_editor_dom_convert_element_from_html_to_plain_text
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *element);
+gchar *                e_editor_dom_process_content_for_draft
+                                               (EEditorPage *editor_page,
+                                                gboolean only_inner_body);
+gchar *                e_editor_dom_process_content_for_plain_text
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_restore_images     (EEditorPage *editor_page,
+                                                GVariant *inline_images_to_restore);
+gchar *                e_editor_dom_process_content_for_html
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_dom_check_if_conversion_needed
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_process_content_after_mode_change
+                                               (EEditorPage *editor_page);
+guint          e_editor_dom_get_caret_offset   (EEditorPage *editor_page);
+guint          e_editor_dom_get_caret_position (EEditorPage *editor_page);
+void           e_editor_dom_drag_and_drop_end  (EEditorPage *editor_page);
+void           e_editor_dom_set_link_color     (EEditorPage *editor_page,
+                                                const gchar *color);
+void           e_editor_dom_set_visited_link_color
+                                               (EEditorPage *editor_page,
+                                                const gchar *color);
+gboolean       e_editor_dom_move_quoted_block_level_up
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_dom_delete_last_character_on_line_in_quoted_block
+                                               (EEditorPage *editor_page,
+                                                glong key_code,
+                                                gboolean control_key);
+gboolean       e_editor_dom_fix_structure_after_delete_before_quoted_content
+                                               (EEditorPage *editor_page,
+                                                glong key_code,
+                                                gboolean control_key,
+                                                gboolean delete_key);
+void           e_editor_dom_disable_quote_marks_select
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_remove_node_and_parents_if_empty
+                                               (WebKitDOMNode *node);
+gboolean       e_editor_dom_return_pressed_in_empty_list_item
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_merge_siblings_if_necessary
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMDocumentFragment *deleted_content);
+void           e_editor_dom_body_key_up_event_process_return_key
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_dom_key_press_event_process_backspace_key
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_dom_key_press_event_process_delete_or_backspace_key
+                                               (EEditorPage *editor_page,
+                                                glong key_code,
+                                                gboolean control_key,
+                                                gboolean delete);
+void           e_editor_dom_body_input_event_process
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMEvent *event);
+void           e_editor_dom_body_key_up_event_process_backspace_or_delete
+                                               (EEditorPage *editor_page,
+                                                gboolean delete);
+gboolean       e_editor_dom_key_press_event_process_return_key
+                                               (EEditorPage *editor_page);
+WebKitDOMElement *
+               e_editor_dom_wrap_and_quote_element
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *element);
+gint           e_editor_dom_get_citation_level (WebKitDOMNode *node,
+                                                gboolean set_plaintext_quoted);
+void           e_editor_dom_save_history_for_drop
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_fix_file_uri_images
+                                               (EEditorPage *editor_page);
+
+/* ******************** Selection ******************** */
+
+void           e_editor_dom_replace_base64_image_src
+                                               (EEditorPage *editor_page,
+                                                const gchar *selector,
+                                                const gchar *base64_content,
+                                                const gchar *filename,
+                                                const gchar *uri);
+WebKitDOMRange *
+               e_editor_dom_get_current_range  (EEditorPage *editor_page);
+void           e_editor_dom_move_caret_into_element
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *element,
+                                                gboolean to_start);
+void           e_editor_dom_insert_base64_image
+                                               (EEditorPage *editor_page,
+                                                const gchar *filename,
+                                                const gchar *uri,
+                                                const gchar *base64_content);
+void           e_editor_dom_insert_image       (EEditorPage *editor_page,
+                                                const gchar *uri);
+void           e_editor_dom_replace_image_src  (EEditorPage *editor_page,
+                                                const gchar *selector,
+                                                const gchar *uri);
+void           e_editor_dom_selection_unlink   (EEditorPage *editor_page);
+void           e_editor_dom_create_link        (EEditorPage *editor_page,
+                                                const gchar *uri);
+void           e_editor_dom_selection_indent   (EEditorPage *editor_page);
+void           e_editor_dom_selection_unindent (EEditorPage *editor_page);
+void           e_editor_dom_selection_save     (EEditorPage *editor_page);
+void           e_editor_dom_selection_restore  (EEditorPage *editor_page);
+gboolean       e_editor_dom_selection_is_collapsed
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_scroll_to_caret    (EEditorPage *editor_page);
+void           e_editor_dom_remove_wrapping_from_element
+                                               (WebKitDOMElement *element);
+void           e_editor_dom_remove_quoting_from_element
+                                               (WebKitDOMElement *element);
+void           e_editor_dom_set_paragraph_style
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *element,
+                                                gint width,
+                                                gint offset,
+                                                const gchar *style_to_add);
+WebKitDOMElement *
+               e_editor_dom_get_paragraph_element
+                                               (EEditorPage *editor_page,
+                                                gint width,
+                                                gint offset);
+WebKitDOMElement *
+               e_editor_dom_put_node_into_paragraph
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMNode *node,
+                                                gboolean with_input);
+void           e_editor_dom_selection_wrap     (EEditorPage *editor_page);
+WebKitDOMElement *
+               e_editor_dom_wrap_paragraph_length
+                                               (EEditorPage *editor_page,
+                                                WebKitDOMElement *paragraph,
+                                                gint length);
+WebKitDOMElement *
+               e_editor_dom_wrap_paragraph     (EEditorPage *editor_page,
+                                                WebKitDOMElement *paragraph);
+void           e_editor_dom_wrap_paragraphs_in_document
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_dom_selection_is_underline
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_underline
+                                               (EEditorPage *editor_page,
+                                                gboolean underline);
+gboolean       e_editor_dom_selection_is_subscript
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_subscript
+                                               (EEditorPage *editor_page,
+                                                gboolean subscript);
+gboolean       e_editor_dom_selection_is_superscript
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_superscript
+                                               (EEditorPage *editor_page,
+                                                gboolean superscript);
+gboolean       e_editor_dom_selection_is_strikethrough
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_strikethrough
+                                               (EEditorPage *editor_page,
+                                                gboolean strikethrough);
+gboolean       e_editor_dom_selection_is_monospace
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_monospace
+                                               (EEditorPage *editor_page,
+                                                gboolean monospaced);
+gboolean       e_editor_dom_selection_is_bold  (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_bold (EEditorPage *editor_page,
+                                                gboolean bold);
+gboolean       e_editor_dom_selection_is_italic
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_italic
+                                               (EEditorPage *editor_page,
+                                                gboolean italic);
+gboolean       e_editor_dom_selection_is_indented
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_dom_selection_is_citation
+                                               (EEditorPage *editor_page);
+guint          e_editor_dom_selection_get_font_size
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_font_size
+                                               (EEditorPage *editor_page,
+                                                guint font_size);
+gchar *                e_editor_dom_selection_get_font_name
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_font_name
+                                               (EEditorPage *editor_page,
+                                                const gchar *font_size);
+gchar *                e_editor_dom_selection_get_font_color
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_font_color
+                                               (EEditorPage *editor_page,
+                                                const gchar *font_color);
+gchar *                e_editor_dom_selection_get_background_color
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_background_color
+                                               (EEditorPage *editor_page,
+                                                const gchar *bg_color);
+EContentEditorBlockFormat
+               e_editor_dom_selection_get_block_format
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_block_format
+                                               (EEditorPage *editor_page,
+                                                EContentEditorBlockFormat format);
+EContentEditorAlignment
+               e_editor_dom_selection_get_alignment
+                                               (EEditorPage *editor_page);
+void           e_editor_dom_selection_set_alignment
+                                               (EEditorPage *editor_page,
+                                                EContentEditorAlignment alignment);
+void           e_editor_dom_selection_replace  (EEditorPage *editor_page,
+                                                const gchar *replacement);
+void           e_editor_dom_replace_caret_word (EEditorPage *editor_page,
+                                                const gchar *replacement);
+gchar *                e_editor_dom_get_caret_word     (EEditorPage *editor_page);
+EContentEditorAlignment
+               e_editor_dom_get_list_alignment_from_node
+                                               (WebKitDOMNode *node);
+WebKitDOMElement *
+               e_editor_dom_prepare_paragraph  (EEditorPage *editor_page,
+                                                gboolean with_selection);
+void           e_editor_dom_selection_set_on_point
+                                               (EEditorPage *editor_page,
+                                                guint x,
+                                                guint y);
+void           e_editor_dom_selection_get_coordinates
+                                               (EEditorPage *editor_page,
+                                                guint *start_x,
+                                                guint *start_y,
+                                                guint *end_x,
+                                                guint *end_y);
+gboolean       e_editor_dom_is_selection_position_node
+                                               (WebKitDOMNode *node);
+
+G_END_DECLS
+
+#endif /* E_EDITOR_DOM_FUNCTIONS_H */
diff --git a/modules/webkit-editor/web-extension/e-editor-page.c 
b/modules/webkit-editor/web-extension/e-editor-page.c
new file mode 100644
index 0000000..3f18d86
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-page.c
@@ -0,0 +1,960 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (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/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <webkit2/webkit-web-extension.h>
+
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-dom-functions.h"
+#include "e-editor-web-extension.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-editor-page.h"
+
+struct _EEditorPagePrivate {
+       WebKitWebPage *web_page; /* not referenced */
+       EEditorWebExtension *web_extension; /* not referenced */
+
+       EEditorUndoRedoManager *undo_redo_manager;
+       ESpellChecker *spell_checker;
+
+       guint spell_check_on_scroll_event_source_id;
+
+       EContentEditorAlignment alignment;
+       EContentEditorBlockFormat block_format;
+       guint32 style_flags; /* bit-OR of EContentEditorStyleFlags */
+       gchar *background_color;
+       gchar *font_color;
+       gchar *font_name;
+       gint font_size;
+
+       guint selection_changed_blocked;
+       gboolean selection_changed;
+
+       gboolean force_image_load;
+       gboolean html_mode;
+       gboolean return_key_pressed;
+       gboolean space_key_pressed;
+       gboolean smiley_written;
+       gint word_wrap_length;
+
+       gboolean convert_in_situ;
+       gboolean body_input_event_removed;
+       gboolean dont_save_history_in_body_input;
+       gboolean composition_in_progress;
+       gboolean pasting_content_from_itself;
+       gboolean renew_history_after_coordinates;
+
+       GHashTable *inline_images;
+
+       WebKitDOMNode *node_under_mouse_click;
+
+       GSettings *mail_settings;
+
+       EContentEditorContentFlags content_flags;
+};
+
+G_DEFINE_TYPE (EEditorPage, e_editor_page, G_TYPE_OBJECT)
+
+
+static void
+web_page_document_loaded_cb (WebKitWebPage *web_page,
+                            EEditorPage *editor_page)
+{
+       g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->body_input_event_removed = TRUE;
+
+       e_editor_undo_redo_manager_clean_history (editor_page->priv->undo_redo_manager);
+       e_editor_dom_process_content_after_load (editor_page);
+}
+
+static gboolean
+web_page_context_menu_cb (WebKitWebPage *web_page,
+                         WebKitContextMenu *context_menu,
+                         WebKitWebHitTestResult *hit_test_result,
+                         EEditorPage *editor_page)
+{
+       WebKitDOMNode *node;
+       EContentEditorNodeFlags flags = 0;
+       GVariant *variant;
+
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       node = webkit_web_hit_test_result_get_node (hit_test_result);
+       editor_page->priv->node_under_mouse_click = node;
+
+       if (WEBKIT_DOM_IS_HTML_HR_ELEMENT (node))
+               flags |= E_CONTENT_EDITOR_NODE_IS_H_RULE;
+
+       if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) ||
+           (dom_node_find_parent_element (node, "A") != NULL))
+               flags |= E_CONTENT_EDITOR_NODE_IS_ANCHOR;
+
+       if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node) ||
+           (dom_node_find_parent_element (node, "IMG") != NULL))
+               flags |= E_CONTENT_EDITOR_NODE_IS_IMAGE;
+
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node) ||
+           (dom_node_find_parent_element (node, "TD") != NULL) ||
+           (dom_node_find_parent_element (node, "TH") != NULL))
+               flags |= E_CONTENT_EDITOR_NODE_IS_TABLE_CELL;
+
+       if (flags & E_CONTENT_EDITOR_NODE_IS_TABLE_CELL &&
+           (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (node) ||
+           dom_node_find_parent_element (node, "TABLE") != NULL))
+               flags |= E_CONTENT_EDITOR_NODE_IS_TABLE;
+
+       if (flags == 0)
+               flags |= E_CONTENT_EDITOR_NODE_IS_TEXT;
+
+       variant = g_variant_new_int32 (flags);
+       webkit_context_menu_set_user_data (context_menu, variant);
+
+       return FALSE;
+}
+
+static void
+e_editor_page_setup (EEditorPage *editor_page,
+                    WebKitWebPage *web_page,
+                    struct _EEditorWebExtension *web_extension)
+{
+       WebKitWebEditor *web_editor;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->web_page = web_page;
+       editor_page->priv->web_extension = web_extension;
+       editor_page->priv->undo_redo_manager = e_editor_undo_redo_manager_new (editor_page);
+
+       g_signal_connect_swapped (
+               editor_page->priv->undo_redo_manager, "notify::can-undo",
+               G_CALLBACK (e_editor_page_emit_undo_redo_state_changed), editor_page);
+
+       g_signal_connect_swapped (
+               editor_page->priv->undo_redo_manager, "notify::can-redo",
+               G_CALLBACK (e_editor_page_emit_undo_redo_state_changed), editor_page);
+
+       web_editor = webkit_web_page_get_editor (web_page);
+
+       g_signal_connect_swapped (
+               web_editor, "selection-changed",
+               G_CALLBACK (e_editor_page_emit_selection_changed), editor_page);
+
+       g_signal_connect (
+               web_page, "document-loaded",
+               G_CALLBACK (web_page_document_loaded_cb), editor_page);
+
+       g_signal_connect (
+               web_page, "context-menu",
+               G_CALLBACK (web_page_context_menu_cb), editor_page);
+}
+
+static void
+e_editor_page_dispose (GObject *object)
+{
+       EEditorPage *editor_page = E_EDITOR_PAGE (object);
+
+       if (editor_page->priv->spell_check_on_scroll_event_source_id > 0) {
+               g_source_remove (editor_page->priv->spell_check_on_scroll_event_source_id);
+               editor_page->priv->spell_check_on_scroll_event_source_id = 0;
+       }
+
+       if (editor_page->priv->background_color != NULL) {
+               g_free (editor_page->priv->background_color);
+               editor_page->priv->background_color = NULL;
+       }
+
+       if (editor_page->priv->font_color != NULL) {
+               g_free (editor_page->priv->font_color);
+               editor_page->priv->font_color = NULL;
+       }
+
+       if (editor_page->priv->font_name != NULL) {
+               g_free (editor_page->priv->font_name);
+               editor_page->priv->font_name = NULL;
+       }
+
+       if (editor_page->priv->mail_settings != NULL) {
+               g_signal_handlers_disconnect_by_data (editor_page->priv->mail_settings, object);
+               g_object_unref (editor_page->priv->mail_settings);
+               editor_page->priv->mail_settings = NULL;
+       }
+
+       g_clear_object (&editor_page->priv->undo_redo_manager);
+       g_clear_object (&editor_page->priv->spell_checker);
+
+       g_hash_table_remove_all (editor_page->priv->inline_images);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_editor_page_parent_class)->dispose (object);
+}
+
+static void
+e_editor_page_finalize (GObject *object)
+{
+       EEditorPage *editor_page = E_EDITOR_PAGE (object);
+
+       g_hash_table_destroy (editor_page->priv->inline_images);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_editor_page_parent_class)->finalize (object);
+}
+
+static void
+e_editor_page_class_init (EEditorPageClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (EEditorPagePrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = e_editor_page_dispose;
+       object_class->finalize = e_editor_page_finalize;
+}
+
+static void
+e_editor_page_init (EEditorPage *editor_page)
+{
+       editor_page->priv = G_TYPE_INSTANCE_GET_PRIVATE (editor_page, E_TYPE_EDITOR_PAGE, EEditorPagePrivate);
+       editor_page->priv->style_flags = 0;
+       editor_page->priv->selection_changed_blocked = 0;
+       editor_page->priv->background_color = g_strdup ("");
+       editor_page->priv->font_color = g_strdup ("");
+       editor_page->priv->font_name = g_strdup ("");
+       editor_page->priv->font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
+       editor_page->priv->alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
+       editor_page->priv->block_format = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
+       editor_page->priv->force_image_load = FALSE;
+       editor_page->priv->html_mode = FALSE;
+       editor_page->priv->return_key_pressed = FALSE;
+       editor_page->priv->space_key_pressed = FALSE;
+       editor_page->priv->smiley_written = FALSE;
+       editor_page->priv->convert_in_situ = FALSE;
+       editor_page->priv->body_input_event_removed = TRUE;
+       editor_page->priv->dont_save_history_in_body_input = FALSE;
+       editor_page->priv->pasting_content_from_itself = FALSE;
+       editor_page->priv->composition_in_progress = FALSE;
+       editor_page->priv->renew_history_after_coordinates = TRUE;
+       editor_page->priv->content_flags = 0;
+       editor_page->priv->spell_check_on_scroll_event_source_id = 0;
+       editor_page->priv->mail_settings = e_util_ref_settings ("org.gnome.evolution.mail");
+       editor_page->priv->word_wrap_length = g_settings_get_int (editor_page->priv->mail_settings, 
"composer-word-wrap-length");
+       editor_page->priv->inline_images = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+       editor_page->priv->spell_checker = e_spell_checker_new ();
+}
+
+EEditorPage *
+e_editor_page_new (WebKitWebPage *web_page,
+                  struct _EEditorWebExtension *web_extension)
+{
+       EEditorPage *editor_page;
+
+       g_return_val_if_fail (WEBKIT_IS_WEB_PAGE (web_page), NULL);
+       g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (web_extension), NULL);
+
+       editor_page = g_object_new (E_TYPE_EDITOR_PAGE, NULL);
+       e_editor_page_setup (editor_page, web_page, web_extension);
+
+       return editor_page;
+}
+
+WebKitWebPage *
+e_editor_page_get_web_page (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return editor_page->priv->web_page;
+}
+
+struct _EEditorWebExtension *
+e_editor_page_get_web_extension (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return editor_page->priv->web_extension;
+}
+
+guint64
+e_editor_page_get_page_id (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       if (!editor_page->priv->web_page)
+               return 0;
+
+       return webkit_web_page_get_id (editor_page->priv->web_page);
+}
+
+WebKitDOMDocument *
+e_editor_page_get_document (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       if (!editor_page->priv->web_page)
+               return NULL;
+
+       return webkit_web_page_get_dom_document (editor_page->priv->web_page);
+}
+
+struct _EEditorUndoRedoManager *
+e_editor_page_get_undo_redo_manager (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return editor_page->priv->undo_redo_manager;
+}
+
+void
+e_editor_page_block_selection_changed (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->selection_changed_blocked++;
+}
+
+void
+e_editor_page_unblock_selection_changed (EEditorPage *editor_page)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+       g_return_if_fail (editor_page->priv->selection_changed_blocked > 0);
+
+       editor_page->priv->selection_changed_blocked--;
+
+       if (!editor_page->priv->selection_changed_blocked &&
+           editor_page->priv->selection_changed) {
+               editor_page->priv->selection_changed = FALSE;
+               e_editor_page_emit_selection_changed (editor_page);
+       }
+}
+
+gboolean
+e_editor_page_get_html_mode (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->html_mode;
+}
+
+void
+e_editor_page_set_html_mode (EEditorPage *editor_page,
+                            gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->html_mode = value;
+}
+
+gboolean
+e_editor_page_get_force_image_load (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->force_image_load;
+}
+
+void
+e_editor_page_set_force_image_load (EEditorPage *editor_page,
+                                   gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->force_image_load = value;
+}
+
+gint
+e_editor_page_get_word_wrap_length (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       return editor_page->priv->word_wrap_length;
+}
+
+static gboolean
+e_editor_page_check_style_flag (EEditorPage *editor_page,
+                               EContentEditorStyleFlags flag)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return (editor_page->priv->style_flags & flag) != 0;
+}
+
+static gboolean
+e_editor_page_set_style_flag (EEditorPage *editor_page,
+                             EContentEditorStyleFlags flag,
+                             gboolean value)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       if ((((editor_page->priv->style_flags & flag) != 0) ? 1 : 0) == (value ? 1 : 0))
+               return FALSE;
+
+       editor_page->priv->style_flags = (editor_page->priv->style_flags & ~flag) | (value ? flag : 0);
+
+       return TRUE;
+}
+
+gboolean
+e_editor_page_get_bold (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_BOLD);
+}
+
+void
+e_editor_page_set_bold (EEditorPage *editor_page,
+                       gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_BOLD, value))
+               e_editor_dom_selection_set_bold (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_italic (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_ITALIC);
+}
+
+void
+e_editor_page_set_italic (EEditorPage *editor_page,
+                         gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_ITALIC, value))
+               e_editor_dom_selection_set_italic (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_underline (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_UNDERLINE);
+}
+
+void
+e_editor_page_set_underline (EEditorPage *editor_page,
+                            gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_UNDERLINE, value))
+               e_editor_dom_selection_set_underline (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_monospace (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_MONOSPACE);
+}
+
+void
+e_editor_page_set_monospace (EEditorPage *editor_page,
+                            gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_MONOSPACE, value))
+               e_editor_dom_selection_set_monospace (editor_page, value);
+}
+
+gboolean
+e_editor_page_get_strikethrough (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return e_editor_page_check_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH);
+}
+
+void
+e_editor_page_set_strikethrough (EEditorPage *editor_page,
+                                gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (e_editor_page_set_style_flag (editor_page, E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH, value))
+               e_editor_dom_selection_set_strikethrough (editor_page, value);
+}
+
+guint
+e_editor_page_get_font_size (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       return editor_page->priv->font_size;
+}
+
+void
+e_editor_page_set_font_size (EEditorPage *editor_page,
+                            guint value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (editor_page->priv->font_size == value)
+               return;
+
+       editor_page->priv->font_size = value;
+}
+
+const gchar *
+e_editor_page_get_font_color (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return editor_page->priv->font_color;
+}
+
+EContentEditorAlignment
+e_editor_page_get_alignment (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_CONTENT_EDITOR_ALIGNMENT_LEFT);
+
+       return editor_page->priv->alignment;
+}
+
+void
+e_editor_page_set_alignment (EEditorPage *editor_page,
+                            EContentEditorAlignment value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->alignment = value;
+}
+
+EContentEditorContentFlags
+e_editor_page_get_current_content_flags (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       return editor_page->priv->content_flags;
+}
+
+void
+e_editor_page_set_current_content_flags (EEditorPage *editor_page,
+                                        guint flags)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->content_flags = flags;
+}
+
+gboolean
+e_editor_page_get_return_key_pressed (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->return_key_pressed;
+}
+
+void
+e_editor_page_set_return_key_pressed (EEditorPage *editor_page,
+                                     gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->return_key_pressed = value;
+}
+
+gboolean
+e_editor_page_get_space_key_pressed (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->space_key_pressed;
+}
+
+void
+e_editor_page_set_space_key_pressed (EEditorPage *editor_page,
+                                    gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->space_key_pressed = value;
+}
+
+gboolean
+e_editor_page_get_magic_links_enabled (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-magic-links");
+}
+
+gboolean
+e_editor_page_get_magic_smileys_enabled (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-magic-smileys");
+}
+
+gboolean
+e_editor_page_get_unicode_smileys_enabled (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-unicode-smileys");
+}
+
+EImageLoadingPolicy
+e_editor_page_get_image_loading_policy (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), E_IMAGE_LOADING_POLICY_NEVER);
+
+       return g_settings_get_enum (editor_page->priv->mail_settings, "image-loading-policy");
+}
+
+gboolean
+e_editor_page_get_inline_spelling_enabled (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return g_settings_get_boolean (editor_page->priv->mail_settings, "composer-inline-spelling");
+}
+
+gboolean
+e_editor_page_check_word_spelling (EEditorPage *editor_page,
+                                  const gchar *word,
+                                  const gchar * const *languages)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), TRUE);
+
+       if (!word || !languages || !*languages)
+               return TRUE;
+
+       e_spell_checker_set_active_languages (editor_page->priv->spell_checker, languages);
+
+       return e_spell_checker_check_word (editor_page->priv->spell_checker, word, -1);
+}
+
+gboolean
+e_editor_page_get_body_input_event_removed (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->body_input_event_removed;
+}
+
+void
+e_editor_page_set_body_input_event_removed (EEditorPage *editor_page,
+                                           gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->body_input_event_removed = value;
+}
+
+gboolean
+e_editor_page_get_convert_in_situ (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->convert_in_situ;
+}
+
+void
+e_editor_page_set_convert_in_situ (EEditorPage *editor_page,
+                                  gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->convert_in_situ = value;
+}
+
+GHashTable *
+e_editor_page_get_inline_images (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return editor_page->priv->inline_images;
+}
+
+void
+e_editor_page_add_new_inline_image_into_list (EEditorPage *editor_page,
+                                             const gchar *cid_src,
+                                             const gchar *src)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       g_hash_table_insert (editor_page->priv->inline_images, g_strdup (cid_src), g_strdup (src));
+}
+
+gboolean
+e_editor_page_get_is_smiley_written (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->smiley_written;
+}
+
+void
+e_editor_page_set_is_smiley_written (EEditorPage *editor_page,
+                                    gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->smiley_written = value;
+}
+
+gboolean
+e_editor_page_get_dont_save_history_in_body_input (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->dont_save_history_in_body_input;
+}
+
+void
+e_editor_page_set_dont_save_history_in_body_input (EEditorPage *editor_page,
+                                                  gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->dont_save_history_in_body_input = value;
+}
+
+gboolean
+e_editor_page_is_pasting_content_from_itself (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->pasting_content_from_itself;
+}
+
+void
+e_editor_page_set_pasting_content_from_itself (EEditorPage *editor_page,
+                                              gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->pasting_content_from_itself = value;
+}
+
+gboolean
+e_editor_page_get_renew_history_after_coordinates (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->renew_history_after_coordinates;
+}
+
+void
+e_editor_page_set_renew_history_after_coordinates (EEditorPage *editor_page,
+                                                  gboolean renew_history_after_coordinates)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->renew_history_after_coordinates = renew_history_after_coordinates;
+}
+
+gboolean
+e_editor_page_is_composition_in_progress (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), FALSE);
+
+       return editor_page->priv->composition_in_progress;
+}
+
+void
+e_editor_page_set_composition_in_progress (EEditorPage *editor_page,
+                                          gboolean value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->composition_in_progress = value;
+}
+
+guint
+e_editor_page_get_spell_check_on_scroll_event_source_id (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), 0);
+
+       return editor_page->priv->spell_check_on_scroll_event_source_id;
+}
+
+void
+e_editor_page_set_spell_check_on_scroll_event_source_id (EEditorPage *editor_page,
+                                                        guint value)
+{
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       editor_page->priv->spell_check_on_scroll_event_source_id = value;
+}
+
+WebKitDOMNode *
+e_editor_page_get_node_under_mouse_click (EEditorPage *editor_page)
+{
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
+
+       return editor_page->priv->node_under_mouse_click;
+}
+
+void
+e_editor_page_emit_selection_changed (EEditorPage *editor_page)
+{
+       WebKitDOMDocument *document;
+       WebKitDOMRange *range;
+       GDBusConnection *connection;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!editor_page->priv->web_extension ||
+           editor_page->priv->selection_changed_blocked) {
+               editor_page->priv->selection_changed = TRUE;
+               return;
+       }
+
+       document = e_editor_page_get_document (editor_page);
+       if (!document)
+               return;
+
+       connection = e_editor_web_extension_get_connection (editor_page->priv->web_extension);
+       if (!connection)
+               return;
+
+       range = e_editor_dom_get_current_range (editor_page);
+       if (!range)
+               return;
+
+       g_object_unref (range);
+
+       editor_page->priv->alignment = e_editor_dom_selection_get_alignment (editor_page);
+       editor_page->priv->block_format = e_editor_dom_selection_get_block_format (editor_page);
+
+       if (editor_page->priv->html_mode) {
+               guint32 style_flags = E_CONTENT_EDITOR_STYLE_NONE;
+
+               #define set_flag_if(tst, flg) G_STMT_START { \
+                       if (tst (editor_page)) \
+                               style_flags |= flg; \
+                       } G_STMT_END
+
+               set_flag_if (e_editor_dom_selection_is_bold, E_CONTENT_EDITOR_STYLE_IS_BOLD);
+               set_flag_if (e_editor_dom_selection_is_italic, E_CONTENT_EDITOR_STYLE_IS_ITALIC);
+               set_flag_if (e_editor_dom_selection_is_underline, E_CONTENT_EDITOR_STYLE_IS_UNDERLINE);
+               set_flag_if (e_editor_dom_selection_is_strikethrough, 
E_CONTENT_EDITOR_STYLE_IS_STRIKETHROUGH);
+               set_flag_if (e_editor_dom_selection_is_monospace, E_CONTENT_EDITOR_STYLE_IS_MONOSPACE);
+               set_flag_if (e_editor_dom_selection_is_subscript, E_CONTENT_EDITOR_STYLE_IS_SUBSCRIPT);
+               set_flag_if (e_editor_dom_selection_is_superscript, E_CONTENT_EDITOR_STYLE_IS_SUPERSCRIPT);
+
+               #undef set_flag_if
+
+               editor_page->priv->style_flags = style_flags;
+               editor_page->priv->font_size = e_editor_dom_selection_get_font_size (editor_page);
+               g_free (editor_page->priv->font_color);
+               editor_page->priv->font_color = e_editor_dom_selection_get_font_color (editor_page);
+       }
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+               "SelectionChanged",
+               g_variant_new ("(tiibiis)",
+                       e_editor_page_get_page_id (editor_page),
+                       (gint32) editor_page->priv->alignment,
+                       (gint32) editor_page->priv->block_format,
+                       e_editor_dom_selection_is_indented (editor_page),
+                       editor_page->priv->style_flags,
+                       (gint32) editor_page->priv->font_size,
+                       editor_page->priv->font_color ? editor_page->priv->font_color : ""),
+               &error);
+
+       if (error) {
+               g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
+               g_error_free (error);
+       }
+}
+
+void
+e_editor_page_emit_content_changed (EEditorPage *editor_page)
+{
+       GDBusConnection *connection;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!editor_page->priv->web_extension)
+               return;
+
+       connection = e_editor_web_extension_get_connection (editor_page->priv->web_extension);
+       if (!connection)
+               return;
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+               "ContentChanged",
+               g_variant_new ("(t)", e_editor_page_get_page_id (editor_page)),
+               &error);
+
+       if (error) {
+               g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
+               g_error_free (error);
+       }
+}
+
+void
+e_editor_page_emit_undo_redo_state_changed (EEditorPage *editor_page)
+{
+       GDBusConnection *connection;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       if (!editor_page->priv->web_extension)
+               return;
+
+       connection = e_editor_web_extension_get_connection (editor_page->priv->web_extension);
+       if (!connection)
+               return;
+
+       g_dbus_connection_emit_signal (
+               connection,
+               NULL,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE,
+               "UndoRedoStateChanged",
+               g_variant_new ("(tbb)",
+                       e_editor_page_get_page_id (editor_page),
+                       e_editor_undo_redo_manager_can_undo (editor_page->priv->undo_redo_manager),
+                       e_editor_undo_redo_manager_can_redo (editor_page->priv->undo_redo_manager)),
+               &error);
+
+       if (error) {
+               g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
+               g_error_free (error);
+       }
+}
diff --git a/modules/webkit-editor/web-extension/e-editor-page.h 
b/modules/webkit-editor/web-extension/e-editor-page.h
new file mode 100644
index 0000000..95f833c
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-page.h
@@ -0,0 +1,203 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2016 Red Hat, Inc. (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/>.
+ */
+
+#ifndef E_EDITOR_PAGE_H
+#define E_EDITOR_PAGE_H
+
+#include <glib-object.h>
+#include <webkit2/webkit-web-extension.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+/* Standard GObject macros */
+#define E_TYPE_EDITOR_PAGE \
+       (e_editor_page_get_type ())
+#define E_EDITOR_PAGE(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_EDITOR_PAGE, EEditorPage))
+#define E_EDITOR_PAGE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_EDITOR_PAGE, EEditorPageClass))
+#define E_IS_EDITOR_PAGE(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_EDITOR_PAGE))
+#define E_IS_EDITOR_PAGE_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_EDITOR_PAGE))
+#define E_EDITOR_PAGE_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_EDITOR_PAGE, EEditorPageClass))
+
+G_BEGIN_DECLS
+
+struct _EEditorWebExtension;
+struct _EEditorUndoRedoManager;
+
+typedef struct _EEditorPage EEditorPage;
+typedef struct _EEditorPageClass EEditorPageClass;
+typedef struct _EEditorPagePrivate EEditorPagePrivate;
+
+struct _EEditorPage {
+       GObject parent;
+       EEditorPagePrivate *priv;
+};
+
+struct _EEditorPageClass {
+       GObjectClass parent_class;
+};
+
+GType          e_editor_page_get_type          (void) G_GNUC_CONST;
+EEditorPage *  e_editor_page_new               (WebKitWebPage *web_page,
+                                                struct _EEditorWebExtension *web_extension);
+WebKitWebPage *        e_editor_page_get_web_page      (EEditorPage *editor_page);
+struct _EEditorWebExtension *
+               e_editor_page_get_web_extension (EEditorPage *editor_page);
+guint64                e_editor_page_get_page_id       (EEditorPage *editor_page);
+WebKitDOMDocument *
+               e_editor_page_get_document      (EEditorPage *editor_page);
+struct _EEditorUndoRedoManager *
+               e_editor_page_get_undo_redo_manager
+                                               (EEditorPage *editor_page);
+
+void           e_editor_page_block_selection_changed
+                                               (EEditorPage *editor_page);
+void           e_editor_page_unblock_selection_changed
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_page_get_html_mode     (EEditorPage *editor_page);
+void           e_editor_page_set_html_mode     (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_force_image_load
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_force_image_load
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_bold          (EEditorPage *editor_page);
+void           e_editor_page_set_bold          (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_italic        (EEditorPage *editor_page);
+void           e_editor_page_set_italic        (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_underline     (EEditorPage *editor_page);
+void           e_editor_page_set_underline     (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_monospace     (EEditorPage *editor_page);
+void           e_editor_page_set_monospace     (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_strikethrough (EEditorPage *editor_page);
+void           e_editor_page_set_strikethrough (EEditorPage *editor_page,
+                                                gboolean value);
+guint          e_editor_page_get_font_size     (EEditorPage *editor_page);
+void           e_editor_page_set_font_size     (EEditorPage *editor_page,
+                                                guint value);
+const gchar *  e_editor_page_get_font_color    (EEditorPage *editor_page);
+EContentEditorAlignment
+               e_editor_page_get_alignment     (EEditorPage *editor_page);
+void           e_editor_page_set_alignment     (EEditorPage *editor_page,
+                                                EContentEditorAlignment value);
+gint           e_editor_page_get_word_wrap_length
+                                               (EEditorPage *editor_page);
+EContentEditorContentFlags
+               e_editor_page_get_current_content_flags
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_current_content_flags
+                                               (EEditorPage *editor_page,
+                                                guint flags);
+gboolean       e_editor_page_get_return_key_pressed
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_return_key_pressed
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_space_key_pressed
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_space_key_pressed
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_magic_links_enabled
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_page_get_magic_smileys_enabled
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_page_get_unicode_smileys_enabled
+                                               (EEditorPage *editor_page);
+EImageLoadingPolicy
+               e_editor_page_get_image_loading_policy
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_page_get_inline_spelling_enabled
+                                               (EEditorPage *editor_page);
+gboolean       e_editor_page_check_word_spelling
+                                               (EEditorPage *editor_page,
+                                                const gchar *word,
+                                                const gchar * const *languages);
+gboolean       e_editor_page_get_body_input_event_removed
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_body_input_event_removed
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_convert_in_situ
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_convert_in_situ
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+GHashTable *   e_editor_page_get_inline_images
+                                               (EEditorPage *editor_page);
+void           e_editor_page_add_new_inline_image_into_list
+                                               (EEditorPage *editor_page,
+                                                const gchar *cid_src,
+                                                const gchar *src);
+gboolean       e_editor_page_get_is_smiley_written
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_is_smiley_written
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_dont_save_history_in_body_input
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_dont_save_history_in_body_input
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_is_pasting_content_from_itself
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_pasting_content_from_itself
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+gboolean       e_editor_page_get_renew_history_after_coordinates
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_renew_history_after_coordinates
+                                               (EEditorPage *editor_page,
+                                                gboolean renew_history_after_coordinates);
+gboolean       e_editor_page_is_composition_in_progress
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_composition_in_progress
+                                               (EEditorPage *editor_page,
+                                                gboolean value);
+guint          e_editor_page_get_spell_check_on_scroll_event_source_id
+                                               (EEditorPage *editor_page);
+void           e_editor_page_set_spell_check_on_scroll_event_source_id
+                                               (EEditorPage *editor_page,
+                                                guint value);
+WebKitDOMNode *        e_editor_page_get_node_under_mouse_click
+                                               (EEditorPage *editor_page);
+
+void           e_editor_page_emit_selection_changed
+                                               (EEditorPage *editor_page);
+void           e_editor_page_emit_content_changed
+                                               (EEditorPage *editor_page);
+void           e_editor_page_emit_undo_redo_state_changed
+                                               (EEditorPage *editor_page);
+G_END_DECLS
+
+#endif /* E_EDITOR_PAGE_H */
diff --git a/modules/webkit-editor/web-extension/e-html-editor-undo-redo-manager.c 
b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
similarity index 72%
rename from modules/webkit-editor/web-extension/e-html-editor-undo-redo-manager.c
rename to modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
index e7a24b9..42f97b0 100644
--- a/modules/webkit-editor/web-extension/e-html-editor-undo-redo-manager.c
+++ b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
@@ -1,5 +1,5 @@
 /*
- * e-html-editor-undo-redo-manager.c
+ * e-editor-undo-redo-manager.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,21 +27,20 @@
 #include <webkitdom/WebKitDOMDOMWindowUnstable.h>
 #include <webkitdom/WebKitDOMHTMLElementUnstable.h>
 #include <webkitdom/WebKitDOMDocumentUnstable.h>
+#undef WEBKIT_DOM_USE_UNSTABLE_API
 
-#include <web-extensions/e-dom-utils.h>
+#include "web-extensions/e-dom-utils.h"
 
-#include "e-html-editor-undo-redo-manager.h"
-#include "e-html-editor-web-extension.h"
-#include "e-html-editor-selection-dom-functions.h"
-#include "e-html-editor-view-dom-functions.h"
+#include "e-editor-page.h"
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
 
-#define E_HTML_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE(obj) \
+#define E_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_HTML_EDITOR_UNDO_REDO_MANAGER, EHTMLEditorUndoRedoManagerPrivate))
+       ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManagerPrivate))
 
-struct _EHTMLEditorUndoRedoManagerPrivate {
-       WebKitDOMDocument *document;
-       GWeakRef extension;
+struct _EEditorUndoRedoManagerPrivate {
+       GWeakRef editor_page;
 
        gboolean operation_in_progress;
 
@@ -53,52 +52,36 @@ enum {
        PROP_0,
        PROP_CAN_REDO,
        PROP_CAN_UNDO,
-       PROP_HTML_EDITOR_WEB_EXTENSION
+       PROP_EDITOR_PAGE
 };
 
 #define HISTORY_SIZE_LIMIT 30
 
 #define d(x)
 
-G_DEFINE_TYPE (
-       EHTMLEditorUndoRedoManager,
-       e_html_editor_undo_redo_manager,
-       G_TYPE_OBJECT
-);
+G_DEFINE_TYPE (EEditorUndoRedoManager, e_editor_undo_redo_manager, G_TYPE_OBJECT)
 
-EHTMLEditorUndoRedoManager *
-e_html_editor_undo_redo_manager_new (EHTMLEditorWebExtension *extension)
+EEditorUndoRedoManager *
+e_editor_undo_redo_manager_new (EEditorPage *editor_page)
 {
-       g_return_val_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension), NULL);
+       g_return_val_if_fail (E_IS_EDITOR_PAGE (editor_page), NULL);
 
-       return g_object_new (E_TYPE_HTML_EDITOR_UNDO_REDO_MANAGER,
-               "html-editor-web-extension", extension,
+       return g_object_new (E_TYPE_EDITOR_UNDO_REDO_MANAGER,
+               "editor-page", editor_page,
                NULL);
 }
 
-void
-e_html_editor_undo_redo_manager_set_document (EHTMLEditorUndoRedoManager *manager,
-                                              WebKitDOMDocument *document)
-{
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
-
-       manager->priv->document = document;
-
-       /* The history is not valid if document is changed. */
-       e_html_editor_undo_redo_manager_clean_history (manager);
-}
-
-static EHTMLEditorWebExtension *
-html_editor_undo_redo_manager_ref_extension (EHTMLEditorUndoRedoManager *manager)
+static EEditorPage *
+editor_undo_redo_manager_ref_editor_page (EEditorUndoRedoManager *manager)
 {
-       g_return_val_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
+       g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
 
-       return g_weak_ref_get (&manager->priv->extension);
+       return g_weak_ref_get (&manager->priv->editor_page);
 }
 
 static WebKitDOMRange *
 get_range_for_point (WebKitDOMDocument *document,
-                     EHTMLEditorSelectionPoint point)
+                     EEditorSelectionPoint point)
 {
        glong scroll_left, scroll_top;
        WebKitDOMHTMLElement *body;
@@ -129,15 +112,19 @@ get_range_for_point (WebKitDOMDocument *document,
 }
 
 static void
-restore_selection_to_history_event_state (WebKitDOMDocument *document,
-                                          EHTMLEditorSelection selection_state)
+restore_selection_to_history_event_state (EEditorPage *editor_page,
+                                          EEditorSelection selection_state)
 {
-       gboolean was_collapsed = FALSE;
+       WebKitDOMDocument *document;
        WebKitDOMDOMWindow *dom_window;
        WebKitDOMDOMSelection *dom_selection;
        WebKitDOMElement *element, *tmp;
        WebKitDOMRange *range;
+       gboolean was_collapsed = FALSE;
 
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
+       document = e_editor_page_get_document (editor_page);
        dom_window = webkit_dom_document_get_default_view (document);
        dom_selection = webkit_dom_dom_window_get_selection (dom_window);
        g_object_unref (dom_window);
@@ -155,7 +142,7 @@ restore_selection_to_history_event_state (WebKitDOMDocument *document,
                return;
        }
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
 
        element = webkit_dom_document_get_element_by_id (
                document, "-x-evo-selection-end-marker");
@@ -172,7 +159,7 @@ restore_selection_to_history_event_state (WebKitDOMDocument *document,
        webkit_dom_dom_selection_add_range (dom_selection, range);
        g_object_unref (range);
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
 
        tmp = webkit_dom_document_get_element_by_id (
                document, "-x-evo-selection-start-marker");
@@ -182,7 +169,7 @@ restore_selection_to_history_event_state (WebKitDOMDocument *document,
        webkit_dom_element_set_id (
                element, "-x-evo-selection-start-marker");
 
-       dom_selection_restore (document);
+       e_editor_dom_selection_restore (editor_page);
 
        g_object_unref (dom_selection);
 }
@@ -206,7 +193,7 @@ print_node_inner_html (WebKitDOMNode *node)
 }
 
 static void
-print_history_event (EHTMLEditorHistoryEvent *event)
+print_history_event (EEditorHistoryEvent *event)
 {
        if (event->type != HISTORY_START && event->type != HISTORY_AND) {
                printf ("  HISTORY EVENT: %d ; \n", event->type);
@@ -269,7 +256,7 @@ print_history_event (EHTMLEditorHistoryEvent *event)
 }
 
 static void
-print_history (EHTMLEditorUndoRedoManager *manager)
+print_history (EEditorUndoRedoManager *manager)
 {
        printf ("-------------------\nWHOLE HISTORY STACK\n");
        if (manager->priv->history) {
@@ -280,7 +267,7 @@ print_history (EHTMLEditorUndoRedoManager *manager)
 }
 
 static void
-print_undo_events (EHTMLEditorUndoRedoManager *manager)
+print_undo_events (EEditorUndoRedoManager *manager)
 {
        GList *item = manager->priv->history;
 
@@ -301,7 +288,7 @@ print_undo_events (EHTMLEditorUndoRedoManager *manager)
 }
 
 static void
-print_redo_events (EHTMLEditorUndoRedoManager *manager)
+print_redo_events (EEditorUndoRedoManager *manager)
 {
        GList *item = manager->priv->history;
 
@@ -322,7 +309,7 @@ print_redo_events (EHTMLEditorUndoRedoManager *manager)
 #endif
 
 static gboolean
-event_selection_was_collapsed (EHTMLEditorHistoryEvent *ev)
+event_selection_was_collapsed (EEditorHistoryEvent *ev)
 {
        return (ev->before.start.x == ev->before.end.x) && (ev->before.start.y == ev->before.end.y);
 }
@@ -392,18 +379,19 @@ split_node_into_two (WebKitDOMNode *item,
 }
 
 static void
-undo_delete (WebKitDOMDocument *document,
-             EHTMLEditorWebExtension *extension,
-             EHTMLEditorHistoryEvent *event)
+undo_delete (EEditorPage *editor_page,
+             EEditorHistoryEvent *event)
 {
        gboolean empty, single_block;
        gchar *content;
+       WebKitDOMDocument *document;
        WebKitDOMDOMWindow *dom_window;
        WebKitDOMDOMSelection *dom_selection;
        WebKitDOMRange *range;
        WebKitDOMElement *element;
        WebKitDOMNode *first_child, *fragment;
 
+       document = e_editor_page_get_document (editor_page);
        dom_window = webkit_dom_document_get_default_view (document);
        dom_selection = webkit_dom_dom_window_get_selection (dom_window);
        g_object_unref (dom_window);
@@ -437,14 +425,14 @@ undo_delete (WebKitDOMDocument *document,
                webkit_dom_dom_selection_add_range (dom_selection, range);
 
                node = webkit_dom_range_get_end_container (range, NULL);
-               block = get_parent_block_node_from_child (node);
+               block = e_editor_dom_get_parent_block_node_from_child (node);
 
                if (webkit_dom_document_fragment_query_selector (event->data.fragment, ".-x-evo-quoted", 
NULL)) {
                        while ((node = webkit_dom_node_get_first_child (fragment))) {
                                if (WEBKIT_DOM_IS_ELEMENT (node) &&
                                    webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (node), 
".-x-evo-quoted", NULL))
 
-                                       if (get_citation_level (block, FALSE) > 0) {
+                                       if (e_editor_dom_get_citation_level (block, FALSE) > 0) {
                                                webkit_dom_node_insert_before (
                                                        webkit_dom_node_get_parent_node (block),
                                                        node,
@@ -454,7 +442,7 @@ undo_delete (WebKitDOMDocument *document,
                                                WebKitDOMNode *next_block;
 
                                                next_block = webkit_dom_node_get_next_sibling (block);
-                                               while (next_block && dom_node_is_citation_node (next_block))
+                                               while (next_block && e_editor_dom_node_is_citation_node 
(next_block))
                                                        next_block = webkit_dom_node_get_first_child 
(next_block);
 
                                                webkit_dom_node_insert_before (
@@ -464,7 +452,7 @@ undo_delete (WebKitDOMDocument *document,
                                                        NULL);
                                        }
                                else {
-                                       if (get_citation_level (block, FALSE) > 0) {
+                                       if (e_editor_dom_get_citation_level (block, FALSE) > 0) {
                                                WebKitDOMNode *next_node;
 
                                                if ((next_node = split_node_into_two (block, -1)))
@@ -499,9 +487,9 @@ undo_delete (WebKitDOMDocument *document,
 
                remove_node (block);
 
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 
-               dom_force_spell_check_in_viewport (document, extension);
+               e_editor_dom_force_spell_check_in_viewport (editor_page);
 
                return;
        }
@@ -509,8 +497,8 @@ undo_delete (WebKitDOMDocument *document,
        /* Redoing Return key press */
        if (event->type == HISTORY_INPUT && (empty ||
            g_object_get_data (G_OBJECT (event->data.fragment), "history-return-key"))) {
-               if (key_press_event_process_return_key (document, extension)) {
-                       body_key_up_event_process_return_key (document, extension);
+               if (e_editor_dom_key_press_event_process_return_key (editor_page)) {
+                       e_editor_dom_body_key_up_event_process_return_key (editor_page);
                } else {
                        WebKitDOMElement *element;
                        WebKitDOMNode *next_sibling;
@@ -521,7 +509,7 @@ undo_delete (WebKitDOMDocument *document,
                        g_object_unref (dom_selection);
                        g_object_unref (range);
 
-                       dom_selection_save (document);
+                       e_editor_dom_selection_save (editor_page);
 
                        element = webkit_dom_document_get_element_by_id (
                                document, "-x-evo-selection-end-marker");
@@ -532,7 +520,7 @@ undo_delete (WebKitDOMDocument *document,
                        } else {
                                WebKitDOMNode *block;
 
-                               block = get_parent_block_node_from_child (
+                               block = e_editor_dom_get_parent_block_node_from_child (
                                        WEBKIT_DOM_NODE (element));
                                dom_remove_selection_markers (document);
                                webkit_dom_node_insert_before (
@@ -541,13 +529,13 @@ undo_delete (WebKitDOMDocument *document,
                                        webkit_dom_node_get_next_sibling (block),
                                        NULL);
                        }
-                       dom_selection_restore (document);
+                       e_editor_dom_selection_restore (editor_page);
                }
 
-               e_html_editor_web_extension_set_return_key_pressed (extension, TRUE);
-               dom_check_magic_links (document, extension, FALSE);
-               e_html_editor_web_extension_set_return_key_pressed (extension, FALSE);
-               dom_force_spell_check_in_viewport (document, extension);
+               e_editor_page_set_return_key_pressed (editor_page, TRUE);
+               e_editor_dom_check_magic_links (editor_page, FALSE);
+               e_editor_page_set_return_key_pressed (editor_page, FALSE);
+               e_editor_dom_force_spell_check_in_viewport (editor_page);
 
                return;
        }
@@ -571,7 +559,7 @@ undo_delete (WebKitDOMDocument *document,
                webkit_dom_dom_selection_remove_all_ranges (dom_selection);
                webkit_dom_dom_selection_add_range (dom_selection, range);
                g_object_unref (range);
-               dom_selection_save (document);
+               e_editor_dom_selection_save (editor_page);
 
                if ((element = webkit_dom_document_get_element_by_id (document, 
"-x-evo-selection-end-marker"))) {
                        WebKitDOMNode *next_sibling;
@@ -626,7 +614,7 @@ undo_delete (WebKitDOMDocument *document,
                                element_has_class (WEBKIT_DOM_ELEMENT (tmp_node), "-x-evo-signature-wrapper");
                }
 
-               current_block = get_parent_block_node_from_child (WEBKIT_DOM_NODE (element));
+               current_block = e_editor_dom_get_parent_block_node_from_child (WEBKIT_DOM_NODE (element));
 
                while (node) {
                        WebKitDOMNode *next_sibling, *parent_node;
@@ -652,7 +640,7 @@ undo_delete (WebKitDOMDocument *document,
                                if (tmp_element)
                                        remove_node (WEBKIT_DOM_NODE (tmp_element));
 
-                               dom_merge_siblings_if_necessary (document, event->data.fragment);
+                               e_editor_dom_merge_siblings_if_necessary (editor_page, event->data.fragment);
 
                                tmp_node = webkit_dom_node_get_last_child (last_child);
                                if (tmp_node && WEBKIT_DOM_IS_ELEMENT (tmp_node) &&
@@ -667,9 +655,9 @@ undo_delete (WebKitDOMDocument *document,
 
                                dom_remove_selection_markers (document);
 
-                               restore_selection_to_history_event_state (document, event->before);
+                               restore_selection_to_history_event_state (editor_page, event->before);
 
-                               dom_force_spell_check_in_viewport (document, extension);
+                               e_editor_dom_force_spell_check_in_viewport (editor_page);
 
                                g_object_unref (dom_selection);
 
@@ -712,7 +700,7 @@ undo_delete (WebKitDOMDocument *document,
                if (insert_before &&
                    WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (
                        webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment))) &&
-                   get_citation_level (insert_before, FALSE > 0))
+                   e_editor_dom_get_citation_level (insert_before, FALSE > 0))
                        insert_before = split_node_into_two (insert_before, -1);
 
                /* Remove the first block from deleted content as its content was already
@@ -733,12 +721,12 @@ undo_delete (WebKitDOMDocument *document,
                                WEBKIT_DOM_NODE (fragment),
                                NULL);
 
-               wrap_and_quote_element (document, extension, WEBKIT_DOM_ELEMENT (current_block));
+               e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (current_block));
 
                if (WEBKIT_DOM_IS_ELEMENT (last_child))
-                       wrap_and_quote_element (document, extension, WEBKIT_DOM_ELEMENT (last_child));
+                       e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_child));
 
-               dom_merge_siblings_if_necessary (document, event->data.fragment);
+               e_editor_dom_merge_siblings_if_necessary (editor_page, event->data.fragment);
 
                /* If undoing drag and drop where the whole line was moved we need
                 * to correct the selection. */
@@ -752,8 +740,8 @@ undo_delete (WebKitDOMDocument *document,
                                        prev_block, WEBKIT_DOM_NODE (element), NULL);
                }
 
-               dom_selection_restore (document);
-               dom_force_spell_check_in_viewport (document, extension);
+               e_editor_dom_selection_restore (editor_page);
+               e_editor_dom_force_spell_check_in_viewport (editor_page);
        } else {
                gboolean empty_text = FALSE, was_link = FALSE;
                WebKitDOMNode *prev_sibling, *next_sibling, *nd;
@@ -863,56 +851,55 @@ undo_delete (WebKitDOMDocument *document,
 
                remove_node (WEBKIT_DOM_NODE (element));
 
-               if (event->type == HISTORY_DELETE && !e_html_editor_web_extension_get_html_mode (extension)) {
+               if (event->type == HISTORY_DELETE && !e_editor_page_get_html_mode (editor_page)) {
                        WebKitDOMNode *current_block;
 
-                       current_block = get_parent_block_node_from_child (parent);
-                       if (get_citation_level (current_block, FALSE) > 0)
-                               wrap_and_quote_element (document, extension, WEBKIT_DOM_ELEMENT 
(current_block));
+                       current_block = e_editor_dom_get_parent_block_node_from_child (parent);
+                       if (e_editor_dom_get_citation_level (current_block, FALSE) > 0)
+                               e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT 
(current_block));
                }
 
                /* If the selection markers are presented restore the selection,
                 * otherwise the selection was not collapsed so select the deleted
                 * content as it was before the delete occurred. */
                if (webkit_dom_document_fragment_query_selector (event->data.fragment, 
"span#-x-evo-selection-start-marker", NULL))
-                       dom_selection_restore (document);
+                       e_editor_dom_selection_restore (editor_page);
                else
-                       restore_selection_to_history_event_state (document, event->before);
+                       restore_selection_to_history_event_state (editor_page, event->before);
 
                if (event->type != HISTORY_INPUT) {
-                       if (e_html_editor_web_extension_get_magic_smileys_enabled (extension))
-                               dom_check_magic_smileys (document, extension);
-                       if (!was_link && e_html_editor_web_extension_get_magic_links_enabled (extension))
-                               dom_check_magic_links (document, extension, FALSE);
+                       if (e_editor_page_get_magic_smileys_enabled (editor_page))
+                               e_editor_dom_check_magic_smileys (editor_page);
+                       if (!was_link && e_editor_page_get_magic_links_enabled (editor_page))
+                               e_editor_dom_check_magic_links (editor_page, FALSE);
                }
-               dom_force_spell_check_for_current_paragraph (document, extension);
+               e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
        }
 
        g_object_unref (dom_selection);
 }
 
 static void
-redo_delete (WebKitDOMDocument *document,
-             EHTMLEditorWebExtension *extension,
-             EHTMLEditorHistoryEvent *event)
+redo_delete (EEditorPage *editor_page,
+             EEditorHistoryEvent *event)
 {
-       EHTMLEditorUndoRedoManager *manager;
+       EEditorUndoRedoManager *manager;
+       WebKitDOMDocumentFragment *fragment = event->data.fragment;
+       WebKitDOMNode *node;
        gboolean delete_key, control_key;
        glong length = 1;
        gint ii;
-       WebKitDOMDocumentFragment *fragment = event->data.fragment;
-       WebKitDOMNode *node;
 
-       manager = e_html_editor_web_extension_get_undo_redo_manager (extension, document);
-       restore_selection_to_history_event_state (document, event->before);
+       manager = e_editor_page_get_undo_redo_manager (editor_page);
+       restore_selection_to_history_event_state (editor_page, event->before);
 
        delete_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment), 
"history-delete-key"));
        control_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment), 
"history-control-key"));
 
-       if (!delete_key && key_press_event_process_backspace_key (document, extension))
+       if (!delete_key && e_editor_dom_key_press_event_process_backspace_key (editor_page))
                goto out;
 
-       if (key_press_event_process_delete_or_backspace_key (document, extension, ~0, 0, delete_key))
+       if (e_editor_dom_key_press_event_process_delete_or_backspace_key (editor_page, ~0, 0, delete_key))
                goto out;
 
        if (control_key) {
@@ -935,20 +922,19 @@ redo_delete (WebKitDOMDocument *document,
                WebKitDOMNode *current_block, *next_block, *node;
                WebKitDOMRange *range;
 
-               range = dom_get_current_range (document);
+               range = e_editor_dom_get_current_range (editor_page);
                node = webkit_dom_range_get_end_container (range, NULL);
                g_object_unref (range);
-               current_block = get_parent_block_node_from_child (node);
-               if (get_citation_level (current_block, FALSE) > 0 &&
+               current_block = e_editor_dom_get_parent_block_node_from_child (node);
+               if (e_editor_dom_get_citation_level (current_block, FALSE) > 0 &&
                    (next_block = webkit_dom_node_get_next_sibling (current_block))) {
-                       dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (next_block));
-                       dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (next_block));
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (next_block));
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (next_block));
                }
        }
 
        for (ii = 0; ii < length; ii++) {
-               dom_exec_command (
-                       document, extension,
+               e_editor_dom_exec_command (editor_page,
                        delete_key ? E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE :
                                     E_CONTENT_EDITOR_COMMAND_DELETE,
                        NULL);
@@ -960,8 +946,7 @@ redo_delete (WebKitDOMDocument *document,
        node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
        while ((node = webkit_dom_node_get_first_child (node))) {
                if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
-                       dom_exec_command (
-                               document, extension,
+                       e_editor_dom_exec_command (editor_page,
                                E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE,
                                NULL);
                        break;
@@ -971,8 +956,7 @@ redo_delete (WebKitDOMDocument *document,
        node = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
        while ((node = webkit_dom_node_get_last_child (node))) {
                if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node)) {
-                       dom_exec_command (
-                               document, extension,
+                       e_editor_dom_exec_command (editor_page,
                                E_CONTENT_EDITOR_COMMAND_FORWARD_DELETE,
                                NULL);
                        break;
@@ -980,150 +964,145 @@ redo_delete (WebKitDOMDocument *document,
        }
 
  out:
-       e_html_editor_web_extension_set_dont_save_history_in_body_input (extension, TRUE);
-       e_html_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
-       body_input_event_process (document, extension, NULL);
-       e_html_editor_web_extension_set_dont_save_history_in_body_input (extension, FALSE);
-       e_html_editor_undo_redo_manager_set_operation_in_progress (manager, TRUE);
-       e_html_editor_web_extension_set_renew_history_after_coordinates (extension, FALSE);
-       body_key_up_event_process_backspace_or_delete (document, extension, delete_key);
-       e_html_editor_web_extension_set_renew_history_after_coordinates (extension, TRUE);
-
-       restore_selection_to_history_event_state (document, event->after);
-
-       dom_force_spell_check_for_current_paragraph (document, extension);
+       e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
+       e_editor_undo_redo_manager_set_operation_in_progress (manager, FALSE);
+       e_editor_dom_body_input_event_process (editor_page, NULL);
+       e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+       e_editor_undo_redo_manager_set_operation_in_progress (manager, TRUE);
+       e_editor_page_set_renew_history_after_coordinates (editor_page, FALSE);
+       e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, delete_key);
+       e_editor_page_set_renew_history_after_coordinates (editor_page, TRUE);
+
+       restore_selection_to_history_event_state (editor_page, event->after);
+
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
 }
 
-typedef void (*SelectionStyleChangeFunc) (WebKitDOMDocument *document, EHTMLEditorWebExtension *extension, 
gint style);
+typedef void (*SelectionStyleChangeFunc) (EEditorPage *editor_page, gint style);
 
 static void
-undo_redo_style_change (WebKitDOMDocument *document,
-                        EHTMLEditorWebExtension *extension,
-                        EHTMLEditorHistoryEvent *event,
+undo_redo_style_change (EEditorPage *editor_page,
+                        EEditorHistoryEvent *event,
                         gboolean undo)
 {
        SelectionStyleChangeFunc func;
 
        switch (event->type) {
                case HISTORY_ALIGNMENT:
-                       func = (SelectionStyleChangeFunc) dom_selection_set_alignment;
+                       func = (SelectionStyleChangeFunc) e_editor_dom_selection_set_alignment;
                        break;
                case HISTORY_BOLD:
-                       func = dom_selection_set_bold;
+                       func = e_editor_dom_selection_set_bold;
                        break;
                case HISTORY_BLOCK_FORMAT:
-                       func = (SelectionStyleChangeFunc) dom_selection_set_block_format;
+                       func = (SelectionStyleChangeFunc) e_editor_dom_selection_set_block_format;
                        break;
                case HISTORY_FONT_SIZE:
-                       func = (SelectionStyleChangeFunc) dom_selection_set_font_size;
+                       func = (SelectionStyleChangeFunc) e_editor_dom_selection_set_font_size;
                        break;
                case HISTORY_ITALIC:
-                       func = dom_selection_set_italic;
+                       func = e_editor_dom_selection_set_italic;
                        break;
                case HISTORY_MONOSPACE:
-                       func = dom_selection_set_monospaced;
+                       func = e_editor_dom_selection_set_monospace;
                        break;
                case HISTORY_STRIKETHROUGH:
-                       func = dom_selection_set_strikethrough;
+                       func = e_editor_dom_selection_set_strikethrough;
                        break;
                case HISTORY_UNDERLINE:
-                       func = dom_selection_set_underline;
+                       func = e_editor_dom_selection_set_underline;
                        break;
                default:
                        return;
        }
 
-       restore_selection_to_history_event_state (document, undo ? event->after : event->before);
+       restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
 
-       func (document, extension, undo ? event->data.style.from : event->data.style.to);
+       func (editor_page, undo ? event->data.style.from : event->data.style.to);
 
-       restore_selection_to_history_event_state (document, undo ? event->before : event->after);
+       restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
 }
 
 static void
-undo_redo_indent (WebKitDOMDocument *document,
-                  EHTMLEditorWebExtension *extension,
-                  EHTMLEditorHistoryEvent *event,
+undo_redo_indent (EEditorPage *editor_page,
+                  EEditorHistoryEvent *event,
                   gboolean undo)
 {
        gboolean was_indent = FALSE;
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
        was_indent = event->data.style.from && event->data.style.to;
 
        if ((undo && was_indent) || (!undo && !was_indent))
-               dom_selection_unindent (document, extension);
+               e_editor_dom_selection_unindent (editor_page);
        else
-               dom_selection_indent (document, extension);
+               e_editor_dom_selection_indent (editor_page);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 }
 
 static void
-undo_redo_font_color (WebKitDOMDocument *document,
-                      EHTMLEditorWebExtension *extension,
-                      EHTMLEditorHistoryEvent *event,
+undo_redo_font_color (EEditorPage *editor_page,
+                      EEditorHistoryEvent *event,
                       gboolean undo)
 {
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
-       dom_exec_command (
-               document,
-               extension,
+       e_editor_dom_exec_command (editor_page,
                E_CONTENT_EDITOR_COMMAND_FORE_COLOR,
                undo ? event->data.string.from : event->data.string.to);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 }
 
 static void
-undo_redo_wrap (WebKitDOMDocument *document,
-                EHTMLEditorWebExtension *extension,
-                EHTMLEditorHistoryEvent *event,
+undo_redo_wrap (EEditorPage *editor_page,
+                EEditorHistoryEvent *event,
                 gboolean undo)
 {
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
        if (undo) {
                WebKitDOMNode *node;
                WebKitDOMElement *element;
                WebKitDOMRange *range;
 
-               range = dom_get_current_range (document);
+               range = e_editor_dom_get_current_range (editor_page);
                node = webkit_dom_range_get_common_ancestor_container (range, NULL);
                g_object_unref (range);
                element = get_parent_block_element (WEBKIT_DOM_NODE (node));
                webkit_dom_element_remove_attribute (element, "data-user-wrapped");
-               dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (element));
+               e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (element));
 
-               dom_force_spell_check_for_current_paragraph (document, extension);
+               e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
        } else
-               dom_selection_wrap (document, extension);
+               e_editor_dom_selection_wrap (editor_page);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 }
 
 static void
-undo_redo_page_dialog (WebKitDOMDocument *document,
-                       EHTMLEditorWebExtension *extension,
-                       EHTMLEditorHistoryEvent *event,
+undo_redo_page_dialog (EEditorPage *editor_page,
+                       EEditorHistoryEvent *event,
                        gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMHTMLElement *body;
        WebKitDOMNamedNodeMap *attributes, *attributes_history;
        gint length, length_history, ii, jj;
 
+       document = e_editor_page_get_document (editor_page);
        body = webkit_dom_document_get_body (document);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
        if (undo) {
                attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
@@ -1166,13 +1145,13 @@ undo_redo_page_dialog (WebKitDOMDocument *document,
                                        gchar *value;
 
                                        value = webkit_dom_node_get_node_value (attr_clone);
-                                       dom_set_link_color (document, value);
+                                       e_editor_dom_set_link_color (editor_page, value);
                                        g_free (value);
                                } else if (g_strcmp0 (name, "vlink") == 0) {
                                        gchar *value;
 
                                        value = webkit_dom_node_get_node_value (attr_clone);
-                                       dom_set_visited_link_color (document, value);
+                                       e_editor_dom_set_visited_link_color (editor_page, value);
                                        g_free (value);
                                }
                                replaced = TRUE;
@@ -1204,21 +1183,23 @@ undo_redo_page_dialog (WebKitDOMDocument *document,
        g_object_unref (attributes_history);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 }
 
 static void
-undo_redo_hrule_dialog (WebKitDOMDocument *document,
-                        EHTMLEditorWebExtension *extension,
-                        EHTMLEditorHistoryEvent *event,
+undo_redo_hrule_dialog (EEditorPage *editor_page,
+                        EEditorHistoryEvent *event,
                         gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMElement *element;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
        element = webkit_dom_document_get_element_by_id (
                document, "-x-evo-selection-start-marker");
 
@@ -1267,24 +1248,26 @@ undo_redo_hrule_dialog (WebKitDOMDocument *document,
        }
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
        else
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
 }
 
 static void
-undo_redo_image_dialog (WebKitDOMDocument *document,
-                        EHTMLEditorWebExtension *extension,
-                        EHTMLEditorHistoryEvent *event,
+undo_redo_image_dialog (EEditorPage *editor_page,
+                        EEditorHistoryEvent *event,
                         gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMElement *element;
        WebKitDOMNode *sibling, *image = NULL;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
        element = webkit_dom_document_get_element_by_id (
                document, "-x-evo-selection-start-marker");
        sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element));
@@ -1316,25 +1299,27 @@ undo_redo_image_dialog (WebKitDOMDocument *document,
                NULL);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
        else
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
 }
 
 static void
-undo_redo_link_dialog (WebKitDOMDocument *document,
-                       EHTMLEditorWebExtension *extension,
-                       EHTMLEditorHistoryEvent *event,
+undo_redo_link_dialog (EEditorPage *editor_page,
+                       EEditorHistoryEvent *event,
                        gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMElement *anchor, *element;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
        else
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
 
        element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
        if (!element)
@@ -1371,30 +1356,32 @@ undo_redo_link_dialog (WebKitDOMDocument *document,
                                        NULL);
 
                                if (event->data.dom.from)
-                                       dom_exec_command (document, extension,
+                                       e_editor_dom_exec_command (editor_page,
                                                E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
                        }
                }
        }
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
        else
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
 }
 
 static void
-undo_redo_table_dialog (WebKitDOMDocument *document,
-                        EHTMLEditorWebExtension *extension,
-                        EHTMLEditorHistoryEvent *event,
+undo_redo_table_dialog (EEditorPage *editor_page,
+                        EEditorHistoryEvent *event,
                         gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMElement *table, *element;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
        element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
        if (!element)
                return;
@@ -1411,7 +1398,7 @@ undo_redo_table_dialog (WebKitDOMDocument *document,
                                webkit_dom_node_clone_node_with_error (undo ? event->data.dom.from : 
event->data.dom.to, TRUE, NULL),
                                WEBKIT_DOM_NODE (parent),
                                NULL);
-                       restore_selection_to_history_event_state (document, event->before);
+                       restore_selection_to_history_event_state (editor_page, event->before);
                        return;
                } else
                        return;
@@ -1438,25 +1425,27 @@ undo_redo_table_dialog (WebKitDOMDocument *document,
        }
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
        else
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
 }
 
 static void
-undo_redo_table_input (WebKitDOMDocument *document,
-                       EHTMLEditorWebExtension *extension,
-                       EHTMLEditorHistoryEvent *event,
+undo_redo_table_input (EEditorPage *editor_page,
+                       EEditorHistoryEvent *event,
                        gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMDOMWindow *dom_window;
        WebKitDOMDOMSelection *dom_selection;
        WebKitDOMElement *element;
        WebKitDOMNode *node;
        WebKitDOMRange *range;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
        dom_window = webkit_dom_document_get_default_view (document);
        dom_selection = webkit_dom_dom_window_get_selection (dom_window);
@@ -1488,23 +1477,26 @@ undo_redo_table_input (WebKitDOMDocument *document,
                WEBKIT_DOM_NODE (element),
                NULL);
 
-       dom_selection_restore (document);
+       e_editor_dom_selection_restore (editor_page);
 }
 
 static void
-undo_redo_paste (WebKitDOMDocument *document,
-                 EHTMLEditorWebExtension *extension,
-                 EHTMLEditorHistoryEvent *event,
+undo_redo_paste (EEditorPage *editor_page,
+                 EEditorHistoryEvent *event,
                  gboolean undo)
 {
+       WebKitDOMDocument *document;
+
+       document = e_editor_page_get_document (editor_page);
+
        if (undo) {
                if (event->type == HISTORY_PASTE_QUOTED) {
                        WebKitDOMElement *tmp;
                        WebKitDOMNode *parent;
 
-                       restore_selection_to_history_event_state (document, event->after);
+                       restore_selection_to_history_event_state (editor_page, event->after);
 
-                       dom_selection_save (document);
+                       e_editor_dom_selection_save (editor_page);
                        tmp = webkit_dom_document_get_element_by_id (
                                document, "-x-evo-selection-start-marker");
                        if (!tmp)
@@ -1516,11 +1508,11 @@ undo_redo_paste (WebKitDOMDocument *document,
 
                        webkit_dom_node_replace_child (
                                webkit_dom_node_get_parent_node (parent),
-                               WEBKIT_DOM_NODE (dom_prepare_paragraph (document, extension, TRUE)),
+                               WEBKIT_DOM_NODE (e_editor_dom_prepare_paragraph (editor_page, TRUE)),
                                parent,
                                NULL);
 
-                       dom_selection_restore (document);
+                       e_editor_dom_selection_restore (editor_page);
                } else {
                        WebKitDOMDOMWindow *dom_window;
                        WebKitDOMDOMSelection *dom_selection;
@@ -1537,7 +1529,7 @@ undo_redo_paste (WebKitDOMDocument *document,
                        webkit_dom_dom_selection_add_range (dom_selection, range);
                        g_object_unref (range);
 
-                       dom_selection_save (document);
+                       e_editor_dom_selection_save (editor_page);
 
                        element = webkit_dom_document_get_element_by_id (
                                document, "-x-evo-selection-end-marker");
@@ -1555,7 +1547,7 @@ undo_redo_paste (WebKitDOMDocument *document,
                        g_object_unref (range);
                        g_object_unref (dom_selection);
 
-                       dom_selection_save (document);
+                       e_editor_dom_selection_save (editor_page);
 
                        tmp = webkit_dom_document_get_element_by_id (
                                document, "-x-evo-selection-start-marker");
@@ -1565,37 +1557,38 @@ undo_redo_paste (WebKitDOMDocument *document,
                        webkit_dom_element_set_id (
                                element, "-x-evo-selection-start-marker");
 
-                       dom_selection_restore (document);
+                       e_editor_dom_selection_restore (editor_page);
 
-                       dom_exec_command (document, extension, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+                       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
 
-                       dom_force_spell_check_for_current_paragraph (document, extension);
+                       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
                }
        } else {
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 
                if (event->type == HISTORY_PASTE)
-                       dom_convert_and_insert_html_into_selection (document, extension, 
event->data.string.to, FALSE);
+                       e_editor_dom_convert_and_insert_html_into_selection (editor_page, 
event->data.string.to, FALSE);
                else if (event->type == HISTORY_PASTE_QUOTED)
-                       dom_quote_and_insert_text_into_selection (document, extension, event->data.string.to);
+                       e_editor_dom_quote_and_insert_text_into_selection (editor_page, 
event->data.string.to);
                else if (event->type == HISTORY_INSERT_HTML)
-                       dom_insert_html (document, extension, event->data.string.to);
+                       e_editor_dom_insert_html (editor_page, event->data.string.to);
                else
-                       dom_convert_and_insert_html_into_selection (document, extension, 
event->data.string.to, FALSE);
-                       //e_html_editor_selection_insert_as_text (selection, event->data.string.to);
+                       e_editor_dom_convert_and_insert_html_into_selection (editor_page, 
event->data.string.to, FALSE);
+                       //e_editor_selection_insert_as_text (selection, event->data.string.to);
        }
 }
 
 static void
-undo_redo_image (WebKitDOMDocument *document,
-                 EHTMLEditorWebExtension *extension,
-                 EHTMLEditorHistoryEvent *event,
+undo_redo_image (EEditorPage *editor_page,
+                 EEditorHistoryEvent *event,
                  gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMDOMWindow *dom_window;
        WebKitDOMDOMSelection *dom_selection;
        WebKitDOMRange *range;
 
+       document = e_editor_page_get_document (editor_page);
        dom_window = webkit_dom_document_get_default_view (document);
        dom_selection = webkit_dom_dom_window_get_selection (dom_window);
        g_object_unref (dom_window);
@@ -1609,7 +1602,7 @@ undo_redo_image (WebKitDOMDocument *document,
                webkit_dom_dom_selection_add_range (dom_selection, range);
                g_object_unref (range);
 
-               dom_selection_save (document);
+               e_editor_dom_selection_save (editor_page);
                element = webkit_dom_document_get_element_by_id (
                        document, "-x-evo-selection-end-marker");
 
@@ -1619,7 +1612,7 @@ undo_redo_image (WebKitDOMDocument *document,
                        if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-resizable-wrapper") ||
                            element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-smiley-wrapper"))
                                remove_node (node);
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
        } else {
                WebKitDOMElement *element;
 
@@ -1629,7 +1622,7 @@ undo_redo_image (WebKitDOMDocument *document,
                webkit_dom_dom_selection_add_range (dom_selection, range);
                g_object_unref (range);
 
-               dom_selection_save (document);
+               e_editor_dom_selection_save (editor_page);
                element = webkit_dom_document_get_element_by_id (
                        document, "-x-evo-selection-start-marker");
 
@@ -1640,20 +1633,23 @@ undo_redo_image (WebKitDOMDocument *document,
                        WEBKIT_DOM_NODE (element),
                        NULL);
 
-               dom_selection_restore (document);
-               dom_force_spell_check_for_current_paragraph (document, extension);
+               e_editor_dom_selection_restore (editor_page);
+               e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
        }
 
        g_object_unref (dom_selection);
 }
 
 static void
-undo_redo_replace (WebKitDOMDocument *document,
-                   EHTMLEditorWebExtension *extension,
-                   EHTMLEditorHistoryEvent *event,
+undo_redo_replace (EEditorPage *editor_page,
+                   EEditorHistoryEvent *event,
                    gboolean undo)
 {
-       restore_selection_to_history_event_state (document, undo ? event->after : event->before);
+       WebKitDOMDocument *document;
+
+       document = e_editor_page_get_document (editor_page);
+
+       restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
 
        if (undo) {
                WebKitDOMDOMWindow *dom_window;
@@ -1667,30 +1663,31 @@ undo_redo_replace (WebKitDOMDocument *document,
                g_object_unref (dom_selection);
        }
 
-       dom_exec_command (
-               document,
-               extension,
+       e_editor_dom_exec_command (editor_page,
                E_CONTENT_EDITOR_COMMAND_INSERT_TEXT,
                undo ? event->data.string.from : event->data.string.to);
 
-       dom_force_spell_check_for_current_paragraph (document, extension);
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
 
-       restore_selection_to_history_event_state (document, undo ? event->before : event->after);
+       restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
 }
 
 static void
-undo_redo_replace_all (EHTMLEditorUndoRedoManager *manager,
-                       WebKitDOMDocument *document,
-                       EHTMLEditorWebExtension *extension,
-                       EHTMLEditorHistoryEvent *event,
+undo_redo_replace_all (EEditorUndoRedoManager *manager,
+                       EEditorPage *editor_page,
+                       EEditorHistoryEvent *event,
                        gboolean undo)
 {
+       WebKitDOMDocument *document;
+
+       document = e_editor_page_get_document (editor_page);
+
        if (undo) {
                if (event->type == HISTORY_REPLACE) {
-                       undo_redo_replace (document, extension, event, undo);
+                       undo_redo_replace (editor_page, event, undo);
                        return;
                } else {
-                       EHTMLEditorHistoryEvent *next_event;
+                       EEditorHistoryEvent *next_event;
                        GList *next_item;
                        WebKitDOMDOMWindow *dom_window;
                        WebKitDOMDOMSelection *dom_selection;
@@ -1709,7 +1706,7 @@ undo_redo_replace_all (EHTMLEditorUndoRedoManager *manager,
                                if (g_strcmp0 (next_event->data.string.to, event->data.string.to) != 0)
                                        break;
 
-                               undo_redo_replace (document, extension, next_event, undo);
+                               undo_redo_replace (editor_page, next_event, undo);
 
                                next_item = next_item->next;
                        }
@@ -1724,7 +1721,7 @@ undo_redo_replace_all (EHTMLEditorUndoRedoManager *manager,
                }
        } else {
                /* Find if this history item is part of HISTORY_REPLACE_ALL. */
-               EHTMLEditorHistoryEvent *prev_event;
+               EEditorHistoryEvent *prev_event;
                GList *prev_item;
                gboolean replace_all = FALSE;
 
@@ -1742,7 +1739,7 @@ undo_redo_replace_all (EHTMLEditorUndoRedoManager *manager,
                }
 
                if (!replace_all) {
-                       undo_redo_replace (document, extension, event, undo);
+                       undo_redo_replace (editor_page, event, undo);
                        return;
                }
 
@@ -1751,7 +1748,7 @@ undo_redo_replace_all (EHTMLEditorUndoRedoManager *manager,
                        prev_event = prev_item->data;
 
                        if (prev_event->type == HISTORY_REPLACE) {
-                               undo_redo_replace (document, extension, prev_event, undo);
+                               undo_redo_replace (editor_page, prev_event, undo);
                                prev_item = prev_item->prev;
                        } else
                                break;
@@ -1762,13 +1759,16 @@ undo_redo_replace_all (EHTMLEditorUndoRedoManager *manager,
 }
 
 static void
-undo_redo_remove_link (WebKitDOMDocument *document,
-                       EHTMLEditorWebExtension *extension,
-                       EHTMLEditorHistoryEvent *event,
+undo_redo_remove_link (EEditorPage *editor_page,
+                       EEditorHistoryEvent *event,
                        gboolean undo)
 {
+       WebKitDOMDocument *document;
+
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
        if (undo) {
                WebKitDOMDOMWindow *dom_window;
@@ -1782,7 +1782,7 @@ undo_redo_remove_link (WebKitDOMDocument *document,
                webkit_dom_dom_selection_modify (dom_selection, "move", "left", "word");
                webkit_dom_dom_selection_modify (dom_selection, "extend", "right", "word");
 
-               range = dom_get_current_range (document);
+               range = e_editor_dom_get_current_range (editor_page);
                element = webkit_dom_document_create_element (document, "SPAN", NULL);
                webkit_dom_range_surround_contents (range, WEBKIT_DOM_NODE (element), NULL);
                g_object_unref (range);
@@ -1795,21 +1795,22 @@ undo_redo_remove_link (WebKitDOMDocument *document,
                g_object_unref (dom_window);
                g_object_unref (dom_selection);
        } else
-               dom_selection_unlink (document, extension);
+               e_editor_dom_selection_unlink (editor_page);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 }
 
 static void
-undo_return_in_empty_list_item (WebKitDOMDocument *document,
-                               EHTMLEditorWebExtension *extension,
-                               EHTMLEditorHistoryEvent *event)
+undo_return_in_empty_list_item (EEditorPage *editor_page,
+                               EEditorHistoryEvent *event)
 {
+       WebKitDOMDocument *document;
        WebKitDOMElement *selection_start_marker;
        WebKitDOMNode *parent;
 
-       dom_selection_save (document);
+       document = e_editor_page_get_document (editor_page);
+       e_editor_dom_selection_save (editor_page);
 
        selection_start_marker = webkit_dom_document_get_element_by_id (document, 
"-x-evo-selection-start-marker");
        parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (selection_start_marker));
@@ -1831,30 +1832,31 @@ undo_return_in_empty_list_item (WebKitDOMDocument *document,
                merge_lists_if_possible (parent_list);
        }
 
-       dom_selection_restore (document);
+       e_editor_dom_selection_restore (editor_page);
 }
 
 static void
-undo_input (EHTMLEditorUndoRedoManager *manager,
-            WebKitDOMDocument *document,
-            EHTMLEditorWebExtension *extension,
-            EHTMLEditorHistoryEvent *event)
+undo_input (EEditorUndoRedoManager *manager,
+            EEditorPage *editor_page,
+            EEditorHistoryEvent *event)
 {
-       gboolean remove_anchor;
+       WebKitDOMDocument *document;
        WebKitDOMDOMWindow *dom_window;
        WebKitDOMDOMSelection *dom_selection;
        WebKitDOMNode *node, *tmp_node;
+       gboolean remove_anchor;
 
+       document = e_editor_page_get_document (editor_page);
        dom_window = webkit_dom_document_get_default_view (document);
        dom_selection = webkit_dom_dom_window_get_selection (dom_window);
 
-       restore_selection_to_history_event_state (document, event->after);
+       restore_selection_to_history_event_state (editor_page, event->after);
 
        webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "character");
-       if (dom_selection_is_citation (document)) {
+       if (e_editor_dom_selection_is_citation (editor_page)) {
                /* Post processing of quoted text in body_input_event_cb needs to be called. */
                manager->priv->operation_in_progress = FALSE;
-               e_html_editor_web_extension_set_dont_save_history_in_body_input (extension, TRUE);
+               e_editor_page_set_dont_save_history_in_body_input (editor_page, TRUE);
        }
 
        /* If we are undoing the text that was appended to the link we have to
@@ -1874,7 +1876,7 @@ undo_input (EHTMLEditorUndoRedoManager *manager,
                g_free (text_content);
        }
 
-       dom_exec_command (document, extension, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
+       e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
 
        if (remove_anchor) {
                WebKitDOMNode *child;
@@ -1895,20 +1897,22 @@ undo_input (EHTMLEditorUndoRedoManager *manager,
        tmp_node = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (event->data.fragment));
        if (WEBKIT_DOM_IS_HTML_LI_ELEMENT (tmp_node) &&
            WEBKIT_DOM_IS_HTML_BR_ELEMENT (webkit_dom_node_get_last_child (tmp_node)))
-               undo_return_in_empty_list_item (document, extension, event);
+               undo_return_in_empty_list_item (editor_page, event);
 
        g_object_unref (dom_window);
        g_object_unref (dom_selection);
 }
 
 static void
-undo_redo_citation_split (WebKitDOMDocument *document,
-                          EHTMLEditorWebExtension *extension,
-                          EHTMLEditorHistoryEvent *event,
+undo_redo_citation_split (EEditorPage *editor_page,
+                          EEditorHistoryEvent *event,
                           gboolean undo)
 {
+       WebKitDOMDocument *document;
        gboolean in_situ = FALSE;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (event->before.start.x == event->after.start.x &&
            event->before.start.y == event->after.start.y &&
            event->before.end.x == event->after.end.x &&
@@ -1919,9 +1923,9 @@ undo_redo_citation_split (WebKitDOMDocument *document,
                WebKitDOMElement *selection_start, *parent;
                WebKitDOMNode *citation_before, *citation_after, *child, *last_child, *tmp;
 
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
-               dom_selection_save (document);
+               e_editor_dom_selection_save (editor_page);
                selection_start = webkit_dom_document_get_element_by_id (
                        document, "-x-evo-selection-start-marker");
                if (!selection_start)
@@ -1930,25 +1934,25 @@ undo_redo_citation_split (WebKitDOMDocument *document,
                parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start));
 
                citation_before = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (parent));
-               if (!dom_node_is_citation_node (citation_before)) {
-                       dom_selection_restore (document);
+               if (!e_editor_dom_node_is_citation_node (citation_before)) {
+                       e_editor_dom_selection_restore (editor_page);
                        return;
                }
 
                citation_after = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
-               if (!dom_node_is_citation_node (citation_after)) {
-                       dom_selection_restore (document);
+               if (!e_editor_dom_node_is_citation_node (citation_after)) {
+                       e_editor_dom_selection_restore (editor_page);
                        return;
                }
 
                /* Get first block in next citation. */
                child = webkit_dom_node_get_first_child (citation_after);
-               while (child && dom_node_is_citation_node (child))
+               while (child && e_editor_dom_node_is_citation_node (child))
                        child = webkit_dom_node_get_first_child (child);
 
                /* Get last block in previous citation. */
                last_child = webkit_dom_node_get_last_child (citation_before);
-               while (last_child && dom_node_is_citation_node (last_child))
+               while (last_child && e_editor_dom_node_is_citation_node (last_child))
                        last_child = webkit_dom_node_get_last_child (last_child);
 
                /* Before appending any content to the block, check that the
@@ -1964,18 +1968,18 @@ undo_redo_citation_split (WebKitDOMDocument *document,
                                        WEBKIT_DOM_NODE (event->data.fragment), TRUE, NULL),
                                NULL);
                } else {
-                       dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (child));
-                       dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (child));
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (child));
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (child));
 
-                       dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
-                       dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
+                       e_editor_dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
+                       e_editor_dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
 
                        /* Copy the content of the first block to the last block to get
                         * to the state how the block looked like before it was split. */
                        while ((tmp = webkit_dom_node_get_first_child (child)))
                                webkit_dom_node_append_child (last_child, tmp, NULL);
 
-                       wrap_and_quote_element (document, extension, WEBKIT_DOM_ELEMENT (last_child));
+                       e_editor_dom_wrap_and_quote_element (editor_page, WEBKIT_DOM_ELEMENT (last_child));
 
                        remove_node (child);
                }
@@ -1991,51 +1995,53 @@ undo_redo_citation_split (WebKitDOMDocument *document,
 
                /* If enter was pressed when some text was selected, restore it. */
                if (event->data.fragment != NULL && !in_situ)
-                       undo_delete (document, extension, event);
+                       undo_delete (editor_page, event);
 
-               dom_merge_siblings_if_necessary (document, NULL);
+               e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
 
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 
-               dom_force_spell_check_in_viewport (document, extension);
+               e_editor_dom_force_spell_check_in_viewport (editor_page);
        } else {
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
 
                if (in_situ) {
                        WebKitDOMElement *selection_start_marker;
                        WebKitDOMNode *block;
 
-                       dom_selection_save (document);
+                       e_editor_dom_selection_save (editor_page);
 
                        selection_start_marker = webkit_dom_document_get_element_by_id (
                                document, "-x-evo-selection-start-marker");
 
-                       block = get_parent_block_node_from_child (
+                       block = e_editor_dom_get_parent_block_node_from_child (
                                WEBKIT_DOM_NODE (selection_start_marker));
                        dom_remove_selection_markers (document);
 
                        /* Remove current block (and all of its parents if they
                         * are empty) as it will be replaced by a new block that
                         * will be in the body and not in the blockquote. */
-                       dom_remove_node_and_parents_if_empty (block);
+                       e_editor_dom_remove_node_and_parents_if_empty (block);
                }
 
-               dom_insert_new_line_into_citation (document, extension, "");
+               e_editor_dom_insert_new_line_into_citation (editor_page, "");
        }
 }
 
 static void
-undo_redo_unquote (WebKitDOMDocument *document,
-                  EHTMLEditorWebExtension *extension,
-                  EHTMLEditorHistoryEvent *event,
+undo_redo_unquote (EEditorPage *editor_page,
+                  EEditorHistoryEvent *event,
                    gboolean undo)
 {
+       WebKitDOMDocument *document;
        WebKitDOMElement *element;
 
+       document = e_editor_page_get_document (editor_page);
+
        if (undo)
-               restore_selection_to_history_event_state (document, event->after);
+               restore_selection_to_history_event_state (editor_page, event->after);
 
-       dom_selection_save (document);
+       e_editor_dom_selection_save (editor_page);
        element = webkit_dom_document_get_element_by_id (
                document, "-x-evo-selection-start-marker");
 
@@ -2048,13 +2054,13 @@ undo_redo_unquote (WebKitDOMDocument *document,
                next_sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (block));
                prev_sibling = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (block));
 
-               if (prev_sibling && dom_node_is_citation_node (prev_sibling)) {
+               if (prev_sibling && e_editor_dom_node_is_citation_node (prev_sibling)) {
                        webkit_dom_node_append_child (
                                prev_sibling,
                                webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE, NULL),
                                NULL);
 
-                       if (next_sibling && dom_node_is_citation_node (next_sibling)) {
+                       if (next_sibling && e_editor_dom_node_is_citation_node (next_sibling)) {
                                WebKitDOMNode *child;
 
                                while  ((child = webkit_dom_node_get_first_child (next_sibling)))
@@ -2063,7 +2069,7 @@ undo_redo_unquote (WebKitDOMDocument *document,
 
                                remove_node (next_sibling);
                        }
-               } else if (next_sibling && dom_node_is_citation_node (next_sibling)) {
+               } else if (next_sibling && e_editor_dom_node_is_citation_node (next_sibling)) {
                        webkit_dom_node_insert_before (
                                next_sibling,
                                webkit_dom_node_clone_node_with_error (event->data.dom.from, TRUE, NULL),
@@ -2073,35 +2079,35 @@ undo_redo_unquote (WebKitDOMDocument *document,
 
                remove_node (WEBKIT_DOM_NODE (block));
        } else
-               dom_move_quoted_block_level_up (document, extension);
+               e_editor_dom_move_quoted_block_level_up (editor_page);
 
        if (undo)
-               restore_selection_to_history_event_state (document, event->before);
+               restore_selection_to_history_event_state (editor_page, event->before);
        else
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
 
-       dom_force_spell_check_for_current_paragraph (document, extension);
+       e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
 }
 
 gboolean
-e_html_editor_undo_redo_manager_is_operation_in_progress (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_is_operation_in_progress (EEditorUndoRedoManager *manager)
 {
-       g_return_val_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
+       g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
 
        return manager->priv->operation_in_progress;
 }
 
 void
-e_html_editor_undo_redo_manager_set_operation_in_progress (EHTMLEditorUndoRedoManager *manager,
+e_editor_undo_redo_manager_set_operation_in_progress (EEditorUndoRedoManager *manager,
                                                            gboolean value)
 {
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
+       g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
 
        manager->priv->operation_in_progress = value;
 }
 
 static void
-free_history_event_content (EHTMLEditorHistoryEvent *event)
+free_history_event_content (EEditorHistoryEvent *event)
 {
        switch (event->type) {
                case HISTORY_INPUT:
@@ -2144,7 +2150,7 @@ free_history_event_content (EHTMLEditorHistoryEvent *event)
 }
 
 static void
-free_history_event (EHTMLEditorHistoryEvent *event)
+free_history_event (EEditorHistoryEvent *event)
 {
        if (event == NULL)
                return;
@@ -2155,7 +2161,7 @@ free_history_event (EHTMLEditorHistoryEvent *event)
 }
 
 static void
-remove_history_event (EHTMLEditorUndoRedoManager *manager,
+remove_history_event (EEditorUndoRedoManager *manager,
                       GList *item)
 {
        free_history_event_content (item->data);
@@ -2165,7 +2171,7 @@ remove_history_event (EHTMLEditorUndoRedoManager *manager,
 }
 
 static void
-remove_forward_redo_history_events_if_needed (EHTMLEditorUndoRedoManager *manager)
+remove_forward_redo_history_events_if_needed (EEditorUndoRedoManager *manager)
 {
        GList *history = manager->priv->history;
        GList *item;
@@ -2183,10 +2189,10 @@ remove_forward_redo_history_events_if_needed (EHTMLEditorUndoRedoManager *manage
 }
 
 void
-e_html_editor_undo_redo_manager_insert_history_event (EHTMLEditorUndoRedoManager *manager,
-                                                      EHTMLEditorHistoryEvent *event)
+e_editor_undo_redo_manager_insert_history_event (EEditorUndoRedoManager *manager,
+                                                EEditorHistoryEvent *event)
 {
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
+       g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
 
        if (manager->priv->operation_in_progress)
                return;
@@ -2199,7 +2205,7 @@ e_html_editor_undo_redo_manager_insert_history_event (EHTMLEditorUndoRedoManager
        if (manager->priv->history_size >= HISTORY_SIZE_LIMIT) {
                remove_history_event (manager, g_list_last (manager->priv->history)->prev);
                /* FIXME WK2 - what if g_list_last (manager->priv->history) returns NULL? */
-               while (((EHTMLEditorHistoryEvent *) (g_list_last (manager->priv->history)->prev))->type == 
HISTORY_AND) {
+               while (((EEditorHistoryEvent *) (g_list_last (manager->priv->history)->prev))->type == 
HISTORY_AND) {
                        remove_history_event (manager, g_list_last (manager->priv->history)->prev);
                        remove_history_event (manager, g_list_last (manager->priv->history)->prev);
                }
@@ -2214,10 +2220,10 @@ e_html_editor_undo_redo_manager_insert_history_event (EHTMLEditorUndoRedoManager
        g_object_notify (G_OBJECT (manager), "can-undo");
 }
 
-EHTMLEditorHistoryEvent *
-e_html_editor_undo_redo_manager_get_current_history_event (EHTMLEditorUndoRedoManager *manager)
+EEditorHistoryEvent *
+e_editor_undo_redo_manager_get_current_history_event (EEditorUndoRedoManager *manager)
 {
-       g_return_val_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
+       g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
 
        if (manager->priv->history)
                return manager->priv->history->data;
@@ -2226,9 +2232,9 @@ e_html_editor_undo_redo_manager_get_current_history_event (EHTMLEditorUndoRedoMa
 }
 
 void
-e_html_editor_undo_redo_manager_remove_current_history_event (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_remove_current_history_event (EEditorUndoRedoManager *manager)
 {
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
+       g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
 
        if (!manager->priv->history)
                return;
@@ -2237,19 +2243,23 @@ e_html_editor_undo_redo_manager_remove_current_history_event (EHTMLEditorUndoRed
 }
 
 void
-e_html_editor_undo_redo_manager_insert_dash_history_event (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_insert_dash_history_event (EEditorUndoRedoManager *manager)
 {
-       EHTMLEditorHistoryEvent *event, *last;
-       GList *history;
-       WebKitDOMDocumentFragment *fragment;
        WebKitDOMDocument *document;
+       WebKitDOMDocumentFragment *fragment;
+       EEditorPage *editor_page;
+       EEditorHistoryEvent *event, *last;
+       GList *history;
 
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
+       g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
 
-       event = g_new0 (EHTMLEditorHistoryEvent, 1);
+       editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+       g_return_if_fail (editor_page != NULL);
+
+       event = g_new0 (EEditorHistoryEvent, 1);
        event->type = HISTORY_INPUT;
 
-       document = manager->priv->document;
+       document = e_editor_page_get_document (editor_page);
        fragment = webkit_dom_document_create_document_fragment (document);
        webkit_dom_node_append_child (
                WEBKIT_DOM_NODE (fragment),
@@ -2268,7 +2278,7 @@ e_html_editor_undo_redo_manager_insert_dash_history_event (EHTMLEditorUndoRedoMa
                NULL);
        event->data.fragment = fragment;
 
-       last = e_html_editor_undo_redo_manager_get_current_history_event (manager);
+       last = e_editor_undo_redo_manager_get_current_history_event (manager);
        /* The dash event needs to have the same coordinates as the character
         * that is right after it. */
        event->after.start.x = last->after.start.x;
@@ -2278,13 +2288,15 @@ e_html_editor_undo_redo_manager_insert_dash_history_event (EHTMLEditorUndoRedoMa
 
        history = manager->priv->history;
        if (history) {
-               EHTMLEditorHistoryEvent *item;
+               EEditorHistoryEvent *item;
                WebKitDOMNode *first_child;
 
                item = history->data;
 
-               if (item->type != HISTORY_INPUT)
+               if (item->type != HISTORY_INPUT) {
+                       g_object_unref (editor_page);
                        return;
+               }
 
                first_child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (item->data.fragment));
                if (WEBKIT_DOM_IS_TEXT (first_child)) {
@@ -2301,15 +2313,17 @@ e_html_editor_undo_redo_manager_insert_dash_history_event (EHTMLEditorUndoRedoMa
                                manager->priv->history, history, event);
                }
        }
+
+       g_object_unref (editor_page);
 }
 
 gboolean
-e_html_editor_undo_redo_manager_can_undo (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_can_undo (EEditorUndoRedoManager *manager)
 {
-       g_return_val_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
+       g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
 
        if (manager->priv->history) {
-               EHTMLEditorHistoryEvent *event;
+               EEditorHistoryEvent *event;
 
                event = manager->priv->history->data;
 
@@ -2319,16 +2333,15 @@ e_html_editor_undo_redo_manager_can_undo (EHTMLEditorUndoRedoManager *manager)
 }
 
 void
-e_html_editor_undo_redo_manager_undo (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_undo (EEditorUndoRedoManager *manager)
 {
-       EHTMLEditorHistoryEvent *event;
-       EHTMLEditorWebExtension *extension;
+       EEditorHistoryEvent *event;
+       EEditorPage *editor_page;
        GList *history;
-       WebKitDOMDocument *document;
 
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
+       g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
 
-       if (!e_html_editor_undo_redo_manager_can_undo (manager))
+       if (!e_editor_undo_redo_manager_can_undo (manager))
                return;
 
        history = manager->priv->history;
@@ -2339,9 +2352,8 @@ e_html_editor_undo_redo_manager_undo (EHTMLEditorUndoRedoManager *manager)
 
        manager->priv->operation_in_progress = TRUE;
 
-       document = manager->priv->document;
-       extension = html_editor_undo_redo_manager_ref_extension (manager);
-       g_return_if_fail (extension != NULL);
+       editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+       g_return_if_fail (editor_page != NULL);
 
        switch (event->type) {
                case HISTORY_BOLD:
@@ -2352,78 +2364,78 @@ e_html_editor_undo_redo_manager_undo (EHTMLEditorUndoRedoManager *manager)
                        if (event_selection_was_collapsed (event)) {
                                if (history->next) {
                                        manager->priv->history = history->next;
-                                       e_html_editor_undo_redo_manager_undo (manager);
+                                       e_editor_undo_redo_manager_undo (manager);
                                }
                                manager->priv->operation_in_progress = FALSE;
-                               g_object_unref (extension);
+                               g_object_unref (editor_page);
                                return;
                        }
                case HISTORY_ALIGNMENT:
                case HISTORY_BLOCK_FORMAT:
                case HISTORY_MONOSPACE:
-                       undo_redo_style_change (document, extension, event, TRUE);
+                       undo_redo_style_change (editor_page, event, TRUE);
                        break;
                case HISTORY_DELETE:
-                       undo_delete (document, extension, event);
+                       undo_delete (editor_page, event);
                        break;
                case HISTORY_INDENT:
-                       undo_redo_indent (document, extension, event, TRUE);
+                       undo_redo_indent (editor_page, event, TRUE);
                        break;
                case HISTORY_INPUT:
-                       undo_input (manager, document, extension, event);
+                       undo_input (manager, editor_page, event);
                        break;
                case HISTORY_REMOVE_LINK:
-                       undo_redo_remove_link (document, extension, event, TRUE);
+                       undo_redo_remove_link (editor_page, event, TRUE);
                        break;
                case HISTORY_FONT_COLOR:
-                       undo_redo_font_color (document, extension, event, TRUE);
+                       undo_redo_font_color (editor_page, event, TRUE);
                        break;
                case HISTORY_CITATION_SPLIT:
-                       undo_redo_citation_split (document, extension, event, TRUE);
+                       undo_redo_citation_split (editor_page, event, TRUE);
                        break;
                case HISTORY_PASTE:
                case HISTORY_PASTE_AS_TEXT:
                case HISTORY_PASTE_QUOTED:
                case HISTORY_INSERT_HTML:
-                       undo_redo_paste (document, extension, event, TRUE);
+                       undo_redo_paste (editor_page, event, TRUE);
                        break;
                case HISTORY_IMAGE:
                case HISTORY_SMILEY:
-                       undo_redo_image (document, extension, event, TRUE);
+                       undo_redo_image (editor_page, event, TRUE);
                        break;
                case HISTORY_WRAP:
-                       undo_redo_wrap (document, extension, event, TRUE);
+                       undo_redo_wrap (editor_page, event, TRUE);
                        break;
                case HISTORY_IMAGE_DIALOG:
-                       undo_redo_image_dialog (document, extension, event, TRUE);
+                       undo_redo_image_dialog (editor_page, event, TRUE);
                        break;
                case HISTORY_LINK_DIALOG:
-                       undo_redo_link_dialog (document, extension, event, TRUE);
+                       undo_redo_link_dialog (editor_page, event, TRUE);
                        break;
                case HISTORY_TABLE_DIALOG:
-                       undo_redo_table_dialog (document, extension, event, TRUE);
+                       undo_redo_table_dialog (editor_page, event, TRUE);
                        break;
                case HISTORY_TABLE_INPUT:
-                       undo_redo_table_input (document, extension, event, TRUE);
+                       undo_redo_table_input (editor_page, event, TRUE);
                        break;
                case HISTORY_PAGE_DIALOG:
-                       undo_redo_page_dialog (document, extension, event, TRUE);
+                       undo_redo_page_dialog (editor_page, event, TRUE);
                        break;
                case HISTORY_HRULE_DIALOG:
-                       undo_redo_hrule_dialog (document, extension, event, TRUE);
+                       undo_redo_hrule_dialog (editor_page, event, TRUE);
                        break;
                case HISTORY_REPLACE:
                case HISTORY_REPLACE_ALL:
-                       undo_redo_replace_all (manager, document, extension, event, TRUE);
+                       undo_redo_replace_all (manager, editor_page, event, TRUE);
                        break;
                case HISTORY_UNQUOTE:
-                       undo_redo_unquote (document, extension, event, TRUE);
+                       undo_redo_unquote (editor_page, event, TRUE);
                        break;
                case HISTORY_AND:
                        g_warning ("Unhandled HISTORY_AND event!");
                        break;
                default:
-                       g_object_unref (extension);
+                       g_object_unref (editor_page);
                        return;
        }
 
@@ -2431,7 +2443,8 @@ e_html_editor_undo_redo_manager_undo (EHTMLEditorUndoRedoManager *manager)
        event = history->next->data;
        if (event->type == HISTORY_AND) {
                manager->priv->history = history->next->next;
-               e_html_editor_undo_redo_manager_undo (manager);
+               e_editor_undo_redo_manager_undo (manager);
+               g_object_unref (editor_page);
                return;
        }
 
@@ -2444,16 +2457,16 @@ e_html_editor_undo_redo_manager_undo (EHTMLEditorUndoRedoManager *manager)
 
        manager->priv->operation_in_progress = FALSE;
 
-       g_object_unref (extension);
+       g_object_unref (editor_page);
 
        g_object_notify (G_OBJECT (manager), "can-undo");
        g_object_notify (G_OBJECT (manager), "can-redo");
 }
 
 gboolean
-e_html_editor_undo_redo_manager_can_redo (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_can_redo (EEditorUndoRedoManager *manager)
 {
-       g_return_val_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
+       g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), FALSE);
 
        if (manager->priv->history && manager->priv->history->prev)
                return TRUE;
@@ -2462,14 +2475,13 @@ e_html_editor_undo_redo_manager_can_redo (EHTMLEditorUndoRedoManager *manager)
 }
 
 void
-e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_redo (EEditorUndoRedoManager *manager)
 {
-       EHTMLEditorWebExtension *extension;
-       EHTMLEditorHistoryEvent *event;
+       EEditorPage *editor_page;
+       EEditorHistoryEvent *event;
        GList *history;
-       WebKitDOMDocument *document;
 
-       if (!e_html_editor_undo_redo_manager_can_redo (manager))
+       if (!e_editor_undo_redo_manager_can_redo (manager))
                return;
 
        history = manager->priv->history;
@@ -2478,9 +2490,8 @@ e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
        d (printf ("\nREDOING EVENT:\n"));
        d (print_history_event (event));
 
-       document = manager->priv->document;
-       extension = html_editor_undo_redo_manager_ref_extension (manager);
-       g_return_if_fail (extension != NULL);
+       editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+       g_return_if_fail (editor_page != NULL);
 
        manager->priv->operation_in_progress = TRUE;
 
@@ -2493,17 +2504,17 @@ e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
                case HISTORY_BLOCK_FORMAT:
                case HISTORY_FONT_SIZE:
                case HISTORY_ITALIC:
-                       undo_redo_style_change (document, extension, event, FALSE);
+                       undo_redo_style_change (editor_page, event, FALSE);
                        break;
                case HISTORY_DELETE:
-                       redo_delete (document, extension, event);
+                       redo_delete (editor_page, event);
                        break;
                case HISTORY_INDENT:
-                       undo_redo_indent (document, extension, event, FALSE);
+                       undo_redo_indent (editor_page, event, FALSE);
                        break;
                case HISTORY_INPUT:
-                       undo_delete (document, extension, event);
-                       dom_check_magic_smileys (document, extension);
+                       undo_delete (editor_page, event);
+                       e_editor_dom_check_magic_smileys (editor_page);
                        {
                                gchar *text_content;
                                WebKitDOMNode *first_child;
@@ -2513,65 +2524,65 @@ e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
                                text_content = webkit_dom_node_get_text_content (first_child);
                                /* Call magic links when the space was pressed. */
                                if (g_str_has_prefix (text_content, UNICODE_NBSP)) {
-                                       e_html_editor_web_extension_set_space_key_pressed (extension, TRUE);
-                                       dom_check_magic_links (document, extension, FALSE);
-                                       e_html_editor_web_extension_set_space_key_pressed (extension, FALSE);
+                                       e_editor_page_set_space_key_pressed (editor_page, TRUE);
+                                       e_editor_dom_check_magic_links (editor_page, FALSE);
+                                       e_editor_page_set_space_key_pressed (editor_page, FALSE);
                                }
                                g_free (text_content);
                        }
                        break;
                case HISTORY_REMOVE_LINK:
-                       undo_redo_remove_link (document, extension, event, FALSE);
+                       undo_redo_remove_link (editor_page, event, FALSE);
                        break;
                case HISTORY_FONT_COLOR:
-                       undo_redo_font_color (document, extension, event, FALSE);
+                       undo_redo_font_color (editor_page, event, FALSE);
                        break;
                case HISTORY_CITATION_SPLIT:
-                       undo_redo_citation_split (document, extension, event, FALSE);
+                       undo_redo_citation_split (editor_page, event, FALSE);
                        break;
                case HISTORY_PASTE:
                case HISTORY_PASTE_AS_TEXT:
                case HISTORY_PASTE_QUOTED:
                case HISTORY_INSERT_HTML:
-                       undo_redo_paste (document, extension, event, FALSE);
+                       undo_redo_paste (editor_page, event, FALSE);
                        break;
                case HISTORY_IMAGE:
                case HISTORY_SMILEY:
-                       undo_redo_image (document, extension, event, FALSE);
+                       undo_redo_image (editor_page, event, FALSE);
                        break;
                case HISTORY_WRAP:
-                       undo_redo_wrap (document, extension, event, FALSE);
+                       undo_redo_wrap (editor_page, event, FALSE);
                        break;
                case HISTORY_IMAGE_DIALOG:
-                       undo_redo_image_dialog (document, extension, event, FALSE);
+                       undo_redo_image_dialog (editor_page, event, FALSE);
                        break;
                case HISTORY_LINK_DIALOG:
-                       undo_redo_link_dialog (document, extension, event, FALSE);
+                       undo_redo_link_dialog (editor_page, event, FALSE);
                        break;
                case HISTORY_TABLE_DIALOG:
-                       undo_redo_table_dialog (document, extension, event, FALSE);
+                       undo_redo_table_dialog (editor_page, event, FALSE);
                        break;
                case HISTORY_TABLE_INPUT:
-                       undo_redo_table_input (document, extension, event, FALSE);
+                       undo_redo_table_input (editor_page, event, FALSE);
                        break;
                case HISTORY_PAGE_DIALOG:
-                       undo_redo_page_dialog (document, extension, event, FALSE);
+                       undo_redo_page_dialog (editor_page, event, FALSE);
                        break;
                case HISTORY_HRULE_DIALOG:
-                       undo_redo_hrule_dialog (document, extension, event, FALSE);
+                       undo_redo_hrule_dialog (editor_page, event, FALSE);
                        break;
                case HISTORY_REPLACE:
                case HISTORY_REPLACE_ALL:
-                       undo_redo_replace_all (manager, document, extension, event, FALSE);
+                       undo_redo_replace_all (manager, editor_page, event, FALSE);
                        break;
                case HISTORY_UNQUOTE:
-                       undo_redo_unquote (document, extension, event, FALSE);
+                       undo_redo_unquote (editor_page, event, FALSE);
                        break;
                case HISTORY_AND:
                        g_warning ("Unhandled HISTORY_AND event!");
                        break;
                default:
-                       g_object_unref (extension);
+                       g_object_unref (editor_page);
                        return;
        }
 
@@ -2580,7 +2591,8 @@ e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
                event = history->prev->prev->data;
                if (event->type == HISTORY_AND) {
                        manager->priv->history = manager->priv->history->prev->prev;
-                       e_html_editor_undo_redo_manager_redo (manager);
+                       e_editor_undo_redo_manager_redo (manager);
+                       g_object_unref (editor_page);
                        return;
                }
        }
@@ -2593,19 +2605,19 @@ e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
 
        manager->priv->operation_in_progress = FALSE;
 
-       g_object_unref (extension);
+       g_object_unref (editor_page);
 
        g_object_notify (G_OBJECT (manager), "can-undo");
        g_object_notify (G_OBJECT (manager), "can-redo");
 }
 
 void
-e_html_editor_undo_redo_manager_clean_history (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_clean_history (EEditorUndoRedoManager *manager)
 {
-       EHTMLEditorWebExtension *extension;
-       EHTMLEditorHistoryEvent *ev;
+       EEditorPage *editor_page;
+       EEditorHistoryEvent *ev;
 
-       g_return_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager));
+       g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
 
        if (manager->priv->history != NULL) {
                g_list_free_full (manager->priv->history, (GDestroyNotify) free_history_event);
@@ -2613,13 +2625,13 @@ e_html_editor_undo_redo_manager_clean_history (EHTMLEditorUndoRedoManager *manag
        }
 
        manager->priv->history_size = 0;
-       extension = html_editor_undo_redo_manager_ref_extension (manager);
-       g_return_if_fail (extension != NULL);
-       e_html_editor_web_extension_set_dont_save_history_in_body_input (extension, FALSE);
-       g_object_unref (extension);
+       editor_page = editor_undo_redo_manager_ref_editor_page (manager);
+       g_return_if_fail (editor_page != NULL);
+       e_editor_page_set_dont_save_history_in_body_input (editor_page, FALSE);
+       g_object_unref (editor_page);
        manager->priv->operation_in_progress = FALSE;
 
-       ev = g_new0 (EHTMLEditorHistoryEvent, 1);
+       ev = g_new0 (EEditorHistoryEvent, 1);
        ev->type = HISTORY_START;
        manager->priv->history = g_list_append (manager->priv->history, ev);
 
@@ -2628,49 +2640,49 @@ e_html_editor_undo_redo_manager_clean_history (EHTMLEditorUndoRedoManager *manag
 }
 
 static void
-html_editor_undo_redo_manager_set_extension (EHTMLEditorUndoRedoManager *manager,
-                                             EHTMLEditorWebExtension *extension)
+editor_undo_redo_manager_set_editor_page (EEditorUndoRedoManager *manager,
+                                         EEditorPage *editor_page)
 {
-       g_return_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension));
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
 
-       g_weak_ref_set (&manager->priv->extension, extension);
+       g_weak_ref_set (&manager->priv->editor_page, editor_page);
 }
 
 static void
-html_editor_undo_redo_manager_dispose (GObject *object)
+editor_undo_redo_manager_dispose (GObject *object)
 {
-       EHTMLEditorUndoRedoManagerPrivate *priv;
+       EEditorUndoRedoManagerPrivate *priv;
 
-       priv = E_HTML_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE (object);
+       priv = E_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE (object);
 
        if (priv->history != NULL) {
                g_list_free_full (priv->history, (GDestroyNotify) free_history_event);
                priv->history = NULL;
        }
 
-       g_weak_ref_set (&priv->extension, NULL);
+       g_weak_ref_set (&priv->editor_page, NULL);
 
        /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_html_editor_undo_redo_manager_parent_class)->dispose (object);
+       G_OBJECT_CLASS (e_editor_undo_redo_manager_parent_class)->dispose (object);
 }
 
 static void
-html_editor_undo_redo_manager_get_property (GObject *object,
-                                            guint property_id,
-                                            GValue *value,
-                                            GParamSpec *pspec)
+editor_undo_redo_manager_get_property (GObject *object,
+                                      guint property_id,
+                                      GValue *value,
+                                      GParamSpec *pspec)
 {
        switch (property_id) {
                case PROP_CAN_REDO:
                        g_value_set_boolean (
-                               value, e_html_editor_undo_redo_manager_can_redo (
-                               E_HTML_EDITOR_UNDO_REDO_MANAGER (object)));
+                               value, e_editor_undo_redo_manager_can_redo (
+                               E_EDITOR_UNDO_REDO_MANAGER (object)));
                        return;
 
                case PROP_CAN_UNDO:
                        g_value_set_boolean (
-                               value, e_html_editor_undo_redo_manager_can_undo (
-                               E_HTML_EDITOR_UNDO_REDO_MANAGER (object)));
+                               value, e_editor_undo_redo_manager_can_undo (
+                               E_EDITOR_UNDO_REDO_MANAGER (object)));
                        return;
        }
 
@@ -2678,15 +2690,15 @@ html_editor_undo_redo_manager_get_property (GObject *object,
 }
 
 static void
-html_editor_undo_redo_manager_set_property (GObject *object,
+editor_undo_redo_manager_set_property (GObject *object,
                                             guint property_id,
                                             const GValue *value,
                                             GParamSpec *pspec)
 {
        switch (property_id) {
-               case PROP_HTML_EDITOR_WEB_EXTENSION:
-                       html_editor_undo_redo_manager_set_extension (
-                               E_HTML_EDITOR_UNDO_REDO_MANAGER (object),
+               case PROP_EDITOR_PAGE:
+                       editor_undo_redo_manager_set_editor_page (
+                               E_EDITOR_UNDO_REDO_MANAGER (object),
                                g_value_get_object (value));
                        return;
        }
@@ -2695,19 +2707,19 @@ html_editor_undo_redo_manager_set_property (GObject *object,
 }
 
 static void
-e_html_editor_undo_redo_manager_class_init (EHTMLEditorUndoRedoManagerClass *class)
+e_editor_undo_redo_manager_class_init (EEditorUndoRedoManagerClass *class)
 {
        GObjectClass *object_class;
 
-       g_type_class_add_private (class, sizeof (EHTMLEditorUndoRedoManagerPrivate));
+       g_type_class_add_private (class, sizeof (EEditorUndoRedoManagerPrivate));
 
        object_class = G_OBJECT_CLASS (class);
-       object_class->dispose = html_editor_undo_redo_manager_dispose;
-       object_class->get_property = html_editor_undo_redo_manager_get_property;
-       object_class->set_property = html_editor_undo_redo_manager_set_property;
+       object_class->dispose = editor_undo_redo_manager_dispose;
+       object_class->get_property = editor_undo_redo_manager_get_property;
+       object_class->set_property = editor_undo_redo_manager_set_property;
 
        /**
-        * EHTMLEditorUndoRedoManager:can-redo
+        * EEditorUndoRedoManager:can-redo
         *
         * Determines whether it's possible to redo previous action. The action
         * is usually disabled when there is no action to redo.
@@ -2724,7 +2736,7 @@ e_html_editor_undo_redo_manager_class_init (EHTMLEditorUndoRedoManagerClass *cla
                        G_PARAM_STATIC_STRINGS));
 
        /**
-        * EHTMLEditorUndoRedoManager:can-undo
+        * EEditorUndoRedoManager:can-undo
         *
         * Determines whether it's possible to undo last action. The action
         * is usually disabled when there is no previous action to undo.
@@ -2742,21 +2754,21 @@ e_html_editor_undo_redo_manager_class_init (EHTMLEditorUndoRedoManagerClass *cla
 
        g_object_class_install_property (
                object_class,
-               PROP_HTML_EDITOR_WEB_EXTENSION,
+               PROP_EDITOR_PAGE,
                g_param_spec_object (
-                       "html-editor-web-extension",
+                       "editor-page",
                        NULL,
                        NULL,
-                       E_TYPE_HTML_EDITOR_WEB_EXTENSION,
+                       E_TYPE_EDITOR_PAGE,
                        G_PARAM_READWRITE |
                        G_PARAM_CONSTRUCT_ONLY |
                        G_PARAM_STATIC_STRINGS));
 }
 
 static void
-e_html_editor_undo_redo_manager_init (EHTMLEditorUndoRedoManager *manager)
+e_editor_undo_redo_manager_init (EEditorUndoRedoManager *manager)
 {
-       manager->priv = E_HTML_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE (manager);
+       manager->priv = E_EDITOR_UNDO_REDO_MANAGER_GET_PRIVATE (manager);
 
        manager->priv->operation_in_progress = FALSE;
        manager->priv->history = NULL;
diff --git a/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h 
b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
new file mode 100644
index 0000000..60dabaf
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
@@ -0,0 +1,175 @@
+/*
+ * e-editor-undo-redo-manager.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_EDITOR_UNDO_REDO_MANAGER_H
+#define E_EDITOR_UNDO_REDO_MANAGER_H
+
+#include <glib-object.h>
+#include <webkitdom/webkitdom.h>
+
+#define E_TYPE_EDITOR_UNDO_REDO_MANAGER \
+       (e_editor_undo_redo_manager_get_type ())
+#define E_EDITOR_UNDO_REDO_MANAGER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManager))
+#define E_EDITOR_UNDO_REDO_MANAGER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManagerClass))
+#define E_IS_EDITOR_UNDO_REDO_MANAGER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER))
+#define E_IS_EDITOR_UNDO_REDO_MANAGER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_EDITOR_UNDO_REDO_MANAGER))
+#define E_EDITOR_UNDO_REDO_MANAGER_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_EDITOR_UNDO_REDO_MANAGER, EEditorUndoRedoManagerClass))
+
+G_BEGIN_DECLS
+
+struct _EEditorPage;
+
+enum EEditorHistoryEventType {
+       HISTORY_ALIGNMENT,
+       HISTORY_AND,
+       HISTORY_BLOCK_FORMAT,
+       HISTORY_BOLD,
+       HISTORY_CELL_DIALOG,
+       HISTORY_DELETE, /* BackSpace, Delete, with and without selection */
+       HISTORY_FONT_COLOR,
+       HISTORY_FONT_SIZE,
+       HISTORY_HRULE_DIALOG,
+       HISTORY_INDENT,
+       HISTORY_INPUT,
+       HISTORY_IMAGE,
+       HISTORY_IMAGE_DIALOG,
+       HISTORY_INSERT_HTML,
+       HISTORY_ITALIC,
+       HISTORY_LINK_DIALOG,
+       HISTORY_MONOSPACE,
+       HISTORY_PAGE_DIALOG,
+       HISTORY_PASTE,
+       HISTORY_PASTE_AS_TEXT,
+       HISTORY_PASTE_QUOTED,
+       HISTORY_REMOVE_LINK,
+       HISTORY_REPLACE,
+       HISTORY_REPLACE_ALL,
+       HISTORY_CITATION_SPLIT,
+       HISTORY_SMILEY,
+       HISTORY_START, /* Start of history */
+       HISTORY_STRIKETHROUGH,
+       HISTORY_TABLE_DIALOG,
+       HISTORY_TABLE_INPUT,
+       HISTORY_UNDERLINE,
+       HISTORY_WRAP,
+       HISTORY_UNQUOTE
+};
+
+typedef struct {
+       gint from; /* From what format we are changing. */
+       gint to; /* To what format we are changing. */
+} EEditorStyleChange;
+
+/* This is used for e-html-editor-*-dialogs */
+typedef struct {
+       WebKitDOMNode *from; /* From what node we are changing. */
+       WebKitDOMNode *to; /* To what node we are changing. */
+} EEditorDOMChange;
+
+typedef struct {
+       gchar *from; /* From what format we are changing. */
+       gchar *to; /* To what format we are changing. */
+} EEditorStringChange;
+
+typedef struct {
+       guint x;
+       guint y;
+} EEditorSelectionPoint;
+
+typedef struct {
+       EEditorSelectionPoint start;
+       EEditorSelectionPoint end;
+} EEditorSelection;
+
+typedef struct {
+       enum EEditorHistoryEventType type;
+       EEditorSelection before;
+       EEditorSelection after;
+       union {
+               WebKitDOMDocumentFragment *fragment;
+               EEditorStyleChange style;
+               EEditorStringChange string;
+               EEditorDOMChange dom;
+       } data;
+} EEditorHistoryEvent;
+
+typedef struct _EEditorUndoRedoManager EEditorUndoRedoManager;
+typedef struct _EEditorUndoRedoManagerClass EEditorUndoRedoManagerClass;
+typedef struct _EEditorUndoRedoManagerPrivate EEditorUndoRedoManagerPrivate;
+
+struct _EEditorUndoRedoManager {
+       GObject parent;
+       EEditorUndoRedoManagerPrivate *priv;
+};
+
+struct _EEditorUndoRedoManagerClass
+{
+       GObjectClass parent_class;
+};
+
+GType          e_editor_undo_redo_manager_get_type
+                                               (void) G_GNUC_CONST;
+
+EEditorUndoRedoManager *
+               e_editor_undo_redo_manager_new  (struct _EEditorPage *editor_page);
+gboolean       e_editor_undo_redo_manager_is_operation_in_progress
+                                               (EEditorUndoRedoManager *manager);
+
+void           e_editor_undo_redo_manager_set_operation_in_progress
+                                               (EEditorUndoRedoManager *manager,
+                                                gboolean value);
+
+void           e_editor_undo_redo_manager_insert_history_event
+                                               (EEditorUndoRedoManager *manager,
+                                                EEditorHistoryEvent *event);
+
+EEditorHistoryEvent *
+               e_editor_undo_redo_manager_get_current_history_event
+                                               (EEditorUndoRedoManager *manager);
+void           e_editor_undo_redo_manager_remove_current_history_event
+                                               (EEditorUndoRedoManager *manager);
+
+void           e_editor_undo_redo_manager_insert_dash_history_event
+                                               (EEditorUndoRedoManager *manager);
+
+gboolean       e_editor_undo_redo_manager_can_undo
+                                               (EEditorUndoRedoManager *manager);
+
+void           e_editor_undo_redo_manager_undo (EEditorUndoRedoManager *manager);
+
+gboolean       e_editor_undo_redo_manager_can_redo
+                                               (EEditorUndoRedoManager *manager);
+
+void           e_editor_undo_redo_manager_redo (EEditorUndoRedoManager *manager);
+
+void           e_editor_undo_redo_manager_clean_history
+                                               (EEditorUndoRedoManager *manager);
+
+G_END_DECLS
+
+#endif /* E_EDITOR_UNDO_REDO_MANAGER_H */
diff --git a/modules/webkit-editor/web-extension/e-html-editor-web-extension-main.c 
b/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
similarity index 79%
rename from modules/webkit-editor/web-extension/e-html-editor-web-extension-main.c
rename to modules/webkit-editor/web-extension/e-editor-web-extension-main.c
index 8c15421..244bc4c 100644
--- a/modules/webkit-editor/web-extension/e-html-editor-web-extension-main.c
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension-main.c
@@ -22,14 +22,14 @@
 
 #include <camel/camel.h>
 
-#include "e-html-editor-web-extension.h"
+#include "e-editor-web-extension.h"
 
 static void
 bus_acquired_cb (GDBusConnection *connection,
                  const gchar *name,
-                 EHTMLEditorWebExtension *extension)
+                 EEditorWebExtension *extension)
 {
-       e_html_editor_web_extension_dbus_register (extension, connection);
+       e_editor_web_extension_dbus_register (extension, connection);
 }
 
 /* Forward declaration */
@@ -38,16 +38,16 @@ G_MODULE_EXPORT void webkit_web_extension_initialize (WebKitWebExtension *wk_ext
 G_MODULE_EXPORT void
 webkit_web_extension_initialize (WebKitWebExtension *wk_extension)
 {
-       EHTMLEditorWebExtension *extension;
+       EEditorWebExtension *extension;
 
        camel_debug_init ();
 
-       extension = e_html_editor_web_extension_get ();
-       e_html_editor_web_extension_initialize (extension, wk_extension);
+       extension = e_editor_web_extension_get_default ();
+       e_editor_web_extension_initialize (extension, wk_extension);
 
        g_bus_own_name (
                G_BUS_TYPE_SESSION,
-               E_HTML_EDITOR_WEB_EXTENSION_SERVICE_NAME,
+               E_WEBKIT_EDITOR_WEB_EXTENSION_SERVICE_NAME,
                G_BUS_NAME_OWNER_FLAGS_NONE,
                (GBusAcquiredCallback) bus_acquired_cb,
                NULL, /* GBusNameAcquiredCallback */
diff --git a/modules/webkit-editor/web-extension/e-msg-composer-dom-functions.h 
b/modules/webkit-editor/web-extension/e-editor-web-extension-names.h
similarity index 59%
rename from modules/webkit-editor/web-extension/e-msg-composer-dom-functions.h
rename to modules/webkit-editor/web-extension/e-editor-web-extension-names.h
index 03453cf..d1b5f02 100644
--- a/modules/webkit-editor/web-extension/e-msg-composer-dom-functions.h
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension-names.h
@@ -1,5 +1,5 @@
 /*
- * e-msg-composer-dom-functions.h
+ * e-editor-web-extension-names.h
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -16,20 +16,11 @@
  *
  */
 
-#ifndef E_MSG_COMPOSER_DOM_FUNCTIONS_H
-#define E_MSG_COMPOSER_DOM_FUNCTIONS_H
+#ifndef E_EDITOR_WEB_EXTENSION_NAMES_H
+#define E_EDITOR_WEB_EXTENSION_NAMES_H
 
-#include <webkitdom/webkitdom.h>
+#define E_WEBKIT_EDITOR_WEB_EXTENSION_SERVICE_NAME "org.gnome.Evolution.WebExtension.EWebKitEditor"
+#define E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH  "/org/gnome/Evolution/WebExtension/EWebKitEditor"
+#define E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE    "org.gnome.Evolution.WebExtension.EWebKitEditor"
 
-G_BEGIN_DECLS
-
-gchar *                dom_get_active_signature_uid    (WebKitDOMDocument *document);
-
-gchar *                dom_get_raw_body_content_without_signature
-                                               (WebKitDOMDocument *document);
-
-gchar *                dom_get_raw_body_content        (WebKitDOMDocument *document);
-
-G_END_DECLS
-
-#endif /* E_MSG_COMPOSER_DOM_FUNCTIONS_H */
+#endif /* E_EDITOR_WEB_EXTENSION_NAMES_H */
diff --git a/modules/webkit-editor/web-extension/e-html-editor-web-extension.c 
b/modules/webkit-editor/web-extension/e-editor-web-extension.c
similarity index 51%
rename from modules/webkit-editor/web-extension/e-html-editor-web-extension.c
rename to modules/webkit-editor/web-extension/e-editor-web-extension.c
index f8f994c..c8d4d1f 100644
--- a/modules/webkit-editor/web-extension/e-html-editor-web-extension.c
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension.c
@@ -1,5 +1,5 @@
 /*
- * e-html-editor-web-extension.c
+ * e-editor-web-extension.c
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -28,105 +28,48 @@
 #include <webkit2/webkit-web-extension.h>
 #include <camel/camel.h>
 
-#include <web-extensions/e-dom-utils.h>
-
-#include "e-composer-private-dom-functions.h"
-#include "e-html-editor-actions-dom-functions.h"
-#include "e-html-editor-cell-dialog-dom-functions.h"
-#include "e-html-editor-hrule-dialog-dom-functions.h"
-#include "e-html-editor-image-dialog-dom-functions.h"
-#include "e-html-editor-link-dialog-dom-functions.h"
-#include "e-html-editor-page-dialog-dom-functions.h"
-#include "e-html-editor-selection-dom-functions.h"
-#include "e-html-editor-spell-check-dialog-dom-functions.h"
-#include "e-html-editor-table-dialog-dom-functions.h"
-#include "e-html-editor-test-dom-functions.h"
-#include "e-html-editor-view-dom-functions.h"
-#include "e-msg-composer-dom-functions.h"
-
-#include "e-html-editor-web-extension.h"
-
-#define E_HTML_EDITOR_WEB_EXTENSION_GET_PRIVATE(obj) \
+#include "web-extensions/e-dom-utils.h"
+
+#include "e-editor-page.h"
+#include "e-composer-dom-functions.h"
+#include "e-dialogs-dom-functions.h"
+#include "e-editor-dom-functions.h"
+#include "e-editor-undo-redo-manager.h"
+
+#include "e-editor-web-extension.h"
+
+#define E_EDITOR_WEB_EXTENSION_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
-       ((obj), E_TYPE_HTML_EDITOR_WEB_EXTENSION, EHTMLEditorWebExtensionPrivate))
+       ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionPrivate))
 
-struct _EHTMLEditorWebExtensionPrivate {
+struct _EEditorWebExtensionPrivate {
        WebKitWebExtension *wk_extension;
 
        GDBusConnection *dbus_connection;
        guint registration_id;
-       guint spell_check_on_scroll_event_source_id;
-       gboolean selection_changed_callbacks_blocked;
-
-       /* These properties show the actual state of EHTMLEditorView */
-       EContentEditorAlignment alignment;
-       EContentEditorBlockFormat block_format;
-       gchar *background_color;
-       gchar *font_color;
-       gchar *font_name;
-       gchar *text;
-       gint font_size;
-       gboolean bold;
-       gboolean indented;
-       gboolean italic;
-       gboolean monospaced;
-       gboolean strikethrough;
-       gboolean subscript;
-       gboolean superscript;
-       gboolean underline;
-
-       gboolean force_image_load;
-       gboolean html_mode;
-       gboolean return_key_pressed;
-       gboolean space_key_pressed;
-       gboolean smiley_written;
-       gint word_wrap_length;
-
-       gboolean convert_in_situ;
-       gboolean body_input_event_removed;
-       gboolean dont_save_history_in_body_input;
-       gboolean composition_in_progress;
-       gboolean is_pasting_content_from_itself;
-       gboolean renew_history_after_coordinates;
-
-       GHashTable *inline_images;
-
-       WebKitDOMNode *node_under_mouse_click;
-
-       GSettings *mail_settings;
-
-       EContentEditorContentFlags content_flags;
-
-       GHashTable *undo_redo_managers /* EHTMLEditorUndoRedoManager * ~> WebKitWebPage * */;
-       GSList *web_pages;
-
-       ESpellChecker *spell_checker;
+
+       GHashTable *editor_pages; /* guint64 *webpage_id ~> EEditorPage * */
 };
 
 static CamelDataCache *emd_global_http_cache = NULL;
 
-static const char introspection_xml[] =
+static const gchar *introspection_xml =
 "<node>"
-"  <interface name='" E_HTML_EDITOR_WEB_EXTENSION_INTERFACE "'>"
+"  <interface name='" E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE "'>"
 "<!-- ********************************************************* -->"
 "<!--                          SIGNALS                          -->"
 "<!-- ********************************************************* -->"
 "    <signal name='SelectionChanged'>"
+"      <arg type='t' name='page_id' direction='out'/>"
 "      <arg type='i' name='alignment' direction='out'/>"
 "      <arg type='i' name='block_format' direction='out'/>"
 "      <arg type='b' name='indented' direction='out'/>"
-"      <arg type='b' name='bold' direction='out'/>"
-"      <arg type='b' name='italic' direction='out'/>"
-"      <arg type='b' name='underline' direction='out'/>"
-"      <arg type='b' name='strikethrough' direction='out'/>"
-"      <arg type='b' name='monospaced' direction='out'/>"
-"      <arg type='b' name='subscript' direction='out'/>"
-"      <arg type='b' name='superscript' direction='out'/>"
-"      <arg type='b' name='underline' direction='out'/>"
+"      <arg type='i' name='style_flags' direction='out'/>"
 "      <arg type='i' name='font_size' direction='out'/>"
 "      <arg type='s' name='font_color' direction='out'/>"
 "    </signal>"
 "    <signal name='ContentChanged'>"
+"      <arg type='t' name='page_id' direction='out'/>"
 "    </signal>"
 "    <signal name='UndoRedoStateChanged'>"
 "      <arg type='t' name='page_id' direction='out'/>"
@@ -201,63 +144,63 @@ static const char introspection_xml[] =
 "      <arg type='s' name='selector' direction='in'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorCellDialog      -->"
+"<!--     Functions that are used in EEditorCellDialog      -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorCellDialogMarkCurrentCellElement'>"
+"    <method name='EEditorCellDialogMarkCurrentCellElement'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='element_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSaveHistoryOnExit'>"
+"    <method name='EEditorCellDialogSaveHistoryOnExit'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementVAlign'>"
+"    <method name='EEditorCellDialogSetElementVAlign'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementAlign'>"
+"    <method name='EEditorCellDialogSetElementAlign'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementNoWrap'>"
+"    <method name='EEditorCellDialogSetElementNoWrap'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='b' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementHeaderStyle'>"
+"    <method name='EEditorCellDialogSetElementHeaderStyle'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='b' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementWidth'>"
+"    <method name='EEditorCellDialogSetElementWidth'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementColSpan'>"
+"    <method name='EEditorCellDialogSetElementColSpan'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='i' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementRowSpan'>"
+"    <method name='EEditorCellDialogSetElementRowSpan'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='i' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorCellDialogSetElementBgColor'>"
+"    <method name='EEditorCellDialogSetElementBgColor'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='value' direction='in'/>"
 "      <arg type='i' name='scope' direction='in'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorHRuleDialog      -->"
+"<!--     Functions that are used in EEditorHRuleDialog      -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorHRuleDialogFindHRule'>"
+"    <method name='EEditorHRuleDialogFindHRule'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='b' name='created_new_hr' direction='out'/>"
 "    </method>"
-"    <method name='EHTMLEditorHRuleDialogSaveHistoryOnExit'>"
+"    <method name='EEditorHRuleDialogSaveHistoryOnExit'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
 "    <method name='HRElementSetNoShade'>"
@@ -271,19 +214,19 @@ static const char introspection_xml[] =
 "      <arg type='b' name='value' direction='out'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorImageDialog     -->"
+"<!--     Functions that are used in EEditorImageDialog     -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorImageDialogMarkImage'>"
+"    <method name='EEditorImageDialogMarkImage'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorImageDialogSaveHistoryOnExit'>"
+"    <method name='EEditorImageDialogSaveHistoryOnExit'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorImageDialogSetElementUrl'>"
+"    <method name='EEditorImageDialogSetElementUrl'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='value' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorImageDialogGetElementUrl'>"
+"    <method name='EEditorImageDialogGetElementUrl'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='value' direction='out'/>"
 "    </method>"
@@ -338,70 +281,70 @@ static const char introspection_xml[] =
 "      <arg type='i' name='value' direction='out'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorLinkDialog      -->"
+"<!--     Functions that are used in EEditorLinkDialog      -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorLinkDialogOk'>"
+"    <method name='EEditorLinkDialogOk'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='url' direction='in'/>"
 "      <arg type='s' name='inner_text' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorLinkDialogShow'>"
+"    <method name='EEditorLinkDialogShow'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='url' direction='out'/>"
 "      <arg type='s' name='inner_text' direction='out'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorPageDialog     -->"
+"<!--     Functions that are used in EEditorPageDialog     -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorPageDialogSaveHistory'>"
+"    <method name='EEditorPageDialogSaveHistory'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorPageDialogSaveHistoryOnExit'>"
+"    <method name='EEditorPageDialogSaveHistoryOnExit'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--   Functions that are used in EHTMLEditorSpellCheckDialog  -->"
+"<!--   Functions that are used in EEditorSpellCheckDialog  -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorSpellCheckDialogNext'>"
+"    <method name='EEditorSpellCheckDialogNext'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='word' direction='in'/>"
 "      <arg type='as' name='languages' direction='in'/>"
 "      <arg type='s' name='next_word' direction='out'/>"
 "    </method>"
-"    <method name='EHTMLEditorSpellCheckDialogPrev'>"
+"    <method name='EEditorSpellCheckDialogPrev'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='word' direction='in'/>"
 "      <arg type='as' name='languages' direction='in'/>"
 "      <arg type='s' name='prev_word' direction='out'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorTableDialog     -->"
+"<!--     Functions that are used in EEditorTableDialog     -->"
 "<!-- ********************************************************* -->"
-"    <method name='EHTMLEditorTableDialogSetRowCount'>"
+"    <method name='EEditorTableDialogSetRowCount'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='u' name='value' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorTableDialogGetRowCount'>"
+"    <method name='EEditorTableDialogGetRowCount'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='u' name='value' direction='out'/>"
 "    </method>"
-"    <method name='EHTMLEditorTableDialogSetColumnCount'>"
+"    <method name='EEditorTableDialogSetColumnCount'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='u' name='value' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorTableDialogGetColumnCount'>"
+"    <method name='EEditorTableDialogGetColumnCount'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='u' name='value' direction='out'/>"
 "    </method>"
-"    <method name='EHTMLEditorTableDialogShow'>"
+"    <method name='EEditorTableDialogShow'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='b' name='created_new_table' direction='out'/>"
 "    </method>"
-"    <method name='EHTMLEditorTableDialogSaveHistoryOnExit'>"
+"    <method name='EEditorTableDialogSaveHistoryOnExit'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorActions         -->"
+"<!--     Functions that are used in EEditorActions         -->"
 "<!-- ********************************************************* -->"
 "    <method name='TableCellElementGetNoWrap'>"
 "      <arg type='t' name='page_id' direction='in'/>"
@@ -418,38 +361,38 @@ static const char introspection_xml[] =
 "      <arg type='s' name='element_id' direction='in'/>"
 "      <arg type='i' name='col_span' direction='out'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogDeleteCellContents'>"
+"    <method name='EEditorDialogDeleteCellContents'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogDeleteColumn'>"
+"    <method name='EEditorDialogDeleteColumn'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogDeleteRow'>"
+"    <method name='EEditorDialogDeleteRow'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogDeleteTable'>"
+"    <method name='EEditorDialogDeleteTable'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogInsertColumnAfter'>"
+"    <method name='EEditorDialogInsertColumnAfter'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogInsertColumnBefore'>"
+"    <method name='EEditorDialogInsertColumnBefore'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogInsertRowAbove'>"
+"    <method name='EEditorDialogInsertRowAbove'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogInsertRowBelow'>"
+"    <method name='EEditorDialogInsertRowBelow'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogDOMUnlink'>"
+"    <method name='EEditorDialogDOMUnlink'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='EHTMLEditorDialogSaveHistoryForCut'>"
+"    <method name='EEditorDialogSaveHistoryForCut'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorView            -->"
+"<!--     Functions that are used in EEditorView            -->"
 "<!-- ********************************************************* -->"
 "    <method name='SetCurrentContentFlags'>"
 "      <arg type='t' name='page_id' direction='in'/>"
@@ -549,17 +492,11 @@ static const char introspection_xml[] =
 "      <arg type='s' name='smiley_name' direction='in'/>"
 "    </method>"
 "<!-- ********************************************************* -->"
-"<!--     Functions that are used in EHTMLEditorSelection       -->"
+"<!--     Functions that are used in EEditorSelection       -->"
 "<!-- ********************************************************* -->"
 "    <method name='DOMSelectionIndent'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "    </method>"
-"    <method name='DOMSelectionSave'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"    </method>"
-"    <method name='DOMSelectionRestore'>"
-"      <arg type='t' name='page_id' direction='in'/>"
-"    </method>"
 "    <method name='DOMSelectionInsertImage'>"
 "      <arg type='t' name='page_id' direction='in'/>"
 "      <arg type='s' name='uri' direction='in'/>"
@@ -663,20 +600,44 @@ static const char introspection_xml[] =
 "  </interface>"
 "</node>";
 
-G_DEFINE_TYPE (EHTMLEditorWebExtension, e_html_editor_web_extension, G_TYPE_OBJECT)
+G_DEFINE_TYPE (EEditorWebExtension, e_editor_web_extension, G_TYPE_OBJECT)
 
-static WebKitWebPage *
-get_webkit_web_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
-                                          WebKitWebExtension *web_extension,
-                                          guint64 page_id)
+static EEditorPage *
+get_editor_page (EEditorWebExtension *extension,
+                guint64 page_id)
 {
-       WebKitWebPage *web_page = webkit_web_extension_get_page (web_extension, page_id);
+       g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+
+       return g_hash_table_lookup (extension->priv->editor_pages, &page_id);
+}
+
+static EEditorPage *
+get_editor_page_or_return_dbus_error (GDBusMethodInvocation *invocation,
+                                     EEditorWebExtension *extension,
+                                     guint64 page_id)
+{
+       WebKitWebPage *web_page;
+       EEditorPage *editor_page;
+
+       g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
+
+       web_page = webkit_web_extension_get_page (extension->priv->wk_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;
        }
-       return web_page;
+
+       editor_page = get_editor_page (extension, page_id);
+       if (!editor_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 editor_page;
 }
 
 static void
@@ -690,12 +651,11 @@ handle_method_call (GDBusConnection *connection,
                     gpointer user_data)
 {
        guint64 page_id;
-        EHTMLEditorWebExtension *extension = E_HTML_EDITOR_WEB_EXTENSION (user_data);
+        EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (user_data);
        WebKitDOMDocument *document;
-       WebKitWebExtension *web_extension = extension->priv->wk_extension;
-       WebKitWebPage *web_page;
+       EEditorPage *editor_page;
 
-       if (g_strcmp0 (interface_name, E_HTML_EDITOR_WEB_EXTENSION_INTERFACE) != 0)
+       if (g_strcmp0 (interface_name, E_WEBKIT_EDITOR_WEB_EXTENSION_INTERFACE) != 0)
                return;
 
        if (g_strcmp0 (method_name, "TestHtmlEqual") == 0) {
@@ -704,13 +664,12 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(t&s&s)", &page_id, &html1, &html2);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               equal = dom_test_html_equal (document, html1, html2);
+               document = e_editor_page_get_document (editor_page);
+               equal = e_editor_dom_test_html_equal (document, html1, html2);
 
                g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", equal));
        } else if (g_strcmp0 (method_name, "ElementHasAttribute") == 0) {
@@ -721,12 +680,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s&s)", &page_id, &element_id, &attribute);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_element_has_attribute (element, attribute);
@@ -741,12 +699,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s&s)", &page_id, &element_id, &attribute);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_element_get_attribute (element, attribute);
@@ -765,12 +722,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s&s)", &page_id, &selector, &attribute);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_query_selector (document, selector, NULL);
                if (element)
                        value = webkit_dom_element_get_attribute (element, attribute);
@@ -788,12 +744,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s&s)", &page_id, &element_id, &attribute);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_element_remove_attribute (element, attribute);
@@ -806,12 +761,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s&s)", &page_id, &selector, &attribute);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_query_selector (document, selector, NULL);
                if (element)
                        webkit_dom_element_remove_attribute (element, attribute);
@@ -826,12 +780,11 @@ handle_method_call (GDBusConnection *connection,
                        "(t&s&s&s)",
                        &page_id, &element_id, &attribute, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_element_set_attribute (
@@ -845,20 +798,19 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s&s&s)", &page_id, &selector, &attribute, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_query_selector (document, selector, NULL);
                if (element) {
                        if (g_strcmp0 (selector, "body") == 0 &&
                            g_strcmp0 (attribute, "link") == 0)
-                               dom_set_link_color (document, value);
+                               e_editor_dom_set_link_color (editor_page, value);
                        else if (g_strcmp0 (selector, "body") == 0 &&
                                 g_strcmp0 (attribute, "vlink") == 0)
-                               dom_set_visited_link_color (document, value);
+                               e_editor_dom_set_visited_link_color (editor_page, value);
                        else
                                webkit_dom_element_set_attribute (
                                        element, attribute, value, NULL);
@@ -872,12 +824,11 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_element_get_tag_name (element);
@@ -895,12 +846,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&s)", &selector);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_query_selector (document, selector, NULL);
                if (element) {
                        webkit_dom_element_remove_attribute (element, "background");
@@ -910,178 +860,152 @@ handle_method_call (GDBusConnection *connection,
                }
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogMarkCurrentCellElement") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogMarkCurrentCellElement") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_mark_current_cell_element (document, extension, element_id);
+               e_dialogs_dom_cell_mark_current_cell_element (editor_page, element_id);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSaveHistoryOnExit") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSaveHistoryOnExit") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_save_history_on_exit (document, extension);
+               e_dialogs_dom_cell_save_history_on_exit (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementVAlign") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementVAlign") == 0) {
                const gchar *value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(t&si)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_v_align (document, value, scope);
+               e_dialogs_dom_cell_set_element_v_align (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementAlign") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementAlign") == 0) {
                const gchar *value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(t&su)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_align (document, value, scope);
+               e_dialogs_dom_cell_set_element_align (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementNoWrap") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementNoWrap") == 0) {
                gboolean value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(tbu)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_no_wrap (document, value, scope);
+               e_dialogs_dom_cell_set_element_no_wrap (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementHeaderStyle") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementHeaderStyle") == 0) {
                gboolean value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(tbu)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_header_style (
-                       document, value, scope);
+               e_dialogs_dom_cell_set_element_header_style (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementWidth") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementWidth") == 0) {
                const gchar *value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(t&su)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_width (document, value, scope);
+               e_dialogs_dom_cell_set_element_width (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementColSpan") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementColSpan") == 0) {
                glong value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(tiu)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_col_span (document, value, scope);
+               e_dialogs_dom_cell_set_element_col_span (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementRowSpan") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementRowSpan") == 0) {
                glong value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(tiu)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_row_span (document, value, scope);
+               e_dialogs_dom_cell_set_element_row_span (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorCellDialogSetElementBgColor") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorCellDialogSetElementBgColor") == 0) {
                const gchar *value;
                EContentEditorScope scope;
 
                g_variant_get (parameters, "(t&su)", &page_id, &value, &scope);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_cell_dialog_set_element_bg_color (document, value, scope);
+               e_dialogs_dom_cell_set_element_bg_color (editor_page, value, scope);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorHRuleDialogFindHRule") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorHRuleDialogFindHRule") == 0) {
                gboolean created_new_hr = 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               created_new_hr = e_html_editor_hrule_dialog_find_hrule (
-                       document, extension, extension->priv->node_under_mouse_click);
+               created_new_hr = e_dialogs_dom_hrule_find_hrule (editor_page, 
e_editor_page_get_node_under_mouse_click (editor_page));
 
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(b)", created_new_hr));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorHRuleDialogSaveHistoryOnExit") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorHRuleDialogSaveHistoryOnExit") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_hrule_dialog_save_history_on_exit (document, extension);
+               e_dialogs_dom_save_history_on_exit (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "HRElementSetNoShade") == 0) {
@@ -1092,12 +1016,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&sb)", &page_id, &element_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_html_hr_element_set_no_shade (
@@ -1112,12 +1035,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_hr_element_get_no_shade (
@@ -1125,57 +1047,48 @@ handle_method_call (GDBusConnection *connection,
 
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(b)", value));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorImageDialogMarkImage") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorImageDialogMarkImage") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_image_dialog_mark_image (
-                       document, extension, extension->priv->node_under_mouse_click);
+               e_dialogs_dom_image_mark_image (editor_page, e_editor_page_get_node_under_mouse_click 
(editor_page));
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorImageDialogSaveHistoryOnExit") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorImageDialogSaveHistoryOnExit") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_image_dialog_save_history_on_exit (document, extension);
+               e_dialogs_dom_image_save_history_on_exit (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorImageDialogSetElementUrl") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorImageDialogSetElementUrl") == 0) {
                const gchar *value;
 
                g_variant_get (parameters, "(t&s)", &page_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_image_dialog_set_element_url (document, value);
+               e_dialogs_dom_image_set_element_url (editor_page, value);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorImageDialogGetElementUrl") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorImageDialogGetElementUrl") == 0) {
                gchar *value;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = e_html_editor_image_dialog_get_element_url (document);
+               value = e_dialogs_dom_image_get_element_url (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -1191,12 +1104,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&si)", &page_id, &element_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_html_image_element_set_width (
@@ -1211,12 +1123,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_image_element_get_width (
@@ -1232,12 +1143,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&si)", &page_id, &element_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_html_image_element_set_width (
@@ -1252,12 +1162,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_image_element_get_height (
@@ -1273,12 +1182,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_image_element_get_natural_width (
@@ -1294,12 +1202,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_image_element_get_natural_height (
@@ -1315,12 +1222,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&si)", &page_id, &element_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_html_image_element_set_hspace (
@@ -1335,12 +1241,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_image_element_get_hspace (
@@ -1356,12 +1261,11 @@ handle_method_call (GDBusConnection *connection,
                g_variant_get (
                        parameters, "(t&si)", &page_id, &element_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        webkit_dom_html_image_element_set_vspace (
@@ -1376,12 +1280,11 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_image_element_get_vspace (
@@ -1389,71 +1292,60 @@ handle_method_call (GDBusConnection *connection,
 
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(i)", value));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorLinkDialogOk") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorLinkDialogOk") == 0) {
                const gchar *url, *inner_text;
 
                g_variant_get (parameters, "(t&s&s)", &page_id, &url, &inner_text);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_link_dialog_ok (document, extension, url, inner_text);
+               e_dialogs_dom_link_commit (editor_page, url, inner_text);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorLinkDialogShow") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorLinkDialogShow") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-
                g_dbus_method_invocation_return_value (
                        invocation,
-                       e_html_editor_link_dialog_show (document));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorPageDialogSaveHistory") == 0) {
+                       e_dialogs_dom_link_show (editor_page));
+       } else if (g_strcmp0 (method_name, "EEditorPageDialogSaveHistory") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_page_dialog_save_history (document, extension);
+               e_dialogs_dom_page_save_history (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorPageDialogSaveHistoryOnExit") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorPageDialogSaveHistoryOnExit") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_page_dialog_save_history_on_exit (document, extension);
+               e_dialogs_dom_page_save_history_on_exit (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorSpellCheckDialogNext") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorSpellCheckDialogNext") == 0) {
                const gchar *from_word = NULL;
                const gchar * const *languages = NULL;
                gchar *value = NULL;
 
                g_variant_get (parameters, "(t&s^as)", &page_id, &from_word, &languages);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = e_html_editor_spell_check_dialog_next (document, extension, from_word, languages);
+               value = e_dialogs_dom_spell_check_next (editor_page, from_word, languages);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -1461,20 +1353,18 @@ handle_method_call (GDBusConnection *connection,
                                "(@s)",
                                g_variant_new_take_string (
                                        value ? value : g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorSpellCheckDialogPrev") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorSpellCheckDialogPrev") == 0) {
                const gchar *from_word = NULL;
                const gchar * const *languages = NULL;
                gchar *value = NULL;
 
                g_variant_get (parameters, "(t&s^as)", &page_id, &from_word, &languages);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = e_html_editor_spell_check_dialog_prev (document, extension, from_word, languages);
+               value = e_dialogs_dom_spell_check_prev (editor_page, from_word, languages);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -1482,233 +1372,187 @@ handle_method_call (GDBusConnection *connection,
                                "(@s)",
                                g_variant_new_take_string (
                                        value ? value : g_strdup (""))));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorTableDialogSetRowCount") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorTableDialogSetRowCount") == 0) {
                gulong value;
 
                g_variant_get (parameters, "(tu)", &page_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_table_dialog_set_row_count (document, value);
+               e_dialogs_dom_table_set_row_count (editor_page, value);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorTableDialogGetRowCount") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorTableDialogGetRowCount") == 0) {
                gulong value;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = e_html_editor_table_dialog_get_row_count (document);
+               value = e_dialogs_dom_table_get_row_count (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(u)", value));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorTableDialogSetColumnCount") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorTableDialogSetColumnCount") == 0) {
                gulong value;
 
                g_variant_get (parameters, "(tu)", &page_id, &value);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_table_dialog_set_column_count (document, value);
+               e_dialogs_dom_table_set_column_count (editor_page, value);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorTableDialogGetColumnCount") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorTableDialogGetColumnCount") == 0) {
                gulong value;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = e_html_editor_table_dialog_get_column_count (document);
+               value = e_dialogs_dom_table_get_column_count (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(u)", value));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorTableDialogShow") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorTableDialogShow") == 0) {
                gboolean created_new_table;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               created_new_table = e_html_editor_table_dialog_show (document, extension);
+               created_new_table = e_dialogs_dom_table_show (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(b)", created_new_table));
-       } else if (g_strcmp0 (method_name, "EHTMLEditorTableDialogSaveHistoryOnExit") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorTableDialogSaveHistoryOnExit") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_table_dialog_save_history_on_exit (document, extension);
+               e_dialogs_dom_table_save_history_on_exit (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogDeleteCellContents") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogDeleteCellContents") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_delete_cell_contents (document, extension);
+               e_editor_dom_delete_cell_contents (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogDeleteColumn") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogDeleteColumn") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_delete_column (document, extension);
+               e_editor_dom_delete_column (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogDeleteRow") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogDeleteRow") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_delete_row (document, extension);
+               e_editor_dom_delete_row (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogDeleteTable") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogDeleteTable") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_delete_table (document, extension);
+               e_editor_dom_delete_table (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogDeleteTable") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogInsertColumnAfter") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_delete_cell_contents (document, extension);
+               e_editor_dom_insert_column_after (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogInsertColumnAfter") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogInsertColumnBefore") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_insert_column_after (document, extension);
+               e_editor_dom_insert_column_before (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogInsertColumnBefore") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogInsertRowAbove") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_insert_column_before (document, extension);
+               e_editor_dom_insert_row_above (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogInsertRowAbove") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogInsertRowBelow") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_insert_row_above (document, extension);
+               e_editor_dom_insert_row_below (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogInsertRowBelow") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogDOMUnlink") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               e_html_editor_dialog_insert_row_below (document, extension);
+               e_editor_dom_selection_unlink (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogDOMUnlink") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogSaveHistoryForCut") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_unlink (document, extension);
+               e_editor_dom_selection_unlink (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogSaveHistoryForCut") == 0) {
+       } else if (g_strcmp0 (method_name, "EEditorDialogSaveHistoryForCut") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_unlink (document, extension);
-
-               g_dbus_method_invocation_return_value (invocation, NULL);
-       } else if (g_strcmp0 (method_name, "EHTMLEditorDialogSaveHistoryForCut") == 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)
-                       goto error;
-
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_save_history_for_cut (document, extension);
+               e_editor_dom_save_history_for_cut (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "TableCellElementGetNoWrap") == 0) {
@@ -1718,12 +1562,11 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_table_cell_element_get_no_wrap (
@@ -1738,12 +1581,11 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_table_cell_element_get_row_span (
@@ -1758,12 +1600,11 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
+               document = e_editor_page_get_document (editor_page);
                element = webkit_dom_document_get_element_by_id (document, element_id);
                if (element)
                        value = webkit_dom_html_table_cell_element_get_col_span (
@@ -1774,78 +1615,68 @@ handle_method_call (GDBusConnection *connection,
        } else if (g_strcmp0 (method_name, "DOMSaveSelection") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_save (document);
+               e_editor_dom_selection_save (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMRestoreSelection") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMUndo") == 0) {
-               EHTMLEditorUndoRedoManager *manager;
+               EEditorUndoRedoManager *manager;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               manager = e_html_editor_web_extension_get_undo_redo_manager (extension, document);
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
 
-               e_html_editor_undo_redo_manager_undo (manager);
+               e_editor_undo_redo_manager_undo (manager);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMRedo") == 0) {
-               EHTMLEditorUndoRedoManager *manager;
+               EEditorUndoRedoManager *manager;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               manager = e_html_editor_web_extension_get_undo_redo_manager (extension, document);
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
 
-               e_html_editor_undo_redo_manager_redo (manager);
+               e_editor_undo_redo_manager_redo (manager);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMTurnSpellCheckOff") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_turn_spell_check_off (document, extension);
+               e_editor_dom_turn_spell_check_off (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMQuoteAndInsertTextIntoSelection") == 0) {
                const gchar *text;
 
                g_variant_get (parameters, "(t&s)", &page_id, &text);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_quote_and_insert_text_into_selection (document, extension, text);
+               e_editor_dom_quote_and_insert_text_into_selection (editor_page, text);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMConvertAndInsertHTMLIntoSelection") == 0) {
                gboolean is_html;
@@ -1853,53 +1684,53 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(t&sb)", &page_id, &text, &is_html);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_convert_and_insert_html_into_selection (document, extension, text, is_html);
+               e_editor_dom_convert_and_insert_html_into_selection (editor_page, text, is_html);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMEmbedStyleSheet") == 0) {
                const gchar *style_sheet_content;
 
                g_variant_get (parameters, "(t&s)", &page_id, &style_sheet_content);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_embed_style_sheet (document, style_sheet_content);
+               e_editor_dom_embed_style_sheet (editor_page, style_sheet_content);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMRemoveEmbeddedStyleSheet") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_remove_embedded_style_sheet (document);
+               e_editor_dom_remove_embedded_style_sheet (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "SetCurrentContentFlags") == 0) {
-               g_variant_get (parameters, "(ti)", &page_id, &extension->priv->content_flags);
+               guint content_flags = 0;
+
+               g_variant_get (parameters, "(ti)", &page_id, &content_flags);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
+               e_editor_page_set_current_content_flags (editor_page, content_flags);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "SetPastingContentFromItself") == 0) {
-               g_variant_get (
-                       parameters,
-                       "(tb)",
-                       &page_id,
-                       &extension->priv->is_pasting_content_from_itself);
+               gboolean value = FALSE;
+
+               g_variant_get (parameters, "(tb)", &page_id, &value);
+
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
+                       goto error;
+
+               e_editor_page_set_pasting_content_from_itself (editor_page, value);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "SetEditorHTMLMode") == 0) {
@@ -1908,53 +1739,50 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(tbb)", &page_id, &html_mode, &convert);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-
-               convert = convert && extension->priv->html_mode && !html_mode;
-               extension->priv->html_mode = html_mode;
+               convert = convert && e_editor_page_get_html_mode (editor_page) && !html_mode;
+               e_editor_page_set_html_mode (editor_page, html_mode);
 
                if (convert)
-                       dom_convert_when_changing_composer_mode (document, extension);
+                       e_editor_dom_convert_when_changing_composer_mode (editor_page);
                else
-                       dom_process_content_after_mode_change (document, extension);
+                       e_editor_dom_process_content_after_mode_change (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "SetConvertInSitu") == 0) {
-               g_variant_get (
-                       parameters,
-                       "(tb)",
-                       &page_id,
-                       &extension->priv->convert_in_situ);
+               gboolean value = FALSE;
+
+               g_variant_get (parameters, "(tb)", &page_id, &value);
+
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
+                       goto error;
+
+               e_editor_page_set_convert_in_situ (editor_page, value);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMForceSpellCheck") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_force_spell_check (document, extension);
+               e_editor_dom_force_spell_check (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMCheckIfConversionNeeded") == 0) {
                gboolean conversion_needed;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               conversion_needed = dom_check_if_conversion_needed (document);
+               conversion_needed = e_editor_dom_check_if_conversion_needed (editor_page);
                g_dbus_method_invocation_return_value (
                        invocation, g_variant_new ("(b)", conversion_needed));
        } else if (g_strcmp0 (method_name, "DOMGetContent") == 0) {
@@ -1965,35 +1793,32 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(t&si)", &page_id, &from_domain, &flags);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-
                if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES) && from_domain && *from_domain)
-                       inline_images = dom_get_inline_images_data (document, extension, from_domain);
+                       inline_images = e_editor_dom_get_inline_images_data (editor_page, from_domain);
 
                if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
                    !(flags & E_CONTENT_EDITOR_GET_PROCESSED)) {
-                       value = dom_process_content_for_draft (
-                               document, extension, (flags & E_CONTENT_EDITOR_GET_BODY));
+                       value = e_editor_dom_process_content_for_draft (
+                               editor_page, (flags & E_CONTENT_EDITOR_GET_BODY));
                } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_HTML) &&
                           (flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
                           !(flags & E_CONTENT_EDITOR_GET_BODY)) {
-                       value = dom_process_content_for_html (document, extension);
+                       value = e_editor_dom_process_content_for_html (editor_page);
                } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_PLAIN) &&
                           (flags & E_CONTENT_EDITOR_GET_PROCESSED) &&
                           !(flags & E_CONTENT_EDITOR_GET_BODY)) {
-                       value = dom_process_content_for_plain_text (document, extension);
+                       value = e_editor_dom_process_content_for_plain_text (editor_page);
                } else if ((flags & E_CONTENT_EDITOR_GET_TEXT_PLAIN) &&
                           (flags & E_CONTENT_EDITOR_GET_BODY) &&
                           !(flags & E_CONTENT_EDITOR_GET_PROCESSED)) {
                        if (flags & E_CONTENT_EDITOR_GET_EXCLUDE_SIGNATURE)
-                               value = dom_get_raw_body_content_without_signature  (document);
+                               value = e_composer_dom_get_raw_body_content_without_signature (editor_page);
                        else
-                               value = dom_get_raw_body_content (document);
+                               value = e_composer_dom_get_raw_body_content (editor_page);
                } else {
                        g_warning ("Unsupported flags combination (%d) in (%s)", flags, G_STRFUNC);
                }
@@ -2010,7 +1835,7 @@ handle_method_call (GDBusConnection *connection,
                g_free (value);
 
                if ((flags & E_CONTENT_EDITOR_GET_INLINE_IMAGES) && from_domain && *from_domain && 
inline_images) {
-                       dom_restore_images (document, inline_images);
+                       e_editor_dom_restore_images (editor_page, inline_images);
                        g_object_unref (inline_images);
                }
        } else if (g_strcmp0 (method_name, "DOMInsertHTML") == 0) {
@@ -2018,42 +1843,36 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(t&s)", &page_id, &html);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_insert_html (document, extension, html);
+               e_editor_dom_insert_html (editor_page, html);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMConvertContent") == 0) {
                const gchar *preferred_text;
 
                g_variant_get (parameters, "(t&s)", &page_id, &preferred_text);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_convert_content (document, extension, preferred_text);
+               e_editor_dom_convert_content (editor_page, preferred_text);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMAddNewInlineImageIntoList") == 0) {
                const gchar *cid_uri, *src, *filename;
 
                g_variant_get (parameters, "(t&s&s&s)", &page_id, &filename, &cid_uri, &src);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               e_html_editor_web_extension_add_new_inline_image_into_list (
-                       extension, cid_uri, src);
+               e_editor_page_add_new_inline_image_into_list (
+                       editor_page, cid_uri, src);
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_insert_base64_image (document, extension, filename, cid_uri, src);
+               e_editor_dom_insert_base64_image (editor_page, filename, cid_uri, src);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMReplaceImageSrc") == 0) {
@@ -2061,38 +1880,32 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(t&s&s)", &page_id, &selector, &uri);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_replace_image_src (document, extension, selector, uri);
+               e_editor_dom_replace_image_src (editor_page, selector, uri);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMDragAndDropEnd") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_drag_and_drop_end (document, extension);
+               e_editor_dom_drag_and_drop_end (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMInsertSmiley") == 0) {
                const gchar *smiley_name;
 
                g_variant_get (parameters, "(t&s)", &page_id, &smiley_name);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_insert_smiley_by_name (document, extension, smiley_name);
+               e_editor_dom_insert_smiley_by_name (editor_page, smiley_name);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMMoveSelectionOnPoint") == 0) {
                gboolean cancel_if_not_collapsed;
@@ -2100,63 +1913,54 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(tiib)", &page_id, &x, &y, &cancel_if_not_collapsed);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
                if (cancel_if_not_collapsed) {
-                       if (dom_selection_is_collapsed (document))
-                               dom_selection_set_on_point (document, x, y);
+                       if (e_editor_dom_selection_is_collapsed (editor_page))
+                               e_editor_dom_selection_set_on_point (editor_page, x, y);
                } else
-                       dom_selection_set_on_point (document, x, y);
+                       e_editor_dom_selection_set_on_point (editor_page, x, y);
+
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionIndent") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_indent (document, extension);
+               e_editor_dom_selection_indent (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSave") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_save (document);
+               e_editor_dom_selection_save (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionRestore") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_restore (document);
+               e_editor_dom_selection_restore (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionInsertImage") == 0) {
                const gchar *uri;
 
                g_variant_get (parameters, "(t&s)", &page_id, &uri);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_insert_image (document, extension, uri);
+               e_editor_dom_insert_image (editor_page, uri);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionReplace") == 0) {
@@ -2164,192 +1968,162 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(t&s)", &page_id, &replacement);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_replace (document, extension, replacement);
+               e_editor_dom_selection_replace (editor_page, replacement);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetAlignment") == 0) {
                EContentEditorAlignment alignment;
 
                g_variant_get (parameters, "(ti)", &page_id, &alignment);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_alignment (document, extension, alignment);
-               extension->priv->alignment = alignment;
+               e_editor_dom_selection_set_alignment (editor_page, alignment);
+               e_editor_page_set_alignment (editor_page, alignment);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetBold") == 0) {
                gboolean bold;
 
                g_variant_get (parameters, "(tb)", &page_id, &bold);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_bold (document, extension, bold);
+               e_editor_page_set_bold (editor_page, bold);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetBlockFormat") == 0) {
                EContentEditorBlockFormat block_format;
 
                g_variant_get (parameters, "(ti)", &page_id, &block_format);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_block_format (document, extension, block_format);
+               e_editor_dom_selection_set_block_format (editor_page, block_format);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetFontColor") == 0) {
                const gchar *color;
 
                g_variant_get (parameters, "(t&s)", &page_id, &color);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_font_color (document, extension, color);
+               e_editor_dom_selection_set_font_color (editor_page, color);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetFontSize") == 0) {
                EContentEditorFontSize font_size;
 
                g_variant_get (parameters, "(ti)", &page_id, &font_size);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_font_size (document, extension, font_size);
+               e_editor_dom_selection_set_font_size (editor_page, font_size);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetItalic") == 0) {
                gboolean italic;
 
                g_variant_get (parameters, "(tb)", &page_id, &italic);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_italic (document, extension, italic);
+               e_editor_page_set_italic (editor_page, italic);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetMonospaced") == 0) {
                gboolean monospaced;
 
                g_variant_get (parameters, "(tb)", &page_id, &monospaced);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_monospaced (document, extension, monospaced);
+               e_editor_page_set_monospace (editor_page, monospaced);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetStrikethrough") == 0) {
                gboolean strikethrough;
 
                g_variant_get (parameters, "(tb)", &page_id, &strikethrough);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_strikethrough (document, extension, strikethrough);
+               e_editor_page_set_strikethrough (editor_page, strikethrough);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetSubscript") == 0) {
                gboolean subscript;
 
                g_variant_get (parameters, "(tb)", &page_id, &subscript);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_subscript (document, extension, subscript);
+               e_editor_dom_selection_set_subscript (editor_page, subscript);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetSuperscript") == 0) {
                gboolean superscript;
 
                g_variant_get (parameters, "(tb)", &page_id, &superscript);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_superscript (document, extension, superscript);
+               e_editor_dom_selection_set_superscript (editor_page, superscript);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionSetUnderline") == 0) {
                gboolean underline;
 
                g_variant_get (parameters, "(tb)", &page_id, &underline);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_set_underline (document, extension, underline);
+               e_editor_page_set_underline (editor_page, underline);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionUnindent") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_unindent (document, extension);
+               e_editor_dom_selection_unindent (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMSelectionWrap") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_selection_wrap (document, extension);
+               e_editor_dom_selection_wrap (editor_page);
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMGetCaretWord") == 0) {
                gchar *word;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               word = dom_get_caret_word (document);
+               word = e_editor_dom_get_caret_word (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -2363,13 +2137,11 @@ handle_method_call (GDBusConnection *connection,
 
                g_variant_get (parameters, "(tb)", &page_id, &top_signature);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               active_signature = dom_remove_signatures (document, extension, top_signature);
+               active_signature = e_composer_dom_remove_signatures (editor_page, top_signature);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -2394,15 +2166,12 @@ handle_method_call (GDBusConnection *connection,
                        &check_if_signature_is_changed,
                        &ignore_next_signature_change);
 
-               web_page = get_webkit_web_page_or_return_dbus_error (
-                       invocation, web_extension, page_id);
-               if (!web_page)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               new_signature_id = dom_insert_signature (
-                       document,
-                       extension,
+               new_signature_id = e_composer_dom_insert_signature (
+                       editor_page,
                        content,
                        is_html,
                        signature_id,
@@ -2424,26 +2193,22 @@ handle_method_call (GDBusConnection *connection,
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_save_drag_and_drop_history (document, extension);
+               e_composer_dom_save_drag_and_drop_history (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMCleanAfterDragAndDrop") == 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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               dom_clean_after_drag_and_drop (document, extension);
+               e_composer_dom_clean_after_drag_and_drop (editor_page);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else if (g_strcmp0 (method_name, "DOMGetActiveSignatureUid") == 0) {
@@ -2451,13 +2216,11 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = dom_get_active_signature_uid (document);
+               value = e_composer_dom_get_active_signature_uid (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -2470,13 +2233,11 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = dom_get_caret_position (document);
+               value = e_editor_dom_get_caret_position (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation,
@@ -2486,30 +2247,27 @@ handle_method_call (GDBusConnection *connection,
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               document = webkit_web_page_get_dom_document (web_page);
-               value = dom_get_caret_offset (document, extension);
+               value = e_editor_dom_get_caret_offset (editor_page);
 
                g_dbus_method_invocation_return_value (
                        invocation,
                        value ? g_variant_new_uint32 (value) : NULL);
        } else if (g_strcmp0 (method_name, "DOMClearUndoRedoHistory") == 0) {
-               EHTMLEditorUndoRedoManager *manager;
+               EEditorUndoRedoManager *manager;
 
                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)
+               editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
+               if (!editor_page)
                        goto error;
 
-               manager = e_html_editor_web_extension_get_undo_redo_manager (extension,
-                       webkit_web_page_get_dom_document (web_page));
+               manager = e_editor_page_get_undo_redo_manager (editor_page);
                if (manager)
-                       e_html_editor_undo_redo_manager_clean_history (manager);
+                       e_editor_undo_redo_manager_clean_history (manager);
 
                g_dbus_method_invocation_return_value (invocation, NULL);
        } else {
@@ -2526,18 +2284,16 @@ static void
 web_page_gone_cb (gpointer user_data,
                  GObject *gone_web_page)
 {
-       EHTMLEditorWebExtension *extension = user_data;
+       EEditorWebExtension *extension = user_data;
        GHashTableIter iter;
        gpointer key, value;
 
-       g_return_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension));
+       g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
 
-       extension->priv->web_pages = g_slist_remove (extension->priv->web_pages, gone_web_page);
-
-       g_hash_table_iter_init (&iter, extension->priv->undo_redo_managers);
+       g_hash_table_iter_init (&iter, extension->priv->editor_pages);
        while (g_hash_table_iter_next (&iter, &key, &value)) {
                if (value == gone_web_page) {
-                       g_hash_table_remove (extension->priv->undo_redo_managers, key);
+                       g_hash_table_remove (extension->priv->editor_pages, key);
                        break;
                }
        }
@@ -2550,14 +2306,9 @@ static const GDBusInterfaceVTable interface_vtable = {
 };
 
 static void
-e_html_editor_web_extension_dispose (GObject *object)
+e_editor_web_extension_dispose (GObject *object)
 {
-       EHTMLEditorWebExtension *extension = E_HTML_EDITOR_WEB_EXTENSION (object);
-
-       if (extension->priv->spell_check_on_scroll_event_source_id > 0) {
-               g_source_remove (extension->priv->spell_check_on_scroll_event_source_id);
-               extension->priv->spell_check_on_scroll_event_source_id = 0;
-       }
+       EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
 
        if (extension->priv->dbus_connection) {
                g_dbus_connection_unregister_object (
@@ -2567,150 +2318,57 @@ e_html_editor_web_extension_dispose (GObject *object)
                extension->priv->dbus_connection = NULL;
        }
 
-       if (extension->priv->background_color != NULL) {
-               g_free (extension->priv->background_color);
-               extension->priv->background_color = NULL;
-       }
-
-       if (extension->priv->font_color != NULL) {
-               g_free (extension->priv->font_color);
-               extension->priv->font_color = NULL;
-       }
-
-       if (extension->priv->font_name != NULL) {
-               g_free (extension->priv->font_name);
-               extension->priv->font_name = NULL;
-       }
-
-       if (extension->priv->text != NULL) {
-               g_free (extension->priv->text);
-               extension->priv->text = NULL;
-       }
-
-       if (extension->priv->undo_redo_managers != NULL) {
-               g_hash_table_destroy (extension->priv->undo_redo_managers);
-               extension->priv->undo_redo_managers = NULL;
-       }
-
-       if (extension->priv->web_pages) {
-               GSList *link;
-
-               for (link = extension->priv->web_pages; link; link = g_slist_next (link)) {
-                       WebKitWebPage *page = link->data;
-
-                       if (!page)
-                               continue;
-
-                       g_object_weak_unref (G_OBJECT (page), web_page_gone_cb, extension);
-               }
-
-               g_slist_free (extension->priv->web_pages);
-               extension->priv->web_pages = NULL;
-       }
-
-       if (extension->priv->mail_settings != NULL) {
-               g_signal_handlers_disconnect_by_data (extension->priv->mail_settings, object);
-               g_object_unref (extension->priv->mail_settings);
-               extension->priv->mail_settings = NULL;
-       }
+       g_hash_table_remove_all (extension->priv->editor_pages);
 
        g_clear_object (&extension->priv->wk_extension);
-       g_clear_object (&extension->priv->spell_checker);
-
-       g_hash_table_remove_all (extension->priv->inline_images);
 
        /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_html_editor_web_extension_parent_class)->dispose (object);
+       G_OBJECT_CLASS (e_editor_web_extension_parent_class)->dispose (object);
 }
+
 static void
-e_html_editor_web_extension_finalize (GObject *object)
+e_editor_web_extension_finalize (GObject *object)
 {
-       EHTMLEditorWebExtension *extension = E_HTML_EDITOR_WEB_EXTENSION (object);
+       EEditorWebExtension *extension = E_EDITOR_WEB_EXTENSION (object);
 
-       g_hash_table_destroy (extension->priv->inline_images);
+       if (extension->priv->editor_pages) {
+               g_hash_table_destroy (extension->priv->editor_pages);
+               extension->priv->editor_pages = NULL;
+       }
 
        /* Chain up to parent's finalize() method. */
-       G_OBJECT_CLASS (e_html_editor_web_extension_parent_class)->finalize (object);
+       G_OBJECT_CLASS (e_editor_web_extension_parent_class)->finalize (object);
 }
 
 static void
-e_html_editor_web_extension_class_init (EHTMLEditorWebExtensionClass *class)
+e_editor_web_extension_class_init (EEditorWebExtensionClass *class)
 {
        GObjectClass *object_class = G_OBJECT_CLASS (class);
 
-       object_class->dispose = e_html_editor_web_extension_dispose;
-       object_class->finalize = e_html_editor_web_extension_finalize;
+       object_class->dispose = e_editor_web_extension_dispose;
+       object_class->finalize = e_editor_web_extension_finalize;
 
-       g_type_class_add_private (object_class, sizeof(EHTMLEditorWebExtensionPrivate));
+       g_type_class_add_private (object_class, sizeof(EEditorWebExtensionPrivate));
 }
 
 static void
-e_html_editor_web_extension_init (EHTMLEditorWebExtension *extension)
+e_editor_web_extension_init (EEditorWebExtension *extension)
 {
-       GSettings *g_settings;
-
-       extension->priv = E_HTML_EDITOR_WEB_EXTENSION_GET_PRIVATE (extension);
-
-       extension->priv->bold = FALSE;
-       extension->priv->background_color = g_strdup ("");
-       extension->priv->font_color = g_strdup ("");
-       extension->priv->font_name = g_strdup ("");
-       extension->priv->text = g_strdup ("");
-       extension->priv->font_size = E_CONTENT_EDITOR_FONT_SIZE_NORMAL;
-       extension->priv->indented = FALSE;
-       extension->priv->italic = FALSE;
-       extension->priv->monospaced = FALSE;
-       extension->priv->strikethrough = FALSE;
-       extension->priv->subscript = FALSE;
-       extension->priv->superscript = FALSE;
-       extension->priv->underline = FALSE;
-       extension->priv->alignment = E_CONTENT_EDITOR_ALIGNMENT_LEFT;
-       extension->priv->block_format = E_CONTENT_EDITOR_BLOCK_FORMAT_PARAGRAPH;
-       extension->priv->force_image_load = FALSE;
-       extension->priv->html_mode = FALSE;
-       extension->priv->return_key_pressed = FALSE;
-       extension->priv->space_key_pressed = FALSE;
-       extension->priv->smiley_written = FALSE;
-
-       extension->priv->convert_in_situ = FALSE;
-       extension->priv->body_input_event_removed = TRUE;
-       extension->priv->dont_save_history_in_body_input = FALSE;
-       extension->priv->is_pasting_content_from_itself = FALSE;
-       extension->priv->composition_in_progress = FALSE;
-       extension->priv->renew_history_after_coordinates = TRUE;
-
-       extension->priv->content_flags = 0;
-
-       extension->priv->spell_check_on_scroll_event_source_id = 0;
-
-       g_settings = e_util_ref_settings ("org.gnome.evolution.mail");
-       extension->priv->mail_settings = g_settings;
-
-       extension->priv->word_wrap_length = g_settings_get_int (
-               extension->priv->mail_settings, "composer-word-wrap-length");
-
-       extension->priv->undo_redo_managers = g_hash_table_new_full (g_direct_hash, g_direct_equal, 
g_object_unref, NULL);
-
-       extension->priv->inline_images = g_hash_table_new_full (
-               g_str_hash, g_str_equal,
-               (GDestroyNotify) g_free,
-               (GDestroyNotify) g_free);
-
-       extension->priv->selection_changed_callbacks_blocked = FALSE;
-       extension->priv->spell_checker = e_spell_checker_new ();
+       extension->priv = E_EDITOR_WEB_EXTENSION_GET_PRIVATE (extension);
+       extension->priv->editor_pages = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, 
g_object_unref);
 }
 
 static gpointer
-e_html_editor_web_extension_create_instance(gpointer data)
+e_editor_web_extension_create_instance(gpointer data)
 {
-       return g_object_new (E_TYPE_HTML_EDITOR_WEB_EXTENSION, NULL);
+       return g_object_new (E_TYPE_EDITOR_WEB_EXTENSION, NULL);
 }
 
-EHTMLEditorWebExtension *
-e_html_editor_web_extension_get (void)
+EEditorWebExtension *
+e_editor_web_extension_get_default (void)
 {
        static GOnce once_init = G_ONCE_INIT;
-       return E_HTML_EDITOR_WEB_EXTENSION (g_once (&once_init, e_html_editor_web_extension_create_instance, 
NULL));
+       return E_EDITOR_WEB_EXTENSION (g_once (&once_init, e_editor_web_extension_create_instance, NULL));
 }
 
 static gboolean
@@ -2744,18 +2402,8 @@ image_exists_in_cache (const gchar *image_uri)
        return exists;
 }
 
-static EImageLoadingPolicy
-get_image_loading_policy (EHTMLEditorWebExtension *extension)
-{
-       EImageLoadingPolicy image_policy;
-
-       image_policy = g_settings_get_enum (extension->priv->mail_settings, "image-loading-policy");
-
-       return image_policy;
-}
-
 static void
-redirect_http_uri (EHTMLEditorWebExtension *extension,
+redirect_http_uri (EEditorWebExtension *extension,
                    WebKitWebPage *web_page,
                    WebKitURIRequest *request)
 {
@@ -2763,8 +2411,12 @@ redirect_http_uri (EHTMLEditorWebExtension *extension,
        gchar *new_uri;
        SoupURI *soup_uri;
        gboolean image_exists;
+       EEditorPage *editor_page;
        EImageLoadingPolicy image_policy;
 
+       editor_page = get_editor_page (extension, webkit_web_page_get_id (web_page));
+       g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
+
        uri = webkit_uri_request_get_uri (request);
 
        /* Check Evolution's cache */
@@ -2773,8 +2425,8 @@ redirect_http_uri (EHTMLEditorWebExtension *extension,
        /* If the URI is not cached and we are not allowed to load it
         * then redirect to invalid URI, so that webkit would display
         * a native placeholder for it. */
-       image_policy = get_image_loading_policy (extension);
-       if (!image_exists && !extension->priv->force_image_load &&
+       image_policy = e_editor_page_get_image_loading_policy (editor_page);
+       if (!image_exists && !e_editor_page_get_force_image_load (editor_page) &&
            (image_policy == E_IMAGE_LOADING_POLICY_NEVER)) {
                webkit_uri_request_set_uri (request, "about:blank");
                return;
@@ -2795,7 +2447,7 @@ static gboolean
 web_page_send_request_cb (WebKitWebPage *web_page,
                           WebKitURIRequest *request,
                           WebKitURIResponse *redirected_response,
-                          EHTMLEditorWebExtension *extension)
+                          EEditorWebExtension *extension)
 {
        const char *request_uri;
        const char *page_uri;
@@ -2821,220 +2473,34 @@ web_page_send_request_cb (WebKitWebPage *web_page,
 }
 
 static void
-web_page_document_loaded_cb (WebKitWebPage *web_page,
-                             EHTMLEditorWebExtension *web_extension)
-{
-       WebKitDOMDocument *document;
-       EHTMLEditorUndoRedoManager *manager;
-
-       document = webkit_web_page_get_dom_document (web_page);
-       manager = e_html_editor_web_extension_get_undo_redo_manager (web_extension, document);
-
-       g_warn_if_fail (manager != NULL);
-       e_html_editor_undo_redo_manager_set_document (manager, document);
-
-       web_extension->priv->body_input_event_removed = TRUE;
-
-       dom_process_content_after_load (document, web_extension);
-}
-
-static gboolean
-web_page_context_menu_cb (WebKitWebPage *web_page,
-                         WebKitContextMenu *context_menu,
-                         WebKitWebHitTestResult *hit_test_result,
-                          EHTMLEditorWebExtension *web_extension)
-{
-       WebKitDOMNode *node;
-       EContentEditorNodeFlags flags = 0;
-       GVariant *variant;
-
-       node = webkit_web_hit_test_result_get_node (hit_test_result);
-       web_extension->priv->node_under_mouse_click = node;
-
-       if (WEBKIT_DOM_IS_HTML_HR_ELEMENT (node))
-               flags |= E_CONTENT_EDITOR_NODE_IS_H_RULE;
-
-       if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (node) ||
-           (dom_node_find_parent_element (node, "A") != NULL))
-               flags |= E_CONTENT_EDITOR_NODE_IS_ANCHOR;
-
-       if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node) ||
-           (dom_node_find_parent_element (node, "IMG") != NULL))
-               flags |= E_CONTENT_EDITOR_NODE_IS_IMAGE;
-
-       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node) ||
-           (dom_node_find_parent_element (node, "TD") != NULL) ||
-           (dom_node_find_parent_element (node, "TH") != NULL))
-               flags |= E_CONTENT_EDITOR_NODE_IS_TABLE_CELL;
-
-       if (flags & E_CONTENT_EDITOR_NODE_IS_TABLE_CELL &&
-           (WEBKIT_DOM_IS_HTML_TABLE_ELEMENT (node) ||
-           dom_node_find_parent_element (node, "TABLE") != NULL))
-               flags |= E_CONTENT_EDITOR_NODE_IS_TABLE;
-
-       if (flags == 0)
-               flags |= E_CONTENT_EDITOR_NODE_IS_TEXT;
-
-       variant = g_variant_new_int32 (flags);
-       webkit_context_menu_set_user_data (context_menu, variant);
-
-       return FALSE;
-}
-
-static GVariant *
-create_parameters_and_update_font_properties (WebKitDOMDocument *document,
-                                              EHTMLEditorWebExtension *extension)
-{
-       extension->priv->alignment = dom_selection_get_alignment (document, extension);
-       extension->priv->block_format = dom_selection_get_block_format (document, extension);
-       extension->priv->indented = dom_selection_is_indented (document);
-
-       if (extension->priv->html_mode) {
-               extension->priv->bold = dom_selection_is_bold (document, extension);
-               extension->priv->italic = dom_selection_is_italic (document, extension);
-               extension->priv->underline = dom_selection_is_underline (document, extension);
-               extension->priv->strikethrough = dom_selection_is_strikethrough (document, extension);
-               extension->priv->monospaced = dom_selection_is_monospaced (document, extension);
-               extension->priv->subscript = dom_selection_is_subscript (document, extension);
-               extension->priv->superscript = dom_selection_is_superscript (document, extension);
-               extension->priv->underline = dom_selection_is_underline (document, extension);
-               extension->priv->font_size = dom_selection_get_font_size (document, extension);
-               g_free (extension->priv->font_color);
-               extension->priv->font_color = dom_selection_get_font_color (document, extension);
-       }
-
-       return g_variant_new ("(iibbbbbbbbbis)",
-               (gint32) extension->priv->alignment,
-               (gint32) extension->priv->block_format,
-               extension->priv->indented,
-               extension->priv->bold,
-               extension->priv->italic,
-               extension->priv->underline,
-               extension->priv->strikethrough,
-               extension->priv->monospaced,
-               extension->priv->subscript,
-               extension->priv->superscript,
-               extension->priv->underline,
-               (gint32) extension->priv->font_size,
-               extension->priv->font_color ? extension->priv->font_color : "");
-}
-
-static void
-web_editor_selection_changed_cb (WebKitWebEditor *editor,
-                                 EHTMLEditorWebExtension *extension)
-{
-       WebKitWebPage *page;
-       WebKitDOMDocument *document;
-       WebKitDOMRange *range;
-       GError *error = NULL;
-       GVariant *parameters;
-
-       if (extension->priv->selection_changed_callbacks_blocked)
-               return;
-
-       if (!extension->priv->dbus_connection)
-               return;
-
-       page = webkit_web_editor_get_page (editor);
-       document = webkit_web_page_get_dom_document (page);
-       range = dom_get_current_range (document);
-       if (!range)
-               return;
-       g_object_unref (range);
-
-       /*
-       g_object_notify (G_OBJECT (selection), "background-color");
-       g_object_notify (G_OBJECT (selection), "font-name");
-       */
-       parameters = create_parameters_and_update_font_properties (document, extension);
-
-       g_dbus_connection_emit_signal (
-               extension->priv->dbus_connection,
-               NULL,
-               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
-               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
-               "SelectionChanged",
-               parameters,
-               &error);
-
-       if (error) {
-               g_warning ("Error emitting signal SelectionChanged: %s\n", error->message);
-               g_error_free (error);
-       }
-}
-
-static void
-web_editor_can_undo_redo_notify_cb (EHTMLEditorUndoRedoManager *manager,
-                                   GParamSpec *param,
-                                   EHTMLEditorWebExtension *extension)
-{
-       GError *error = NULL;
-
-       g_return_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension));
-
-       g_dbus_connection_emit_signal (
-               extension->priv->dbus_connection,
-               NULL,
-               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
-               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
-               "UndoRedoStateChanged",
-               g_variant_new ("(tbb)",
-                       e_html_editor_web_extension_get_undo_redo_manager_page_id (extension, manager),
-                       e_html_editor_undo_redo_manager_can_undo (manager),
-                       e_html_editor_undo_redo_manager_can_redo (manager)),
-               &error);
-
-       if (error)
-               g_warning ("%s: Failed to emit signal: %s", G_STRFUNC, error->message);
-       g_clear_error (&error);
-}
-
-static void
 web_page_created_cb (WebKitWebExtension *wk_extension,
                      WebKitWebPage *web_page,
-                     EHTMLEditorWebExtension *extension)
+                     EEditorWebExtension *extension)
 {
-       EHTMLEditorUndoRedoManager *manager;
-       WebKitWebEditor *web_editor;
+       EEditorPage *editor_page;
+       guint64 *ppage_id;
 
-       extension->priv->web_pages = g_slist_prepend (extension->priv->web_pages, web_page);
-       g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
+       g_return_if_fail (WEBKIT_IS_WEB_PAGE (web_page));
+       g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
 
-       manager = e_html_editor_undo_redo_manager_new (extension);
-       g_hash_table_insert (extension->priv->undo_redo_managers, manager, web_page);
+       ppage_id = g_new (guint64, 1);
+       *ppage_id = webkit_web_page_get_id (web_page);
 
-       g_signal_connect (
-               manager, "notify::can-undo",
-               G_CALLBACK (web_editor_can_undo_redo_notify_cb), extension);
+       editor_page = e_editor_page_new (web_page, extension);
+       g_hash_table_insert (extension->priv->editor_pages, ppage_id, editor_page);
 
-       g_signal_connect (
-               manager, "notify::can-redo",
-               G_CALLBACK (web_editor_can_undo_redo_notify_cb), extension);
+       g_object_weak_ref (G_OBJECT (web_page), web_page_gone_cb, extension);
 
        g_signal_connect (
                web_page, "send-request",
                G_CALLBACK (web_page_send_request_cb), extension);
-
-       g_signal_connect (
-               web_page, "document-loaded",
-               G_CALLBACK (web_page_document_loaded_cb), extension);
-
-       g_signal_connect (
-               web_page, "context-menu",
-               G_CALLBACK (web_page_context_menu_cb), extension);
-
-       web_editor = webkit_web_page_get_editor (web_page);
-
-       g_signal_connect (
-               web_editor, "selection-changed",
-               G_CALLBACK (web_editor_selection_changed_cb), extension);
 }
 
 void
-e_html_editor_web_extension_initialize (EHTMLEditorWebExtension *extension,
-                                        WebKitWebExtension *wk_extension)
+e_editor_web_extension_initialize (EEditorWebExtension *extension,
+                                  WebKitWebExtension *wk_extension)
 {
-       g_return_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension));
+       g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
 
        extension->priv->wk_extension = g_object_ref (wk_extension);
 
@@ -3057,13 +2523,13 @@ e_html_editor_web_extension_initialize (EHTMLEditorWebExtension *extension,
 }
 
 void
-e_html_editor_web_extension_dbus_register (EHTMLEditorWebExtension *extension,
-                                           GDBusConnection *connection)
+e_editor_web_extension_dbus_register (EEditorWebExtension *extension,
+                                     GDBusConnection *connection)
 {
        GError *error = NULL;
        static GDBusNodeInfo *introspection_data = NULL;
 
-       g_return_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension));
+       g_return_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension));
        g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
 
        if (!introspection_data) {
@@ -3073,7 +2539,7 @@ e_html_editor_web_extension_dbus_register (EHTMLEditorWebExtension *extension,
                extension->priv->registration_id =
                        g_dbus_connection_register_object (
                                connection,
-                               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
+                               E_WEBKIT_EDITOR_WEB_EXTENSION_OBJECT_PATH,
                                introspection_data->interfaces[0],
                                &interface_vtable,
                                extension,
@@ -3092,338 +2558,10 @@ e_html_editor_web_extension_dbus_register (EHTMLEditorWebExtension *extension,
        }
 }
 
-void
-e_html_editor_web_extension_set_content_changed (EHTMLEditorWebExtension *extension)
-{
-       GError *error = NULL;
-
-       if (!extension->priv->dbus_connection)
-               return;
-
-       g_dbus_connection_emit_signal (
-               extension->priv->dbus_connection,
-               NULL,
-               E_HTML_EDITOR_WEB_EXTENSION_OBJECT_PATH,
-               E_HTML_EDITOR_WEB_EXTENSION_INTERFACE,
-               "ContentChanged",
-               NULL,
-               &error);
-
-       if (error) {
-               g_warning ("Error emitting signal ContentChanged: %s\n", error->message);
-               g_error_free (error);
-       }
-}
-
-gboolean
-e_html_editor_web_extension_get_html_mode (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->html_mode;
-}
-
 GDBusConnection *
-e_html_editor_web_extension_get_connection (EHTMLEditorWebExtension *extension)
+e_editor_web_extension_get_connection (EEditorWebExtension *extension)
 {
-       return extension->priv->dbus_connection;
-}
-
-gint
-e_html_editor_web_extension_get_word_wrap_length (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->word_wrap_length;
-}
-
-const gchar *
-e_html_editor_web_extension_get_selection_text (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->text;
-}
-
-gboolean
-e_html_editor_web_extension_get_bold (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->bold;
-}
-
-gboolean
-e_html_editor_web_extension_get_italic (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->italic;
-}
-
-gboolean
-e_html_editor_web_extension_get_underline (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->underline;
-}
-
-gboolean
-e_html_editor_web_extension_get_monospaced (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->monospaced;
-}
-
-gboolean
-e_html_editor_web_extension_get_strikethrough (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->strikethrough;
-}
-
-guint
-e_html_editor_web_extension_get_font_size (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->font_size;
-}
-
-const gchar *
-e_html_editor_web_extension_get_font_color (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->font_color;
-}
-
-EContentEditorAlignment
-e_html_editor_web_extension_get_alignment (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->alignment;
-}
-
-EContentEditorContentFlags
-e_html_editor_web_extension_get_current_content_flags (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->content_flags;
-}
-
-gboolean
-e_html_editor_web_extension_get_return_key_pressed (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->return_key_pressed;
-}
-
-void
-e_html_editor_web_extension_set_return_key_pressed (EHTMLEditorWebExtension *extension,
-                                                    gboolean value)
-{
-       extension->priv->return_key_pressed = value;
-}
-
-gboolean
-e_html_editor_web_extension_get_space_key_pressed (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->space_key_pressed;
-}
-
-void
-e_html_editor_web_extension_set_space_key_pressed (EHTMLEditorWebExtension *extension,
-                                                   gboolean value)
-{
-       extension->priv->space_key_pressed = value;
-}
-
-gboolean
-e_html_editor_web_extension_get_magic_links_enabled (EHTMLEditorWebExtension *extension)
-{
-       return g_settings_get_boolean (
-               extension->priv->mail_settings, "composer-magic-links");
-}
-
-gboolean
-e_html_editor_web_extension_get_magic_smileys_enabled (EHTMLEditorWebExtension *extension)
-{
-       return g_settings_get_boolean (
-               extension->priv->mail_settings, "composer-magic-smileys");
-}
-
-gboolean
-e_html_editor_web_extension_get_unicode_smileys_enabled (EHTMLEditorWebExtension *extension)
-{
-       return g_settings_get_boolean (
-               extension->priv->mail_settings, "composer-unicode-smileys");
-}
-
-gboolean
-e_html_editor_web_extension_get_inline_spelling_enabled (EHTMLEditorWebExtension *extension)
-{
-       return g_settings_get_boolean (
-               extension->priv->mail_settings, "composer-inline-spelling");
-}
-
-gboolean
-e_html_editor_web_extension_check_word_spelling (EHTMLEditorWebExtension *extension,
-                                                const gchar *word,
-                                                const gchar * const *languages)
-{
-       g_return_val_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension), TRUE);
-
-       if (!word || !languages || !*languages)
-               return TRUE;
-
-       e_spell_checker_set_active_languages (extension->priv->spell_checker, languages);
-
-       return e_spell_checker_check_word (extension->priv->spell_checker, word, -1);
-}
-
-gboolean
-e_html_editor_web_extension_get_body_input_event_removed (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->body_input_event_removed;
-}
-
-void
-e_html_editor_web_extension_set_body_input_event_removed (EHTMLEditorWebExtension *extension,
-                                                          gboolean value)
-{
-       extension->priv->body_input_event_removed = value;
-}
-
-gboolean
-e_html_editor_web_extension_get_convert_in_situ (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->convert_in_situ;
-}
+       g_return_val_if_fail (E_IS_EDITOR_WEB_EXTENSION (extension), NULL);
 
-void
-e_html_editor_web_extension_set_convert_in_situ (EHTMLEditorWebExtension *extension,
-                                                 gboolean value)
-{
-       extension->priv->convert_in_situ = value;
-}
-
-GHashTable *
-e_html_editor_web_extension_get_inline_images (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->inline_images;
-}
-
-void
-e_html_editor_web_extension_add_new_inline_image_into_list (EHTMLEditorWebExtension *extension,
-                                                            const gchar *cid_src,
-                                                            const gchar *src)
-{
-       g_hash_table_insert (extension->priv->inline_images, g_strdup (cid_src), g_strdup (src));
-}
-
-gboolean
-e_html_editor_web_extension_get_is_smiley_written (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->smiley_written;
-}
-
-void
-e_html_editor_web_extension_set_is_smiley_written (EHTMLEditorWebExtension *extension,
-                                                   gboolean value)
-{
-       extension->priv->smiley_written = value;
-}
-
-gboolean
-e_html_editor_web_extension_get_dont_save_history_in_body_input (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->dont_save_history_in_body_input;
-}
-
-void
-e_html_editor_web_extension_set_dont_save_history_in_body_input (EHTMLEditorWebExtension *extension,
-                                                                 gboolean value)
-{
-       extension->priv->dont_save_history_in_body_input = value;
-}
-
-gboolean
-e_html_editor_web_extension_is_pasting_content_from_itself (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->is_pasting_content_from_itself;
-}
-
-gboolean
-e_html_editor_web_extension_get_renew_history_after_coordinates (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->renew_history_after_coordinates;
-}
-
-void
-e_html_editor_web_extension_set_renew_history_after_coordinates (EHTMLEditorWebExtension *extension,
-                                                                gboolean renew_history_after_coordinates)
-{
-       extension->priv->renew_history_after_coordinates = renew_history_after_coordinates;
-}
-
-guint64
-e_html_editor_web_extension_get_undo_redo_manager_page_id (EHTMLEditorWebExtension *extension,
-                                                          EHTMLEditorUndoRedoManager *manager)
-{
-       WebKitWebPage *web_page;
-
-       g_return_val_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension), 0);
-       g_return_val_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (manager), 0);
-
-       web_page = g_hash_table_lookup (extension->priv->undo_redo_managers, manager);
-       g_return_val_if_fail (web_page != NULL, 0);
-       g_return_val_if_fail (WEBKIT_IS_WEB_PAGE (web_page), 0);
-
-       return webkit_web_page_get_id (web_page);
-}
-
-EHTMLEditorUndoRedoManager *
-e_html_editor_web_extension_get_undo_redo_manager (EHTMLEditorWebExtension *extension,
-                                                  WebKitDOMDocument *document)
-{
-       GHashTableIter iter;
-       gpointer key, value;
-
-       g_return_val_if_fail (E_IS_HTML_EDITOR_WEB_EXTENSION (extension), NULL);
-       g_return_val_if_fail (WEBKIT_DOM_IS_DOCUMENT (document), NULL);
-
-       g_hash_table_iter_init (&iter, extension->priv->undo_redo_managers);
-       while (g_hash_table_iter_next (&iter, &key, &value)) {
-               g_warn_if_fail (E_IS_HTML_EDITOR_UNDO_REDO_MANAGER (key));
-               g_warn_if_fail (WEBKIT_IS_WEB_PAGE (value));
-
-               if (document == webkit_web_page_get_dom_document (value))
-                       return key;
-       }
-
-       g_warn_if_reached ();
-
-       return NULL;
-}
-
-gboolean
-e_html_editor_web_extension_is_composition_in_progress (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->composition_in_progress;
-}
-
-
-void
-e_html_editor_web_extension_set_composition_in_progress (EHTMLEditorWebExtension *extension,
-                                                         gboolean value)
-{
-       extension->priv->composition_in_progress = value;
-}
-
-guint
-e_html_editor_web_extension_get_spell_check_on_scroll_event_source_id (EHTMLEditorWebExtension *extension)
-{
-       return extension->priv->spell_check_on_scroll_event_source_id;
-}
-
-void
-e_html_editor_web_extension_set_spell_check_on_scroll_event_source_id (EHTMLEditorWebExtension *extension,
-                                                                       guint value)
-{
-       extension->priv->spell_check_on_scroll_event_source_id = value;
-}
-
-void
-e_html_editor_web_extension_block_selection_changed_callback (EHTMLEditorWebExtension *extension)
-{
-       if (!extension->priv->selection_changed_callbacks_blocked)
-               extension->priv->selection_changed_callbacks_blocked = TRUE;
-}
-
-void
-e_html_editor_web_extension_unblock_selection_changed_callback (EHTMLEditorWebExtension *extension)
-{
-       if (extension->priv->selection_changed_callbacks_blocked)
-               extension->priv->selection_changed_callbacks_blocked = FALSE;
+       return extension->priv->dbus_connection;
 }
diff --git a/modules/webkit-editor/web-extension/e-editor-web-extension.h 
b/modules/webkit-editor/web-extension/e-editor-web-extension.h
new file mode 100644
index 0000000..987b3de
--- /dev/null
+++ b/modules/webkit-editor/web-extension/e-editor-web-extension.h
@@ -0,0 +1,82 @@
+/*
+ * e-editor-web-extension.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_EDITOR_WEB_EXTENSION_H
+#define E_EDITOR_WEB_EXTENSION_H
+
+#include <glib-object.h>
+#include <webkit2/webkit-web-extension.h>
+
+#define E_UTIL_INCLUDE_WITHOUT_WEBKIT
+#include <e-util/e-util.h>
+#undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
+
+#include "e-editor-web-extension-names.h"
+
+/* Standard GObject macros */
+#define E_TYPE_EDITOR_WEB_EXTENSION \
+       (e_editor_web_extension_get_type ())
+#define E_EDITOR_WEB_EXTENSION(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtension))
+#define E_EDITOR_WEB_EXTENSION_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionClass))
+#define E_IS_EDITOR_WEB_EXTENSION(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_EDITOR_WEB_EXTENSION))
+#define E_IS_EDITOR_WEB_EXTENSION_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_EDITOR_WEB_EXTENSION))
+#define E_EDITOR_WEB_EXTENSION_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_EDITOR_WEB_EXTENSION, EEditorWebExtensionClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EEditorWebExtension EEditorWebExtension;
+typedef struct _EEditorWebExtensionClass EEditorWebExtensionClass;
+typedef struct _EEditorWebExtensionPrivate EEditorWebExtensionPrivate;
+
+struct _EEditorWebExtension {
+       GObject parent;
+       EEditorWebExtensionPrivate *priv;
+};
+
+struct _EEditorWebExtensionClass
+{
+       GObjectClass parent_class;
+};
+
+GType          e_editor_web_extension_get_type (void) G_GNUC_CONST;
+
+EEditorWebExtension *
+               e_editor_web_extension_get_default
+                                               (void);
+
+void           e_editor_web_extension_initialize
+                                               (EEditorWebExtension *extension,
+                                                WebKitWebExtension *wk_extension);
+void           e_editor_web_extension_dbus_register
+                                               (EEditorWebExtension *extension,
+                                                GDBusConnection *connection);
+GDBusConnection *
+               e_editor_web_extension_get_connection
+                                               (EEditorWebExtension *extension);
+
+#endif /* E_EDITOR_WEB_EXTENSION_H */


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