[evolution/wip/webkit2] Bug 750615 - Using Ctrl+Z in plain text composer messes up content
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution/wip/webkit2] Bug 750615 - Using Ctrl+Z in plain text composer messes up content
- Date: Thu, 25 Feb 2016 20:36:05 +0000 (UTC)
commit dd80bec9b548053e4e4a394bd1dde302c6f5a1ae
Author: Tomas Popela <tpopela redhat com>
Date: Thu Feb 25 21:01:32 2016 +0100
Bug 750615 - Using Ctrl+Z in plain text composer messes up content
.../e-html-editor-selection-dom-functions.c | 10 +-
.../e-html-editor-selection-dom-functions.h | 1 +
.../composer/e-html-editor-undo-redo-manager.c | 237 ++++++++--
.../composer/e-html-editor-view-dom-functions.c | 535 ++++++++++++++-----
.../composer/e-html-editor-view-dom-functions.h | 13 +
5 files changed, 614 insertions(+), 182 deletions(-)
---
diff --git a/web-extensions/composer/e-html-editor-selection-dom-functions.c
b/web-extensions/composer/e-html-editor-selection-dom-functions.c
index a2576bc..03918f5 100644
--- a/web-extensions/composer/e-html-editor-selection-dom-functions.c
+++ b/web-extensions/composer/e-html-editor-selection-dom-functions.c
@@ -839,8 +839,8 @@ dom_create_selection_marker (WebKitDOMDocument *document,
return element;
}
-static void
-remove_selection_markers (WebKitDOMDocument *document)
+void
+dom_remove_selection_markers (WebKitDOMDocument *document)
{
WebKitDOMElement *marker;
@@ -862,7 +862,7 @@ dom_add_selection_markers_into_element_start (WebKitDOMDocument *document,
{
WebKitDOMElement *marker;
- remove_selection_markers (document);
+ dom_remove_selection_markers (document);
marker = dom_create_selection_marker (document, FALSE);
webkit_dom_node_insert_before (
WEBKIT_DOM_NODE (element),
@@ -890,7 +890,7 @@ dom_add_selection_markers_into_element_end (WebKitDOMDocument *document,
{
WebKitDOMElement *marker;
- remove_selection_markers (document);
+ dom_remove_selection_markers (document);
marker = dom_create_selection_marker (document, TRUE);
webkit_dom_node_append_child (
WEBKIT_DOM_NODE (element), WEBKIT_DOM_NODE (marker), NULL);
@@ -1443,7 +1443,7 @@ dom_selection_save (WebKitDOMDocument *document)
WebKitDOMElement *start_marker = NULL, *end_marker = NULL;
/* First remove all markers (if present) */
- remove_selection_markers (document);
+ dom_remove_selection_markers (document);
dom_window = webkit_dom_document_get_default_view (document);
dom_selection = webkit_dom_dom_window_get_selection (dom_window);
diff --git a/web-extensions/composer/e-html-editor-selection-dom-functions.h
b/web-extensions/composer/e-html-editor-selection-dom-functions.h
index 8220bff..855b3b7 100644
--- a/web-extensions/composer/e-html-editor-selection-dom-functions.h
+++ b/web-extensions/composer/e-html-editor-selection-dom-functions.h
@@ -284,6 +284,7 @@ void dom_selection_get_coordinates (WebKitDOMDocument *document,
guint *start_y,
guint *end_x,
guint *end_y);
+void dom_remove_selection_markers (WebKitDOMDocument *document);
G_END_DECLS
#endif /* E_HTML_EDITOR_SELECTION_DOM_FUNCTIONS_H */
diff --git a/web-extensions/composer/e-html-editor-undo-redo-manager.c
b/web-extensions/composer/e-html-editor-undo-redo-manager.c
index a76eee2..ecaf56a 100644
--- a/web-extensions/composer/e-html-editor-undo-redo-manager.c
+++ b/web-extensions/composer/e-html-editor-undo-redo-manager.c
@@ -328,6 +328,61 @@ event_selection_was_collapsed (EHTMLEditorHistoryEvent *ev)
}
static void
+merge_duplicates_if_necessarry (WebKitDOMDocument *document,
+ WebKitDOMDocumentFragment *deleted_content)
+{
+ gboolean equal_nodes;
+ WebKitDOMElement *element, *prev_element;
+ WebKitDOMNode *child;
+
+ element = webkit_dom_document_query_selector (document, "blockquote + blockquote", NULL);
+ if (!element)
+ goto signature;
+
+ prev_element = WEBKIT_DOM_ELEMENT (webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (element)));
+ equal_nodes = webkit_dom_node_is_equal_node (
+ webkit_dom_node_clone_node (WEBKIT_DOM_NODE (element), FALSE),
+ webkit_dom_node_clone_node (WEBKIT_DOM_NODE (prev_element), FALSE));
+
+ if (equal_nodes) {
+ if (webkit_dom_element_get_child_element_count (element) >
+ webkit_dom_element_get_child_element_count (prev_element)) {
+ while ((child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (element))))
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (prev_element), child, NULL);
+ remove_node (WEBKIT_DOM_NODE (element));
+ } else {
+ while ((child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (prev_element))))
+ webkit_dom_node_insert_before (
+ WEBKIT_DOM_NODE (element),
+ child,
+ webkit_dom_node_get_first_child (
+ WEBKIT_DOM_NODE (element)),
+ NULL);
+ remove_node (WEBKIT_DOM_NODE (prev_element));
+ }
+ }
+
+ signature:
+ /* Replace the corrupted signatures with the right one. */
+ element = webkit_dom_document_query_selector (
+ document, ".-x-evo-signature-wrapper + .-x-evo-signature-wrapper", NULL);
+ if (element) {
+ WebKitDOMElement *right_signature;
+
+ right_signature = webkit_dom_document_fragment_query_selector (
+ deleted_content, ".-x-evo-signature-wrapper", NULL);
+ remove_node (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element)));
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+ webkit_dom_node_clone_node (WEBKIT_DOM_NODE (right_signature), TRUE),
+ WEBKIT_DOM_NODE (element),
+ NULL);
+ }
+}
+
+static void
undo_delete (WebKitDOMDocument *document,
EHTMLEditorWebExtension *extension,
EHTMLEditorHistoryEvent *event)
@@ -392,6 +447,8 @@ undo_delete (WebKitDOMDocument *document,
/* Multi block delete */
if (WEBKIT_DOM_IS_ELEMENT (first_child) && !single_block) {
+ gboolean delete;
+ WebKitDOMElement *signature;
WebKitDOMNode *node, *parent, *last_child;
WebKitDOMNode *parent_deleted_content;
WebKitDOMNode *parent_current_block;
@@ -414,11 +471,68 @@ undo_delete (WebKitDOMDocument *document,
/* All the nodes that are in current block after the caret position
* belongs on the end of the deleted content. */
node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (element));
+
+ /* FIXME Ugly hack */
+ /* If the selection ended in signature, the structure will be broken
+ * thus we saved the while signature into deleted fragment and we will
+ * restore the whole signature, but we need to remove the rest of the
+ * signature that's left after delete to avoid duplications. */
+ signature = webkit_dom_document_query_selector (document, ".-x-evo-signature-wrapper", NULL);
+ delete = signature && webkit_dom_node_contains (WEBKIT_DOM_NODE (signature), WEBKIT_DOM_NODE
(element));
+ if (!delete) {
+ WebKitDOMNode *tmp_node;
+
+ tmp_node = webkit_dom_node_get_last_child (fragment);
+ delete = tmp_node && WEBKIT_DOM_IS_ELEMENT (tmp_node) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (tmp_node), "-x-evo-signature-wrapper");
+ }
+
while (node) {
WebKitDOMNode *next_sibling;
next_sibling = webkit_dom_node_get_next_sibling (node);
- webkit_dom_node_append_child (last_child, node, NULL);
+ if (!next_sibling && WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ /* Check if the whole element was deleted. If so replace it and
+ * skip the code down there. */
+ if (!webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (element))) {
+ WebKitDOMNode *tmp_node;
+ WebKitDOMElement *tmp_element;
+
+ tmp_node = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE
(element));
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (tmp_node),
+ fragment,
+ tmp_node,
+ NULL);
+
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-tmp-block");
+ if (tmp_element)
+ webkit_dom_element_remove_attribute (tmp_element, "id");
+
+ /* Remove empty blockquotes, if presented. */
+ tmp_element = webkit_dom_document_query_selector (
+ document, "blockquote[type=cite]:empty", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ merge_duplicates_if_necessarry (document, event->data.fragment);
+
+ dom_remove_selection_markers (document);
+
+ restore_selection_to_history_event_state (document, event->before);
+
+ dom_force_spell_check_in_viewport (document, extension);
+
+ g_object_unref (dom_selection);
+
+ return;
+ }
+ }
+ if (delete)
+ remove_node (node);
+ else
+ webkit_dom_node_append_child (last_child, node, NULL);
node = next_sibling;
}
@@ -441,27 +555,31 @@ undo_delete (WebKitDOMDocument *document,
remove_node (first_child);
/* Move the deleted content back to the body. Start from the next sibling
- * of the first block (if presented) where the delete occured. */
+ * of the first block (if presented) where the delete occurred. */
while (parent_deleted_content) {
- WebKitDOMNode *tmp, *sibling;
+ WebKitDOMNode *tmp, *child;
/* Move all the siblings from current level back to the body. */
- sibling = webkit_dom_node_get_first_child (parent_deleted_content);
- while (sibling) {
+ child = webkit_dom_node_get_first_child (parent_deleted_content);
+ while (child) {
WebKitDOMNode *next_sibling;
- next_sibling = webkit_dom_node_get_next_sibling (sibling);
+ next_sibling = webkit_dom_node_get_next_sibling (child);
webkit_dom_node_insert_before (
- parent_current_block, sibling, insert_before, NULL);
- sibling = next_sibling;
+ parent_current_block, child, insert_before, NULL);
+ child = next_sibling;
}
tmp = webkit_dom_node_get_parent_node (parent_deleted_content);
remove_node (parent_deleted_content);
parent_deleted_content = tmp;
insert_before = webkit_dom_node_get_next_sibling (parent_current_block);
- parent_current_block = webkit_dom_node_get_parent_node (parent_current_block);
+ /* Be sure that we don't go above body. */
+ if (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent_current_block))
+ parent_current_block = webkit_dom_node_get_parent_node (parent_current_block);
}
+ merge_duplicates_if_necessarry (document, event->data.fragment);
+
dom_selection_restore (document);
dom_force_spell_check_in_viewport (document, extension);
} else {
@@ -504,8 +622,8 @@ undo_delete (WebKitDOMDocument *document,
remove_node (WEBKIT_DOM_NODE (element));
/* If the selection markers are presented restore the selection,
- * otherwise the selection was not callapsed so select the deleted
- * content as it was before the delete occured. */
+ * otherwise the selection was not collapsed so select the deleted
+ * content as it was before the delete occurred. */
if (webkit_dom_document_fragment_query_selector (event->data.fragment,
"span#-x-evo-selection-start-marker", NULL))
dom_selection_restore (document);
else
@@ -552,7 +670,7 @@ redo_delete (WebKitDOMDocument *document,
text_content = webkit_dom_node_get_text_content (WEBKIT_DOM_NODE (fragment));
length = g_utf8_strlen (text_content, -1);
- control_key = control_key && length > 1;
+ control_key = length > 1;
g_free (text_content);
}
@@ -569,8 +687,15 @@ redo_delete (WebKitDOMDocument *document,
}
g_object_unref (dom_selection);
- } else
- dom_exec_command (document, extension, E_HTML_EDITOR_VIEW_COMMAND_DELETE, NULL);
+ } else {
+ if (!dom_delete_character_from_quoted_line_start (document, extension, ~0, 0))
+ if (!dom_fix_structure_after_delete_before_quoted_content (document, extension, ~0,
0))
+ dom_exec_command (document, extension, E_HTML_EDITOR_VIEW_COMMAND_DELETE,
NULL);
+
+ dom_disable_quote_marks_select (document);
+ }
+
+ restore_selection_to_history_event_state (document, event->after);
dom_force_spell_check_for_current_paragraph (document, extension);
}
@@ -1450,6 +1575,14 @@ undo_redo_citation_split (WebKitDOMDocument *document,
EHTMLEditorHistoryEvent *event,
gboolean undo)
{
+ gboolean in_situ = FALSE;
+
+ if (event->before.start.x == event->after.start.x &&
+ event->before.start.y == event->after.start.y &&
+ event->after.end.x == event->after.end.x &&
+ event->after.end.y == event->after.end.y)
+ in_situ = TRUE;
+
if (undo) {
gint citation_level = 1, length, word_wrap_length;
WebKitDOMElement *selection_start, *parent;
@@ -1466,12 +1599,16 @@ undo_redo_citation_split (WebKitDOMDocument *document,
parent = get_parent_block_element (WEBKIT_DOM_NODE (selection_start));
citation_before = webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (parent));
- if (!dom_node_is_citation_node (citation_before))
+ if (!dom_node_is_citation_node (citation_before)) {
+ dom_selection_restore (document);
return;
+ }
citation_after = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (parent));
- if (!dom_node_is_citation_node (citation_after))
+ if (!dom_node_is_citation_node (citation_after)) {
+ dom_selection_restore (document);
return;
+ }
/* Get first block in next citation. */
child = webkit_dom_node_get_first_child (citation_after);
@@ -1480,48 +1617,77 @@ undo_redo_citation_split (WebKitDOMDocument *document,
child = webkit_dom_node_get_first_child (child);
}
- dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (child));
- dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (child));
-
/* Get last block in previous citation. */
last_child = webkit_dom_node_get_last_child (citation_before);
while (last_child && dom_node_is_citation_node (last_child))
last_child = webkit_dom_node_get_last_child (last_child);
- dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
- dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
+ if (in_situ) {
+ webkit_dom_node_append_child (
+ webkit_dom_node_get_parent_node (last_child),
+ webkit_dom_node_clone_node (
+ WEBKIT_DOM_NODE (event->data.fragment), TRUE),
+ NULL);
+ } else {
+ dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (child));
+ dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (child));
- /* Copy the content of the first block to the last block to get
- * to the state how the block looked like before it was split. */
- while ((tmp = webkit_dom_node_get_first_child (child)))
- webkit_dom_node_append_child (last_child, tmp, NULL);
+ dom_remove_quoting_from_element (WEBKIT_DOM_ELEMENT (last_child));
+ dom_remove_wrapping_from_element (WEBKIT_DOM_ELEMENT (last_child));
- word_wrap_length = e_html_editor_web_extension_get_word_wrap_length (extension);
- length = word_wrap_length - 2 * citation_level;
+ /* Copy the content of the first block to the last block to get
+ * to the state how the block looked like before it was split. */
+ while ((tmp = webkit_dom_node_get_first_child (child)))
+ webkit_dom_node_append_child (last_child, tmp, NULL);
- /* We need to re-wrap and re-quote the block. */
- last_child = WEBKIT_DOM_NODE (dom_wrap_paragraph_length (
- document, extension, WEBKIT_DOM_ELEMENT (last_child), length));
- dom_quote_plain_text_element_after_wrapping (
- document, WEBKIT_DOM_ELEMENT (last_child), citation_level);
+ word_wrap_length = e_html_editor_web_extension_get_word_wrap_length (extension);
+ length = word_wrap_length - 2 * citation_level;
- remove_node (child);
+ /* We need to re-wrap and re-quote the block. */
+ last_child = WEBKIT_DOM_NODE (dom_wrap_paragraph_length (
+ document, extension, WEBKIT_DOM_ELEMENT (last_child), length));
+ dom_quote_plain_text_element_after_wrapping (
+ document, WEBKIT_DOM_ELEMENT (last_child), citation_level);
+
+ remove_node (child);
+ }
/* Move all the block from next citation to the previous one. */
while ((child = webkit_dom_node_get_first_child (citation_after)))
webkit_dom_node_append_child (citation_before, child, NULL);
+ dom_remove_selection_markers (document);
+
remove_node (WEBKIT_DOM_NODE (parent));
remove_node (WEBKIT_DOM_NODE (citation_after));
/* If enter was pressed when some text was selected, restore it. */
- if (event->data.fragment != NULL)
+ if (event->data.fragment != NULL && !in_situ)
undo_delete (document, extension, event);
restore_selection_to_history_event_state (document, event->before);
dom_force_spell_check_in_viewport (document, extension);
} else {
+ if (in_situ) {
+ WebKitDOMElement *selection_start_marker;
+ WebKitDOMNode *block;
+
+ dom_selection_save (document);
+
+ selection_start_marker = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+
+ block = get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ dom_remove_selection_markers (document);
+
+ /* Remove current block (and all of its parents if they
+ * are empty) as it will be replaced by a new block that
+ * will be in the body and not in the blockquote. */
+ dom_remove_node_and_parents_if_empty (block);
+ }
+
dom_insert_new_line_into_citation (document, extension, "");
}
}
@@ -1612,9 +1778,8 @@ undo_redo_unquote (WebKitDOMDocument *document,
}
remove_node (WEBKIT_DOM_NODE (block));
- } else {
+ } else
dom_change_quoted_block_to_normal (document, extension);
- }
if (undo)
restore_selection_to_history_event_state (document, event->before);
diff --git a/web-extensions/composer/e-html-editor-view-dom-functions.c
b/web-extensions/composer/e-html-editor-view-dom-functions.c
index 4ec593f..b6f69ba 100644
--- a/web-extensions/composer/e-html-editor-view-dom-functions.c
+++ b/web-extensions/composer/e-html-editor-view-dom-functions.c
@@ -2585,8 +2585,8 @@ remove_empty_blocks (WebKitDOMDocument *document)
* the selection. This will avoid it as when the delete or backspace key is pressed
* we will make the quote marks user selectable so they will act as any other text.
* On HTML keyup event callback we will make them again non-selectable. */
-static void
-disable_quote_marks_select (WebKitDOMDocument *document)
+void
+dom_disable_quote_marks_select (WebKitDOMDocument *document)
{
WebKitDOMHTMLHeadElement *head;
WebKitDOMElement *style_element;
@@ -2615,6 +2615,39 @@ enable_quote_marks_select (WebKitDOMDocument *document)
remove_node (WEBKIT_DOM_NODE (style_element));
}
+void
+dom_remove_node_and_parents_if_empty (WebKitDOMNode *node)
+{
+ WebKitDOMNode *parent;
+
+ parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (node));
+
+ remove_node (WEBKIT_DOM_NODE (node));
+
+ while (parent && !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+ WebKitDOMNode *prev_sibling, *next_sibling;
+
+ prev_sibling = webkit_dom_node_get_previous_sibling (parent);
+ next_sibling = webkit_dom_node_get_next_sibling (parent);
+ /* Empty or BR as sibling, but no sibling after it. */
+ if ((!prev_sibling ||
+ (WEBKIT_DOM_IS_HTML_BR_ELEMENT (prev_sibling) &&
+ !webkit_dom_node_get_previous_sibling (prev_sibling))) &&
+ (!next_sibling ||
+ (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling) &&
+ !webkit_dom_node_get_next_sibling (next_sibling)))) {
+ WebKitDOMNode *tmp;
+
+ tmp = webkit_dom_node_get_parent_node (parent);
+ remove_node (parent);
+ parent = tmp;
+ } else {
+ remove_node (parent);
+ return;
+ }
+ }
+}
+
static void
body_keyup_event_cb (WebKitDOMElement *element,
WebKitDOMUIEvent *event,
@@ -2638,12 +2671,12 @@ body_keyup_event_cb (WebKitDOMElement *element,
gint level;
WebKitDOMElement *selection_start_marker, *selection_end_marker;
WebKitDOMElement *tmp_element;
- WebKitDOMNode *parent;
+ WebKitDOMNode *parent, *node;
if (e_html_editor_web_extension_get_html_mode (extension))
return;
- disable_quote_marks_select (document);
+ dom_disable_quote_marks_select (document);
/* Remove empty blocks if presented. */
remove_empty_blocks (document);
@@ -2675,7 +2708,8 @@ body_keyup_event_cb (WebKitDOMElement *element,
/* Under some circumstances we will end with block inside the citation
* that has the quote marks removed and we have to reinsert them back. */
level = get_citation_level (WEBKIT_DOM_NODE (selection_start_marker), FALSE);
- if (level > 0) {
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+ if (level > 0 && node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
WebKitDOMNode *prev_sibling;
prev_sibling = webkit_dom_node_get_previous_sibling (
@@ -2687,19 +2721,77 @@ body_keyup_event_cb (WebKitDOMElement *element,
block = WEBKIT_DOM_ELEMENT (get_parent_block_node_from_child (
WEBKIT_DOM_NODE (selection_start_marker)));
- if (element_has_class (block, "-x-evo-paragraph")) {
- gint length, word_wrap_length;
-
- word_wrap_length = e_html_editor_web_extension_get_word_wrap_length
(extension);
- length = word_wrap_length - 2 * (level - 1);
- block = dom_wrap_paragraph_length (
- document, extension, block, length);
- webkit_dom_node_normalize (WEBKIT_DOM_NODE (block));
+ if (webkit_dom_element_has_attribute (block, "data-no-quote")) {
+ webkit_dom_element_remove_attribute (block, "data-no-quote");
+ } else {
+ if (element_has_class (block, "-x-evo-paragraph")) {
+ gint length, word_wrap_length;
+
+ word_wrap_length =
e_html_editor_web_extension_get_word_wrap_length (extension);
+ length = word_wrap_length - 2 * (level - 1);
+ block = dom_wrap_paragraph_length (
+ document, extension, block, length);
+ webkit_dom_node_normalize (WEBKIT_DOM_NODE (block));
+ }
+ dom_quote_plain_text_element_after_wrapping (
+ document, block, level);
}
- dom_quote_plain_text_element_after_wrapping (
- document, block, level);
}
- }
+ } else if (node && WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ EHTMLEditorUndoRedoManager *manager;
+ EHTMLEditorHistoryEvent *event;
+ WebKitDOMDocumentFragment *fragment;
+ WebKitDOMNode *block;
+
+ manager = e_html_editor_web_extension_get_undo_redo_manager (extension);
+ block = get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ dom_remove_selection_markers (document);
+
+ event = g_new0 (EHTMLEditorHistoryEvent, 1);
+ event->type = HISTORY_AND;
+
+ e_html_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ event = g_new0 (EHTMLEditorHistoryEvent, 1);
+ event->type = HISTORY_CITATION_SPLIT;
+
+ dom_selection_get_coordinates (
+ document,
+ &event->before.start.x,
+ &event->before.start.y,
+ &event->before.end.x,
+ &event->before.end.y);
+
+ fragment = webkit_dom_document_create_document_fragment (document);
+
+ /* Save the current block as it will be removed few lines after this. */
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (fragment),
+ webkit_dom_node_clone_node (block, TRUE),
+ NULL);
+
+ event->data.fragment = fragment;
+
+ /* Remove current block (and all of its parents if they
+ * are empty) as it will be replaced by a new block that
+ * will be in the body and not in the blockquote. */
+ dom_remove_node_and_parents_if_empty (block);
+
+ dom_insert_new_line_into_citation (document, extension, "");
+
+ dom_selection_get_coordinates (
+ document,
+ &event->after.start.x,
+ &event->after.start.y,
+ &event->after.end.x,
+ &event->after.end.y);
+
+ e_html_editor_undo_redo_manager_insert_history_event (manager, event);
+
+ return;
+ }
/* Situation where the start of the selection was in the beginning
* of the block in quoted content and the end in the beginning of
@@ -2715,6 +2807,18 @@ body_keyup_event_cb (WebKitDOMElement *element,
if (tmp_element) {
dom_remove_wrapping_from_element (tmp_element);
dom_remove_quoting_from_element (tmp_element);
+
+ /* Append the BR element if the block is empty, but the
+ * selection is there to be able to move to the block
+ * with caret later. */
+ if (!webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker)) &&
+ !webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)))
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (tmp_element),
+ WEBKIT_DOM_NODE (webkit_dom_document_create_element (
+ document, "br", NULL)),
+ NULL);
+
webkit_dom_element_remove_attribute (tmp_element, "id");
parent = webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp_element));
@@ -4400,7 +4504,7 @@ clear_attributes (WebKitDOMDocument *document)
remove_node (webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (head)));
/* Make the quote marks non-selectable. */
- disable_quote_marks_select (document);
+ dom_disable_quote_marks_select (document);
/* Remove non Evolution attributes from BODY element */
attributes = webkit_dom_element_get_attributes (WEBKIT_DOM_ELEMENT (body));
@@ -6847,7 +6951,7 @@ dom_process_content_after_load (WebKitDOMDocument *document,
if (e_html_editor_web_extension_get_convert_in_situ (extension)) {
dom_convert_content (document, extension, NULL);
/* Make the quote marks non-selectable. */
- disable_quote_marks_select (document);
+ dom_disable_quote_marks_select (document);
dom_set_links_active (document, FALSE);
e_html_editor_web_extension_set_convert_in_situ (extension, FALSE);
@@ -6855,7 +6959,7 @@ dom_process_content_after_load (WebKitDOMDocument *document,
}
/* Make the quote marks non-selectable. */
- disable_quote_marks_select (document);
+ dom_disable_quote_marks_select (document);
dom_set_links_active (document, FALSE);
put_body_in_citation (document);
move_elements_to_body (document, extension);
@@ -7102,122 +7206,6 @@ dom_insert_html (WebKitDOMDocument *document,
}
}
-static gboolean
-fix_structure_after_delete_before_quoted_content (WebKitDOMDocument *document)
-{
- gboolean collapsed = FALSE;
- WebKitDOMElement *selection_start_marker, *selection_end_marker;
- WebKitDOMNode *block, *node;
-
- collapsed = dom_selection_is_collapsed (document);
-
- dom_selection_save (document);
-
- selection_start_marker = webkit_dom_document_query_selector (
- document, "span#-x-evo-selection-start-marker", NULL);
- selection_end_marker = webkit_dom_document_query_selector (
- document, "span#-x-evo-selection-end-marker", NULL);
-
- if (!selection_start_marker || !selection_end_marker)
- return FALSE;
-
- if (collapsed) {
- WebKitDOMNode *next_sibling;
-
- block = get_parent_block_node_from_child (
- WEBKIT_DOM_NODE (selection_start_marker));
-
- next_sibling = webkit_dom_node_get_next_sibling (block);
-
- /* Next block is quoted content */
- if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (next_sibling))
- goto restore;
-
- /* Delete was pressed in block without any content */
- if (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)))
- goto restore;
-
- /* If there is just BR element go ahead */
- node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
- if (node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node))
- goto restore;
- else {
- /* Remove the empty block and move caret into the beginning of the citation */
- remove_node (block);
-
- dom_move_caret_into_element (
- document, WEBKIT_DOM_ELEMENT (next_sibling), TRUE);
-
- return TRUE;
- }
- } else {
- WebKitDOMNode *end_block;
-
- /* Let the quote marks be selectable to nearly correctly remove the
- * selection. Corrections after are done in body_keyup_event_cb. */
- enable_quote_marks_select (document);
-
- node = webkit_dom_node_get_previous_sibling (
- WEBKIT_DOM_NODE (selection_start_marker));
-
- if (!node || !WEBKIT_DOM_IS_ELEMENT (node))
- goto restore;
-
- if (!element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted"))
- goto restore;
-
- webkit_dom_node_insert_before (
- webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (node)),
- WEBKIT_DOM_NODE (selection_start_marker),
- WEBKIT_DOM_NODE (node),
- NULL);
-
- block = get_parent_block_node_from_child (
- WEBKIT_DOM_NODE (selection_start_marker));
- end_block = get_parent_block_node_from_child (
- WEBKIT_DOM_NODE (selection_end_marker));
-
- /* Situation where the start of the selection is in the beginning
- + * of the block in quoted content and the end in the beginning of
- + * content that is after the citation or the selection end is in
- + * the end of the quoted content (showed by ^). We have to
- + * mark the start block to correctly restore the structure
- + * afterwards.
- *
- * > |xxx
- * > xxx^
- * |xxx
- */
- if (get_citation_level (end_block, FALSE) > 0) {
- WebKitDOMNode *parent;
-
- if (webkit_dom_node_get_next_sibling (end_block))
- goto restore;
-
- parent = webkit_dom_node_get_parent_node (end_block);
- while (parent && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent)) {
- WebKitDOMNode *next_parent = webkit_dom_node_get_parent_node (parent);
-
- if (webkit_dom_node_get_next_sibling (parent) &&
- !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (next_parent))
- goto restore;
-
- parent = next_parent;
- }
- }
- node = webkit_dom_node_get_next_sibling (
- WEBKIT_DOM_NODE (selection_end_marker));
- if (!node || WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
- webkit_dom_element_set_id (
- WEBKIT_DOM_ELEMENT (block), "-x-evo-tmp-block");
- }
- }
- restore:
- dom_selection_restore (document);
-
- return FALSE;
-}
-
static void
save_history_for_delete_or_backspace (WebKitDOMDocument *document,
EHTMLEditorWebExtension *extension,
@@ -7382,11 +7370,123 @@ save_history_for_delete_or_backspace (WebKitDOMDocument *document,
e_html_editor_web_extension_unblock_selection_changed_callback (extension);
} else {
+ WebKitDOMElement *tmp_element;
+ WebKitDOMNode *sibling;
+
ev->after.start.x = ev->before.start.x;
ev->after.start.y = ev->before.start.y;
ev->after.end.x = ev->before.start.x;
ev->after.end.y = ev->before.start.y;
+
fragment = webkit_dom_range_clone_contents (range, NULL);
+
+ tmp_element = webkit_dom_document_fragment_query_selector (
+ fragment, "#-x-evo-selection-start-marker", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ tmp_element = webkit_dom_document_fragment_query_selector (
+ fragment, "#-x-evo-selection-end-marker", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ /* If any empty blockquote is presented, remove it. */
+ tmp_element = webkit_dom_document_query_selector (
+ document, "blockquote[type=cite]:empty", NULL);
+ if (tmp_element)
+ remove_node (WEBKIT_DOM_NODE (tmp_element));
+
+ /* Selection starts in the beginning of blockquote. */
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-start-marker");
+ sibling = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (tmp_element));
+ if (sibling && WEBKIT_DOM_IS_ELEMENT (sibling) &&
+ element_has_class (WEBKIT_DOM_ELEMENT (sibling), "-x-evo-quoted")) {
+ WebKitDOMNode *child;
+
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+
+ /* If there is no text after the selection end it means that
+ * the block will be replaced with block that is body's descendant
+ * and not the blockquote's one. Also if the selection started
+ * in the beginning of blockquote we have to insert the quote
+ * characters into the deleted content to correctly restore
+ * them during undo/redo operations. */
+ if (!(tmp_element && webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE
(tmp_element)))) {
+ child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (fragment));
+ while (child && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (child))
+ child = webkit_dom_node_get_first_child (child);
+
+ child = webkit_dom_node_get_first_child (child);
+ if (child && (WEBKIT_DOM_IS_TEXT (child) ||
+ (WEBKIT_DOM_IS_ELEMENT (child) &&
+ !element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-quoted")))) {
+ printf ("%s\n", __FUNCTION__);
+ printf ("%s\n", __FUNCTION__);
+ printf ("%s\n", __FUNCTION__);
+ printf ("%s\n", __FUNCTION__);
+ printf ("%s\n", __FUNCTION__);
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (child),
+ webkit_dom_node_clone_node (sibling, TRUE),
+ child,
+ NULL);
+ }
+ }
+ }
+
+ /* When we were cloning the range above and the range contained
+ * quoted content there will still be blockquote missing in the
+ * final range. Let's modify the fragment and add it there. */
+ tmp_element = webkit_dom_document_get_element_by_id (
+ document, "-x-evo-selection-end-marker");
+ if (tmp_element) {
+ WebKitDOMNode *node;
+
+ node = WEBKIT_DOM_NODE (tmp_element);
+ while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (node))) {
+ if (webkit_dom_node_get_next_sibling (node))
+ break;
+ node = webkit_dom_node_get_parent_node (node);
+ }
+
+ if (node && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (node)) {
+ WebKitDOMNode *last_child;
+
+ last_child = webkit_dom_node_get_last_child (WEBKIT_DOM_NODE (fragment));
+
+ if (last_child && !WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (last_child)) {
+ WebKitDOMDocumentFragment *tmp_fragment;
+ WebKitDOMNode *clone;
+
+ tmp_fragment = webkit_dom_document_create_document_fragment
(document);
+ clone = webkit_dom_node_clone_node (node, FALSE);
+ clone = webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (tmp_fragment), clone, NULL);
+ webkit_dom_node_append_child (clone, WEBKIT_DOM_NODE (fragment),
NULL);
+ fragment = tmp_fragment;
+ }
+ }
+ }
+
+ /* FIXME Ugly hack */
+ /* If the deleted selection contained the signature (or at least its
+ * part) replace it with the unchanged signature to correctly perform
+ * undo operation. */
+ tmp_element = webkit_dom_document_fragment_query_selector (fragment,
".-x-evo-signature-wrapper", NULL);
+ if (tmp_element) {
+ WebKitDOMElement *signature;
+
+ signature = webkit_dom_document_query_selector (document,
".-x-evo-signature-wrapper", NULL);
+ if (signature) {
+ webkit_dom_node_replace_child (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (tmp_element)),
+ webkit_dom_node_clone_node (WEBKIT_DOM_NODE (signature), TRUE),
+ WEBKIT_DOM_NODE (tmp_element),
+ NULL);
+ }
+ }
}
g_object_unref (range);
@@ -7398,6 +7498,142 @@ save_history_for_delete_or_backspace (WebKitDOMDocument *document,
e_html_editor_undo_redo_manager_insert_history_event (manager, ev);
}
+gboolean
+dom_fix_structure_after_delete_before_quoted_content (WebKitDOMDocument *document,
+ EHTMLEditorWebExtension *extension,
+ guint key_val,
+ guint state)
+{
+ gboolean collapsed = FALSE;
+ WebKitDOMElement *selection_start_marker, *selection_end_marker;
+ WebKitDOMNode *block, *node;
+
+ collapsed = dom_selection_is_collapsed (document);
+
+ dom_selection_save (document);
+
+ selection_start_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-start-marker", NULL);
+ selection_end_marker = webkit_dom_document_query_selector (
+ document, "span#-x-evo-selection-end-marker", NULL);
+
+ if (!selection_start_marker || !selection_end_marker)
+ return FALSE;
+
+ if (collapsed) {
+ WebKitDOMNode *next_sibling;
+
+ block = get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ next_sibling = webkit_dom_node_get_next_sibling (block);
+
+ /* Next block is quoted content */
+ if (!WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (next_sibling))
+ goto restore;
+
+ /* Delete was pressed in block without any content */
+ if (webkit_dom_node_get_previous_sibling (WEBKIT_DOM_NODE (selection_start_marker)))
+ goto restore;
+
+ /* If there is just BR element go ahead */
+ node = webkit_dom_node_get_next_sibling (WEBKIT_DOM_NODE (selection_end_marker));
+ if (node && !WEBKIT_DOM_IS_HTML_BR_ELEMENT (node))
+ goto restore;
+ else {
+ if (key_val != ~0)
+ save_history_for_delete_or_backspace (
+ document, extension, key_val == GDK_KEY_Delete, (state &
GDK_CONTROL_MASK) != 0);
+
+ /* Remove the empty block and move caret into the beginning of the citation */
+ remove_node (block);
+
+ dom_move_caret_into_element (
+ document, WEBKIT_DOM_ELEMENT (next_sibling), TRUE);
+
+ return TRUE;
+ }
+ } else {
+ WebKitDOMNode *end_block, *parent;
+
+ /* Let the quote marks be selectable to nearly correctly remove the
+ * selection. Corrections after are done in body_keyup_event_cb. */
+ enable_quote_marks_select (document);
+
+ parent = webkit_dom_node_get_parent_node (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ if (WEBKIT_DOM_IS_HTML_ANCHOR_ELEMENT (parent) ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "b") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "i") ||
+ element_has_tag (WEBKIT_DOM_ELEMENT (parent), "u"))
+ node = webkit_dom_node_get_previous_sibling (parent);
+ else
+ node = webkit_dom_node_get_previous_sibling (
+ WEBKIT_DOM_NODE (selection_start_marker));
+
+ if (!node || !WEBKIT_DOM_IS_ELEMENT (node))
+ goto restore;
+
+ if (!element_has_class (WEBKIT_DOM_ELEMENT (node), "-x-evo-quoted"))
+ goto restore;
+
+ webkit_dom_node_insert_before (
+ webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (node)),
+ WEBKIT_DOM_NODE (selection_start_marker),
+ WEBKIT_DOM_NODE (node),
+ NULL);
+
+ block = get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_start_marker));
+ end_block = get_parent_block_node_from_child (
+ WEBKIT_DOM_NODE (selection_end_marker));
+
+ /* Situation where the start of the selection is in the beginning
+ + * of the block in quoted content and the end in the beginning of
+ + * content that is after the citation or the selection end is in
+ + * the end of the quoted content (showed by ^). We have to
+ + * mark the start block to correctly restore the structure
+ + * afterwards.
+ *
+ * > |xxx
+ * > xxx^
+ * |xxx
+ */
+ if (get_citation_level (end_block, FALSE) > 0) {
+ WebKitDOMNode *parent;
+
+ if (webkit_dom_node_get_next_sibling (end_block))
+ goto restore;
+
+ parent = webkit_dom_node_get_parent_node (end_block);
+ while (parent && WEBKIT_DOM_IS_HTML_QUOTE_ELEMENT (parent)) {
+ WebKitDOMNode *next_parent = webkit_dom_node_get_parent_node (parent);
+
+ if (webkit_dom_node_get_next_sibling (parent) &&
+ !WEBKIT_DOM_IS_HTML_BODY_ELEMENT (next_parent))
+ goto restore;
+
+ parent = next_parent;
+ }
+ }
+
+ node = webkit_dom_node_get_next_sibling (
+ WEBKIT_DOM_NODE (selection_end_marker));
+ if (!node || WEBKIT_DOM_IS_HTML_BR_ELEMENT (node)) {
+ webkit_dom_element_set_id (
+ WEBKIT_DOM_ELEMENT (block), "-x-evo-tmp-block");
+ }
+ }
+ restore:
+ if (key_val != ~0)
+ save_history_for_delete_or_backspace (
+ document, extension, key_val == GDK_KEY_Delete, (state & GDK_CONTROL_MASK) != 0);
+
+ dom_selection_restore (document);
+
+ return FALSE;
+}
+
static gboolean
split_citation (WebKitDOMDocument *document,
EHTMLEditorWebExtension *extension)
@@ -7597,8 +7833,11 @@ jump_to_next_table_cell (WebKitDOMDocument *document,
return TRUE;
}
-static gboolean
-delete_character_from_quoted_line_start (WebKitDOMDocument *document)
+gboolean
+dom_delete_character_from_quoted_line_start (WebKitDOMDocument *document,
+ EHTMLEditorWebExtension *extension,
+ guint key_val,
+ guint state)
{
WebKitDOMElement *element;
WebKitDOMNode *node, *beginning;
@@ -7640,7 +7879,22 @@ delete_character_from_quoted_line_start (WebKitDOMDocument *document)
if (!(element_has_class (WEBKIT_DOM_ELEMENT (beginning), "-x-evo-quoted")))
return FALSE;
- remove_node (beginning);
+ if (key_val != ~0)
+ save_history_for_delete_or_backspace (
+ document, extension, key_val == GDK_KEY_Delete, (state & GDK_CONTROL_MASK) != 0);
+
+ element = webkit_dom_node_get_parent_element (beginning);
+
+ dom_remove_quoting_from_element (element);
+
+ webkit_dom_node_append_child (
+ WEBKIT_DOM_NODE (element),
+ WEBKIT_DOM_NODE (
+ webkit_dom_document_create_element (document, "br", NULL)),
+ NULL);
+
+ webkit_dom_element_set_attribute (element, "data-no-quote", "", NULL);
+
remove_node (node);
dom_selection_restore (document);
@@ -7856,12 +8110,11 @@ dom_process_on_key_press (WebKitDOMDocument *document,
}
dom_selection_restore (document);
}
- save_history_for_delete_or_backspace (document, extension, key_val == GDK_KEY_Delete, (state
& GDK_CONTROL_MASK) != 0);
if (key_val == GDK_KEY_BackSpace && !html_mode) {
- if (delete_character_from_quoted_line_start (document))
+ if (dom_delete_character_from_quoted_line_start (document, extension, key_val, state))
return TRUE;
}
- if (fix_structure_after_delete_before_quoted_content (document))
+ if (dom_fix_structure_after_delete_before_quoted_content (document, extension, key_val,
state))
return TRUE;
}
diff --git a/web-extensions/composer/e-html-editor-view-dom-functions.h
b/web-extensions/composer/e-html-editor-view-dom-functions.h
index 213d3f0..81242f4 100644
--- a/web-extensions/composer/e-html-editor-view-dom-functions.h
+++ b/web-extensions/composer/e-html-editor-view-dom-functions.h
@@ -160,6 +160,19 @@ void dom_set_visited_link_color (WebKitDOMDocument *document,
gboolean dom_change_quoted_block_to_normal
(WebKitDOMDocument *document,
EHTMLEditorWebExtension *extension);
+gboolean dom_delete_character_from_quoted_line_start
+ (WebKitDOMDocument *document,
+ EHTMLEditorWebExtension *extension,
+ guint key_val,
+ guint state);
+gboolean dom_fix_structure_after_delete_before_quoted_content
+ (WebKitDOMDocument *document,
+ EHTMLEditorWebExtension *extension,
+ guint key_val,
+ guint state);
+void dom_disable_quote_marks_select (WebKitDOMDocument *document);
+void dom_remove_node_and_parents_if_empty
+ (WebKitDOMNode *node);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]