Blame SOURCES/evolution-3.22.6-composer-image-insert-undo.patch

a00a81
diff -up evolution-3.22.6/composer/e-composer-private.c.composer-image-insert-undo evolution-3.22.6/composer/e-composer-private.c
a00a81
--- evolution-3.22.6/composer/e-composer-private.c.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/composer/e-composer-private.c	2017-03-24 15:12:21.893422514 +0100
a00a81
@@ -134,8 +134,6 @@ e_composer_private_constructed (EMsgComp
a00a81
 	priv->disable_signature = FALSE;
a00a81
 	priv->busy = FALSE;
a00a81
 	priv->saved_editable = FALSE;
a00a81
-	priv->drop_occured = FALSE;
a00a81
-	priv->dnd_is_uri = FALSE;
a00a81
 	priv->dnd_history_saved = FALSE;
a00a81
 	priv->check_if_signature_is_changed = FALSE;
a00a81
 	priv->ignore_next_signature_change = FALSE;
a00a81
diff -up evolution-3.22.6/composer/e-composer-private.h.composer-image-insert-undo evolution-3.22.6/composer/e-composer-private.h
a00a81
--- evolution-3.22.6/composer/e-composer-private.h.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/composer/e-composer-private.h	2017-03-24 15:12:21.893422514 +0100
a00a81
@@ -100,8 +100,6 @@ struct _EMsgComposerPrivate {
a00a81
 	 * This is used to restore the previous editable state. */
a00a81
 	gboolean saved_editable;
a00a81
 	gboolean set_signature_from_message;
a00a81
-	gboolean drop_occured;
a00a81
-	gboolean dnd_is_uri;
a00a81
 	gboolean is_sending_message;
a00a81
 	gboolean dnd_history_saved;
a00a81
 	gboolean check_if_signature_is_changed;
a00a81
@@ -119,6 +117,8 @@ struct _EMsgComposerPrivate {
a00a81
 	gulong notify_signature_uid_handler;
a00a81
 	gulong notify_subject_handler;
a00a81
 	gulong notify_subject_changed_handler;
a00a81
+
a00a81
+	gulong drag_data_received_handler_id;
a00a81
 };
a00a81
 
a00a81
 void		e_composer_private_constructed	(EMsgComposer *composer);
a00a81
diff -up evolution-3.22.6/composer/e-msg-composer.c.composer-image-insert-undo evolution-3.22.6/composer/e-msg-composer.c
a00a81
--- evolution-3.22.6/composer/e-msg-composer.c.composer-image-insert-undo	2016-11-30 20:06:07.000000000 +0100
a00a81
+++ evolution-3.22.6/composer/e-msg-composer.c	2017-03-24 15:12:21.894422514 +0100
a00a81
@@ -105,24 +105,14 @@ enum {
a00a81
 	LAST_SIGNAL
a00a81
 };
a00a81
 
a00a81
-enum DndTargetType {
a00a81
-	DND_TARGET_TYPE_TEXT_URI_LIST,
a00a81
-	DND_TARGET_TYPE_MOZILLA_URL,
a00a81
-	DND_TARGET_TYPE_TEXT_HTML,
a00a81
-	DND_TARGET_TYPE_UTF8_STRING,
a00a81
-	DND_TARGET_TYPE_TEXT_PLAIN,
a00a81
-	DND_TARGET_TYPE_STRING,
a00a81
-	DND_TARGET_TYPE_TEXT_PLAIN_UTF8
a00a81
-};
a00a81
-
a00a81
 static GtkTargetEntry drag_dest_targets[] = {
a00a81
-	{ (gchar *) "text/uri-list", 0, DND_TARGET_TYPE_TEXT_URI_LIST },
a00a81
-	{ (gchar *) "_NETSCAPE_URL", 0, DND_TARGET_TYPE_MOZILLA_URL },
a00a81
-	{ (gchar *) "text/html", 0, DND_TARGET_TYPE_TEXT_HTML },
a00a81
-	{ (gchar *) "UTF8_STRING", 0, DND_TARGET_TYPE_UTF8_STRING },
a00a81
-	{ (gchar *) "text/plain", 0, DND_TARGET_TYPE_TEXT_PLAIN },
a00a81
-	{ (gchar *) "STRING", 0, DND_TARGET_TYPE_STRING },
a00a81
-	{ (gchar *) "text/plain;charset=utf-8", 0, DND_TARGET_TYPE_TEXT_PLAIN_UTF8 },
a00a81
+	{ (gchar *) "text/uri-list", 0, E_DND_TARGET_TYPE_TEXT_URI_LIST },
a00a81
+	{ (gchar *) "_NETSCAPE_URL", 0, E_DND_TARGET_TYPE_MOZILLA_URL },
a00a81
+	{ (gchar *) "text/html", 0, E_DND_TARGET_TYPE_TEXT_HTML },
a00a81
+	{ (gchar *) "UTF8_STRING", 0, E_DND_TARGET_TYPE_UTF8_STRING },
a00a81
+	{ (gchar *) "text/plain", 0, E_DND_TARGET_TYPE_TEXT_PLAIN },
a00a81
+	{ (gchar *) "STRING", 0, E_DND_TARGET_TYPE_STRING },
a00a81
+	{ (gchar *) "text/plain;charset=utf-8", 0, E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8 },
a00a81
 };
a00a81
 
a00a81
 static guint signals[LAST_SIGNAL];
a00a81
@@ -1784,160 +1774,6 @@ msg_composer_paste_clipboard_cb (EConten
a00a81
 
a00a81
 	return TRUE;
a00a81
 }
a00a81
-#if 0 /* FIXME WK2 */
a00a81
-static gboolean
a00a81
-msg_composer_drag_motion_cb (GtkWidget *widget,
a00a81
-                             GdkDragContext *context,
a00a81
-                             gint x,
a00a81
-                             gint y,
a00a81
-                             guint time,
a00a81
-                             EMsgComposer *composer)
a00a81
-{
a00a81
-	GtkWidget *source_widget;
a00a81
-	EHTMLEditor *editor = e_msg_composer_get_editor (composer);
a00a81
-	EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
a00a81
-
a00a81
-	source_widget = gtk_drag_get_source_widget (context);
a00a81
-	/* When we are doind DnD just inside the web view, the DnD is supposed
a00a81
-	 * to move things around. */
a00a81
-	if (E_IS_HTML_EDITOR_VIEW (source_widget)) {
a00a81
-		if ((gpointer) editor_view == (gpointer) source_widget) {
a00a81
-			gdk_drag_status (context, GDK_ACTION_MOVE, time);
a00a81
-
a00a81
-			return FALSE;
a00a81
-		}
a00a81
-	}
a00a81
-
a00a81
-	gdk_drag_status (context, GDK_ACTION_COPY, time);
a00a81
-
a00a81
-	return FALSE;
a00a81
-}
a00a81
-
a00a81
-static gboolean
a00a81
-msg_composer_drag_drop_cb (GtkWidget *widget,
a00a81
-                           GdkDragContext *context,
a00a81
-                           gint x,
a00a81
-                           gint y,
a00a81
-                           guint time,
a00a81
-                           EMsgComposer *composer)
a00a81
-{
a00a81
-	GdkAtom target;
a00a81
-	GtkWidget *source_widget;
a00a81
-
a00a81
-	/* When we are doing DnD just inside the web view, the DnD is supposed
a00a81
-	 * to move things around. */
a00a81
-	source_widget = gtk_drag_get_source_widget (context);
a00a81
-	if (E_IS_HTML_EDITOR_VIEW (source_widget)) {
a00a81
-		EHTMLEditor *editor = e_msg_composer_get_editor (composer);
a00a81
-		EHTMLEditorView *editor_view = e_html_editor_get_view (editor);
a00a81
-
a00a81
-		if ((gpointer) editor_view == (gpointer) source_widget) {
a00a81
-			GDBusProxy *web_extension;
a00a81
-
a00a81
-			web_extension = e_html_editor_view_get_web_extension_proxy (editor_view);
a00a81
-			if (web_extension) {
a00a81
-				e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
a00a81
-					web_extension,
a00a81
-					"DOMSaveDragAndDropHistory",
a00a81
-					g_variant_new (
a00a81
-						"(t)",
a00a81
-						webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (editor_view))),
a00a81
-					NULL);
a00a81
-			}
a00a81
-			return FALSE;
a00a81
-		}
a00a81
-	}
a00a81
-
a00a81
-	target = gtk_drag_dest_find_target (widget, context, NULL);
a00a81
-	if (target == GDK_NONE)
a00a81
-		gdk_drag_status (context, 0, time);
a00a81
-	else {
a00a81
-		/* Prevent WebKit from pasting the URI of file into the view. Also
a00a81
-		 * prevent it from inserting the text/plain or text/html content as we
a00a81
-		 * want to insert it ourselves. */
a00a81
-		if (composer->priv->dnd_is_uri || !E_IS_HTML_EDITOR_VIEW (source_widget))
a00a81
-			g_signal_stop_emission_by_name (widget, "drag-drop");
a00a81
-
a00a81
-		composer->priv->dnd_is_uri = FALSE;
a00a81
-
a00a81
-		if (E_IS_HTML_EDITOR_VIEW (source_widget))
a00a81
-			gdk_drag_status (context, GDK_ACTION_MOVE, time);
a00a81
-		else
a00a81
-			gdk_drag_status (context, GDK_ACTION_COPY, time);
a00a81
-
a00a81
-		composer->priv->drop_occured = TRUE;
a00a81
-		gtk_drag_get_data (widget, context, target, time);
a00a81
-
a00a81
-		return TRUE;
a00a81
-	}
a00a81
-
a00a81
-	return FALSE;
a00a81
-}
a00a81
-
a00a81
-static void
a00a81
-msg_composer_drag_data_received_after_cb (GtkWidget *widget,
a00a81
-                                          GdkDragContext *context,
a00a81
-                                          gint x,
a00a81
-                                          gint y,
a00a81
-                                          GtkSelectionData *selection,
a00a81
-                                          guint info,
a00a81
-                                          guint time,
a00a81
-                                          EMsgComposer *composer)
a00a81
-{
a00a81
-	EHTMLEditor *editor;
a00a81
-	EHTMLEditorView *view;
a00a81
-	GDBusProxy *web_extension;
a00a81
-
a00a81
-	if (!composer->priv->drop_occured)
a00a81
-		goto out;
a00a81
-
a00a81
-	/* Save just history for events handled by WebKit. */
a00a81
-	if (composer->priv->dnd_history_saved)
a00a81
-		goto out;
a00a81
-
a00a81
-	editor = e_msg_composer_get_editor (composer);
a00a81
-	view = e_html_editor_get_view (editor);
a00a81
-	web_extension = e_html_editor_view_get_web_extension_proxy (view);
a00a81
-	if (!web_extension)
a00a81
-		goto out;
a00a81
-
a00a81
-	e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
a00a81
-		web_extension,
a00a81
-		"DOMCleanAfterDragAndDrop",
a00a81
-		g_variant_new (
a00a81
-			"(t)",
a00a81
-			webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (view))),
a00a81
-		NULL);
a00a81
-
a00a81
- out:
a00a81
-	composer->priv->drop_occured = FALSE;
a00a81
-	composer->priv->dnd_history_saved = FALSE;
a00a81
-}
a00a81
-
a00a81
-static gchar *
a00a81
-next_uri (guchar **uri_list,
a00a81
-          gint *len,
a00a81
-          gint *list_len)
a00a81
-{
a00a81
-	guchar *uri, *begin;
a00a81
-
a00a81
-	begin = *uri_list;
a00a81
-	*len = 0;
a00a81
-	while (**uri_list && **uri_list != '\n' && **uri_list != '\r' && *list_len) {
a00a81
-		(*uri_list) ++;
a00a81
-		(*len) ++;
a00a81
-		(*list_len) --;
a00a81
-	}
a00a81
-
a00a81
-	uri = (guchar *) g_strndup ((gchar *) begin, *len);
a00a81
-
a00a81
-	while ((!**uri_list || **uri_list == '\n' || **uri_list == '\r') && *list_len) {
a00a81
-		(*uri_list) ++;
a00a81
-		(*list_len) --;
a00a81
-	}
a00a81
-
a00a81
-	return (gchar *) uri;
a00a81
-}
a00a81
 
a00a81
 static void
