[evolution/webkit-composer] Implement indentation of elements when no selection is active in composer.



commit 7909d14efe20e40ceb118865c8fcc3a48c705e02
Author: Tomas Popela <tpopela redhat com>
Date:   Tue Sep 24 16:24:01 2013 +0200

    Implement indentation of elements when no selection is active in composer.

 e-util/e-editor-selection.c |  225 +++++++++++++++++++++++++++++++++++++++++--
 e-util/e-editor-widget.c    |  180 +++++++++++++++++++++++++---------
 2 files changed, 347 insertions(+), 58 deletions(-)
---
diff --git a/e-util/e-editor-selection.c b/e-util/e-editor-selection.c
index 4b8ee8a..3d976dc 100644
--- a/e-util/e-editor-selection.c
+++ b/e-util/e-editor-selection.c
@@ -1718,14 +1718,68 @@ e_editor_selection_indent (EEditorSelection *selection)
        editor_widget = e_editor_selection_ref_editor_widget (selection);
        g_return_if_fail (editor_widget != NULL);
 
-       command = E_EDITOR_WIDGET_COMMAND_INDENT;
-       e_editor_widget_exec_command (editor_widget, command, NULL);
+       if (g_strcmp0 (e_editor_selection_get_string (selection), "") == 0) {
+               WebKitDOMDocument *document;
+               WebKitDOMRange *range;
+               WebKitDOMNode *node;
+               WebKitDOMNode *clone;
+               WebKitDOMElement *element;
+
+               document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (editor_widget));
+
+               e_editor_selection_save_caret_position (selection);
+
+               range = editor_selection_get_current_range (selection);
+               if (!range) {
+                       g_object_unref (editor_widget);
+                       return;
+               }
+
+               node = webkit_dom_range_get_end_container (range, NULL);
+               if (!WEBKIT_DOM_IS_ELEMENT (node))
+                       node = WEBKIT_DOM_NODE (webkit_dom_node_get_parent_element (node));
+
+               element = webkit_dom_node_get_parent_element (node);
+
+               clone = webkit_dom_node_clone_node (node, TRUE);
+               element = webkit_dom_document_create_element (document, "BLOCKQUOTE", NULL);
+               element_add_class (element, "-x-evo-indented");
+               /* We don't want vertical space bellow and above blockquote inserted by
+                * WebKit's User Agent Stylesheet. We have to override it through style attribute. */
+               webkit_dom_element_set_attribute (
+                       element,
+                       "style",
+                       "-webkit-margin-before: 0em; -webkit-margin-after: 0em;",
+                       NULL);
+
+               webkit_dom_node_append_child (
+                       WEBKIT_DOM_NODE (element),
+                       clone,
+                       NULL);
+
+               webkit_dom_node_replace_child (
+                       webkit_dom_node_get_parent_node (node),
+                       WEBKIT_DOM_NODE (element),
+                       node,
+                       NULL);
+
+               e_editor_selection_restore_caret_position (selection);
+       } else {
+               command = E_EDITOR_WIDGET_COMMAND_INDENT;
+               e_editor_widget_exec_command (editor_widget, command, NULL);
+       }
 
        g_object_unref (editor_widget);
 
        g_object_notify (G_OBJECT (selection), "indented");
 }
 
