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