a00a81
 msg_composer_drag_data_received_cb (GtkWidget *widget,
a00a81
@@ -1951,90 +1787,16 @@ msg_composer_drag_data_received_cb (GtkW
a00a81
 {
a00a81
 	EHTMLEditor *editor;
a00a81
 	EContentEditor *cnt_editor;
a00a81
-	gboolean html_mode, same_widget = FALSE;
a00a81
-	GtkWidget *source_widget;
a00a81
+	gboolean html_mode, is_move;
a00a81
 
a00a81
 	editor = e_msg_composer_get_editor (composer);
a00a81
 	cnt_editor = e_html_editor_get_content_editor (editor);
a00a81
 	html_mode = e_content_editor_get_html_mode (cnt_editor);
a00a81
 
a00a81
-	composer->priv->dnd_history_saved = TRUE;
a00a81
-
a00a81
-	/* When we are doing DnD just inside the web view, the DnD is supposed
a00a81
-	 * to move things around. */
a00a81
-	source_widget = gtk_drag_get_source_widget (context);
a00a81
-	if (E_IS_CONTENT_EDITOR (source_widget) &&
a00a81
-	    ((gpointer) cnt_editor == (gpointer) source_widget))
a00a81
-		same_widget = TRUE;
a00a81
-
a00a81
-	/* Leave DnD inside the view on WebKit. */
a00a81
-	if (composer->priv->drop_occured && same_widget) {
a00a81
-		gdk_drag_status (context, 0, time);
a00a81
-		return;
a00a81
-	}
a00a81
-
a00a81
-	if (!composer->priv->drop_occured) {
a00a81
-		if (!same_widget) {
a00a81
-			/* Check if we are DnD'ing some URI, if so WebKit will
a00a81
-			 * insert the URI into the view and we have to prevent it
a00a81
-			 * from doing that. */
a00a81
-			if (info == DND_TARGET_TYPE_TEXT_URI_LIST) {
a00a81
-				gchar **uris;
a00a81
-
a00a81
-				uris = gtk_selection_data_get_uris (selection);
a00a81
-				/* I don't know what regressed outside of Evo, but
a00a81
-				 * this is called twice. Firstly with uris set
a00a81
-				 * following by one with uris not set. */
a00a81
-				if (!composer->priv->dnd_is_uri)
a00a81
-					composer->priv->dnd_is_uri = uris != NULL;
a00a81
-				g_strfreev (uris);
a00a81
-			}
a00a81
-		}
a00a81
-		return;
a00a81
-	}
a00a81
+	g_signal_handler_disconnect (cnt_editor, composer->priv->drag_data_received_handler_id);
a00a81
+	composer->priv->drag_data_received_handler_id = 0;
a00a81
 
a00a81
-	composer->priv->dnd_is_uri = FALSE;
a00a81
-
a00a81
-	/* Leave the text on WebKit to handle it. */
a00a81
-	if (info == DND_TARGET_TYPE_UTF8_STRING ||
a00a81
-	    info == DND_TARGET_TYPE_STRING ||
a00a81
-	    info == DND_TARGET_TYPE_TEXT_PLAIN ||
a00a81
-	    info == DND_TARGET_TYPE_TEXT_PLAIN_UTF8) {
a00a81
-		composer->priv->dnd_history_saved = FALSE;
a00a81
-		gdk_drag_status (context, 0, time);
a00a81
-		return;
a00a81
-	}
a00a81
-
a00a81
-	if (info == DND_TARGET_TYPE_TEXT_HTML) {
a00a81
-		const guchar *data;
a00a81
-		gint length;
a00a81
-		gint list_len, len;
a00a81
-		gchar *text;
a00a81
-
a00a81
-		data = gtk_selection_data_get_data (selection);
a00a81
-		length = gtk_selection_data_get_length (selection);
a00a81
-
a00a81
-		if (!data || length < 0) {
a00a81
-			gtk_drag_finish (context, FALSE, FALSE, time);
a00a81
-			return;
a00a81
-		}
a00a81
-
a00a81
-		e_content_editor_move_caret_on_coordinates (cnt_editor, x, y, FALSE);
a00a81
-
a00a81
-		list_len = length;
a00a81
-		do {
a00a81
-			text = next_uri ((guchar **) &data, &len, &list_len);
a00a81
-			e_content_editor_insert_content (
a00a81
-				cnt_editor,
a00a81
-				text,
a00a81
-				E_CONTENT_EDITOR_INSERT_TEXT_HTML);
a00a81
-			g_free (text);
a00a81
-		} while (list_len);
a00a81
-
a00a81
-		gtk_drag_finish (context, TRUE, FALSE, time);
a00a81
-
a00a81
-		return;
a00a81
-	}
a00a81
+	is_move = gdk_drag_context_get_selected_action (context) == GDK_ACTION_MOVE;
a00a81
 
a00a81
 	/* HTML mode has a few special cases for drops... */
a00a81
 	/* If we're receiving URIs and -all- the URIs point to
a00a81
@@ -2060,12 +1822,12 @@ msg_composer_drag_data_received_cb (GtkW
a00a81
 
a00a81
 		list_len = length;
a00a81
 		do {
a00a81
-			uri = next_uri ((guchar **) &data, &len, &list_len);
a00a81
+			uri = e_util_next_uri_from_uri_list ((guchar **) &data, &len, &list_len);
a00a81
 			e_content_editor_insert_image (cnt_editor, uri);
a00a81
 			g_free (uri);
a00a81
 		} while (list_len);
a00a81
 
a00a81
-		gtk_drag_finish (context, TRUE, FALSE, time);
a00a81
+		gtk_drag_finish (context, TRUE, is_move, time);
a00a81
 	} else {
a00a81
 		EAttachmentView *attachment_view =
a00a81
 			e_msg_composer_get_attachment_view (composer);
a00a81
@@ -2078,7 +1840,43 @@ msg_composer_drag_data_received_cb (GtkW
a00a81
 			context, x, y, selection, info, time);
a00a81
 	}
a00a81
 }
a00a81
-#endif
a00a81
+
a00a81
+static gboolean
a00a81
+msg_composer_drag_drop_cb (GtkWidget *widget,
a00a81
+                           GdkDragContext *context,
a00a81
+                           gint x,
a00a81
+                           gint y,
a00a81
+                           guint time,
a00a81
+                           EMsgComposer *composer)
a00a81
+{
a00a81
+	GdkAtom target = gtk_drag_dest_find_target (widget, context, NULL);
a00a81
+
a00a81
+	if (target == GDK_NONE) {
a00a81
+		gdk_drag_status (context, 0, time);
a00a81
+	} else {
a00a81
+		composer->priv->drag_data_received_handler_id = g_signal_connect (
a00a81
+			E_CONTENT_EDITOR (widget), "drag-data-received",
a00a81
+			G_CALLBACK (msg_composer_drag_data_received_cb), composer);
a00a81
+
a00a81
+		gtk_drag_get_data (widget, context, target, time);
a00a81
+
a00a81
+		return TRUE;
a00a81
+	}
a00a81
+
a00a81
+	return FALSE;
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+msg_composer_drag_begin_cb (GtkWidget *widget,
a00a81
+                            GdkDragContext *context,
a00a81
+                            EMsgComposer *composer)
a00a81
+{
a00a81
+	if (composer->priv->drag_data_received_handler_id != 0) {
a00a81
+		g_signal_handler_disconnect (E_CONTENT_EDITOR( widget), composer->priv->drag_data_received_handler_id);
a00a81
+		composer->priv->drag_data_received_handler_id = 0;
a00a81
+	}
a00a81
+}
a00a81
+
a00a81
 static void
a00a81
 msg_composer_notify_header_cb (EMsgComposer *composer)
a00a81
 {
a00a81
@@ -2465,28 +2263,14 @@ msg_composer_constructed (GObject *objec
a00a81
 		G_CALLBACK (msg_composer_paste_primary_clipboard_cb), composer);
a00a81
 
a00a81
 	/* Drag-and-Drop Support */
a00a81
-#if 0 /* FIXME WK2 */
a00a81
-	EHTMLEditorView *view;
a00a81
-
a00a81
-	view = e_html_editor_get_view (editor);
a00a81
-
a00a81
 	g_signal_connect (
a00a81
-		view, "drag-motion",
a00a81
-		G_CALLBACK (msg_composer_drag_motion_cb), composer);
a00a81
-
a00a81
-	 g_signal_connect (
a00a81
-		view, "drag-drop",
a00a81
+		cnt_editor, "drag-drop",
a00a81
 		G_CALLBACK (msg_composer_drag_drop_cb), composer);
a00a81
 
a00a81
 	g_signal_connect (
a00a81
-		view, "drag-data-received",
a00a81
-		G_CALLBACK (msg_composer_drag_data_received_cb), composer);
a00a81
+		cnt_editor, "drag-begin",
a00a81
+		G_CALLBACK (msg_composer_drag_begin_cb), composer);
a00a81
 
a00a81
-	/* Used for fixing various stuff after WebKit processed the DnD data. */
a00a81
-	g_signal_connect_after (
a00a81
-		view, "drag-data-received",
a00a81
-		G_CALLBACK (msg_composer_drag_data_received_after_cb), composer);
a00a81
-#endif
a00a81
 	g_signal_connect (
a00a81
 		composer->priv->gallery_icon_view, "drag-data-get",
a00a81
 		G_CALLBACK (msg_composer_gallery_drag_data_get), NULL);
a00a81
@@ -5531,8 +5315,6 @@ e_msg_composer_restore_focus_on_composer
a00a81
 
a00a81
 	if (E_IS_CONTENT_EDITOR (widget)) {
a00a81
 		EContentEditor *cnt_editor = E_CONTENT_EDITOR (widget);
a00a81
-		/* FIXME WK2
a00a81
-		e_html_editor_view_force_spell_check (view);*/
a00a81
 		e_content_editor_selection_restore (cnt_editor);
a00a81
 	}
a00a81
 
a00a81
diff -up evolution-3.22.6/e-util/e-attachment-view.c.composer-image-insert-undo evolution-3.22.6/e-util/e-attachment-view.c
a00a81
--- evolution-3.22.6/e-util/e-attachment-view.c.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/e-util/e-attachment-view.c	2017-03-24 15:12:21.894422514 +0100
a00a81
@@ -39,6 +39,7 @@ enum {
a00a81
 
a00a81
 /* Note: Do not use the info field. */
a00a81
 static GtkTargetEntry target_table[] = {
a00a81
+	{ (gchar *) "text/uri-list", 0, 0 },
a00a81
 	{ (gchar *) "_NETSCAPE_URL", 0, 0 }
a00a81
 };
a00a81
 
a00a81
@@ -428,6 +429,125 @@ attachment_view_netscape_url (EAttachmen
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
+attachment_view_uri_list (EAttachmentView *view,
a00a81
+                          GdkDragContext *drag_context,
a00a81
+                          gint x,
a00a81
+                          gint y,
a00a81
+                          GtkSelectionData *selection_data,
a00a81
+                          guint info,
a00a81
+                          guint time)
a00a81
+{
a00a81
+	static GdkAtom atom = GDK_NONE;
a00a81
+	EAttachmentStore *store;
a00a81
+	EAttachment *attachment;
a00a81
+	const gchar *data;
a00a81
+	gpointer parent;
a00a81
+	gint length = 0, list_length = 0, uri_length = 0;
a00a81
+	gchar *uri;
a00a81
+
a00a81
+
a00a81
+	if (G_UNLIKELY (atom == GDK_NONE))
a00a81
+		atom = gdk_atom_intern_static_string ("text/uri-list");
a00a81
+
a00a81
+	if (gtk_selection_data_get_target (selection_data) != atom)
a00a81
+		return;
a00a81
+
a00a81
+	g_signal_stop_emission_by_name (view, "drag-data-received");
a00a81
+
a00a81
+	data = (const gchar *) gtk_selection_data_get_data (selection_data);
a00a81
+	length = gtk_selection_data_get_length (selection_data);
a00a81
+
a00a81
+	if (!data || length < 0) {
a00a81
+		gtk_drag_finish (drag_context, FALSE, FALSE, time);
a00a81
+		return;
a00a81
+	}
a00a81
+
a00a81
+	store = e_attachment_view_get_store (view);
a00a81
+
a00a81
+	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
a00a81
+	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
a00a81
+
a00a81
+	list_length = length;
a00a81
+	do {
a00a81
+		uri = e_util_next_uri_from_uri_list ((guchar **) &data, &uri_length, &list_length);
a00a81
+
a00a81
+		if (strstr (uri, ";base64,")) {
a00a81
+			/* base64 encoded data */
a00a81
+			CamelMimePart *mime_part;
a00a81
+			gchar *mime_type = NULL, *filename = NULL;
a00a81
+			guchar *base64_data;
a00a81
+			gsize base64_data_length;
a00a81
+
a00a81
+			if (g_str_has_prefix (uri, "data:")) {
a00a81
+				const gchar *base64 = strstr (uri, ";") + 1;
a00a81
+				/* strlen ("data:") == 5 */
a00a81
+				mime_type = g_strndup (uri + 5, base64 - uri - 5 - 1);
a00a81
+
a00a81
+				base64 = strstr (base64, ",") + 1;
a00a81
+				base64_data = g_base64_decode (base64, &base64_data_length);
a00a81
+			} else if (strstr (uri, ";data")) {
a00a81
+				/* CID attachment from mail preview that has
a00a81
+				 * the filename prefixed before the base64 data -
a00a81
+				 * see EMailDisplay. */
a00a81
+				const gchar *base64 = strstr (uri, ";") + 1;
a00a81
+				glong filename_length, mime_type_length, base64_length;
a00a81
+
a00a81
+				base64_length = g_utf8_strlen (base64, -1);
a00a81
+
a00a81
+				filename_length = uri_length - base64_length - 1;
a00a81
+				filename = g_strndup (uri, filename_length);
a00a81
+
a00a81
+				/* strlen ("data:") == 5 */
a00a81
+				mime_type_length = base64_length - g_utf8_strlen (strstr (base64, ";"), -1) - 5;
a00a81
+				mime_type = g_strndup (uri + filename_length + 5 + 1, mime_type_length);
a00a81
+
a00a81
+				base64 = strstr (base64, ",") + 1;
a00a81
+				base64_data = g_base64_decode (base64, &base64_data_length);
a00a81
+			} else {
a00a81
+				g_free (uri);
a00a81
+				gtk_drag_finish (drag_context, FALSE, FALSE, time);
a00a81
+				return;
a00a81
+			}
a00a81
+
a00a81
+			mime_part = camel_mime_part_new ();
a00a81
+
a00a81
+			camel_mime_part_set_content (mime_part, (const gchar *) base64_data, base64_data_length, mime_type);
a00a81
+			camel_mime_part_set_disposition (mime_part, "inline");
a00a81
+			if (filename && *filename)
a00a81
+				camel_mime_part_set_filename (mime_part, filename);
a00a81
+			camel_mime_part_set_encoding (mime_part, CAMEL_TRANSFER_ENCODING_BASE64);
a00a81
+
a00a81
+			attachment = e_attachment_new ();
a00a81
+			e_attachment_set_mime_part (attachment, mime_part);
a00a81
+			e_attachment_store_add_attachment (store, attachment);
a00a81
+			e_attachment_load_async (
a00a81
+				attachment, (GAsyncReadyCallback)
a00a81
+				call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
a00a81
+
a00a81
+			g_object_unref (attachment);
a00a81
+			g_object_unref (mime_part);
a00a81
+			if (mime_type)
a00a81
+				g_free (mime_type);
a00a81
+			if (filename)
a00a81
+				g_free (filename);
a00a81
+			g_free (base64_data);
a00a81
+		} else {
a00a81
+			/* regular URIs */
a00a81
+			attachment = e_attachment_new_for_uri (uri);
a00a81
+			e_attachment_store_add_attachment (store, attachment);
a00a81
+			e_attachment_load_async (
a00a81
+				attachment, (GAsyncReadyCallback)
a00a81
+				call_attachment_load_handle_error, parent ? g_object_ref (parent) : NULL);
a00a81
+			g_object_unref (attachment);
a00a81
+		}
a00a81
+
a00a81
+		g_free (uri);
a00a81
+	} while (list_length);
a00a81
+
a00a81
+	gtk_drag_finish (drag_context, TRUE, FALSE, time);
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
 attachment_view_text_calendar (EAttachmentView *view,
a00a81
                                GdkDragContext *drag_context,
a00a81
                                gint x,
a00a81
@@ -809,6 +929,10 @@ e_attachment_view_init (EAttachmentView
a00a81
 
a00a81
 	g_signal_connect (
a00a81
 		view, "drag-data-received",
a00a81
+		G_CALLBACK (attachment_view_uri_list), NULL);
a00a81
+
a00a81
+	g_signal_connect (
a00a81
+		view, "drag-data-received",
a00a81
 		G_CALLBACK (attachment_view_text_x_vcard), NULL);
a00a81
 
a00a81
 	g_signal_connect (
a00a81
diff -up evolution-3.22.6/e-util/e-html-editor-dialog.h.composer-image-insert-undo evolution-3.22.6/e-util/e-html-editor-dialog.h
a00a81
--- evolution-3.22.6/e-util/e-html-editor-dialog.h.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/e-util/e-html-editor-dialog.h	2017-03-24 15:12:21.894422514 +0100
a00a81
@@ -62,16 +62,6 @@ struct _EHTMLEditorDialogClass {
a00a81
 	GtkWindowClass parent_class;
a00a81
 };
a00a81
 
a00a81
-#if 0 /* FIXME WK2 */
a00a81
-struct _EContentEditorDialogInterface {
a00a81
-	GTypeInterface parent_interface;
a00a81
-
a00a81
-	void		(*dialog_opened)		(EContentEditorDialog *dialog);
a00a81
-
a00a81
-	void		(*dialog_closed)		(EContentEditorDialog *dialog);
a00a81
-};
a00a81
-#endif
a00a81
-
a00a81
 GType		e_html_editor_dialog_get_type	(void) G_GNUC_CONST;
a00a81
 EHTMLEditor *	e_html_editor_dialog_get_editor	(EHTMLEditorDialog *dialog);
a00a81
 GtkBox *	e_html_editor_dialog_get_button_box
a00a81
diff -up evolution-3.22.6/e-util/e-misc-utils.c.composer-image-insert-undo evolution-3.22.6/e-util/e-misc-utils.c
a00a81
--- evolution-3.22.6/e-util/e-misc-utils.c.composer-image-insert-undo	2017-01-18 11:36:05.000000000 +0100
a00a81
+++ evolution-3.22.6/e-util/e-misc-utils.c	2017-03-24 15:12:21.894422514 +0100
a00a81
@@ -3908,3 +3908,38 @@ e_util_get_webkit_developer_mode_enabled
a00a81
 
a00a81
 	return enabled != 0;
a00a81
 }
a00a81
+
a00a81
+/**
a00a81
+ * e_util_next_uri_from_uri_list:
a00a81
+ * @uri_list: array of URIs separated by new lines
a00a81
+ * @len: (out): a length of the found URI
a00a81
+ * @list_len: (out): a length of the array
a00a81
+ *
a00a81
+ * Returns: A newly allocated string with found URI.
a00a81
+ *
a00a81
+ * Since: 3.26
a00a81
+ **/
a00a81
+gchar *
a00a81
+e_util_next_uri_from_uri_list (guchar **uri_list,
a00a81
+                               gint *len,
a00a81
+                               gint *list_len)
a00a81
+{
a00a81
+	guchar *uri, *begin;
a00a81
+
a00a81
+	begin = *uri_list;
a00a81
+	*len = 0;
a00a81
+	while (**uri_list && **uri_list != '\n' && **uri_list != '\r' && *list_len) {
a00a81
+		(*uri_list) ++;
a00a81
+		(*len) ++;
a00a81
+		(*list_len) --;
a00a81
+	}
a00a81
+
a00a81
+	uri = (guchar *) g_strndup ((gchar *) begin, *len);
a00a81
+
a00a81
+	while ((!**uri_list || **uri_list == '\n' || **uri_list == '\r') && *list_len) {
a00a81
+		(*uri_list) ++;
a00a81
+		(*list_len) --;
a00a81
+	}
a00a81
+
a00a81
+	return (gchar *) uri;
a00a81
+}
a00a81
diff -up evolution-3.22.6/e-util/e-misc-utils.h.composer-image-insert-undo evolution-3.22.6/e-util/e-misc-utils.h
a00a81
--- evolution-3.22.6/e-util/e-misc-utils.h.composer-image-insert-undo	2017-01-18 11:36:05.000000000 +0100
a00a81
+++ evolution-3.22.6/e-util/e-misc-utils.h	2017-03-24 15:12:21.894422514 +0100
a00a81
@@ -332,6 +332,9 @@ void		e_util_save_file_chooser_folder	(G
a00a81
 void		e_util_load_file_chooser_folder	(GtkFileChooser *file_chooser);
a00a81
 gboolean	e_util_get_webkit_developer_mode_enabled
a00a81
 						(void);
a00a81
+gchar *		e_util_next_uri_from_uri_list	(guchar **uri_list,
a00a81
+						 gint *len,
a00a81
+						 gint *list_len);
a00a81
 
a00a81
 G_END_DECLS
a00a81
 
a00a81
diff -up evolution-3.22.6/e-util/e-util-enums.h.composer-image-insert-undo evolution-3.22.6/e-util/e-util-enums.h
a00a81
--- evolution-3.22.6/e-util/e-util-enums.h.composer-image-insert-undo	2016-11-28 16:56:59.000000000 +0100
a00a81
+++ evolution-3.22.6/e-util/e-util-enums.h	2017-03-24 15:12:21.894422514 +0100
a00a81
@@ -548,6 +548,30 @@ typedef enum {
a00a81
 	E_CLIPBOARD_CAN_PASTE	= 1 << 2 */
a00a81
 } EClipboardFlags;
a00a81
 
a00a81
+/**
a00a81
+ * EDnDTargetType:
a00a81
+ * DND_TARGET_TYPE_TEXT_URI_LIST: text/uri-list
a00a81
+ * DND_TARGET_TYPE_MOZILLA_URL: _NETSCAPE_URL
a00a81
+ * DND_TARGET_TYPE_TEXT_HTML: text/html
a00a81
+ * DND_TARGET_TYPE_UTF8_STRING: UTF8_STRING
a00a81
+ * DND_TARGET_TYPE_TEXT_PLAIN: text/plain
a00a81
+ * DND_TARGET_TYPE_STRING: STRING
a00a81
+ * DND_TARGET_TYPE_TEXT_PLAIN_UTF8: text/plain;charser=utf-8
a00a81
+ *
a00a81
+ * Drag and drop targets supported by EContentEditor.
a00a81
+ *
a00a81
+ * Since: 3.26
a00a81
+ **/
a00a81
+typedef enum {
a00a81
+	E_DND_TARGET_TYPE_TEXT_URI_LIST = 0,
a00a81
+	E_DND_TARGET_TYPE_MOZILLA_URL,
a00a81
+	E_DND_TARGET_TYPE_TEXT_HTML,
a00a81
+	E_DND_TARGET_TYPE_UTF8_STRING,
a00a81
+	E_DND_TARGET_TYPE_TEXT_PLAIN,
a00a81
+	E_DND_TARGET_TYPE_STRING,
a00a81
+	E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8
a00a81
+} EDnDTargetType;
a00a81
+
a00a81
 G_END_DECLS
a00a81
 
a00a81
 #endif /* E_UTIL_ENUMS_H */
a00a81
diff -up evolution-3.22.6/e-util/e-web-view.c.composer-image-insert-undo evolution-3.22.6/e-util/e-web-view.c
a00a81
--- evolution-3.22.6/e-util/e-web-view.c.composer-image-insert-undo	2017-01-27 12:06:11.000000000 +0100
a00a81
+++ evolution-3.22.6/e-util/e-web-view.c	2017-03-24 15:12:21.895422514 +0100
a00a81
@@ -2386,11 +2386,7 @@ e_web_view_init (EWebView *web_view)
a00a81
 	g_signal_connect (
a00a81
 		web_view, "load-changed",
a00a81
 		G_CALLBACK (web_view_load_changed_cb), NULL);
a00a81
-/* FIXME WK2
a00a81
-	g_signal_connect (
a00a81
-		web_view, "document-load-finished",
a00a81
-		G_CALLBACK (style_updated_cb), NULL);
a00a81
-*/
a00a81
+
a00a81
 	g_signal_connect (
a00a81
 		web_view, "style-updated",
a00a81
 		G_CALLBACK (style_updated_cb), NULL);
a00a81
diff -up evolution-3.22.6/e-util/test-html-editor-units.c.composer-image-insert-undo evolution-3.22.6/e-util/test-html-editor-units.c
a00a81
--- evolution-3.22.6/e-util/test-html-editor-units.c.composer-image-insert-undo	2017-03-24 15:12:21.888422514 +0100
a00a81
+++ evolution-3.22.6/e-util/test-html-editor-units.c	2017-03-24 15:12:21.895422514 +0100
a00a81
@@ -978,6 +978,8 @@ test_image_insert (TestFixture *fixture)
a00a81
 	/* Mimic what the action:insert-image does, without invoking the image chooser dialog */
a00a81
 	cnt_editor = e_html_editor_get_content_editor (fixture->editor);
a00a81
 	e_content_editor_insert_image (cnt_editor, uri);
a00a81
+	/* Wait some time until the operation is finished */
a00a81
+	test_utils_wait_milliseconds (500);
a00a81
 
a00a81
 	g_free (uri);
a00a81
 
a00a81
@@ -991,6 +993,10 @@ test_image_insert (TestFixture *fixture)
a00a81
 	g_free (image_data);
a00a81
 
a00a81
 	if (!test_utils_run_simple_test (fixture,
a00a81
+		"undo:save\n" /* 1 */
a00a81
+		"undo:undo\n"
a00a81
+		"undo:redo\n"
a00a81
+		"undo:test:1\n"
a00a81
 		"type:+after\n",
a00a81
 		expected_html,
a00a81
 		"before*+after"))
a00a81
@@ -2663,6 +2669,48 @@ test_delete_after_quoted (TestFixture *f
a00a81
 		g_test_fail ();
a00a81
 }
a00a81
 
a00a81
+static void
a00a81
+test_replace_dialog (TestFixture *fixture)
a00a81
+{
a00a81
+	if (!test_utils_run_simple_test (fixture,
a00a81
+		"mode:plain\n"
a00a81
+		"type:text to replace\n"
a00a81
+		"undo:save\n"	/* 1 */
a00a81
+		"seq:h\n"
a00a81
+		"action:show-replace\n"
a00a81
+		"type:to\t2\n"
a00a81
+		"type:\t\t\t\t\t\t\n" /* Jump to 'Replace' */
a00a81
+		"seq:n\n" /* Press it */
a00a81
+		"seq:^\n" /* Close the dialog */
a00a81
+		"undo:undo\n"
a00a81
+		"undo:test:1\n"
a00a81
+		"undo:redo\n",
a00a81
+		HTML_PREFIX "
text 2 replace
" HTML_SUFFIX,
a00a81
+		"text 2 replace"))
a00a81
+		g_test_fail ();
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+test_replace_dialog_all (TestFixture *fixture)
a00a81
+{
a00a81
+	if (!test_utils_run_simple_test (fixture,
a00a81
+		"mode:plain\n"
a00a81
+		"type:text to replace\n"
a00a81
+		"undo:save\n"	/* 1 */
a00a81
+		"seq:h\n"
a00a81
+		"action:show-replace\n"
a00a81
+		"type:e\t3\n"
a00a81
+		"type:\t\t\t\t\t\t\t\n" /* Jump to 'Replace All' */
a00a81
+		"seq:n\n" /* Press it */
a00a81
+		"seq:^\n" /* Close the dialog */
a00a81
+		"undo:undo\n"
a00a81
+		"undo:test:1\n"
a00a81
+		"undo:redo\n",
a00a81
+		HTML_PREFIX "
t3xt to r3plac3
" HTML_SUFFIX,
a00a81
+		"t3xt to r3plac3"))
a00a81
+		g_test_fail ();
a00a81
+}
a00a81
+
a00a81
 gint
a00a81
 main (gint argc,
a00a81
       gchar *argv[])
a00a81
@@ -2824,6 +2872,8 @@ main (gint argc,
a00a81
 	test_utils_add_test ("/undo/link-paste/plain", test_undo_link_paste_plain);
a00a81
 	test_utils_add_test ("/delete/quoted", test_delete_quoted);
a00a81
 	test_utils_add_test ("/delete/after-quoted", test_delete_after_quoted);
a00a81
+	test_utils_add_test ("/replace/dialog", test_replace_dialog);
a00a81
+	test_utils_add_test ("/replace-all/dialog", test_replace_dialog_all);
a00a81
 
a00a81
 	test_add_html_editor_bug_tests ();
a00a81
 
a00a81
diff -up evolution-3.22.6/mail/e-mail-display.c.composer-image-insert-undo evolution-3.22.6/mail/e-mail-display.c
a00a81
--- evolution-3.22.6/mail/e-mail-display.c.composer-image-insert-undo	2017-03-24 15:12:21.888422514 +0100
a00a81
+++ evolution-3.22.6/mail/e-mail-display.c	2017-03-24 15:12:21.895422514 +0100
a00a81
@@ -1768,7 +1768,6 @@ mail_display_uri_requested_cb (EWebView
a00a81
 	}
a00a81
 }
a00a81
 
a00a81
-#if 0 /* FIXME WK2 */
a00a81
 static CamelMimePart *
a00a81
 camel_mime_part_from_cid (EMailDisplay *display,
a00a81
                           const gchar *uri)
a00a81
@@ -1876,7 +1875,6 @@ mail_display_drag_data_get (GtkWidget *w
a00a81
  out:
a00a81
 	g_free (uri);
a00a81
 }
a00a81
-#endif
a00a81
 
a00a81
 static void
a00a81
 e_mail_display_test_change_and_update_fonts_cb (EMailDisplay *mail_display,
a00a81
@@ -1922,9 +1920,7 @@ e_mail_display_class_init (EMailDisplayC
a00a81
 	widget_class->button_press_event = mail_display_button_press_event;
a00a81
 
a00a81
 	web_view_class = E_WEB_VIEW_CLASS (class);
a00a81
-#if 0 /* FIXME WK2 */
a00a81
 	web_view_class->suggest_filename = mail_display_suggest_filename;
a00a81
-#endif
a00a81
 	web_view_class->set_fonts = mail_display_set_fonts;
a00a81
 
a00a81
 	g_object_class_install_property (
a00a81
@@ -2054,11 +2050,11 @@ e_mail_display_init (EMailDisplay *displ
a00a81
 	g_signal_connect (
a00a81
 		display, "process-mailto",
a00a81
 		G_CALLBACK (mail_display_process_mailto), NULL);
a00a81
-#if 0 /* FIXME WK2 */
a00a81
+
a00a81
 	g_signal_connect_after (
a00a81
 		display, "drag-data-get",
a00a81
 		G_CALLBACK (mail_display_drag_data_get), display);
a00a81
-#endif
a00a81
+
a00a81
 	display->priv->settings = e_util_ref_settings ("org.gnome.evolution.mail");
a00a81
 	g_signal_connect_swapped (
a00a81
 		display->priv->settings , "changed::monospace-font",
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c
a00a81
--- evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c.composer-image-insert-undo	2017-03-24 15:12:21.889422514 +0100
a00a81
+++ evolution-3.22.6/modules/webkit-editor/e-webkit-editor.c	2017-03-24 15:13:40.145419038 +0100
a00a81
@@ -131,6 +131,10 @@ struct _EWebKitEditorPrivate {
a00a81
 	gchar *replace_with;
a00a81
 	gulong found_text_handler_id;
a00a81
 	gulong failed_to_find_text_handler_id;
a00a81
+	gboolean current_text_not_found;
a00a81
+
a00a81
+	gboolean performing_drag;
a00a81
+	gulong drag_data_received_handler_id;
a00a81
 
a00a81
 	gchar *last_hover_uri;
a00a81
 };
a00a81
@@ -386,6 +390,9 @@ web_extension_selection_changed_cb (GDBu
a00a81
 	}
a00a81
 	g_free (font_color);
a00a81
 
a00a81
+	g_object_notify (G_OBJECT (wk_editor), "can-undo");
a00a81
+	g_object_notify (G_OBJECT (wk_editor), "can-redo");
a00a81
+
a00a81
 	g_object_notify (G_OBJECT (wk_editor), "alignment");
a00a81
 	g_object_notify (G_OBJECT (wk_editor), "block-format");
a00a81
 	g_object_notify (G_OBJECT (wk_editor), "indented");
a00a81
@@ -2468,7 +2475,7 @@ webkit_editor_replace_caret_word (EConte
a00a81
 		return;
a00a81
 	}
a00a81
 
a00a81
-	e_util_invoke_g_dbus_proxy_call_with_error_check (
a00a81
+	e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
a00a81
 		wk_editor->priv->web_extension,
a00a81
 		"DOMReplaceCaretWord",
a00a81
 		g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
a00a81
@@ -2521,10 +2528,39 @@ find_flags_to_webkit_find_options (guint
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
+webkit_editor_replace (EContentEditor *editor,
a00a81
+                       const gchar *replacement)
a00a81
+{
a00a81
+	EWebKitEditor *wk_editor;
a00a81
+
a00a81
+	wk_editor = E_WEBKIT_EDITOR (editor);
a00a81
+	if (!wk_editor->priv->web_extension) {
a00a81
+		g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
a00a81
+		return;
a00a81
+	}
a00a81
+
a00a81
+	e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
a00a81
+		wk_editor->priv->web_extension,
a00a81
+		"DOMSelectionReplace",
a00a81
+		g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
a00a81
+		wk_editor->priv->cancellable);
a00a81
+}
a00a81
+
a00a81
+static gboolean
a00a81
+search_next_on_idle (EWebKitEditor *wk_editor)
a00a81
+{
a00a81
+	webkit_find_controller_search_next (wk_editor->priv->find_controller);
a00a81
+
a00a81
+	return G_SOURCE_REMOVE;
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
 webkit_find_controller_found_text_cb (WebKitFindController *find_controller,
a00a81
                                       guint match_count,
a00a81
                                       EWebKitEditor *wk_editor)
a00a81
 {
a00a81
+	wk_editor->priv->current_text_not_found = FALSE;
a00a81
+
a00a81
 	if (wk_editor->priv->performing_replace_all) {
a00a81
 		if (!wk_editor->priv->replaced_count)
a00a81
 			wk_editor->priv->replaced_count = match_count;
a00a81
@@ -2532,12 +2568,13 @@ webkit_find_controller_found_text_cb (We
a00a81
 		/* Repeatedly search for 'word', then replace selection by
a00a81
 		 * 'replacement'. Repeat until there's at least one occurrence of
a00a81
 		 * 'word' in the document */
a00a81
-		e_content_editor_insert_content (
a00a81
-			E_CONTENT_EDITOR (wk_editor),
a00a81
-			wk_editor->priv->replace_with,
a00a81
-			E_CONTENT_EDITOR_INSERT_TEXT_PLAIN);
a00a81
+		e_util_invoke_g_dbus_proxy_call_with_error_check (
a00a81
+			wk_editor->priv->web_extension,
a00a81
+			"DOMSelectionReplace",
a00a81
+			g_variant_new ("(ts)", current_page_id (wk_editor), wk_editor->priv->replace_with),
a00a81
+			wk_editor->priv->cancellable);
a00a81
 
a00a81
-		webkit_find_controller_search_next (find_controller);
a00a81
+		g_idle_add ((GSourceFunc) search_next_on_idle, wk_editor);
a00a81
 	} else {
a00a81
 		e_content_editor_emit_find_done (E_CONTENT_EDITOR (wk_editor), match_count);
a00a81
 	}
a00a81
@@ -2547,9 +2584,26 @@ static void
a00a81
 webkit_find_controller_failed_to_find_text_cb (WebKitFindController *find_controller,
a00a81
                                                EWebKitEditor *wk_editor)
a00a81
 {
a00a81
+	wk_editor->priv->current_text_not_found = TRUE;
a00a81
+
a00a81
 	if (wk_editor->priv->performing_replace_all) {
a00a81
 		guint replaced_count = wk_editor->priv->replaced_count;
a00a81
 
a00a81
+		if (replaced_count > 0) {
a00a81
+			if (!wk_editor->priv->web_extension) {
a00a81
+				g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
a00a81
+			} else {
a00a81
+				e_util_invoke_g_dbus_proxy_call_sync_wrapper_with_error_check (
a00a81
+					wk_editor->priv->web_extension,
a00a81
+					"DOMInsertReplaceAllHistoryEvent",
a00a81
+					g_variant_new ("(tss)",
a00a81
+						current_page_id (wk_editor),
a00a81
+						webkit_find_controller_get_search_text (find_controller),
a00a81
+						wk_editor->priv->replace_with),
a00a81
+					NULL);
a00a81
+			}
a00a81
+		}
a00a81
+
a00a81
 		webkit_editor_finish_search (wk_editor);
a00a81
 		e_content_editor_emit_replace_all_done (E_CONTENT_EDITOR (wk_editor), replaced_count);
a00a81
 	} else {
a00a81
@@ -2575,6 +2629,7 @@ webkit_editor_prepare_find_controller (E
a00a81
 
a00a81
 	wk_editor->priv->performing_replace_all = FALSE;
a00a81
 	wk_editor->priv->replaced_count = 0;
a00a81
+	wk_editor->priv->current_text_not_found = FALSE;
a00a81
 	g_free (wk_editor->priv->replace_with);
a00a81
 	wk_editor->priv->replace_with = NULL;
a00a81
 }
a00a81
@@ -2613,25 +2668,6 @@ webkit_editor_find (EContentEditor *edit
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
-webkit_editor_replace (EContentEditor *editor,
a00a81
-                       const gchar *replacement)
a00a81
-{
a00a81
-	EWebKitEditor *wk_editor;
a00a81
-
a00a81
-	wk_editor = E_WEBKIT_EDITOR (editor);
a00a81
-	if (!wk_editor->priv->web_extension) {
a00a81
-		g_warning ("EHTMLEditorWebExtension not ready at %s!", G_STRFUNC);
a00a81
-		return;
a00a81
-	}
a00a81
-
a00a81
-	e_util_invoke_g_dbus_proxy_call_with_error_check (
a00a81
-		wk_editor->priv->web_extension,
a00a81
-		"DOMSelectionReplace",
a00a81
-		g_variant_new ("(ts)", current_page_id (wk_editor), replacement),
a00a81
-		wk_editor->priv->cancellable);
a00a81
-}
a00a81
-
a00a81
-static void
a00a81
 webkit_editor_replace_all (EContentEditor *editor,
a00a81
                            guint32 flags,
a00a81
                            const gchar *find_text,
a00a81
@@ -2647,6 +2683,11 @@ webkit_editor_replace_all (EContentEdito
a00a81
 	wk_editor = E_WEBKIT_EDITOR (editor);
a00a81
 	wk_options = find_flags_to_webkit_find_options (flags);
a00a81
 
a00a81
+	wk_options |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
a00a81
+
a00a81
+	if (wk_editor->priv->current_text_not_found)
a00a81
+		return;
a00a81
+
a00a81
 	if (!wk_editor->priv->find_controller)
a00a81
 		webkit_editor_prepare_find_controller (wk_editor);
a00a81
 
a00a81
@@ -5770,17 +5811,111 @@ webkit_editor_context_menu_cb (EWebKitEd
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
+webkit_editor_drag_begin_cb (EWebKitEditor *wk_editor,
a00a81
+                             GdkDragContext *context)
a00a81
+{
a00a81
+	wk_editor->priv->performing_drag = TRUE;
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+webkit_editor_drag_failed_cb (EWebKitEditor *wk_editor,
a00a81
+                              GdkDragContext *context,
a00a81
+                              GtkDragResult result)
a00a81
+{
a00a81
+	wk_editor->priv->performing_drag = FALSE;
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
 webkit_editor_drag_end_cb (EWebKitEditor *wk_editor,
a00a81
                            GdkDragContext *context)
a00a81
 {
a00a81
-	webkit_editor_call_simple_extension_function (wk_editor, "DOMDragAndDropEnd");
a00a81
+	wk_editor->priv->performing_drag = FALSE;
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+webkit_editor_drag_data_received_cb (GtkWidget *widget,
a00a81
+                                     GdkDragContext *context,
a00a81
+                                     gint x,
a00a81
+                                     gint y,
a00a81
+                                     GtkSelectionData *selection,
a00a81
+                                     guint info,
a00a81
+                                     guint time)
a00a81
+{
a00a81
+	EWebKitEditor *wk_editor = E_WEBKIT_EDITOR (widget);
a00a81
+	gboolean is_move = FALSE;
a00a81
+
a00a81
+	g_signal_handler_disconnect (wk_editor, wk_editor->priv->drag_data_received_handler_id);
a00a81
+	wk_editor->priv->drag_data_received_handler_id = 0;
a00a81
+
a00a81
+	is_move = gdk_drag_context_get_selected_action(context) == GDK_ACTION_MOVE;
a00a81
+
a00a81
+	/* Leave DnD inside the view on WebKit */
a00a81
+	/* Leave the text on WebKit to handle it. */
a00a81
+	if (wk_editor->priv->performing_drag ||
a00a81
+	    info == E_DND_TARGET_TYPE_UTF8_STRING || info == E_DND_TARGET_TYPE_STRING ||
a00a81
+	    info == E_DND_TARGET_TYPE_TEXT_PLAIN || info == E_DND_TARGET_TYPE_TEXT_PLAIN_UTF8) {
a00a81
+		gdk_drag_status (context, gdk_drag_context_get_selected_action(context), time);
a00a81
+		GTK_WIDGET_CLASS (e_webkit_editor_parent_class)->drag_drop (widget, context, x, y, time);
a00a81
+		g_signal_stop_emission_by_name (widget, "drag-data-received");
a00a81
+		if (!is_move)
a00a81
+			webkit_editor_call_simple_extension_function (wk_editor, "DOMLastDropOperationDidCopy");
a00a81
+		return;
a00a81
+	}
a00a81
+
a00a81
+	if (info == E_DND_TARGET_TYPE_TEXT_HTML) {
a00a81
+		const guchar *data;
a00a81
+		gint length;
a00a81
+		gint list_len, len;
a00a81
+		gchar *text;
a00a81
+
a00a81
+		data = gtk_selection_data_get_data (selection);
a00a81
+		length = gtk_selection_data_get_length (selection);
a00a81
+
a00a81
+		if (!data || length < 0) {
a00a81
+			gtk_drag_finish (context, FALSE, is_move, time);
a00a81
+			g_signal_stop_emission_by_name (widget, "drag-data-received");
a00a81
+			return;
a00a81
+		}
a00a81
+
a00a81
+		webkit_editor_move_caret_on_coordinates (E_CONTENT_EDITOR (widget), x, y, FALSE);
a00a81
+
a00a81
+		list_len = length;
a00a81
+		do {
a00a81
+			text = e_util_next_uri_from_uri_list ((guchar **) &data, &len, &list_len);
a00a81
+			webkit_editor_insert_content (
a00a81
+				E_CONTENT_EDITOR (wk_editor),
a00a81
+				text,
a00a81
+				E_CONTENT_EDITOR_INSERT_TEXT_HTML);
a00a81
+			g_free (text);
a00a81
+		} while (list_len);
a00a81
+
a00a81
+		gtk_drag_finish (context, TRUE, is_move, time);
a00a81
+		g_signal_stop_emission_by_name (widget, "drag-data-received");
a00a81
+		return;
a00a81
+	}
a00a81
+}
a00a81
+
a00a81
+static gboolean
a00a81
+webkit_editor_drag_drop_cb (EWebKitEditor *wk_editor,
a00a81
+                            GdkDragContext *context,
a00a81
+                            gint x,
a00a81
+                            gint y,
a00a81
+                            guint time)
a00a81
+{
a00a81
+	wk_editor->priv->drag_data_received_handler_id = g_signal_connect (
a00a81
+		wk_editor, "drag-data-received",
a00a81
+		G_CALLBACK (webkit_editor_drag_data_received_cb), NULL);
a00a81
+
a00a81
+	webkit_editor_set_changed (wk_editor, TRUE);
a00a81
+
a00a81
+	return FALSE;
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
 webkit_editor_web_process_crashed_cb (EWebKitEditor *wk_editor)
a00a81
 {
a00a81
 	g_warning (
a00a81
-		"WebKitWebProcess (page id %ld) for EWebKitEditor crashed",
a00a81
+		"WebKitWebProcess (page id %" G_GUINT64_FORMAT ") for EWebKitEditor crashed",
a00a81
 		webkit_web_view_get_page_id (WEBKIT_WEB_VIEW (wk_editor)));
a00a81
 }
a00a81
 
a00a81
@@ -6050,10 +6185,22 @@ e_webkit_editor_init (EWebKitEditor *wk_
a00a81
 		G_CALLBACK (webkit_editor_mouse_target_changed_cb), NULL);
a00a81
 
a00a81
 	g_signal_connect (
a00a81
+		wk_editor, "drag-begin",
a00a81
+		G_CALLBACK (webkit_editor_drag_begin_cb), NULL);
a00a81
+
a00a81
+	g_signal_connect (
a00a81
+		wk_editor, "drag-failed",
a00a81
+		G_CALLBACK (webkit_editor_drag_failed_cb), NULL);
a00a81
+
a00a81
+	g_signal_connect (
a00a81
 		wk_editor, "drag-end",
a00a81
 		G_CALLBACK (webkit_editor_drag_end_cb), NULL);
a00a81
 
a00a81
 	g_signal_connect (
a00a81
+		wk_editor, "drag-drop",
a00a81
+		G_CALLBACK (webkit_editor_drag_drop_cb), NULL);
a00a81
+
a00a81
+	g_signal_connect (
a00a81
 		wk_editor, "web-process-crashed",
a00a81
 		G_CALLBACK (webkit_editor_web_process_crashed_cb), NULL);
a00a81
 
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c.composer-image-insert-undo	2017-02-07 17:48:51.000000000 +0100
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.c	2017-03-24 15:12:21.896422514 +0100
a00a81
@@ -591,247 +591,3 @@ e_composer_dom_get_raw_body_content (EEd
a00a81
 
a00a81
 	return  webkit_dom_html_element_get_inner_text (body);
a00a81
 }
a00a81
-
a00a81
-static void
a00a81
-insert_nbsp_history_event (WebKitDOMDocument *document,
a00a81
-                           EEditorUndoRedoManager *manager,
a00a81
-                           gboolean delete,
a00a81
-                           guint x,
a00a81
-                           guint y)
a00a81
-{
a00a81
-	EEditorHistoryEvent *event;
a00a81
-	WebKitDOMDocumentFragment *fragment;
a00a81
-
a00a81
-	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
-	event->type = HISTORY_AND;
a00a81
-	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
-
a00a81
-	fragment = webkit_dom_document_create_document_fragment (document);
a00a81
-	webkit_dom_node_append_child (
a00a81
-		WEBKIT_DOM_NODE (fragment),
a00a81
-		WEBKIT_DOM_NODE (
a00a81
-			webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
a00a81
-		NULL);
a00a81
-
a00a81
-	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
-	event->type = HISTORY_DELETE;
a00a81
-
a00a81
-	if (delete)
a00a81
-		g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
a00a81
-
a00a81
-	event->data.fragment = fragment;
a00a81
-
a00a81
-	event->before.start.x = x;
a00a81
-	event->before.start.y = y;
a00a81
-	event->before.end.x = x;
a00a81
-	event->before.end.y = y;
a00a81
-
a00a81
-	event->after.start.x = x;
a00a81
-	event->after.start.y = y;
a00a81
-	event->after.end.x = x;
a00a81
-	event->after.end.y = y;
a00a81
-
a00a81
-	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
-}
a00a81
-
a00a81
-void
a00a81
-e_composer_dom_save_drag_and_drop_history (EEditorPage *editor_page)
a00a81
-{
a00a81
-	WebKitDOMDocument *document;
a00a81
-	WebKitDOMDocumentFragment *fragment;
a00a81
-	WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
-	WebKitDOMDOMWindow *dom_window = NULL;
a00a81
-	WebKitDOMRange *beginning_of_line = NULL;
a00a81
-	WebKitDOMRange *range = NULL, *range_clone = NULL;
a00a81
-	EEditorHistoryEvent *event;
a00a81
-	EEditorUndoRedoManager *manager;
a00a81
-	gboolean start_to_start, end_to_end;
a00a81
-	gchar *range_text;
a00a81
-	guint x, y;
a00a81
-
a00a81
-	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
-
a00a81
-	document = e_editor_page_get_document (editor_page);
a00a81
-	manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
-
a00a81
-	if (!(dom_window = webkit_dom_document_get_default_view (document)))
a00a81
-		return;
a00a81
-
a00a81
-	if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
a00a81
-		g_clear_object (&dom_window);
a00a81
-		return;
a00a81
-	}
a00a81
-
a00a81
-	g_clear_object (&dom_window);
a00a81
-
a00a81
-	if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
a00a81
-		g_clear_object (&dom_selection);
a00a81
-		return;
a00a81
-	}
a00a81
-
a00a81
-	/* Obtain the dragged content. */
a00a81
-	range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
-	range_clone = webkit_dom_range_clone_range (range, NULL);
a00a81
-
a00a81
-	/* Create the history event for the content that will
a00a81
-	 * be removed by DnD. */
a00a81
-	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
-	event->type = HISTORY_DELETE;
a00a81
-
a00a81
-	e_editor_dom_selection_get_coordinates (editor_page,
a00a81
-		&event->before.start.x,
a00a81
-		&event->before.start.y,
a00a81
-		&event->before.end.x,
a00a81
-		&event->before.end.y);
a00a81
-
a00a81
-	x = event->before.start.x;
a00a81
-	y = event->before.start.y;
a00a81
-
a00a81
-	event->after.start.x = x;
a00a81
-	event->after.start.y = y;
a00a81
-	event->after.end.x = x;
a00a81
-	event->after.end.y = y;
a00a81
-
a00a81
-	/* Save the content that will be removed. */
a00a81
-	fragment = webkit_dom_range_clone_contents (range_clone, NULL);
a00a81
-
a00a81
-	/* Extend the cloned range to point one character after
a00a81
-	 * the selection ends to later check if there is a whitespace
a00a81
-	 * after it. */
a00a81
-	webkit_dom_range_set_end (
a00a81
-		range_clone,
a00a81
-		webkit_dom_range_get_end_container (range_clone, NULL),
a00a81
-		webkit_dom_range_get_end_offset (range_clone, NULL) + 1,
a00a81
-		NULL);
a00a81
-	range_text = webkit_dom_range_get_text (range_clone);
a00a81
-
a00a81
-	/* Check if the current selection starts on the beginning
a00a81
-	 * of line. */
a00a81
-	webkit_dom_dom_selection_modify (
a00a81
-		dom_selection, "extend", "left", "lineboundary");
a00a81
-	beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
-	start_to_start = webkit_dom_range_compare_boundary_points (
a00a81
-		beginning_of_line, 0 /* START_TO_START */, range, NULL) == 0;
a00a81
-
a00a81
-	/* Restore the selection to state before the check. */
a00a81
-	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
-	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
-	g_clear_object (&beginning_of_line);
a00a81
-
a00a81
-	/* Check if the current selection end on the end of the line. */
a00a81
-	webkit_dom_dom_selection_modify (
a00a81
-		dom_selection, "extend", "right", "lineboundary");
a00a81
-	beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
-	end_to_end = webkit_dom_range_compare_boundary_points (
a00a81
-		beginning_of_line, 2 /* END_TO_END */, range, NULL) == 0;
a00a81
-
a00a81
-	/* Dragging the whole line. */
a00a81
-	if (start_to_start && end_to_end) {
a00a81
-		WebKitDOMNode *container, *actual_block, *tmp_block;
a00a81
-
a00a81
-		/* Select the whole line (to the beginning of the next
a00a81
-		 * one so we can reuse the undo code while undoing this.
a00a81
-		 * Because of this we need to special mark the event
a00a81
-		 * with history-drag-and-drop to correct the selection
a00a81
-		 * after undoing it (otherwise the beginning of the next
a00a81
-		 * line will be selected as well. */
a00a81
-		webkit_dom_dom_selection_modify (
a00a81
-			dom_selection, "extend", "right", "character");
a00a81
-		g_clear_object (&beginning_of_line);
a00a81
-		beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
-
a00a81
-		container = webkit_dom_range_get_end_container (range, NULL);
a00a81
-		actual_block = e_editor_dom_get_parent_block_node_from_child (container);
a00a81
-
a00a81
-		tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
a00a81
-		if ((tmp_block = e_editor_dom_get_parent_block_node_from_child (tmp_block))) {
a00a81
-			e_editor_dom_selection_get_coordinates (editor_page,
a00a81
-				&event->before.start.x,
a00a81
-				&event->before.start.y,
a00a81
-				&event->before.end.x,
a00a81
-				&event->before.end.y);
a00a81
-
a00a81
-			/* Create the right content for the history event. */
a00a81
-			fragment = webkit_dom_document_create_document_fragment (document);
a00a81
-			/* The removed line. */
a00a81
-			webkit_dom_node_append_child (
a00a81
-				WEBKIT_DOM_NODE (fragment),
a00a81
-				webkit_dom_node_clone_node_with_error (actual_block, TRUE, NULL),
a00a81
-				NULL);
a00a81
-			/* The following block, but empty. */
a00a81
-			webkit_dom_node_append_child (
a00a81
-				WEBKIT_DOM_NODE (fragment),
a00a81
-				webkit_dom_node_clone_node_with_error (tmp_block, FALSE, NULL),
a00a81
-				NULL);
a00a81
-			g_object_set_data (
a00a81
-				G_OBJECT (fragment),
a00a81
-				"history-drag-and-drop",
a00a81
-				GINT_TO_POINTER (1));
a00a81
-			/* It should act as a Delete key press. */
a00a81
-			g_object_set_data (
a00a81
-				G_OBJECT (fragment),
a00a81
-				"history-delete-key",
a00a81
-				GINT_TO_POINTER (1));
a00a81
-		}
a00a81
-	}
a00a81
-
a00a81
-	event->data.fragment = fragment;
a00a81
-	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
-
a00a81
-	/* Selection is ending on the end of the line, check if
a00a81
-	 * there is a space before the selection start. If so, it
a00a81
-	 * will be removed and we need create the history event
a00a81
-	 * for it. */
a00a81
-	if (end_to_end) {
a00a81
-		gchar *range_text_start;
a00a81
-		glong start_offset;
a00a81
-
a00a81
-		start_offset = webkit_dom_range_get_start_offset (range_clone, NULL);
a00a81
-		webkit_dom_range_set_start (
a00a81
-			range_clone,
a00a81
-			webkit_dom_range_get_start_container (range_clone, NULL),
a00a81
-			start_offset > 0 ? start_offset - 1 : 0,
a00a81
-			NULL);
a00a81
-
a00a81
-		range_text_start = webkit_dom_range_get_text (range_clone);
a00a81
-		if (g_str_has_prefix (range_text_start, " ") ||
a00a81
-		    g_str_has_prefix (range_text_start, UNICODE_NBSP))
a00a81
-			insert_nbsp_history_event (document, manager, FALSE, x, y);
a00a81
-
a00a81
-		g_free (range_text_start);
a00a81
-	}
a00a81
-
a00a81
-	/* WebKit removes the space (if presented) after selection and
a00a81
-	 * we need to create a new history event for it. */
a00a81
-	if (g_str_has_suffix (range_text, " ") ||
a00a81
-	    g_str_has_suffix (range_text, UNICODE_NBSP))
a00a81
-		insert_nbsp_history_event (document, manager, TRUE, x, y);
a00a81
-
a00a81
-	g_free (range_text);
a00a81
-
a00a81
-	/* Restore the selection to original state. */
a00a81
-	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
-	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
-	g_clear_object (&beginning_of_line);
a00a81
-
a00a81
-	/* All the things above were about removing the content,
a00a81
-	 * create an AND event to continue later with inserting
a00a81
-	 * the dropped content. */
a00a81
-	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
-	event->type = HISTORY_AND;
a00a81
-	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
-
a00a81
-	g_clear_object (&dom_selection);
a00a81
-
a00a81
-	g_clear_object (&range);
a00a81
-	g_clear_object (&range_clone);
a00a81
-}
a00a81
-
a00a81
-void
a00a81
-e_composer_dom_clean_after_drag_and_drop (EEditorPage *editor_page)
a00a81
-{
a00a81
-	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
-
a00a81
-	e_editor_dom_save_history_for_drop (editor_page);
a00a81
-	e_editor_dom_check_magic_links (editor_page, FALSE);
a00a81
-}
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-composer-dom-functions.h	2017-03-24 15:12:21.896422514 +0100
a00a81
@@ -38,10 +38,6 @@ gchar *		e_composer_dom_get_raw_body_con
a00a81
 						(EEditorPage *editor_page);
a00a81
 gchar *		e_composer_dom_get_raw_body_content
a00a81
 						(EEditorPage *editor_page);
a00a81
-void		e_composer_dom_save_drag_and_drop_history
a00a81
-						(EEditorPage *editor_page);
a00a81
-void		e_composer_dom_clean_after_drag_and_drop
a00a81
-						(EEditorPage *editor_page);
a00a81
 
a00a81
 G_END_DECLS
a00a81
 
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c.composer-image-insert-undo	2017-03-24 15:12:21.891422514 +0100
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.c	2017-03-24 15:13:16.839420073 +0100
a00a81
@@ -3408,6 +3408,7 @@ e_editor_dom_body_input_event_process (E
a00a81
 		}
a00a81
 
a00a81
 		if (WEBKIT_DOM_IS_TEXT (node)) {
a00a81
+			WebKitDOMElement *parent;
a00a81
 			gchar *text;
a00a81
 
a00a81
 			text = webkit_dom_node_get_text_content (node);
a00a81
@@ -3429,6 +3430,43 @@ e_editor_dom_body_input_event_process (E
a00a81
 						e_editor_dom_check_magic_links (editor_page, FALSE);
a00a81
 				}
a00a81
 			}
a00a81
+
a00a81
+			parent = webkit_dom_node_get_parent_element (node);
a00a81
+			if (element_has_class (parent, "-x-evo-resizable-wrapper") ||
a00a81
+			    element_has_class (parent, "-x-evo-smiley-wrapper")) {
a00a81
+				WebKitDOMDOMWindow *dom_window = NULL;
a00a81
+				WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
+				WebKitDOMNode *prev_sibling;
a00a81
+				gboolean writing_before = TRUE;
a00a81
+
a00a81
+				dom_window = webkit_dom_document_get_default_view (document);
a00a81
+				dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
+
a00a81
+				prev_sibling = webkit_dom_node_get_previous_sibling (node);
a00a81
+				if (prev_sibling && WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (prev_sibling))
a00a81
+					writing_before = FALSE;
a00a81
+
a00a81
+				webkit_dom_node_insert_before (
a00a81
+					webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (parent)),
a00a81
+					node,
a00a81
+					writing_before ?
a00a81
+						WEBKIT_DOM_NODE (parent) :
a00a81
+						webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent)),
a00a81
+					NULL);
a00a81
+
a00a81
+				g_clear_object (&range);
a00a81
+
a00a81
+				range = webkit_dom_document_create_range (document);
a00a81
+				webkit_dom_range_select_node_contents (range, node, NULL);
a00a81
+				webkit_dom_range_collapse (range, FALSE, NULL);
a00a81
+
a00a81
+				webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
+				webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
+
a00a81
+				g_clear_object (&dom_window);
a00a81
+				g_clear_object (&dom_selection);
a00a81
+			}
a00a81
+
a00a81
 			g_free (text);
a00a81
 		}
a00a81
 	}
a00a81
@@ -5751,6 +5789,94 @@ body_compositionend_event_cb (WebKitDOME
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
+body_drop_event_cb (WebKitDOMElement *element,
a00a81
+                    WebKitDOMUIEvent *event,
a00a81
+                    EEditorPage *editor_page)
a00a81
+{
a00a81
+	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
+
a00a81
+	if (e_editor_page_is_pasting_content_from_itself (editor_page)) {
a00a81
+		EEditorUndoRedoManager *manager;
a00a81
+		EEditorHistoryEvent *and_event, *event = NULL;
a00a81
+
a00a81
+		/* There is a weird thing going on and I still don't know if it's
a00a81
+		 * caused by WebKit or Evolution. If dragging content around the
a00a81
+		 * editor sometimes the current selection is changed. The problem
a00a81
+		 * is that if moving the content, then WebKit is removing the
a00a81
+		 * currently selected content and at that point it could be a
a00a81
+		 * different one from the dragged one. So before the drop is
a00a81
+		 * performed we restore the selection to the state when the
a00a81
+		 * drag was initiated. */
a00a81
+		manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
+		and_event = e_editor_undo_redo_manager_get_current_history_event (manager);
a00a81
+		while (and_event && and_event->type == HISTORY_AND) {
a00a81
+			event = e_editor_undo_redo_manager_get_next_history_event_for (manager, and_event);
a00a81
+			and_event = e_editor_undo_redo_manager_get_next_history_event_for (manager, event);
a00a81
+		}
a00a81
+
a00a81
+		if (event)
a00a81
+			e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
+
a00a81
+		e_editor_dom_save_history_for_drop (editor_page);
a00a81
+	}
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+body_dragstart_event_cb (WebKitDOMElement *element,
a00a81
+                         WebKitDOMUIEvent *event,
a00a81
+                         EEditorPage *editor_page)
a00a81
+{
a00a81
+	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
+
a00a81
+	e_editor_dom_remove_input_event_listener_from_body (editor_page);
a00a81
+	e_editor_page_set_pasting_content_from_itself (editor_page, TRUE);
a00a81
+	e_editor_dom_save_history_for_drag (editor_page);
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+body_dragend_event_cb (WebKitDOMElement *element,
a00a81
+                       WebKitDOMUIEvent *event,
a00a81
+                       EEditorPage *editor_page)
a00a81
+{
a00a81
+	EEditorHistoryEvent *ev;
a00a81
+	EEditorUndoRedoManager *manager;
a00a81
+
a00a81
+	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
+
a00a81
+	manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
+	if (e_editor_page_is_pasting_content_from_itself (editor_page) &&
a00a81
+	   (ev = e_editor_undo_redo_manager_get_current_history_event (manager))) {
a00a81
+		if (ev->type == HISTORY_INSERT_HTML &&
a00a81
+		    ev->after.start.x == 0 && ev->after.start.y == 0 &&
a00a81
+		    ev->after.end.x == 0 && ev->after.end.y == 0) {
a00a81
+			e_editor_dom_selection_get_coordinates (editor_page,
a00a81
+				&ev->after.start.x,
a00a81
+				&ev->after.start.y,
a00a81
+				&ev->after.end.x,
a00a81
+				&ev->after.end.y);
a00a81
+			ev->before.start.x = ev->after.start.x;
a00a81
+			ev->before.start.y = ev->after.start.y;
a00a81
+			ev->before.end.x = ev->after.start.x;
a00a81
+			ev->before.end.y = ev->after.start.y;
a00a81
+			e_editor_dom_force_spell_check_in_viewport (editor_page);
a00a81
+		} else {
a00a81
+			/* Drag and Drop was cancelled */
a00a81
+			while (ev && ev->type == HISTORY_AND) {
a00a81
+				e_editor_undo_redo_manager_remove_current_history_event (manager);
a00a81
+				ev = e_editor_undo_redo_manager_get_current_history_event (manager);
a00a81
+				/* Basically the same as in body_drop_event_cb().  See the comment there. */
a00a81
+				e_editor_dom_selection_restore_to_history_event_state (editor_page, ev->before);
a00a81
+				e_editor_undo_redo_manager_remove_current_history_event (manager);
a00a81
+				ev = e_editor_undo_redo_manager_get_current_history_event (manager);
a00a81
+			}
a00a81
+		}
a00a81
+	}
a00a81
+
a00a81
+	e_editor_page_set_pasting_content_from_itself (editor_page, FALSE);
a00a81
+	e_editor_dom_register_input_event_listener_on_body (editor_page);
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
 register_html_events_handlers (EEditorPage *editor_page,
a00a81
                                WebKitDOMHTMLElement *body)
a00a81
 {
a00a81
@@ -5790,6 +5916,27 @@ register_html_events_handlers (EEditorPa
a00a81
 		G_CALLBACK (body_compositionend_event_cb),
a00a81
 		FALSE,
a00a81
 		editor_page);
a00a81
+
a00a81
+	webkit_dom_event_target_add_event_listener (
a00a81
+		WEBKIT_DOM_EVENT_TARGET (body),
a00a81
+		"drop",
a00a81
+		G_CALLBACK (body_drop_event_cb),
a00a81
+		FALSE,
a00a81
+		editor_page);
a00a81
+
a00a81
+	webkit_dom_event_target_add_event_listener (
a00a81
+		WEBKIT_DOM_EVENT_TARGET (body),
a00a81
+		"dragstart",
a00a81
+		G_CALLBACK (body_dragstart_event_cb),
a00a81
+		FALSE,
a00a81
+		editor_page);
a00a81
+
a00a81
+	webkit_dom_event_target_add_event_listener (
a00a81
+		WEBKIT_DOM_EVENT_TARGET (body),
a00a81
+		"dragend",
a00a81
+		G_CALLBACK (body_dragend_event_cb),
a00a81
+		FALSE,
a00a81
+		editor_page);
a00a81
 }
a00a81
 
a00a81
 void
a00a81
@@ -8523,11 +8670,25 @@ e_editor_dom_process_content_after_load
a00a81
 
a00a81
 	if (e_editor_page_get_convert_in_situ (editor_page)) {
a00a81
 		e_editor_dom_convert_content (editor_page, NULL);
a00a81
+		/* The BODY could be replaced during the conversion */
a00a81
+		body = webkit_dom_document_get_body (document);
a00a81
 		/* Make the quote marks non-selectable. */
a00a81
 		e_editor_dom_disable_quote_marks_select (editor_page);
a00a81
 		dom_set_links_active (document, FALSE);
a00a81
 		e_editor_page_set_convert_in_situ (editor_page, FALSE);
a00a81
 
a00a81
+		/* The composer body could be empty in some case (loading an empty string
a00a81
+		 * or empty HTML). In that case create the initial paragraph. */
a00a81
+		if (!webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (body))) {
a00a81
+			WebKitDOMElement *paragraph;
a00a81
+
a00a81
+			paragraph = e_editor_dom_prepare_paragraph (editor_page, TRUE);
a00a81
+			webkit_dom_element_set_id (paragraph, "-x-evo-input-start");
a00a81
+			webkit_dom_node_append_child (
a00a81
+				WEBKIT_DOM_NODE (body), WEBKIT_DOM_NODE (paragraph), NULL);
a00a81
+			e_editor_dom_selection_restore (editor_page);
a00a81
+		}
a00a81
+
a00a81
 		goto out;
a00a81
 	}
a00a81
 
a00a81
@@ -8933,35 +9094,6 @@ e_editor_dom_insert_html (EEditorPage *e
a00a81
 		if (strstr (html_text, "id=\"-x-evo-selection-start-marker\""))
a00a81
 			e_editor_dom_selection_restore (editor_page);
a00a81
 
a00a81
-		if (!html_mode) {
a00a81
-			WebKitDOMNodeList *list = NULL;
a00a81
-			gint ii, length;
a00a81
-
a00a81
-			list = webkit_dom_document_query_selector_all (
a00a81
-				document, "span[style^=font-family]", NULL);
a00a81
-			length = webkit_dom_node_list_get_length (list);
a00a81
-			if (length > 0)
a00a81
-				e_editor_dom_selection_save (editor_page);
a00a81
-
a00a81
-			for (ii = length; ii--;) {
a00a81
-				WebKitDOMNode *span, *child;
a00a81
-
a00a81
-				span = webkit_dom_node_list_item (list, ii);
a00a81
-				while ((child = webkit_dom_node_get_first_child (span)))
a00a81
-					webkit_dom_node_insert_before (
a00a81
-						webkit_dom_node_get_parent_node (span),
a00a81
-						child,
a00a81
-						span,
a00a81
-						NULL);
a00a81
-
a00a81
-				remove_node (span);
a00a81
-			}
a00a81
-			g_clear_object (&list);
a00a81
-
a00a81
-			if (length > 0)
a00a81
-				e_editor_dom_selection_restore (editor_page);
a00a81
-		}
a00a81
-
a00a81
 		e_editor_dom_check_magic_links (editor_page, FALSE);
a00a81
 		e_editor_dom_scroll_to_caret (editor_page);
a00a81
 		e_editor_dom_force_spell_check_in_viewport (editor_page);
a00a81
@@ -10833,6 +10965,240 @@ e_editor_dom_get_caret_position (EEditor
a00a81
 	return ret_val;
a00a81
 }
a00a81
 
a00a81
+static void
a00a81
+insert_nbsp_history_event (WebKitDOMDocument *document,
a00a81
+                           EEditorUndoRedoManager *manager,
a00a81
+                           gboolean delete,
a00a81
+                           guint x,
a00a81
+                           guint y)
a00a81
+{
a00a81
+	EEditorHistoryEvent *event;
a00a81
+	WebKitDOMDocumentFragment *fragment;
a00a81
+
a00a81
+	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
+	event->type = HISTORY_AND;
a00a81
+	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
+
a00a81
+	fragment = webkit_dom_document_create_document_fragment (document);
a00a81
+	webkit_dom_node_append_child (
a00a81
+		WEBKIT_DOM_NODE (fragment),
a00a81
+		WEBKIT_DOM_NODE (
a00a81
+			webkit_dom_document_create_text_node (document, UNICODE_NBSP)),
a00a81
+		NULL);
a00a81
+
a00a81
+	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
+	event->type = HISTORY_DELETE;
a00a81
+
a00a81
+	if (delete)
a00a81
+		g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
a00a81
+
a00a81
+	event->data.fragment = fragment;
a00a81
+
a00a81
+	event->before.start.x = x;
a00a81
+	event->before.start.y = y;
a00a81
+	event->before.end.x = x;
a00a81
+	event->before.end.y = y;
a00a81
+
a00a81
+	event->after.start.x = x;
a00a81
+	event->after.start.y = y;
a00a81
+	event->after.end.x = x;
a00a81
+	event->after.end.y = y;
a00a81
+
a00a81
+	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
+}
a00a81
+void
a00a81
+e_editor_dom_save_history_for_drag (EEditorPage *editor_page)
a00a81
+{
a00a81
+	WebKitDOMDocument *document;
a00a81
+	WebKitDOMDocumentFragment *fragment;
a00a81
+	WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
+	WebKitDOMDOMWindow *dom_window = NULL;
a00a81
+	WebKitDOMRange *beginning_of_line = NULL;
a00a81
+	WebKitDOMRange *range = NULL, *range_clone = NULL;
a00a81
+	EEditorHistoryEvent *event;
a00a81
+	EEditorUndoRedoManager *manager;
a00a81
+	gboolean start_to_start = FALSE, end_to_end = FALSE;
a00a81
+	gchar *range_text;
a00a81
+	guint x, y;
a00a81
+
a00a81
+	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
+
a00a81
+	document = e_editor_page_get_document (editor_page);
a00a81
+	manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
+
a00a81
+	if (!(dom_window = webkit_dom_document_get_default_view (document)))
a00a81
+		return;
a00a81
+
a00a81
+	if (!(dom_selection = webkit_dom_dom_window_get_selection (dom_window))) {
a00a81
+		g_clear_object (&dom_window);
a00a81
+		return;
a00a81
+	}
a00a81
+
a00a81
+	g_clear_object (&dom_window);
a00a81
+
a00a81
+	if (webkit_dom_dom_selection_get_range_count (dom_selection) < 1) {
a00a81
+		g_clear_object (&dom_selection);
a00a81
+		return;
a00a81
+	}
a00a81
+
a00a81
+	/* Obtain the dragged content. */
a00a81
+	range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
+	range_clone = webkit_dom_range_clone_range (range, NULL);
a00a81
+
a00a81
+	/* Create the history event for the content that will
a00a81
+	 * be removed by DnD. */
a00a81
+	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
+	event->type = HISTORY_DELETE;
a00a81
+
a00a81
+	e_editor_dom_selection_get_coordinates (editor_page,
a00a81
+		&event->before.start.x,
a00a81
+		&event->before.start.y,
a00a81
+		&event->before.end.x,
a00a81
+		&event->before.end.y);
a00a81
+
a00a81
+	x = event->before.start.x;
a00a81
+	y = event->before.start.y;
a00a81
+
a00a81
+	event->after.start.x = x;
a00a81
+	event->after.start.y = y;
a00a81
+	event->after.end.x = x;
a00a81
+	event->after.end.y = y;
a00a81
+
a00a81
+	/* Save the content that will be removed. */
a00a81
+	fragment = webkit_dom_range_clone_contents (range_clone, NULL);
a00a81
+
a00a81
+	/* Extend the cloned range to point one character after
a00a81
+	 * the selection ends to later check if there is a whitespace
a00a81
+	 * after it. */
a00a81
+	webkit_dom_range_set_end (
a00a81
+		range_clone,
a00a81
+		webkit_dom_range_get_end_container (range_clone, NULL),
a00a81
+		webkit_dom_range_get_end_offset (range_clone, NULL) + 1,
a00a81
+		NULL);
a00a81
+	range_text = webkit_dom_range_get_text (range_clone);
a00a81
+
a00a81
+	/* Check if the current selection starts on the beginning of line. */
a00a81
+	webkit_dom_dom_selection_modify (
a00a81
+		dom_selection, "extend", "left", "lineboundary");
a00a81
+	beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
+	start_to_start = webkit_dom_range_compare_boundary_points (
a00a81
+		beginning_of_line, WEBKIT_DOM_RANGE_START_TO_START, range, NULL) == 0;
a00a81
+
a00a81
+	/* Restore the selection to state before the check. */
a00a81
+	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
+	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
+	g_clear_object (&beginning_of_line);
a00a81
+
a00a81
+	/* Check if the current selection end on the end of the line. */
a00a81
+	webkit_dom_dom_selection_modify (
a00a81
+		dom_selection, "extend", "right", "lineboundary");
a00a81
+	beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
+	end_to_end = webkit_dom_range_compare_boundary_points (
a00a81
+		beginning_of_line, WEBKIT_DOM_RANGE_END_TO_END, range, NULL) == 0;
a00a81
+
a00a81
+	/* Dragging the whole line. */
a00a81
+	if (start_to_start && end_to_end) {
a00a81
+		WebKitDOMNode *container, *actual_block, *tmp_block;
a00a81
+
a00a81
+		/* Select the whole line (to the beginning of the next
a00a81
+		 * one so we can reuse the undo code while undoing this.
a00a81
+		 * Because of this we need to special mark the event
a00a81
+		 * with history-drag-and-drop to correct the selection
a00a81
+		 * after undoing it (otherwise the beginning of the next
a00a81
+		 * line will be selected as well. */
a00a81
+		webkit_dom_dom_selection_modify (
a00a81
+			dom_selection, "extend", "right", "character");
a00a81
+		g_clear_object (&beginning_of_line);
a00a81
+		beginning_of_line = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
+
a00a81
+		container = webkit_dom_range_get_end_container (range, NULL);
a00a81
+		actual_block = e_editor_dom_get_parent_block_node_from_child (container);
a00a81
+
a00a81
+		tmp_block = webkit_dom_range_get_end_container (beginning_of_line, NULL);
a00a81
+		if ((tmp_block = e_editor_dom_get_parent_block_node_from_child (tmp_block))) {
a00a81
+			e_editor_dom_selection_get_coordinates (editor_page,
a00a81
+				&event->before.start.x,
a00a81
+				&event->before.start.y,
a00a81
+				&event->before.end.x,
a00a81
+				&event->before.end.y);
a00a81
+
a00a81
+			/* Create the right content for the history event. */
a00a81
+			fragment = webkit_dom_document_create_document_fragment (document);
a00a81
+			/* The removed line. */
a00a81
+			webkit_dom_node_append_child (
a00a81
+				WEBKIT_DOM_NODE (fragment),
a00a81
+				webkit_dom_node_clone_node_with_error (actual_block, TRUE, NULL),
a00a81
+				NULL);
a00a81
+			/* The following block, but empty. */
a00a81
+			webkit_dom_node_append_child (
a00a81
+				WEBKIT_DOM_NODE (fragment),
a00a81
+				webkit_dom_node_clone_node_with_error (tmp_block, FALSE, NULL),
a00a81
+				NULL);
a00a81
+			g_object_set_data (
a00a81
+				G_OBJECT (fragment),
a00a81
+				"history-drag-and-drop",
a00a81
+				GINT_TO_POINTER (1));
a00a81
+		}
a00a81
+	}
a00a81
+	/* It should act as a Delete key press. */
a00a81
+	g_object_set_data (G_OBJECT (fragment), "history-delete-key", GINT_TO_POINTER (1));
a00a81
+
a00a81
+	event->data.fragment = fragment;
a00a81
+	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
+
a00a81
+	/* WebKit removes the space (if presented) after selection and
a00a81
+	 * we need to create a new history event for it. */
a00a81
+	if (g_str_has_suffix (range_text, " ") ||
a00a81
+	    g_str_has_suffix (range_text, UNICODE_NBSP))
a00a81
+		insert_nbsp_history_event (document, manager, TRUE, x, y);
a00a81
+	else {
a00a81
+		/* If there is a space before the selection WebKit will remove
a00a81
+		 * it as well unless there is a space after the selection. */
a00a81
+		gchar *range_text_start;
a00a81
+		glong start_offset;
a00a81
+
a00a81
+		start_offset = webkit_dom_range_get_start_offset (range_clone, NULL);
a00a81
+		webkit_dom_range_set_start (
a00a81
+			range_clone,
a00a81
+			webkit_dom_range_get_start_container (range_clone, NULL),
a00a81
+			start_offset > 0 ? start_offset - 1 : 0,
a00a81
+			NULL);
a00a81
+
a00a81
+		range_text_start = webkit_dom_range_get_text (range_clone);
a00a81
+		if (g_str_has_prefix (range_text_start, " ") ||
a00a81
+		    g_str_has_prefix (range_text_start, UNICODE_NBSP)) {
a00a81
+			if (!end_to_end) {
a00a81
+				webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
a00a81
+				webkit_dom_dom_selection_modify (
a00a81
+					dom_selection, "move", "backward", "character");
a00a81
+				e_editor_dom_selection_get_coordinates (editor_page, &x, &y, &x, &y);
a00a81
+			}
a00a81
+			insert_nbsp_history_event (document, manager, TRUE, x, y);
a00a81
+		}
a00a81
+
a00a81
+		g_free (range_text_start);
a00a81
+	}
a00a81
+
a00a81
+	g_free (range_text);
a00a81
+
a00a81
+	/* Restore the selection to original state. */
a00a81
+	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
+	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
+	g_clear_object (&beginning_of_line);
a00a81
+
a00a81
+	/* All the things above were about removing the content,
a00a81
+	 * create an AND event to continue later with inserting
a00a81
+	 * the dropped content. */
a00a81
+	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
+	event->type = HISTORY_AND;
a00a81
+	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
+
a00a81
+	g_clear_object (&dom_selection);
a00a81
+
a00a81
+	g_clear_object (&range);
a00a81
+	g_clear_object (&range_clone);
a00a81
+}
a00a81
+
a00a81
 void
a00a81
 e_editor_dom_save_history_for_drop (EEditorPage *editor_page)
a00a81
 {
a00a81
@@ -10880,14 +11246,6 @@ e_editor_dom_save_history_for_drop (EEdi
a00a81
 
a00a81
 	range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
a00a81
 
a00a81
-	/* Remove the last inserted history event as this one was inserted in
a00a81
-	 * body_input_event_cb and is wrong as its type is HISTORY_INPUT. */
a00a81
-	/* FIXME we could probably disable the HTML input event callback while
a00a81
-	 * doing DnD within the view */
a00a81
-	event = e_editor_undo_redo_manager_get_current_history_event (manager);
a00a81
-	if (event && event->type == HISTORY_INPUT)
a00a81
-		e_editor_undo_redo_manager_remove_current_history_event (manager);
a00a81
-
a00a81
 	event = g_new0 (EEditorHistoryEvent, 1);
a00a81
 	event->type = HISTORY_INSERT_HTML;
a00a81
 
a00a81
@@ -10897,68 +11255,12 @@ e_editor_dom_save_history_for_drop (EEdi
a00a81
 	/* Get the HTML content of the dropped content. */
a00a81
 	event->data.string.to = dom_get_node_inner_html (WEBKIT_DOM_NODE (fragment));
a00a81
 
a00a81
-	e_editor_dom_selection_get_coordinates (editor_page,
a00a81
-		&event->before.start.x,
a00a81
-		&event->before.start.y,
a00a81
-		&event->before.end.x,
a00a81
-		&event->before.end.y);
a00a81
-
a00a81
-	event->before.end.x = event->before.start.x;
a00a81
-	event->before.end.y = event->before.start.y;
a00a81
-
a00a81
-	if (length > 0)
a00a81
-		webkit_dom_dom_selection_collapse_to_start (dom_selection, NULL);
a00a81
-	else
a00a81
-		webkit_dom_dom_selection_collapse_to_end (dom_selection, NULL);
a00a81
-
a00a81
-	e_editor_dom_selection_get_coordinates (editor_page,
a00a81
-		&event->after.start.x,
a00a81
-		&event->after.start.y,
a00a81
-		&event->after.end.x,
a00a81
-		&event->after.end.y);
a00a81
-
a00a81
 	e_editor_undo_redo_manager_insert_history_event (manager, event);
a00a81
 
a00a81
-	if (!e_editor_page_get_html_mode (editor_page)) {
a00a81
-		list = webkit_dom_document_query_selector_all (
a00a81
-			document, "span[style^=font-family]", NULL);
a00a81
-		length = webkit_dom_node_list_get_length (list);
a00a81
-		if (length > 0)
a00a81
-			e_editor_dom_selection_save (editor_page);
a00a81
-
a00a81
-		for (ii = length; ii--;) {
a00a81
-			WebKitDOMNode *span, *child;
a00a81
-
a00a81
-			span = webkit_dom_node_list_item (list, ii);
a00a81
-			while ((child = webkit_dom_node_get_first_child (span)))
a00a81
-				webkit_dom_node_insert_before (
a00a81
-					webkit_dom_node_get_parent_node (span),
a00a81
-					child,
a00a81
-					span,
a00a81
-					NULL);
a00a81
-
a00a81
-			remove_node (span);
a00a81
-		}
a00a81
-		g_clear_object (&list);
a00a81
-
a00a81
-		if (length > 0)
a00a81
-			e_editor_dom_selection_restore (editor_page);
a00a81
-	}
a00a81
-
a00a81
-	e_editor_dom_force_spell_check_in_viewport (editor_page);
a00a81
-
a00a81
 	g_clear_object (&range);
a00a81
 	g_clear_object (&dom_selection);
a00a81
 }
a00a81
 
a00a81
-void
a00a81
-e_editor_dom_drag_and_drop_end (EEditorPage *editor_page)
a00a81
-{
a00a81
-	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
-
a00a81
-	e_editor_dom_save_history_for_drop (editor_page);
a00a81
-}
a00a81
-
a00a81
 static void
a00a81
 dom_set_link_color_in_document (EEditorPage *editor_page,
a00a81
                                 const gchar *color,
a00a81
@@ -17086,6 +17388,28 @@ e_editor_dom_selection_set_alignment (EE
a00a81
 	e_editor_page_emit_content_changed (editor_page);
a00a81
 }
a00a81
 
a00a81
+void
a00a81
+e_editor_dom_insert_replace_all_history_event (EEditorPage *editor_page,
a00a81
+                                               const gchar *search_text,
a00a81
+                                               const gchar *replacement)
a00a81
+{
a00a81
+	EEditorUndoRedoManager *manager;
a00a81
+
a00a81
+	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
+
a00a81
+	manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
+
a00a81
+	if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
a00a81
+		EEditorHistoryEvent *ev = g_new0 (EEditorHistoryEvent, 1);
a00a81
+		ev->type = HISTORY_REPLACE_ALL;
a00a81
+
a00a81
+		ev->data.string.from = g_strdup (search_text);
a00a81
+		ev->data.string.to = g_strdup (replacement);
a00a81
+
a00a81
+		e_editor_undo_redo_manager_insert_history_event (manager, ev);
a00a81
+	}
a00a81
+}
a00a81
+
a00a81
 /*
a00a81
  * e_html_editor_selection_replace:
a00a81
  * @selection: an #EEditorSelection
a00a81
@@ -17099,14 +17423,17 @@ e_editor_dom_selection_replace (EEditorP
a00a81
 {
a00a81
 	EEditorHistoryEvent *ev = NULL;
a00a81
 	EEditorUndoRedoManager *manager;
a00a81
+	WebKitDOMRange *range = NULL;
a00a81
 
a00a81
 	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
 
a00a81
 	manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
 
a00a81
-	if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
a00a81
-		WebKitDOMRange *range = NULL;
a00a81
+	if (!(range = e_editor_dom_get_current_range (editor_page)) ||
a00a81
+	     e_editor_dom_selection_is_collapsed (editor_page))
a00a81
+		return;
a00a81
 
a00a81
+	if (!e_editor_undo_redo_manager_is_operation_in_progress (manager)) {
a00a81
 		ev = g_new0 (EEditorHistoryEvent, 1);
a00a81
 		ev->type = HISTORY_REPLACE;
a00a81
 
a00a81
@@ -17116,14 +17443,12 @@ e_editor_dom_selection_replace (EEditorP
a00a81
 			&ev->before.end.x,
a00a81
 			&ev->before.end.y);
a00a81
 
a00a81
-		range = e_editor_dom_get_current_range (editor_page);
a00a81
-
a00a81
 		ev->data.string.from = webkit_dom_range_get_text (range);
a00a81
 		ev->data.string.to = g_strdup (replacement);
a00a81
-
a00a81
-		g_clear_object (&range);
a00a81
 	}
a00a81
 
a00a81
+	g_clear_object (&range);
a00a81
+
a00a81
 	e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_INSERT_TEXT, replacement);
a00a81
 
a00a81
 	if (ev) {
a00a81
@@ -17382,3 +17707,98 @@ e_editor_dom_selection_get_coordinates (
a00a81
 	*start_y += 1;
a00a81
 	*end_y += 1;
a00a81
 }
a00a81
+
a00a81
+WebKitDOMRange *
a00a81
+e_editor_dom_get_range_for_point (WebKitDOMDocument *document,
a00a81
+                                  EEditorSelectionPoint point)
a00a81
+{
a00a81
+	glong scroll_left, scroll_top;
a00a81
+	WebKitDOMHTMLElement *body;
a00a81
+	WebKitDOMRange *range = NULL;
a00a81
+
a00a81
+	body = webkit_dom_document_get_body (document);
a00a81
+	scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
a00a81
+	scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
a00a81
+
a00a81
+	range = webkit_dom_document_caret_range_from_point (
a00a81
+		document, point.x - scroll_left, point.y - scroll_top);
a00a81
+
a00a81
+	/* The point is outside the viewport, scroll to it. */
a00a81
+	if (!range) {
a00a81
+		WebKitDOMDOMWindow *dom_window = NULL;
a00a81
+
a00a81
+		dom_window = webkit_dom_document_get_default_view (document);
a00a81
+		webkit_dom_dom_window_scroll_to (dom_window, point.x, point.y);
a00a81
+
a00a81
+		scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
a00a81
+		scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
a00a81
+		range = webkit_dom_document_caret_range_from_point (
a00a81
+			document, point.x - scroll_left, point.y - scroll_top);
a00a81
+		g_clear_object (&dom_window);
a00a81
+	}
a00a81
+
a00a81
+	return range;
a00a81
+}
a00a81
+
a00a81
+void
a00a81
+e_editor_dom_selection_restore_to_history_event_state (EEditorPage *editor_page,
a00a81
+                                                       EEditorSelection selection_state)
a00a81
+{
a00a81
+	WebKitDOMDocument *document;
a00a81
+	WebKitDOMDOMWindow *dom_window = NULL;
a00a81
+	WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
+	WebKitDOMElement *element, *tmp;
a00a81
+	WebKitDOMRange *range = NULL;
a00a81
+	gboolean was_collapsed = FALSE;
a00a81
+
a00a81
+	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
+
a00a81
+	document = e_editor_page_get_document (editor_page);
a00a81
+	dom_window = webkit_dom_document_get_default_view (document);
a00a81
+	dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
+	g_clear_object (&dom_window);
a00a81
+
a00a81
+	/* Restore the selection how it was before the event occured. */
a00a81
+	range = e_editor_dom_get_range_for_point (document, selection_state.start);
a00a81
+	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
+	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
+	g_clear_object (&range);
a00a81
+
a00a81
+	was_collapsed = selection_state.start.x == selection_state.end.x;
a00a81
+	was_collapsed = was_collapsed && selection_state.start.y == selection_state.end.y;
a00a81
+	if (was_collapsed) {
a00a81
+		g_clear_object (&dom_selection);
a00a81
+		return;
a00a81
+	}
a00a81
+
a00a81
+	e_editor_dom_selection_save (editor_page);
a00a81
+
a00a81
+	element = webkit_dom_document_get_element_by_id (
a00a81
+		document, "-x-evo-selection-end-marker");
a00a81
+
a00a81
+	remove_node (WEBKIT_DOM_NODE (element));
a00a81
+
a00a81
+	element = webkit_dom_document_get_element_by_id (
a00a81
+		document, "-x-evo-selection-start-marker");
a00a81
+
a00a81
+	webkit_dom_element_remove_attribute (element, "id");
a00a81
+
a00a81
+	range = e_editor_dom_get_range_for_point (document, selection_state.end);
a00a81
+	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
+	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
+	g_clear_object (&range);
a00a81
+
a00a81
+	e_editor_dom_selection_save (editor_page);
a00a81
+
a00a81
+	tmp = webkit_dom_document_get_element_by_id (
a00a81
+		document, "-x-evo-selection-start-marker");
a00a81
+
a00a81
+	remove_node (WEBKIT_DOM_NODE (tmp));
a00a81
+
a00a81
+	webkit_dom_element_set_id (
a00a81
+		element, "-x-evo-selection-start-marker");
a00a81
+
a00a81
+	e_editor_dom_selection_restore (editor_page);
a00a81
+
a00a81
+	g_clear_object (&dom_selection);
a00a81
+}
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-dom-functions.h	2017-03-24 15:12:21.898422514 +0100
a00a81
@@ -24,6 +24,7 @@
a00a81
 #undef E_UTIL_INCLUDE_WITHOUT_WEBKIT
a00a81
 
a00a81
 #include "e-editor-page.h"
a00a81
+#include "e-editor-undo-redo-manager.h"
a00a81
 
a00a81
 /* stephenhay from https://mathiasbynens.be/demo/url-regex */
a00a81
 #define URL_PROTOCOLS "news|telnet|nntp|file|https?|s?ftp|webcal|localhost|ssh"
a00a81
@@ -158,7 +159,6 @@ void		e_editor_dom_process_content_after
a00a81
 						(EEditorPage *editor_page);
a00a81
 guint		e_editor_dom_get_caret_offset	(EEditorPage *editor_page);
a00a81
 guint		e_editor_dom_get_caret_position	(EEditorPage *editor_page);
a00a81
-void		e_editor_dom_drag_and_drop_end	(EEditorPage *editor_page);
a00a81
 void		e_editor_dom_set_link_color	(EEditorPage *editor_page,
a00a81
 						 const gchar *color);
a00a81
 void		e_editor_dom_set_visited_link_color
a00a81
@@ -208,6 +208,8 @@ WebKitDOMElement *
a00a81
 						 WebKitDOMElement *element);
a00a81
 gint		e_editor_dom_get_citation_level	(WebKitDOMNode *node,
a00a81
 						 gboolean set_plaintext_quoted);
a00a81
+void		e_editor_dom_save_history_for_drag
a00a81
+						(EEditorPage *editor_page);
a00a81
 void		e_editor_dom_save_history_for_drop
a00a81
 						(EEditorPage *editor_page);
a00a81
 void		e_editor_dom_fix_file_uri_images
a00a81
@@ -347,6 +349,10 @@ EContentEditorAlignment
a00a81
 void		e_editor_dom_selection_set_alignment
a00a81
 						(EEditorPage *editor_page,
a00a81
 						 EContentEditorAlignment alignment);
a00a81
+void		e_editor_dom_insert_replace_all_history_event
a00a81
+						(EEditorPage *editor_page,
a00a81
+						 const gchar *search_text,
a00a81
+						 const gchar *replacement);
a00a81
 void		e_editor_dom_selection_replace	(EEditorPage *editor_page,
a00a81
 						 const gchar *replacement);
a00a81
 void		e_editor_dom_replace_caret_word	(EEditorPage *editor_page,
a00a81
@@ -370,7 +376,13 @@ void		e_editor_dom_selection_get_coordin
a00a81
 						 guint *end_y);
a00a81
 gboolean	e_editor_dom_is_selection_position_node
a00a81
 						(WebKitDOMNode *node);
a00a81
-
a00a81
+WebKitDOMRange *
a00a81
+		e_editor_dom_get_range_for_point
a00a81
+						(WebKitDOMDocument *document,
a00a81
+						 EEditorSelectionPoint point);
a00a81
+void		e_editor_dom_selection_restore_to_history_event_state
a00a81
+						(EEditorPage *editor_page,
a00a81
+						 EEditorSelection selection_state);
a00a81
 G_END_DECLS
a00a81
 
a00a81
 #endif /* E_EDITOR_DOM_FUNCTIONS_H */
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c.composer-image-insert-undo	2017-03-24 15:12:21.891422514 +0100
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.c	2017-03-24 15:12:21.899422514 +0100
a00a81
@@ -113,114 +113,19 @@ editor_undo_redo_manager_ref_editor_page
a00a81
 	return g_weak_ref_get (&manager->priv->editor_page);
a00a81
 }
a00a81
 
a00a81
-static WebKitDOMRange *
a00a81
-get_range_for_point (WebKitDOMDocument *document,
a00a81
-                     EEditorSelectionPoint point)
a00a81
-{
a00a81
-	glong scroll_left, scroll_top;
a00a81
-	WebKitDOMHTMLElement *body;
a00a81
-	WebKitDOMRange *range = NULL;
a00a81
-
a00a81
-	body = webkit_dom_document_get_body (document);
a00a81
-	scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
a00a81
-	scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
a00a81
-
a00a81
-	range = webkit_dom_document_caret_range_from_point (
a00a81
-		document, point.x - scroll_left, point.y - scroll_top);
a00a81
-
a00a81
-	/* The point is outside the viewport, scroll to it. */
a00a81
-	if (!range) {
a00a81
-		WebKitDOMDOMWindow *dom_window = NULL;
a00a81
-
a00a81
-		dom_window = webkit_dom_document_get_default_view (document);
a00a81
-		webkit_dom_dom_window_scroll_to (dom_window, point.x, point.y);
a00a81
-
a00a81
-		scroll_left = webkit_dom_element_get_scroll_left (WEBKIT_DOM_ELEMENT (body));
a00a81
-		scroll_top = webkit_dom_element_get_scroll_top (WEBKIT_DOM_ELEMENT (body));
a00a81
-		range = webkit_dom_document_caret_range_from_point (
a00a81
-			document, point.x - scroll_left, point.y - scroll_top);
a00a81
-		g_clear_object (&dom_window);
a00a81
-	}
a00a81
-
a00a81
-	return range;
a00a81
-}
a00a81
-
a00a81
-static void
a00a81
-restore_selection_to_history_event_state (EEditorPage *editor_page,
a00a81
-                                          EEditorSelection selection_state)
a00a81
-{
a00a81
-	WebKitDOMDocument *document;
a00a81
-	WebKitDOMDOMWindow *dom_window = NULL;
a00a81
-	WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
-	WebKitDOMElement *element, *tmp;
a00a81
-	WebKitDOMRange *range = NULL;
a00a81
-	gboolean was_collapsed = FALSE;
a00a81
-
a00a81
-	g_return_if_fail (E_IS_EDITOR_PAGE (editor_page));
a00a81
-
a00a81
-	document = e_editor_page_get_document (editor_page);
a00a81
-	dom_window = webkit_dom_document_get_default_view (document);
a00a81
-	dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
-	g_clear_object (&dom_window);
a00a81
-
a00a81
-	/* Restore the selection how it was before the event occured. */
a00a81
-	range = get_range_for_point (document, selection_state.start);
a00a81
-	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
-	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
-	g_clear_object (&range);
a00a81
-
a00a81
-	was_collapsed = selection_state.start.x == selection_state.end.x;
a00a81
-	was_collapsed = was_collapsed && selection_state.start.y == selection_state.end.y;
a00a81
-	if (was_collapsed) {
a00a81
-		g_clear_object (&dom_selection);
a00a81
-		return;
a00a81
-	}
a00a81
-
a00a81
-	e_editor_dom_selection_save (editor_page);
a00a81
-
a00a81
-	element = webkit_dom_document_get_element_by_id (
a00a81
-		document, "-x-evo-selection-end-marker");
a00a81
-
a00a81
-	remove_node (WEBKIT_DOM_NODE (element));
a00a81
-
a00a81
-	element = webkit_dom_document_get_element_by_id (
a00a81
-		document, "-x-evo-selection-start-marker");
a00a81
-
a00a81
-	webkit_dom_element_remove_attribute (element, "id");
a00a81
-
a00a81
-	range = get_range_for_point (document, selection_state.end);
a00a81
-	webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
-	webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
-	g_clear_object (&range);
a00a81
-
a00a81
-	e_editor_dom_selection_save (editor_page);
a00a81
-
a00a81
-	tmp = webkit_dom_document_get_element_by_id (
a00a81
-		document, "-x-evo-selection-start-marker");
a00a81
-
a00a81
-	remove_node (WEBKIT_DOM_NODE (tmp));
a00a81
-
a00a81
-	webkit_dom_element_set_id (
a00a81
-		element, "-x-evo-selection-start-marker");
a00a81
-
a00a81
-	e_editor_dom_selection_restore (editor_page);
a00a81
-
a00a81
-	g_clear_object (&dom_selection);
a00a81
-}
a00a81
-
a00a81
 static void
a00a81
 print_node_inner_html (WebKitDOMNode *node)
a00a81
 {
a00a81
 	gchar *inner_html;
a00a81
 
a00a81
 	if (!node) {
a00a81
-		printf ("    none\n");
a00a81
+		printf ("    content: none\n");
a00a81
 		return;
a00a81
 	}
a00a81
 
a00a81
 	inner_html = dom_get_node_inner_html (node);
a00a81
 
a00a81
-	printf ("    '%s'\n", inner_html);
a00a81
+	printf ("    content: '%s'\n", inner_html);
a00a81
 
a00a81
 	g_free (inner_html);
a00a81
 }
a00a81
@@ -230,14 +135,22 @@ print_history_event (EEditorHistoryEvent
a00a81
 {
a00a81
 	if (event->type != HISTORY_START && event->type != HISTORY_AND) {
a00a81
 		printf ("  %s\n", event_type_string[event->type]);
a00a81
-		printf ("    before: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u ;\n",
a00a81
+		printf ("    before: start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u\n",
a00a81
 			event->before.start.x, event->before.start.y, event->before.end.x, event->before.end.y);
a00a81
-		printf ("    after:  start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u ;\n",
a00a81
+		printf ("    after:  start_x: %u ; start_y: %u ; end_x: %u ; end_y: %u\n",
a00a81
 			event->after.start.x, event->after.start.y, event->after.end.x, event->after.end.y);
a00a81
 	}
a00a81
 	switch (event->type) {
a00a81
 		case HISTORY_DELETE:
a00a81
+			if (g_object_get_data (G_OBJECT (event->data.fragment), "history-delete-key")) {
a00a81
+				printf ("    type: delete\n");
a00a81
+			} else
a00a81
+				printf ("    type: backspace\n");
a00a81
+			if (g_object_get_data (G_OBJECT (event->data.fragment), "history-control-key"))
a00a81
+				printf ("          control\n");
a00a81
 		case HISTORY_INPUT:
a00a81
+			if (g_object_get_data (G_OBJECT (event->data.fragment), "history-return-key"))
a00a81
+				printf ("    type: return\n");
a00a81
 		case HISTORY_REMOVE_LINK:
a00a81
 		case HISTORY_SMILEY:
a00a81
 		case HISTORY_IMAGE:
a00a81
@@ -254,13 +167,13 @@ print_history_event (EEditorHistoryEvent
a00a81
 		case HISTORY_UNDERLINE:
a00a81
 		case HISTORY_STRIKETHROUGH:
a00a81
 		case HISTORY_WRAP:
a00a81
-			printf ("    from %d to %d ;\n", event->data.style.from, event->data.style.to);
a00a81
+			printf ("    from %d to %d\n", event->data.style.from, event->data.style.to);
a00a81
 			break;
a00a81
 		case HISTORY_PASTE:
a00a81
 		case HISTORY_PASTE_AS_TEXT:
a00a81
 		case HISTORY_PASTE_QUOTED:
a00a81
 		case HISTORY_INSERT_HTML:
a00a81
-			printf ("    pasting: '%s' ; \n", event->data.string.to);
a00a81
+			printf ("    pasting: '%s' \n", event->data.string.to);
a00a81
 			break;
a00a81
 		case HISTORY_HRULE_DIALOG:
a00a81
 		case HISTORY_IMAGE_DIALOG:
a00a81
@@ -275,7 +188,7 @@ print_history_event (EEditorHistoryEvent
a00a81
 		case HISTORY_FONT_COLOR:
a00a81
 		case HISTORY_REPLACE:
a00a81
 		case HISTORY_REPLACE_ALL:
a00a81
-			printf ("    from '%s' to '%s';\n", event->data.string.from, event->data.string.to);
a00a81
+			printf ("    from '%s' to '%s'\n", event->data.string.from, event->data.string.to);
a00a81
 			break;
a00a81
 		case HISTORY_START:
a00a81
 			printf ("  HISTORY START\n");
a00a81
@@ -454,7 +367,7 @@ undo_delete (EEditorPage *editor_page,
a00a81
 	     g_object_get_data (G_OBJECT (event->data.fragment), "history-concatenating-blocks")) {
a00a81
 		WebKitDOMNode *node, *block;
a00a81
 
a00a81
-		range = get_range_for_point (document, event->after.start);
a00a81
+		range = e_editor_dom_get_range_for_point (document, event->after.start);
a00a81
 		webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 		webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
 
a00a81
@@ -528,7 +441,7 @@ undo_delete (EEditorPage *editor_page,
a00a81
 		g_clear_object (&range);
a00a81
 		g_clear_object (&dom_selection);
a00a81
 
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 		e_editor_dom_force_spell_check_in_viewport (editor_page);
a00a81
 
a00a81
@@ -544,7 +457,7 @@ undo_delete (EEditorPage *editor_page,
a00a81
 			WebKitDOMElement *element;
a00a81
 			WebKitDOMNode *next_sibling;
a00a81
 
a00a81
-			range = get_range_for_point (document, event->before.start);
a00a81
+			range = e_editor_dom_get_range_for_point (document, event->before.start);
a00a81
 			webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 			webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
 			g_clear_object (&range);
a00a81
@@ -598,7 +511,7 @@ undo_delete (EEditorPage *editor_page,
a00a81
 		WebKitDOMNode *node, *current_block, *last_child;
a00a81
 		WebKitDOMNode *next_block, *insert_before;
a00a81
 
a00a81
-		range = get_range_for_point (document, event->after.start);
a00a81
+		range = e_editor_dom_get_range_for_point (document, event->after.start);
a00a81
 		webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 		webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
 		g_clear_object (&range);
a00a81
@@ -698,7 +611,7 @@ undo_delete (EEditorPage *editor_page,
a00a81
 
a00a81
 				dom_remove_selection_markers (document);
a00a81
 
a00a81
-				restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+				e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 				e_editor_dom_force_spell_check_in_viewport (editor_page);
a00a81
 
a00a81
@@ -794,9 +707,9 @@ undo_delete (EEditorPage *editor_page,
a00a81
 
a00a81
 		/* Create temporary node on the selection where the delete occured. */
a00a81
 		if (webkit_dom_document_fragment_query_selector (event->data.fragment, ".Apple-tab-span", NULL))
a00a81
-			range = get_range_for_point (document, event->before.start);
a00a81
+			range = e_editor_dom_get_range_for_point (document, event->before.start);
a00a81
 		else
a00a81
-			range = get_range_for_point (document, event->after.start);
a00a81
+			range = e_editor_dom_get_range_for_point (document, event->after.start);
a00a81
 
a00a81
 		/* If redoing an INPUT event that was done in the middle of the
a00a81
 		 * text we need to move one character backward as the range is
a00a81
@@ -940,7 +853,7 @@ undo_delete (EEditorPage *editor_page,
a00a81
 		if (webkit_dom_document_fragment_query_selector (event->data.fragment, "span#-x-evo-selection-start-marker", NULL))
a00a81
 			e_editor_dom_selection_restore (editor_page);
a00a81
 		else
a00a81
-			restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+			e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 		if (event->type != HISTORY_INPUT) {
a00a81
 			if (e_editor_page_get_magic_smileys_enabled (editor_page))
a00a81
@@ -966,7 +879,7 @@ redo_delete (EEditorPage *editor_page,
a00a81
 	gint ii;
a00a81
 
a00a81
 	manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
-	restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 	delete_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment), "history-delete-key"));
a00a81
 	control_key = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (event->data.fragment), "history-control-key"));
a00a81
@@ -1048,7 +961,7 @@ redo_delete (EEditorPage *editor_page,
a00a81
 	e_editor_dom_body_key_up_event_process_backspace_or_delete (editor_page, delete_key);
a00a81
 	e_editor_page_set_renew_history_after_coordinates (editor_page, TRUE);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
 
a00a81
 	e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
a00a81
 }
a00a81
@@ -1091,11 +1004,11 @@ undo_redo_style_change (EEditorPage *edi
a00a81
 			return;
a00a81
 	}
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	func (editor_page, undo ? event->data.style.from : event->data.style.to);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1105,7 +1018,7 @@ undo_redo_indent (EEditorPage *editor_pa
a00a81
 {
a00a81
 	gboolean was_indent = FALSE;
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	was_indent = event->data.style.from && event->data.style.to;
a00a81
 
a00a81
@@ -1114,7 +1027,7 @@ undo_redo_indent (EEditorPage *editor_pa
a00a81
 	else
a00a81
 		e_editor_dom_selection_indent (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1122,13 +1035,13 @@ undo_redo_font_color (EEditorPage *edito
a00a81
                       EEditorHistoryEvent *event,
a00a81
                       gboolean undo)
a00a81
 {
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	e_editor_dom_exec_command (editor_page,
a00a81
 		E_CONTENT_EDITOR_COMMAND_FORE_COLOR,
a00a81
 		undo ? event->data.string.from : event->data.string.to);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1136,7 +1049,7 @@ undo_redo_wrap (EEditorPage *editor_page
a00a81
                 EEditorHistoryEvent *event,
a00a81
                 gboolean undo)
a00a81
 {
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	if (undo) {
a00a81
 		WebKitDOMNode *node;
a00a81
@@ -1154,7 +1067,7 @@ undo_redo_wrap (EEditorPage *editor_page
a00a81
 	} else
a00a81
 		e_editor_dom_selection_wrap (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1170,7 +1083,7 @@ undo_redo_page_dialog (EEditorPage *edit
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 	body = webkit_dom_document_get_body (document);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	if (undo) {
a00a81
 		attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
a00a81
@@ -1249,7 +1162,7 @@ undo_redo_page_dialog (EEditorPage *edit
a00a81
 	g_clear_object (&attributes);
a00a81
 	g_clear_object (&attributes_history);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1262,7 +1175,7 @@ undo_redo_hrule_dialog (EEditorPage *edi
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	e_editor_dom_selection_save (editor_page);
a00a81
 	element = webkit_dom_document_get_element_by_id (
a00a81
@@ -1314,7 +1227,7 @@ undo_redo_hrule_dialog (EEditorPage *edi
a00a81
 
a00a81
 	if (undo) {
a00a81
 		dom_remove_selection_markers (document);
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 	} else
a00a81
 		e_editor_dom_selection_restore (editor_page);
a00a81
 }
a00a81
@@ -1330,7 +1243,7 @@ undo_redo_image_dialog (EEditorPage *edi
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	e_editor_dom_selection_save (editor_page);
a00a81
 	element = webkit_dom_document_get_element_by_id (
a00a81
@@ -1364,7 +1277,7 @@ undo_redo_image_dialog (EEditorPage *edi
a00a81
 		NULL);
a00a81
 
a00a81
 	if (undo)
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 	else
a00a81
 		e_editor_dom_selection_restore (editor_page);
a00a81
 }
a00a81
@@ -1379,7 +1292,7 @@ undo_redo_link_dialog (EEditorPage *edit
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	e_editor_dom_selection_save (editor_page);
a00a81
 
a00a81
@@ -1425,7 +1338,7 @@ undo_redo_link_dialog (EEditorPage *edit
a00a81
 	}
a00a81
 
a00a81
 	if (undo)
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 	else
a00a81
 		e_editor_dom_selection_restore (editor_page);
a00a81
 }
a00a81
@@ -1440,7 +1353,7 @@ undo_redo_table_dialog (EEditorPage *edi
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	e_editor_dom_selection_save (editor_page);
a00a81
 	element = webkit_dom_document_get_element_by_id (document, "-x-evo-selection-start-marker");
a00a81
@@ -1459,7 +1372,7 @@ undo_redo_table_dialog (EEditorPage *edi
a00a81
 				webkit_dom_node_clone_node_with_error (undo ? event->data.dom.from : event->data.dom.to, TRUE, NULL),
a00a81
 				WEBKIT_DOM_NODE (parent),
a00a81
 				NULL);
a00a81
-			restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+			e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 			return;
a00a81
 		} else
a00a81
 			return;
a00a81
@@ -1486,7 +1399,7 @@ undo_redo_table_dialog (EEditorPage *edi
a00a81
 	}
a00a81
 
a00a81
 	if (undo)
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 	else
a00a81
 		e_editor_dom_selection_restore (editor_page);
a00a81
 }
a00a81
@@ -1505,7 +1418,7 @@ undo_redo_table_input (EEditorPage *edit
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	dom_window = webkit_dom_document_get_default_view (document);
a00a81
 	dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
@@ -1554,7 +1467,7 @@ undo_redo_paste (EEditorPage *editor_pag
a00a81
 			WebKitDOMElement *tmp;
a00a81
 			WebKitDOMNode *parent;
a00a81
 
a00a81
-			restore_selection_to_history_event_state (editor_page, event->after);
a00a81
+			e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
 
a00a81
 			e_editor_dom_selection_save (editor_page);
a00a81
 			tmp = webkit_dom_document_get_element_by_id (
a00a81
@@ -1573,7 +1486,9 @@ undo_redo_paste (EEditorPage *editor_pag
a00a81
 				NULL);
a00a81
 
a00a81
 			e_editor_dom_selection_restore (editor_page);
a00a81
-		} else {
a00a81
+		} else if (event->after.start.x == event->after.end.x &&
a00a81
+		           event->after.start.y == event->after.end.y) {
a00a81
+			/* Selection was collapsed after the event */
a00a81
 			WebKitDOMDOMWindow *dom_window = NULL;
a00a81
 			WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
 			WebKitDOMElement *element, *tmp;
a00a81
@@ -1583,8 +1498,8 @@ undo_redo_paste (EEditorPage *editor_pag
a00a81
 			dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
 			g_clear_object (&dom_window);
a00a81
 
a00a81
-			/* Restore the selection how it was before the event occured. */
a00a81
-			range = get_range_for_point (document, event->before.start);
a00a81
+			/* Restore the selection how it was before the event occurred. */
a00a81
+			range = e_editor_dom_get_range_for_point (document, event->before.start);
a00a81
 			webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 			webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
 			g_clear_object (&range);
a00a81
@@ -1601,7 +1516,7 @@ undo_redo_paste (EEditorPage *editor_pag
a00a81
 
a00a81
 			webkit_dom_element_remove_attribute (element, "id");
a00a81
 
a00a81
-			range = get_range_for_point (document, event->after.start);
a00a81
+			range = e_editor_dom_get_range_for_point (document, event->after.start);
a00a81
 			webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 			webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
 			g_clear_object (&range);
a00a81
@@ -1622,9 +1537,15 @@ undo_redo_paste (EEditorPage *editor_pag
a00a81
 			e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
a00a81
 
a00a81
 			e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
a00a81
+		} else {
a00a81
+			e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
+
a00a81
+			e_editor_dom_exec_command (editor_page, E_CONTENT_EDITOR_COMMAND_DELETE, NULL);
a00a81
+
a00a81
+			e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
a00a81
 		}
a00a81
 	} else {
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 		if (event->type == HISTORY_PASTE)
a00a81
 			e_editor_dom_convert_and_insert_html_into_selection (editor_page, event->data.string.to, FALSE);
a00a81
@@ -1635,6 +1556,8 @@ undo_redo_paste (EEditorPage *editor_pag
a00a81
 		else
a00a81
 			e_editor_dom_convert_and_insert_html_into_selection (editor_page, event->data.string.to, FALSE);
a00a81
 			/* e_editor_selection_insert_as_text (selection, event->data.string.to); */
a00a81
+
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
 	}
a00a81
 }
a00a81
 
a00a81
@@ -1657,7 +1580,7 @@ undo_redo_image (EEditorPage *editor_pag
a00a81
 		WebKitDOMElement *element;
a00a81
 		WebKitDOMNode *node;
a00a81
 
a00a81
-		range = get_range_for_point (document, event->before.start);
a00a81
+		range = e_editor_dom_get_range_for_point (document, event->before.start);
a00a81
 		webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 		webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
 		g_clear_object (&range);
a00a81
@@ -1668,15 +1591,24 @@ undo_redo_image (EEditorPage *editor_pag
a00a81
 
a00a81
 		node = webkit_dom_node_get_next_sibling  (WEBKIT_DOM_NODE (element));
a00a81
 
a00a81
-		if (WEBKIT_DOM_IS_ELEMENT (node))
a00a81
+		if (WEBKIT_DOM_IS_ELEMENT (node)) {
a00a81
 			if (element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-resizable-wrapper") ||
a00a81
 			    element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-smiley-wrapper"))
a00a81
 				remove_node (node);
a00a81
+			else if (WEBKIT_DOM_IS_HTML_IMAGE_ELEMENT (node)) {
a00a81
+				WebKitDOMNode *parent;
a00a81
+
a00a81
+				parent = webkit_dom_node_get_parent_node (node);
a00a81
+				if (element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-resizable-wrapper") ||
a00a81
+				    element_has_class (WEBKIT_DOM_ELEMENT (parent), "-x-evo-smiley-wrapper"))
a00a81
+					remove_node (parent);
a00a81
+			}
a00a81
+		}
a00a81
 		e_editor_dom_selection_restore (editor_page);
a00a81
 	} else {
a00a81
 		WebKitDOMElement *element;
a00a81
 
a00a81
-		range = get_range_for_point (document, event->before.start);
a00a81
+		range = e_editor_dom_get_range_for_point (document, event->before.start);
a00a81
 		/* Create temporary node on the selection where the delete occured. */
a00a81
 		webkit_dom_dom_selection_remove_all_ranges (dom_selection);
a00a81
 		webkit_dom_dom_selection_add_range (dom_selection, range);
a00a81
@@ -1709,9 +1641,10 @@ undo_redo_replace (EEditorPage *editor_p
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	if (undo) {
a00a81
+		gint ii = 0;
a00a81
 		WebKitDOMDOMWindow *dom_window = NULL;
a00a81
 		WebKitDOMDOMSelection *dom_selection = NULL;
a00a81
 
a00a81
@@ -1719,7 +1652,9 @@ undo_redo_replace (EEditorPage *editor_p
a00a81
 		dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
 		g_clear_object (&dom_window);
a00a81
 
a00a81
-		webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "word");
a00a81
+		for (ii = g_utf8_strlen (event->data.string.to, -1); ii--;)
a00a81
+			webkit_dom_dom_selection_modify (dom_selection, "extend", "left", "character");
a00a81
+
a00a81
 		g_clear_object (&dom_selection);
a00a81
 	}
a00a81
 
a00a81
@@ -1729,7 +1664,7 @@ undo_redo_replace (EEditorPage *editor_p
a00a81
 
a00a81
 	e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1828,7 +1763,7 @@ undo_redo_remove_link (EEditorPage *edit
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	if (undo) {
a00a81
 		WebKitDOMDOMWindow *dom_window = NULL;
a00a81
@@ -1857,7 +1792,7 @@ undo_redo_remove_link (EEditorPage *edit
a00a81
 	} else
a00a81
 		e_editor_dom_selection_unlink (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->before : event->after);
a00a81
 }
a00a81
 
a00a81
 static void
a00a81
@@ -1916,7 +1851,7 @@ undo_return_press_after_h_rule (EEditorP
a00a81
 	     WEBKIT_DOM_IS_HTML_HR_ELEMENT (node)) {
a00a81
 
a00a81
 		remove_node_if_empty (WEBKIT_DOM_NODE (block));
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 		return TRUE;
a00a81
 	}
a00a81
@@ -1939,7 +1874,7 @@ undo_input (EEditorUndoRedoManager *mana
a00a81
 	dom_window = webkit_dom_document_get_default_view (document);
a00a81
 	dom_selection = webkit_dom_dom_window_get_selection (dom_window);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, event->after);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
 
a00a81
 	/* Undoing Return press after the HR element */
a00a81
 	if (e_editor_page_get_html_mode (editor_page) &&
a00a81
@@ -2053,7 +1988,7 @@ undo_redo_citation_split (EEditorPage *e
a00a81
 		WebKitDOMElement *selection_start, *parent;
a00a81
 		WebKitDOMNode *citation_before, *citation_after, *child, *last_child, *tmp;
a00a81
 
a00a81
-		restore_selection_to_history_event_state (editor_page, event->after);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
 
a00a81
 		e_editor_dom_selection_save (editor_page);
a00a81
 		selection_start = webkit_dom_document_get_element_by_id (
a00a81
@@ -2137,11 +2072,11 @@ undo_redo_citation_split (EEditorPage *e
a00a81
  out:
a00a81
 		e_editor_dom_merge_siblings_if_necessary (editor_page, NULL);
a00a81
 
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 		e_editor_dom_force_spell_check_in_viewport (editor_page);
a00a81
 	} else {
a00a81
-		restore_selection_to_history_event_state (editor_page, event->before);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->before);
a00a81
 
a00a81
 		if (in_situ) {
a00a81
 			WebKitDOMElement *selection_start_marker;
a00a81
@@ -2176,7 +2111,7 @@ undo_redo_unquote (EEditorPage *editor_p
a00a81
 
a00a81
 	document = e_editor_page_get_document (editor_page);
a00a81
 
a00a81
-	restore_selection_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
+	e_editor_dom_selection_restore_to_history_event_state (editor_page, undo ? event->after : event->before);
a00a81
 
a00a81
 	e_editor_dom_selection_save (editor_page);
a00a81
 	element = webkit_dom_document_get_element_by_id (
a00a81
@@ -2221,7 +2156,7 @@ undo_redo_unquote (EEditorPage *editor_p
a00a81
 	if (undo)
a00a81
 		e_editor_dom_selection_restore (editor_page);
a00a81
 	else
a00a81
-		restore_selection_to_history_event_state (editor_page, event->after);
a00a81
+		e_editor_dom_selection_restore_to_history_event_state (editor_page, event->after);
a00a81
 
a00a81
 	e_editor_dom_force_spell_check_for_current_paragraph (editor_page);
a00a81
 }
a00a81
@@ -2366,6 +2301,21 @@ e_editor_undo_redo_manager_get_current_h
a00a81
 	return NULL;
a00a81
 }
a00a81
 
a00a81
+EEditorHistoryEvent *
a00a81
+e_editor_undo_redo_manager_get_next_history_event_for (EEditorUndoRedoManager *manager,
a00a81
+                                                       EEditorHistoryEvent *event)
a00a81
+{
a00a81
+	g_return_val_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager), NULL);
a00a81
+
a00a81
+	if (manager->priv->history) {
a00a81
+		GList *item = g_list_find (manager->priv->history, event);
a00a81
+		if (item && item->next)
a00a81
+			return item->next->data;
a00a81
+	}
a00a81
+
a00a81
+	return NULL;
a00a81
+}
a00a81
+
a00a81
 void
a00a81
 e_editor_undo_redo_manager_remove_current_history_event (EEditorUndoRedoManager *manager)
a00a81
 {
a00a81
@@ -2458,6 +2408,85 @@ e_editor_undo_redo_manager_insert_dash_h
a00a81
 	}
a00a81
 
a00a81
 	g_object_unref (editor_page);
a00a81
+}
a00a81
+
a00a81
+static void
a00a81
+copy_event_coordinates_to_event (EEditorHistoryEvent *source,
a00a81
+                                 EEditorHistoryEvent *target)
a00a81
+{
a00a81
+	target->before.start.x = source->before.start.x;
a00a81
+	target->before.start.y = source->before.start.y;
a00a81
+	target->before.end.x = source->before.end.x;
a00a81
+	target->before.end.y = source->before.end.y;
a00a81
+	target->after.start.x = source->after.start.x;
a00a81
+	target->after.start.y = source->after.start.y;
a00a81
+	target->after.end.x = source->after.end.x;
a00a81
+	target->after.end.y = source->after.end.y;
a00a81
+}
a00a81
+
a00a81
+void
a00a81
+e_editor_undo_redo_manager_last_drop_operation_did_copy (EEditorUndoRedoManager *manager)
a00a81
+{
a00a81
+	EEditorPage *editor_page;
a00a81
+	GList *history;
a00a81
+
a00a81
+	g_return_if_fail (E_IS_EDITOR_UNDO_REDO_MANAGER (manager));
a00a81
+
a00a81
+	editor_page = editor_undo_redo_manager_ref_editor_page (manager);
a00a81
+	g_return_if_fail (editor_page != NULL);
a00a81
+
a00a81
+	history = manager->priv->history;
a00a81
+	if (history) {
a00a81
+		GList *history_and, *history_delete;
a00a81
+		EEditorHistoryEvent *original_insert, *item;
a00a81
+		WebKitDOMDocumentFragment *fragment;
a00a81
+
a00a81
+		/* When a drag operation within an editor is performed, we save
a00a81
+		 * the history for it. We always assume that the drop will move
a00a81
+		 * the content (the default action) and not copy it, thus the
a00a81
+		 * history contains one delete item and one 'and' item. If the
a00a81
+		 * action is changed to copy (by holding the Control key during
a00a81
+		 * drop) there is not content deleted, but we saved it to the
a00a81
+		 * history. What this function does is that it changes the
a00a81
+		 * history to not delete any content, but to only insert the
a00a81
+		 * dropped one. */
a00a81
+		original_insert = history->data;
a00a81
+		if (original_insert->type != HISTORY_INSERT_HTML || !history->next) {
a00a81
+			g_object_unref (editor_page);
a00a81
+			return;
a00a81
+		}
a00a81
+
a00a81
+		history_and = history->next;
a00a81
+		item = history_and->data;
a00a81
+		if (item->type != HISTORY_AND || !history_and->next) {
a00a81
+			g_object_unref (editor_page);
a00a81
+			return;
a00a81
+		}
a00a81
+
a00a81
+		history_delete = history_and->next;
a00a81
+		item = history_delete->data;
a00a81
+		if (item->type != HISTORY_DELETE) {
a00a81
+			g_object_unref (editor_page);
a00a81
+			return;
a00a81
+		}
a00a81
+
a00a81
+		/* Change the history type from 'Delete' to 'Insert' */
a00a81
+		item->type = HISTORY_INSERT_HTML;
a00a81
+		copy_event_coordinates_to_event (original_insert, item);
a00a81
+
a00a81
+		/* Copy the content */
a00a81
+		fragment = item->data.fragment;
a00a81
+		item->data.fragment = NULL;
a00a81
+		item->data.string.to = dom_get_node_inner_html (WEBKIT_DOM_NODE (fragment));
a00a81
+		g_clear_object (&fragment);
a00a81
+
a00a81
+		/* Remove the old insert event */
a00a81
+		remove_history_event (manager, manager->priv->history);
a00a81
+		/* And the 'AND' event */
a00a81
+		remove_history_event (manager, manager->priv->history);
a00a81
+	}
a00a81
+
a00a81
+	g_object_unref (editor_page);
a00a81
 }
a00a81
 
a00a81
 gboolean
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h.composer-image-insert-undo	2016-09-19 10:22:58.000000000 +0200
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-undo-redo-manager.h	2017-03-24 15:12:21.899422514 +0100
a00a81
@@ -151,12 +151,21 @@ void		e_editor_undo_redo_manager_insert_
a00a81
 EEditorHistoryEvent *
a00a81
 		e_editor_undo_redo_manager_get_current_history_event
a00a81
 						(EEditorUndoRedoManager *manager);
a00a81
+
a00a81
+EEditorHistoryEvent *
a00a81
+		e_editor_undo_redo_manager_get_next_history_event_for
a00a81
+						(EEditorUndoRedoManager *manager,
a00a81
+						 EEditorHistoryEvent *event);
a00a81
+
a00a81
 void		e_editor_undo_redo_manager_remove_current_history_event
a00a81
 						(EEditorUndoRedoManager *manager);
a00a81
 
a00a81
 void		e_editor_undo_redo_manager_insert_dash_history_event
a00a81
 						(EEditorUndoRedoManager *manager);
a00a81
 
a00a81
+void		e_editor_undo_redo_manager_last_drop_operation_did_copy
a00a81
+						(EEditorUndoRedoManager *manager);
a00a81
+
a00a81
 gboolean	e_editor_undo_redo_manager_can_undo
a00a81
 						(EEditorUndoRedoManager *manager);
a00a81
 
a00a81
diff -up evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c.composer-image-insert-undo evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c
a00a81
--- evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c.composer-image-insert-undo	2017-03-13 11:24:55.000000000 +0100
a00a81
+++ evolution-3.22.6/modules/webkit-editor/web-extension/e-editor-web-extension.c	2017-03-24 15:13:16.839420073 +0100
a00a81
@@ -480,9 +480,6 @@ static const gchar *introspection_xml =
a00a81
 "      <arg type='s' name='selector' direction='in'/>"
a00a81
 "      <arg type='s' name='uri' direction='in'/>"
a00a81
 "    </method>"
a00a81
-"    <method name='DOMDragAndDropEnd'>"
a00a81
-"      <arg type='t' name='page_id' direction='in'/>"
a00a81
-"    </method>"
a00a81
 "    <method name='DOMMoveSelectionOnPoint'>"
a00a81
 "      <arg type='t' name='page_id' direction='in'/>"
a00a81
 "      <arg type='i' name='x' direction='in'/>"
a00a81
@@ -493,6 +490,9 @@ static const gchar *introspection_xml =
a00a81
 "      <arg type='t' name='page_id' direction='in'/>"
a00a81
 "      <arg type='s' name='smiley_name' direction='in'/>"
a00a81
 "    </method>"
a00a81
+"    <method name='DOMLastDropOperationDidCopy'>"
a00a81
+"      <arg type='t' name='page_id' direction='in'/>"
a00a81
+"    </method>"
a00a81
 ""
a00a81
 ""
a00a81
 ""
a00a81
@@ -503,6 +503,11 @@ static const gchar *introspection_xml =
a00a81
 "      <arg type='t' name='page_id' direction='in'/>"
a00a81
 "      <arg type='s' name='uri' direction='in'/>"
a00a81
 "    </method>"
a00a81
+"    <method name='DOMInsertReplaceAllHistoryEvent'>"
a00a81
+"      <arg type='t' name='page_id' direction='in'/>"
a00a81
+"      <arg type='s' name='search_text' direction='in'/>"
a00a81
+"      <arg type='s' name='replacement' direction='in'/>"
a00a81
+"    </method>"
a00a81
 "    <method name='DOMSelectionReplace'>"
a00a81
 "      <arg type='t' name='page_id' direction='in'/>"
a00a81
 "      <arg type='s' name='replacement' direction='in'/>"
a00a81
@@ -581,12 +586,6 @@ static const gchar *introspection_xml =
a00a81
 "      <arg type='b' name='out_check_if_signature_is_changed' direction='out'/>"
a00a81
 "      <arg type='b' name='out_ignore_next_signature_change' direction='out'/>"
a00a81
 "    </method>"
a00a81
-"    <method name='DOMSaveDragAndDropHistory'>"
a00a81
-"      <arg type='t' name='page_id' direction='in'/>"
a00a81
-"    </method>"
a00a81
-"    <method name='DOMCleanAfterDragAndDrop'>"
a00a81
-"      <arg type='t' name='page_id' direction='in'/>"
a00a81
-"    </method>"
a00a81
 "    <method name='DOMGetActiveSignatureUid'>"
a00a81
 "      <arg type='t' name='page_id' direction='in'/>"
a00a81
 "      <arg type='s' name='uid' direction='out'/>"
a00a81
@@ -1859,15 +1858,6 @@ handle_method_call (GDBusConnection *con
a00a81
 		e_editor_dom_replace_image_src (editor_page, selector, uri);
a00a81
 
a00a81
 		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
-	} else if (g_strcmp0 (method_name, "DOMDragAndDropEnd") == 0) {
a00a81
-		g_variant_get (parameters, "(t)", &page_id);
a00a81
-
a00a81
-		editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
a00a81
-		if (!editor_page)
a00a81
-			goto error;
a00a81
-
a00a81
-		e_editor_dom_drag_and_drop_end (editor_page);
a00a81
-		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
 	} else if (g_strcmp0 (method_name, "DOMInsertSmiley") == 0) {
a00a81
 		const gchar *smiley_name;
a00a81
 
a00a81
@@ -1935,6 +1925,17 @@ handle_method_call (GDBusConnection *con
a00a81
 		e_editor_dom_insert_image (editor_page, uri);
a00a81
 
a00a81
 		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
+	} else if (g_strcmp0 (method_name, "DOMInsertReplaceAllHistoryEvent") == 0) {
a00a81
+		const gchar *replacement, *search_text;
a00a81
+
a00a81
+		g_variant_get (parameters, "(t&s&s)", &page_id, &search_text, &replacement);
a00a81
+
a00a81
+		editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
a00a81
+		if (!editor_page)
a00a81
+			goto error;
a00a81
+
a00a81
+		e_editor_dom_insert_replace_all_history_event (editor_page, search_text, replacement);
a00a81
+		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
 	} else if (g_strcmp0 (method_name, "DOMSelectionReplace") == 0) {
a00a81
 		const gchar *replacement;
a00a81
 
a00a81
@@ -2155,28 +2156,6 @@ handle_method_call (GDBusConnection *con
a00a81
 				ignore_next_signature_change));
a00a81
 
a00a81
 		g_free (new_signature_id);
a00a81
-	} else if (g_strcmp0 (method_name, "DOMSaveDragAndDropHistory") == 0) {
a00a81
-		g_variant_get (
a00a81
-			parameters, "(t)", &page_id);
a00a81
-
a00a81
-		editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
a00a81
-		if (!editor_page)
a00a81
-			goto error;
a00a81
-
a00a81
-		e_composer_dom_save_drag_and_drop_history (editor_page);
a00a81
-
a00a81
-		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
-	} else if (g_strcmp0 (method_name, "DOMCleanAfterDragAndDrop") == 0) {
a00a81
-		g_variant_get (
a00a81
-			parameters, "(t)", &page_id);
a00a81
-
a00a81
-		editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
a00a81
-		if (!editor_page)
a00a81
-			goto error;
a00a81
-
a00a81
-		e_composer_dom_clean_after_drag_and_drop (editor_page);
a00a81
-
a00a81
-		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
 	} else if (g_strcmp0 (method_name, "DOMGetActiveSignatureUid") == 0) {
a00a81
 		gchar *value;
a00a81
 
a00a81
@@ -2194,6 +2173,20 @@ handle_method_call (GDBusConnection *con
a00a81
 				"(@s)",
a00a81
 				g_variant_new_take_string (
a00a81
 					value ? value : g_strdup (""))));
a00a81
+	} else if (g_strcmp0 (method_name, "DOMLastDropOperationDidCopy") == 0) {
a00a81
+		EEditorUndoRedoManager *manager;
a00a81
+
a00a81
+		g_variant_get (parameters, "(t)", &page_id);
a00a81
+
a00a81
+		editor_page = get_editor_page_or_return_dbus_error (invocation, extension, page_id);
a00a81
+		if (!editor_page)
a00a81
+			goto error;
a00a81
+
a00a81
+		manager = e_editor_page_get_undo_redo_manager (editor_page);
a00a81
+		if (manager)
a00a81
+			e_editor_undo_redo_manager_last_drop_operation_did_copy (manager);
a00a81
+
a00a81
+		g_dbus_method_invocation_return_value (invocation, NULL);
a00a81
 	} else if (g_strcmp0 (method_name, "DOMGetCaretPosition") == 0) {
a00a81
 		guint32 value;
a00a81
 
a00a81
@@ -2243,7 +2236,7 @@ handle_method_call (GDBusConnection *con
a00a81
 	return;
a00a81
 
a00a81
  error:
a00a81
-	g_warning ("Cannot obtain WebKitWebPage for '%ld'", page_id);
a00a81
+	g_warning ("Cannot obtain WebKitWebPage for '%" G_GUINT64_FORMAT "'", page_id);
a00a81
 }
a00a81
 
a00a81
 static void