+static gboolean
+is_caret_position_node (WebKitDOMNode *node)
+{
+       return element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-caret-position");
+}
+
 /**
  * e_editor_selection_unindent:
  * @selection: an #EEditorSelection
@@ -1743,8 +1797,148 @@ e_editor_selection_unindent (EEditorSelection *selection)
        editor_widget = e_editor_selection_ref_editor_widget (selection);
        g_return_if_fail (editor_widget != NULL);
 
-       command = E_EDITOR_WIDGET_COMMAND_OUTDENT;
-       e_editor_widget_exec_command (editor_widget, command, NULL);
+       if (g_strcmp0 (e_editor_selection_get_string (selection), "") == 0) {
+               WebKitDOMDocument *document;
+               WebKitDOMElement *element;
+               WebKitDOMElement *prev_blockquote = NULL;
+               WebKitDOMElement *next_blockquote = NULL;
+               WebKitDOMNode *node;
+               WebKitDOMNode *clone;
+               WebKitDOMNode *node_clone;
+               WebKitDOMNode *caret_node;
+               WebKitDOMRange *range;
+               gboolean before_node = TRUE;
+               gboolean reinsert_caret_position = FALSE;
+
+               document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (editor_widget));
+
+               e_editor_selection_save_caret_position (selection);
+
+               range = editor_selection_get_current_range (selection);
+               if (!range) {
+                       g_object_unref (editor_widget);
+                       return;
+               }
+
+               node = webkit_dom_range_get_end_container (range, NULL);
+               if (!WEBKIT_DOM_IS_ELEMENT (node))
+                       node = WEBKIT_DOM_NODE (webkit_dom_node_get_parent_element (node));
+
+               element = webkit_dom_node_get_parent_element (node);
+
+               if (!element || !element_has_tag (element, "blockquote")) {
+                       return;
+               }
+
+               clone = WEBKIT_DOM_NODE (webkit_dom_node_clone_node (WEBKIT_DOM_NODE (element), TRUE));
+
+               /* Look if we have previous siblings, if so, we have to
+                * create new blockquote that will include them */
+               if (webkit_dom_node_get_previous_sibling (node)) {
+                       prev_blockquote = webkit_dom_document_create_element (document, "BLOCKQUOTE", NULL);
+                       /* We don't want vertical space bellow and above blockquote inserted by
+                        * WebKit's User Agent Stylesheet. We have to override it through style attribute. */
+                       element_add_class (prev_blockquote, "-x-evo-indented");
+                       webkit_dom_element_set_attribute (
+                               prev_blockquote,
+                               "style",
+                               "-webkit-margin-before: 0em; -webkit-margin-after: 0em;",
+                               NULL);
+               }
+
+               /* Look if we have next siblings, if so, we have to
+                * create new blockquote that will include them */
+               if (webkit_dom_node_get_next_sibling (node)) {
+                       next_blockquote = webkit_dom_document_create_element (document, "BLOCKQUOTE", NULL);
+                       /* We don't want vertical space bellow and above blockquote inserted by
+                        * WebKit's User Agent Stylesheet. We have to override it through style attribute. */
+                       element_add_class (next_blockquote, "-x-evo-indented");
+                       webkit_dom_element_set_attribute (
+                               next_blockquote,
+                               "style",
+                               "-webkit-margin-before: 0em; -webkit-margin-after: 0em;",
+                               NULL);
+               }
+
+               /* Copy nodes that are before / after the element that we want to unindent */
+               while (webkit_dom_node_has_child_nodes (clone)) {
+                       WebKitDOMNode *child;
+
+                       child = webkit_dom_node_get_first_child (clone);
+
+                       if (is_caret_position_node (child)) {
+                               reinsert_caret_position = TRUE;
+                               caret_node = webkit_dom_node_clone_node (child, TRUE);
+                               webkit_dom_node_remove_child (clone, child, NULL);
+                               continue;
+                       }
+
+                       if (webkit_dom_node_is_equal_node (child, node)) {
+                               before_node = FALSE;
+                               node_clone = webkit_dom_node_clone_node (child, TRUE);
+                               webkit_dom_node_remove_child (clone, child, NULL);
+                               continue;
+                       }
+
+                       webkit_dom_node_append_child (
+                               before_node ?
+                                       WEBKIT_DOM_NODE (prev_blockquote) :
+                                       WEBKIT_DOM_NODE (next_blockquote),
+                               child,
+                               NULL);
+
+                       webkit_dom_node_remove_child (clone, child, NULL);
+               }
+
+               /* Insert blockqoute with nodes that were before the element that we want to unindent */
+               if (prev_blockquote) {
+                       if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (prev_blockquote))) {
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                                       WEBKIT_DOM_NODE (prev_blockquote),
+                                       WEBKIT_DOM_NODE (element),
+                                       NULL);
+                       }
+               }
+
+               /* Reinsert the caret position */
+               if (reinsert_caret_position) {
+                       webkit_dom_node_insert_before (
+                               node_clone,
+                               caret_node,
+                               webkit_dom_node_get_first_child (node_clone),
+                               NULL);
+               }
+
+               /* Insert the unindented element */
+               webkit_dom_node_insert_before (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       node_clone,
+                       WEBKIT_DOM_NODE (element),
+                       NULL);
+
+               /* Insert blockqoute with nodes that were after the element that we want to unindent */
+               if (next_blockquote) {
+                       if (webkit_dom_node_has_child_nodes (WEBKIT_DOM_NODE (prev_blockquote))) {
+                               webkit_dom_node_insert_before (
+                                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                                       WEBKIT_DOM_NODE (next_blockquote),
+                                       WEBKIT_DOM_NODE (element),
+                                       NULL);
+                       }
+               }
+
+               /* Remove old blockquote */
+               webkit_dom_node_remove_child (
+                       webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
+                       WEBKIT_DOM_NODE (element),
+                       NULL);
+
+               e_editor_selection_restore_caret_position (selection);
+       } else {
+               command = E_EDITOR_WIDGET_COMMAND_OUTDENT;
+               e_editor_widget_exec_command (editor_widget, command, NULL);
+       }
 
        g_object_unref (editor_widget);
 
