[evolution/wip/webkit2] EHTMLEditorView - Implement undo and redo on text operations in table



commit 727652068d330ceeb234ec6e4b8cb8ca15f8eb95
Author: Tomas Popela <tpopela redhat com>
Date:   Wed Apr 22 14:00:17 2015 +0200

    EHTMLEditorView - Implement undo and redo on text operations in table
    
    The problem here is that we can't use the same solution for other
    operations as the webkit_dom_document_caret_range_from_point will
    return range that will just contain the focused TD element and not the
    exact caret position. This is the WebKit limitation (the same applies
    for TEXTAREA elements) so we have to save the whole TD element instead
    of just saving what was added or removed.

 e-util/e-html-editor-view.c                        |    7 +
 web-extensions/e-html-editor-history-event.h       |    1 +
 .../e-html-editor-selection-dom-functions.c        |    7 +
 web-extensions/e-html-editor-undo-redo-manager.c   |   50 ++++++++
 web-extensions/e-html-editor-view-dom-functions.c  |  119 +++++++++++++++++++-
 5 files changed, 178 insertions(+), 6 deletions(-)
---
diff --git a/e-util/e-html-editor-view.c b/e-util/e-html-editor-view.c
index 5da9b4e..9417e7e 100644
--- a/e-util/e-html-editor-view.c
+++ b/e-util/e-html-editor-view.c
@@ -2510,6 +2510,13 @@ e_html_editor_view_update_fonts (EHTMLEditorView *view)
 
        g_string_append (
                stylesheet,
+               "td > *"
+               "{\n"
+               "  display : inline-block;\n"
+               "}\n");
+
+       g_string_append (
+               stylesheet,
                "ul,ol "
                "{\n"
                "  -webkit-padding-start: 7ch; \n"
diff --git a/web-extensions/e-html-editor-history-event.h b/web-extensions/e-html-editor-history-event.h
index 6050765..872f2b5 100644
--- a/web-extensions/e-html-editor-history-event.h
+++ b/web-extensions/e-html-editor-history-event.h
@@ -52,6 +52,7 @@ enum EHTMLEditorHistoryEventType {
        HISTORY_START, /* Start of history */
        HISTORY_STRIKETHROUGH,
        HISTORY_TABLE_DIALOG,
+       HISTORY_TABLE_INPUT,
        HISTORY_UNDERLINE,
        HISTORY_WRAP
 };
diff --git a/web-extensions/e-html-editor-selection-dom-functions.c 
b/web-extensions/e-html-editor-selection-dom-functions.c
index 9ff7c6c..c3da54d 100644
--- a/web-extensions/e-html-editor-selection-dom-functions.c
+++ b/web-extensions/e-html-editor-selection-dom-functions.c
@@ -1459,6 +1459,13 @@ dom_selection_save (WebKitDOMDocument *document)
                        webkit_dom_node_get_next_sibling (container),
                        NULL);
                goto insert_end_marker;