@@ -2782,6 +2976,11 @@ e_editor_selection_restore_caret_position (EEditorSelection *selection)
        element = webkit_dom_document_get_element_by_id (document, "-x-evo-caret-position");
 
        if (element) {
+               WebKitDOMDOMWindow *window;
+               WebKitDOMDOMSelection *window_selection;
+
+               window = webkit_dom_document_get_default_view (document);
+               window_selection = webkit_dom_dom_window_get_selection (window);
                /* If parent is BODY element, we try to restore the position on the 
                 * element that is next to us */
                if (WEBKIT_DOM_IS_HTML_BODY_ELEMENT (
@@ -2800,6 +2999,12 @@ e_editor_selection_restore_caret_position (EEditorSelection *selection)
 
                                move_caret_into_element (document, WEBKIT_DOM_ELEMENT (next_sibling));
 
+                               /* FIXME If caret position is restored and afterwards the position is saved
+                                * it is not on the place where it supposed to be (it is in the beginning of
+                                * parent's element. It can be avoided by moving with the caret. */
+                               webkit_dom_dom_selection_modify (window_selection, "move", "right", 
"character");
+                               webkit_dom_dom_selection_modify (window_selection, "move", "left", 
"character");
+
                                return;
                        }
                }
@@ -2809,6 +3014,12 @@ e_editor_selection_restore_caret_position (EEditorSelection *selection)
                        webkit_dom_node_get_parent_node (WEBKIT_DOM_NODE (element)),
                        WEBKIT_DOM_NODE (element),
                        NULL);
+
+               /* FIXME If caret position is restored and afterwards the position is saved
+                * it is not on the place where it supposed to be (it is in the beginning of
+                * parent's element. It can be avoided by moving with the caret. */
+               webkit_dom_dom_selection_modify (window_selection, "move", "right", "character");
+               webkit_dom_dom_selection_modify (window_selection, "move", "left", "character");
        }
 }
 
@@ -2890,12 +3101,6 @@ find_where_to_break_line (WebKitDOMNode *node,
        return ret_val;
 }
 
-static gboolean
-is_caret_position_node (WebKitDOMNode *node)
-{
-       return element_has_id (WEBKIT_DOM_ELEMENT (node), "-x-evo-caret-position");
-}
-
 static void
 wrap_lines (EEditorSelection *selection,
            WebKitDOMNode *paragraph,
diff --git a/e-util/e-editor-widget.c b/e-util/e-editor-widget.c
index dc4f2c8..3bc5271 100644
--- a/e-util/e-editor-widget.c
+++ b/e-util/e-editor-widget.c
@@ -1967,6 +1967,123 @@ e_editor_widget_get_html_mode (EEditorWidget *widget)
 }
 
 static void
+process_blockquote (WebKitDOMElement *blockquote)
+{
+       WebKitDOMNodeList *list;
+       int jj, length;
+
+       /* First replace wrappers */
+       list = webkit_dom_element_query_selector_all (
+               blockquote,
+               "span.-x-evo-temp-text-wrapper",
+               NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+
+       for (jj = 0; jj < length; jj++) {
+               WebKitDOMNode *quoted_node;
+               gchar *text_content;
+
+               quoted_node = webkit_dom_node_list_item (list, jj);
+               text_content = webkit_dom_node_get_text_content (quoted_node);
+
+               webkit_dom_html_element_set_outer_html (
+                       WEBKIT_DOM_HTML_ELEMENT (quoted_node),
+                       text_content,
+                       NULL);
+               g_free (text_content);
+       }
+
+       /* Afterwards replace quote nodes with symbols */
+       list = webkit_dom_element_query_selector_all (
+               blockquote,
+               "span.-x-evo-quoted",
+               NULL);
+
+       length = webkit_dom_node_list_get_length (list);
+
+       for (jj = 0; jj < length; jj++) {
+               WebKitDOMNode *quoted_node;
+               gchar *text_content;
+
+               quoted_node = webkit_dom_node_list_item (list, jj);
+               text_content = webkit_dom_node_get_text_content (quoted_node);
+
+               webkit_dom_html_element_set_outer_html (
+                       WEBKIT_DOM_HTML_ELEMENT (quoted_node),
+                       text_content,
+                       NULL);
+               g_free (text_content);
+       }
+
+       if (element_has_class (blockquote, "-x-evo-indented")) {
+               WebKitDOMElement *parent;
+               WebKitDOMNode *child;
+               gint level = 1;
+               gchar *spaces;
+
+               webkit_dom_element_remove_attribute (blockquote, "style");
+               element_remove_class (blockquote, "-x-evo-indented");
+
+               parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (blockquote));
+               /* Count level of indentation */
+               while (!WEBKIT_DOM_IS_HTML_BODY_ELEMENT (parent)) {
+                       if (element_has_class (parent, "-x-evo-indented"))
+                               level++;
+
+                       parent = webkit_dom_node_get_parent_element (WEBKIT_DOM_NODE (parent));
+               }
+
+               spaces = g_strnfill (4 * level, ' ');
+
+               child = webkit_dom_node_get_first_child (WEBKIT_DOM_NODE (blockquote));
+               while (child) {
+                       /* If next sibling is indented blockqoute skip it,
+                        * it will be processed afterwards */
+                       if (WEBKIT_DOM_IS_ELEMENT (child) &&
+                           element_has_class (WEBKIT_DOM_ELEMENT (child), "-x-evo-indented"))
+                               child = webkit_dom_node_get_next_sibling (child);
+
+                       if (WEBKIT_DOM_IS_TEXT (child)) {
+                               gchar *text_content;
+                               gchar *indented_text;
+
+                               text_content = webkit_dom_text_get_whole_text (WEBKIT_DOM_TEXT (child));
+
+                               /* FIXME Fix properly in wrapping => do not include space on the beginning of 
the line */
+                               if (g_str_has_prefix (text_content, " "))
+                                       indented_text = g_strconcat (spaces + 1, text_content, NULL);
+                               else
+                                       indented_text = g_strconcat (spaces, text_content, NULL);
+
+                               webkit_dom_text_replace_whole_text (
+                                       WEBKIT_DOM_TEXT (child),
+                                       indented_text,
+                                       NULL);
+
+                               g_free (text_content);
+                               g_free (indented_text);
+                       }
+
+                       /* Move to next node */
+                       if (webkit_dom_node_has_child_nodes (child))
+                               child = webkit_dom_node_get_first_child (child);
+                       else if (webkit_dom_node_get_next_sibling (child))
+                               child = webkit_dom_node_get_next_sibling (child);
+                       else {
+                               if (webkit_dom_node_is_equal_node (child, child))
+                                       break;
+
+                               child = webkit_dom_node_get_parent_node (child);
+                               if (child)
+                                       child = webkit_dom_node_get_next_sibling (child);
+                       }
+               }
+               g_free (spaces);
+       }
+}
+
+static void
 process_elements (WebKitDOMNode *node,
                   GString *buffer,
                  gboolean process_nodes)