+       } else if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (container)) {
+               marker_node = webkit_dom_node_insert_before (
+                       container,
+                       WEBKIT_DOM_NODE (start_marker),
+                       webkit_dom_node_get_first_child (container),
+                       NULL);
+               goto insert_end_marker;
        } else {
                /* Insert the selection marker on the right position in
                 * an empty paragraph in the quoted content */
diff --git a/web-extensions/e-html-editor-undo-redo-manager.c 
b/web-extensions/e-html-editor-undo-redo-manager.c
index 02847ad..d298e38 100644
--- a/web-extensions/e-html-editor-undo-redo-manager.c
+++ b/web-extensions/e-html-editor-undo-redo-manager.c
@@ -257,6 +257,7 @@ print_history_event (EHTMLEditorHistoryEvent *event)
                case HISTORY_IMAGE_DIALOG:
                case HISTORY_CELL_DIALOG:
                case HISTORY_TABLE_DIALOG:
+               case HISTORY_TABLE_DIALOG:
                case HISTORY_PAGE_DIALOG:
                        print_node_inner_html (event->data.dom.from);
                        print_node_inner_html (event->data.dom.to);
@@ -930,6 +931,48 @@ undo_redo_table_dialog (WebKitDOMDocument *document,
 }
 
 static void
+undo_redo_table_input (WebKitDOMDocument *document,
+                       EHTMLEditorWebExtension *extension,
+                       EHTMLEditorHistoryEvent *event,
+                       gboolean undo)
+{
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+
+       if (undo)
+               restore_selection_to_history_event_state (document, event->after);
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection))
+               return;
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       /* Find if writing into table. */
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+               element = WEBKIT_DOM_ELEMENT (node);
+       else
+               element = get_parent_block_element (node);
+
+       /* If writing to table we have to create different history event. */
+       if (!WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (element))
+               return;
+
+       webkit_dom_node_replace_child (
+               webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+               undo ? event->data.dom.from : event->data.dom.to,
+               WEBKIT_DOM_NODE (element),
+               NULL);
+
+       dom_selection_restore (document);
+}
+
+static void
 undo_redo_paste (WebKitDOMDocument *document,
                  EHTMLEditorWebExtension *extension,
                  EHTMLEditorHistoryEvent *event,
@@ -1420,6 +1463,7 @@ free_history_event_content (EHTMLEditorHistoryEvent *event)
                case HISTORY_IMAGE_DIALOG:
                case HISTORY_CELL_DIALOG:
                case HISTORY_TABLE_DIALOG:
+               case HISTORY_TABLE_INPUT:
                case HISTORY_PAGE_DIALOG:
                        if (event->data.dom.from != NULL)
                                g_object_unref (event->data.dom.from);
@@ -1684,6 +1728,9 @@ e_html_editor_undo_redo_manager_undo (EHTMLEditorUndoRedoManager *manager)
                case HISTORY_TABLE_DIALOG:
                        undo_redo_table_dialog (document, extension, event, TRUE);
                        break;
+               case HISTORY_TABLE_INPUT:
+                       undo_redo_table_input (document, extension, event, TRUE);
+                       break;
                case HISTORY_PAGE_DIALOG:
                        undo_redo_page_dialog (document, extension, event, TRUE);
                        break;
@@ -1795,6 +1842,9 @@ e_html_editor_undo_redo_manager_redo (EHTMLEditorUndoRedoManager *manager)
                case HISTORY_TABLE_DIALOG:
                        undo_redo_table_dialog (document, extension, event, FALSE);
                        break;
+               case HISTORY_TABLE_INPUT:
+                       undo_redo_table_input (document, extension, event, FALSE);
+                       break;
                case HISTORY_PAGE_DIALOG:
                        undo_redo_page_dialog (document, extension, event, FALSE);
                        break;
diff --git a/web-extensions/e-html-editor-view-dom-functions.c 
b/web-extensions/e-html-editor-view-dom-functions.c
index 80ddf98..73009ef 100644
--- a/web-extensions/e-html-editor-view-dom-functions.c
+++ b/web-extensions/e-html-editor-view-dom-functions.c
@@ -1623,13 +1623,15 @@ surround_text_with_paragraph_if_needed (WebKitDOMDocument *document,
 {
        WebKitDOMNode *next_sibling = webkit_dom_node_get_next_sibling (node);
        WebKitDOMNode *prev_sibling = webkit_dom_node_get_previous_sibling (node);
+       WebKitDOMNode *parent = webkit_dom_node_get_parent_node (node);
        WebKitDOMElement *element;
 
        /* All text in composer has to be written in div elements, so if
         * we are writing something straight to the body, surround it with
         * paragraph */
        if (WEBKIT_DOM_IS_TEXT (node) &&
-           WEBKIT_DOM_IS_HTML_BODY_ELEMENT (webkit_dom_node_get_parent_node (node))) {
+           (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent) ||
+            WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (parent))) {
                element = dom_put_node_into_paragraph (document, extension, node, TRUE);
 
                if (WEBKIT_DOM_IS_HTML_BR_ELEMENT (next_sibling))
@@ -1668,6 +1670,50 @@ body_keydown_event_cb (WebKitDOMElement *element,
                e_html_editor_web_extension_set_dont_save_history_in_body_input (extension, TRUE);
 }
 
+static gboolean
+save_history_before_event_in_table (WebKitDOMDocument *document,
+                                    EHTMLEditorWebExtension *extension,
+                                    WebKitDOMRange *range)
+{
+       WebKitDOMNode *node;
+       WebKitDOMElement *block;
+
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+               block = WEBKIT_DOM_ELEMENT (node);
+       else
+               block = get_parent_block_element (node);
+
+       if (block && WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (block)) {
+               EHTMLEditorUndoRedoManager *manager;
+               EHTMLEditorHistoryEvent *ev;
+
+               ev = g_new0 (EHTMLEditorHistoryEvent, 1);
+               ev->type = HISTORY_TABLE_INPUT;
+
+               if (block) {
+                       dom_selection_save (document);
+                       ev->data.dom.from = webkit_dom_node_clone_node (WEBKIT_DOM_NODE (block), TRUE);
+                       dom_selection_restore (document);
+               } else
+                       ev->data.dom.from = NULL;
+
+               dom_selection_get_coordinates (
+                       document,
+                       &ev->before.start.x,
+                       &ev->before.start.y,
+                       &ev->before.end.x,
+                       &ev->before.end.y);
+
+               manager = e_html_editor_web_extension_get_undo_redo_manager (extension);
+               e_html_editor_undo_redo_manager_insert_history_event (manager, ev);
+
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
 static void
 body_keypress_event_cb (WebKitDOMElement *element,
                         WebKitDOMUIEvent *event,
@@ -1693,6 +1739,9 @@ body_keypress_event_cb (WebKitDOMElement *element,
        dom_selection = webkit_dom_dom_window_get_selection (dom_window);
        range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
 
+       if (save_history_before_event_in_table (document, extension, range))
+               return;
+
        if (!webkit_dom_range_get_collapsed (range, NULL)) {
                EHTMLEditorHistoryEvent *ev;
                EHTMLEditorUndoRedoManager *manager;
@@ -1715,6 +1764,57 @@ body_keypress_event_cb (WebKitDOMElement *element,
        }
 }
 
+static gboolean
+save_history_after_event_in_table (WebKitDOMDocument *document,
+                                   EHTMLEditorWebExtension *extension)
+{
+       EHTMLEditorHistoryEvent *ev;
+       EHTMLEditorUndoRedoManager *manager;
+       WebKitDOMDOMWindow *dom_window;
+       WebKitDOMDOMSelection *dom_selection;
+       WebKitDOMElement *element;
+       WebKitDOMNode *node;
+       WebKitDOMRange *range;
+
+       dom_window = webkit_dom_document_get_default_view (document);
+       dom_selection = webkit_dom_dom_window_get_selection (dom_window);
+
+       if (!webkit_dom_dom_selection_get_range_count (dom_selection))
+               return FALSE;
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       /* Find if writing into table. */
+       node = webkit_dom_range_get_start_container (range, NULL);
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (node))
+               element = WEBKIT_DOM_ELEMENT (node);
+       else
+               element = get_parent_block_element (node);
+
+       manager = e_html_editor_web_extension_get_undo_redo_manager (extension);
+       /* If writing to table we have to create different history event. */
+       if (WEBKIT_DOM_IS_HTML_TABLE_CELL_ELEMENT (element)) {
+               ev = e_html_editor_undo_redo_manager_get_current_history_event (manager);
+               if (ev->type != HISTORY_TABLE_INPUT)
+                       return FALSE;
+       } else
+               return FALSE;
+
+       dom_selection_save (document);
+
+       dom_selection_get_coordinates (
+               document,
+               &ev->after.start.x,
+               &ev->after.start.y,
+               &ev->after.end.x,
+               &ev->after.end.y);
+
+       ev->data.dom.to = webkit_dom_node_clone_node (WEBKIT_DOM_NODE (element), TRUE);
+
+       dom_selection_restore (document);
+
+       return TRUE;
+}
+
 static void
 save_history_for_input (WebKitDOMDocument *document,
                         EHTMLEditorWebExtension *extension)
@@ -1814,10 +1914,12 @@ body_input_event_cb (WebKitDOMElement *element,
                return;
        }
 
-       if (!e_html_editor_web_extension_get_dont_save_history_in_body_input (extension))
-               save_history_for_input (document, extension);
-       else
-               dom_force_spell_check_for_current_paragraph (document, extension);
+       if (!save_history_after_event_in_table (document, extension)) {
+               if (!e_html_editor_web_extension_get_dont_save_history_in_body_input (extension))
+                       save_history_for_input (document, extension);
+               else
+                       dom_force_spell_check_for_current_paragraph (document, extension);
+       }
 
        /* Don't try to look for smileys if we are deleting text. */
        if (!e_html_editor_web_extension_get_dont_save_history_in_body_input (extension))
@@ -1866,7 +1968,7 @@ body_input_event_cb (WebKitDOMElement *element,
 
        /* After toggling monospaced format, we are using UNICODE_ZERO_WIDTH_SPACE
         * to move caret into right space. When this callback is called it is not
-        * necassary anymore so remove it */
+        * necessary anymore so remove it */
        if (html_mode) {
                WebKitDOMElement *parent = webkit_dom_node_get_parent_element (node);
 
@@ -6653,6 +6755,11 @@ save_history_for_delete_or_backspace (WebKitDOMDocument *document,
        if (!webkit_dom_dom_selection_get_range_count (dom_selection))
                return;
 
+       range = webkit_dom_dom_selection_get_range_at (dom_selection, 0, NULL);
+
+       if (save_history_before_event_in_table (document, extension, range))
+               return;
+
        ev = g_new0 (EHTMLEditorHistoryEvent, 1);
        ev->type = HISTORY_DELETE;
 


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