@@ -2054,54 +2171,8 @@ process_elements (WebKitDOMNode *node,
                                        g_string_append (buffer, content);
                                        g_free (content);
                                        skip_node = TRUE;
-                               } else {
-                                       WebKitDOMNodeList *list;
-                                       int jj, length;
-
-                                       /* First replace wrappers */
-                                       list = webkit_dom_element_query_selector_all (
-                                                       WEBKIT_DOM_ELEMENT (child),
-                                                       "span.-x-evo-temp-text-wrapper",
-                                                       NULL);
-
-                                       length = webkit_dom_node_list_get_length (list);
-
-                                       for (jj = 0; jj < length; jj++) {
-                                               WebKitDOMNode *quoted_node;
-                                               gchar *text_content;
-
-                                               quoted_node = webkit_dom_node_list_item (list, jj);
-                                               text_content = webkit_dom_node_get_text_content (quoted_node);
-
-                                               webkit_dom_html_element_set_outer_html (
-                                                       WEBKIT_DOM_HTML_ELEMENT (quoted_node),
-                                                       text_content,
-                                                       NULL);
-                                               g_free (text_content);
-                                       }
-
-                                       /* Afterwards replace quote nodes with symbols */
-                                       list = webkit_dom_element_query_selector_all (
-                                                       WEBKIT_DOM_ELEMENT (child),
-                                                       "span.-x-evo-quoted",
-                                                       NULL);
-
-                                       length = webkit_dom_node_list_get_length (list);
-
-                                       for (jj = 0; jj < length; jj++) {
-                                               WebKitDOMNode *quoted_node;
-                                               gchar *text_content;
-
-                                               quoted_node = webkit_dom_node_list_item (list, jj);
-                                               text_content = webkit_dom_node_get_text_content (quoted_node);
-
-                                               webkit_dom_html_element_set_outer_html (
-                                                       WEBKIT_DOM_HTML_ELEMENT (quoted_node),
-                                                       text_content,
-                                                       NULL);
-                                               g_free (text_content);
-                                       }
-                               }
+                               } else
+                                       process_blockquote (WEBKIT_DOM_ELEMENT (child));
                        }
 
                        /* Leave wrapped paragraphs as they are */
@@ -2114,6 +2185,16 @@ process_elements (WebKitDOMNode *node,
                                }
                        }
 
+                       /* Leave PRE elements untouched */
+                       if (WEBKIT_DOM_IS_HTML_PRE_ELEMENT (child)) {
+                               if (!process_nodes) {
+                                       content = webkit_dom_html_element_get_outer_html 
(WEBKIT_DOM_HTML_ELEMENT (child));
+                                       g_string_append (buffer, content);
+                                       g_free (content);
+                                       skip_node = TRUE;
+                               }
+                       }
+
                        /* Insert new line when we hit BR element */
                        if (WEBKIT_DOM_IS_HTMLBR_ELEMENT (child))
                                g_string_append (buffer, process_nodes ? "\n" : "<br>");
@@ -2132,6 +2213,9 @@ process_elements (WebKitDOMNode *node,
                if (!next_sibling)
                        add_br = FALSE;
 
+               if (element_has_class (webkit_dom_node_get_parent_element (node), "-x-evo-indented"))
+                       add_br = TRUE;
+
                if (next_sibling && WEBKIT_DOM_IS_HTML_DIV_ELEMENT (next_sibling)) {
                        if (webkit_dom_element_query_selector (WEBKIT_DOM_ELEMENT (next_sibling), 
"span.-x-evolution-signature", NULL))
                                add_br = FALSE;


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