[evolution/wip/mcrha/webkit-jsc-api: 247/292] Indent/Unindent in lists (UL/OL)



commit d7bc63bcae9977575cf496a9996261bd3eb65b10
Author: Milan Crha <mcrha redhat com>
Date:   Fri Nov 29 09:58:23 2019 +0100

    Indent/Unindent in lists (UL/OL)

 data/webkit/e-convert.js                    |  14 +-
 data/webkit/e-editor.js                     | 391 +++++++++++++++++++++++-----
 data/webkit/e-undo-redo.js                  | 233 ++++++++++-------
 src/e-util/test-html-editor-units-utils.c   |   4 +-
 src/e-util/test-html-editor-units.c         | 145 ++++++-----
 src/modules/webkit-editor/e-webkit-editor.c |  96 ++++---
 6 files changed, 620 insertions(+), 263 deletions(-)
---
diff --git a/data/webkit/e-convert.js b/data/webkit/e-convert.js
index 9701f70ae8..50a67d592a 100644
--- a/data/webkit/e-convert.js
+++ b/data/webkit/e-convert.js
@@ -177,10 +177,18 @@ EvoConvert.replaceList = function(element, tagName)
                                        level++;
                        }
 
-                       if (!(level % 2))
+                       switch (level % 2) {
+                       default:
+                       case 0:
                                prefixSuffix = " * ";
-                       else
-                               prefixSuffix = " # ";
+                               break;
+                       case 1:
+                               prefixSuffix = " - ";
+                               break;
+                       case 2:
+                               prefixSuffix = " + ";
+                               break;
+                       }
 
                        indent = 3;
                } else {
diff --git a/data/webkit/e-editor.js b/data/webkit/e-editor.js
index 7068339ed2..9d4c5eb45f 100644
--- a/data/webkit/e-editor.js
+++ b/data/webkit/e-editor.js
@@ -322,6 +322,9 @@ EvoEditor.maybeUpdateFormattingState = function(force)
                        if (Number.isInteger(tmp)) {
                                obj.indented = tmp > 0;
                        }
+
+                       if (parent.tagName == "UL" || parent.tagName == "OL")
+                               obj.indented = true;
                }
 
                if (obj.bgColor == null && parent.style.backgroundColor != "") {
@@ -414,18 +417,18 @@ EvoEditor.foreachChildRecur = function(topParent, parent, firstChildIndex, lastC
        while (child && ii >= 0) {
                next = child.nextElementSibling;
 
-               if (!traversar.onlyBlockElements || EvoEditor.IsBlockNode(child)) {
-                       if (!traversar.exec(topParent, child)) {
-                               return false;
-                       }
-               }
-
                if (child.children.length > 0 &&
                    !traversar.flat &&
                    !EvoEditor.foreachChildRecur(topParent, child, 0, child.children.length - 1, traversar)) {
                        return false;
                }
 
+               if (!traversar.onlyBlockElements || EvoEditor.IsBlockNode(child)) {
+                       if (!traversar.exec(topParent, child)) {
+                               return false;
+                       }
+               }
+
                child = next;
                ii--;
        }
@@ -651,6 +654,12 @@ EvoEditor.RestoreSelection = function()
        }
 }
 
+EvoEditor.removeEmptyStyleAttribute = function(element)
+{
+       if (element && !element.style.length)
+               element.removeAttribute("style");
+}
+
 EvoEditor.applySetAlignment = function(record, isUndo)
 {
        if (record.changes) {
@@ -662,14 +671,23 @@ EvoEditor.applySetAlignment = function(record, isUndo)
                }
 
                for (ii = 0; ii < record.changes.length; ii++) {
-                       var change = record.changes[ii];
+                       var change = record.changes[isUndo ? (record.changes.length - ii - 1) : ii];
 
                        child = EvoSelection.FindElementByPath(parent, change.path);
                        if (!child) {
                                throw "EvoEditor.applySetAlignment: Cannot find child";
                        }
 
-                       child.style.textAlign = isUndo ? change.before : record.applyValueAfter;
+                       if (isUndo) {
+                               child.style.textAlign = change.before;
+                       } else if ((record.applyValueAfter == "left" && child.style.direction != "rtl" && 
window.getComputedStyle(child).direction != "rtl") ||
+                                  (record.applyValueAfter == "right" && (child.style.direction == "rtl" || 
window.getComputedStyle(child).direction == "rtl"))) {
+                               child.style.textAlign = "";
+                       } else {
+                               child.style.textAlign = record.applyValueAfter;
+                       }
+
+                       EvoEditor.removeEmptyStyleAttribute(child);
                }
        }
 }
@@ -699,7 +717,15 @@ EvoEditor.SetAlignment = function(alignment)
                                }
 
                                traversar.anyChanged = true;
-                               element.style.textAlign = traversar.toSet;
+
+                               if ((traversar.toSet == "left" && element.style.direction != "rtl" && 
window.getComputedStyle(element).direction != "rtl") ||
+                                   (traversar.toSet == "right" && (element.style.direction == "rtl" || 
window.getComputedStyle(element).direction == "rtl"))) {
+                                       element.style.textAlign = "";
+                               } else {
+                                       element.style.textAlign = traversar.toSet;
+                               }
+
+                               EvoEditor.removeEmptyStyleAttribute(element);
                        }
 
                        return true;
@@ -993,6 +1019,91 @@ EvoEditor.SetBlockFormat = function(format)
        }
 }
 
+EvoEditor.allChildrenInSelection = function(element, allowPartial, affected)
+{
+       if (!element || !element.firstChild)
+               return false;
+
+       var selection = document.getSelection(), all;
+
+       all = selection.containsNode(element.firstElementChild, allowPartial) &&
+             selection.containsNode(element.lastElementChild, allowPartial);
+
+       var node;
+
+       affected.length = 0;
+
+       for (node = element.firstElementChild; node; node = node.nextElementSibling) {
+               if (all || selection.containsNode(node, allowPartial))
+                       affected[affected.length] = node;
+       }
+
+       return all;
+}
+
+EvoEditor.splitList = function(element, nParents, onlyAffected)
+{
+       var parent, from;
+
+       if (onlyAffected && onlyAffected.length)
+               from = onlyAffected[onlyAffected.length - 1].nextElementSibling;
+       else
+               from = element.nextElementSibling;
+
+       if (nParents == -1) {
+               nParents = 0;
+
+               for (parent = from; parent && parent.tagName != "BODY"; parent = parent.parentElement) {
+                       nParents++;
+               }
+       }
+
+       var nextFrom, clone;
+
+       parent = from ? from.parentElement : element.parentElement;
+
+       while (nParents > 0 && parent && parent.tagName != "HTML") {
+               nParents--;
+               nextFrom = null;
+
+               if (from) {
+                       clone = from.parentElement.cloneNode(false);
+                       from.parentElement.parentElement.insertBefore(clone, 
from.parentElement.nextElementSibling);
+
+                       nextFrom = clone;
+
+                       while (from.nextElementSibling) {
+                               clone.appendChild(from.nextElementSibling);
+                       }
+
+                       clone.insertBefore(from, clone.firstElementChild);
+               }
+
+               from = nextFrom;
+               parent = parent.parentElement;
+       }
+
+       if (nextFrom)
+               return nextFrom;
+
+       return parent.nextElementSibling;
+}
+
+EvoEditor.insertListChildBefore = function(child, parent, insBefore)
+{
+       if (child.tagName == "LI") {
+               var node = document.createElement("DIV");
+
+               while(child.firstChild)
+                       node.appendChild(child.firstChild);
+
+               parent.insertBefore(node, insBefore);
+               child.parentElement.removeChild(child);
+       } else {
+               parent.insertBefore(child, insBefore);
+       }
+}
+
 EvoEditor.applyIndent = function(record, isUndo)
 {
        if (record.changes) {
@@ -1004,13 +1115,18 @@ EvoEditor.applyIndent = function(record, isUndo)
                }
 
                for (ii = 0; ii < record.changes.length; ii++) {
-                       var change = record.changes[ii];
+                       var change = record.changes[isUndo ? (record.changes.length - ii - 1) : ii];
 
-                       child = EvoSelection.FindElementByPath(parent, change.path);
+                       child = EvoSelection.FindElementByPath(change.pathIsFromBody ? document.body : 
parent, change.path);
                        if (!child) {
                                throw "EvoEditor.applyIndent: Cannot find child";
                        }
 
+                       if (change.isList) {
+                               EvoUndoRedo.RestoreChildren(change, child, isUndo);
+                               continue;
+                       }
+
                        if (isUndo) {
                                child.style.marginLeft = change.beforeMarginLeft;
                                child.style.marginRight = change.beforeMarginRight;
@@ -1018,6 +1134,8 @@ EvoEditor.applyIndent = function(record, isUndo)
                                child.style.marginLeft = change.afterMarginLeft;
                                child.style.marginRight = change.afterMarginRight;
                        }
+
+                       EvoEditor.removeEmptyStyleAttribute(child);
                }
        }
 }
@@ -1026,63 +1144,203 @@ EvoEditor.Indent = function(increment)
 {
        var traversar = {
                record : null,
+               selectionUpdater : null,
                increment : increment,
 
-               flat : false,
+               flat : true,
                onlyBlockElements : true,
 
                exec : function(parent, element) {
-                       var change = null;
+                       var change = null, isList = element.tagName == "UL" || element.tagName == "OL";
+                       var isNested = isList && (element.parentElement.tagName == "UL" || 
element.parentElement.tagName == "OL");
 
                        if (traversar.record) {
                                if (!traversar.record.changes)
                                        traversar.record.changes = [];
 
                                change = {};
-                               change.path = EvoSelection.GetChildPath(parent, element);
-                               change.beforeMarginLeft = element.style.marginLeft;
-                               change.beforeMarginRight = element.style.marginRight;
+
+                               change.pathIsFromBody = false;
+
+                               if (isList) {
+                                       change.isList = isList;
+                                       change.path = EvoSelection.GetChildPath(parent, element);
+                               } else {
+                                       change.path = EvoSelection.GetChildPath(parent, element);
+                                       change.beforeMarginLeft = element.style.marginLeft;
+                                       change.beforeMarginRight = element.style.marginRight;
+                               }
 
                                traversar.record.changes[traversar.record.changes.length] = change;
                        }
 
-                       var currValue = null, dir;
+                       if (isList) {
+                               var elemParent = null, all, affected = [], jj;
 
-                       dir = window.getComputedStyle(element).direction;
+                               all = EvoEditor.allChildrenInSelection(element, true, affected);
 
-                       if (dir == "rtl") {
-                               if (element.style.marginRight.endsWith("ch"))
-                                       currValue = element.style.marginRight;
-                       } else { // "ltr" or other
-                               if (element.style.marginLeft.endsWith("ch"))
-                                       currValue = element.style.marginLeft;
-                       }
+                               if (this.increment) {
+                                       var clone;
+
+                                       clone = element.cloneNode(false);
+
+                                       if (all) {
+                                               if (change) {
+                                                       var childIndex = 
EvoEditor.GetChildIndex(element.parentElement, element);
+                                                       EvoUndoRedo.BackupChildrenBefore(change, 
element.parentElement, childIndex, childIndex);
+                                                       change.path = EvoSelection.GetChildPath(parent, 
element.parentElement);
+                                               }
+
+                                               element.parentElement.insertBefore(clone, element);
+                                               clone.appendChild(element);
+
+                                               if (change)
+                                                       EvoUndoRedo.BackupChildrenAfter(change, 
clone.parentElement);
+                                       } else if (affected.length > 0) {
+                                               if (change) {
+                                                       EvoUndoRedo.BackupChildrenBefore(change, element,
+                                                               EvoEditor.GetChildIndex(element, affected[0]),
+                                                               EvoEditor.GetChildIndex(element, 
affected[affected.length - 1]));
+                                               }
+
+                                               element.insertBefore(clone, affected[0]);
+
+                                               for (jj = 0; jj < affected.length; jj++) {
+                                                       clone.appendChild(affected[jj]);
+                                               }
+
+                                               if (change)
+                                                       EvoUndoRedo.BackupChildrenAfter(change, element);
+                                       }
+                               } else {
+                                       var insBefore = null;
+
+                                       elemParent = element.parentElement;
+
+                                       // decrease indent in nested lists of the same type will merge items 
into one list
+                                       if (isNested && elemParent.tagName == element.tagName &&
+                                           elemParent.getAttribute("type") == element.getAttribute("type")) {
+                                               if (change) {
+                                                       var childIndex = EvoEditor.GetChildIndex(elemParent, 
element);
+                                                       EvoUndoRedo.BackupChildrenBefore(change, elemParent, 
childIndex, childIndex);
+                                                       change.path = EvoSelection.GetChildPath(parent, 
elemParent);
+                                               }
+
+                                               if (!all && affected.length > 0 && !(affected[0] === 
element.firstElementChild)) {
+                                                       insBefore = EvoEditor.splitList(element, 1, affected);
+                                               } else {
+                                                       insBefore = element;
+                                               }
+
+                                               for (jj = 0; jj < affected.length; jj++) {
+                                                       elemParent.insertBefore(affected[jj], insBefore);
+                                               }
+
+                                               if (!element.childElementCount) {
+                                                       this.selectionUpdater.beforeRemove(element);
+
+                                                       element.parentElement.removeChild(element);
+
+                                                       this.selectionUpdater.afterRemove(affected[0]);
+                                               }
+
+                                               if (change)
+                                                       EvoUndoRedo.BackupChildrenAfter(change, elemParent);
+                                       } else {
+                                               var tmpElement = element;
+
+                                               if (isNested) {
+                                                       tmpElement = elemParent;
+                                                       elemParent = elemParent.parentElement;
+                                               }
+
+                                               if (change) {
+                                                       var childIndex = EvoEditor.GetChildIndex(elemParent, 
tmpElement);
+                                                       EvoUndoRedo.BackupChildrenBefore(change, elemParent, 
childIndex, childIndex);
+                                                       if (isNested) {
+                                                               change.pathIsFromBody = true;
+                                                               change.path = 
EvoSelection.GetChildPath(document.body, elemParent);
+                                                       } else {
+                                                               change.path = 
EvoSelection.GetChildPath(parent, elemParent);
+                                                       }
+                                               }
+
+                                               if (isNested) {
+                                                       var clone;
+
+                                                       insBefore = EvoEditor.splitList(element, 2, affected);
+
+                                                       clone = element.cloneNode(false);
+                                                       elemParent.insertBefore(clone, insBefore);
 
-                       if (!currValue) {
-                               currValue = 0;
+                                                       for (jj = 0; jj < affected.length; jj++) {
+                                                               clone.appendChild(affected[jj]);
+                                                       }
+                                               } else {
+                                                       if (!all && affected.length > 0 && !(affected[0] === 
element.firstElementChild)) {
+                                                               insBefore = EvoEditor.splitList(element, 1, 
affected);
+                                                       } else {
+                                                               insBefore = element.nextElementSibling;
+                                                       }
+
+                                                       for (jj = 0; jj < affected.length; jj++) {
+                                                               EvoEditor.insertListChildBefore(affected[jj], 
insBefore ? insBefore.parentElement : elemParent, insBefore);
+                                                       }
+                                               }
+
+                                               if (!element.childElementCount) {
+                                                       this.selectionUpdater.beforeRemove(element);
+
+                                                       element.parentElement.removeChild(element);
+
+                                                       this.selectionUpdater.afterRemove(insBefore ? 
insBefore.previousElementSibling : elemParent.lastElementChild);
+                                               }
+
+                                               if (change)
+                                                       EvoUndoRedo.BackupChildrenAfter(change, elemParent);
+                                       }
+                               }
                        } else {
-                               currValue = parseInt(currValue.slice(0, -2));
-                               if (!Number.isInteger(currValue))
+                               var currValue = null, dir;
+
+                               dir = window.getComputedStyle(element).direction;
+
+                               if (dir == "rtl") {
+                                       if (element.style.marginRight.endsWith("ch"))
+                                               currValue = element.style.marginRight;
+                               } else { // "ltr" or other
+                                       if (element.style.marginLeft.endsWith("ch"))
+                                               currValue = element.style.marginLeft;
+                               }
+
+                               if (!currValue) {
                                        currValue = 0;
-                       }
+                               } else {
+                                       currValue = parseInt(currValue.slice(0, -2));
+                                       if (!Number.isInteger(currValue))
+                                               currValue = 0;
+                               }
 
-                       if (traversar.increment) {
-                               currValue = (currValue + EvoEditor.TEXT_INDENT_SIZE) + "ch";
-                       } else if (currValue > EvoEditor.TEXT_INDENT_SIZE) {
-                               currValue = (currValue - EvoEditor.TEXT_INDENT_SIZE) + "ch";
-                       } else if (currValue > 0) {
-                               currValue = "";
-                       }
+                               if (traversar.increment) {
+                                       currValue = (currValue + EvoEditor.TEXT_INDENT_SIZE) + "ch";
+                               } else if (currValue > EvoEditor.TEXT_INDENT_SIZE) {
+                                       currValue = (currValue - EvoEditor.TEXT_INDENT_SIZE) + "ch";
+                               } else if (currValue > 0) {
+                                       currValue = "";
+                               }
 
-                       if (dir == "rtl") {
-                               element.style.marginRight = currValue;
-                       } else { // "ltr" or other
-                               element.style.marginLeft = currValue;
-                       }
+                               if (dir == "rtl") {
+                                       element.style.marginRight = currValue;
+                               } else { // "ltr" or other
+                                       element.style.marginLeft = currValue;
+                               }
+
+                               if (change) {
+                                       change.afterMarginLeft = element.style.marginLeft;
+                                       change.afterMarginRight = element.style.marginRight;
+                               }
 
-                       if (change) {
-                               change.afterMarginLeft = element.style.marginLeft;
-                               change.afterMarginRight = element.style.marginRight;
+                               EvoEditor.removeEmptyStyleAttribute(element);
                        }
 
                        return true;
@@ -1092,6 +1350,7 @@ EvoEditor.Indent = function(increment)
        var affected = EvoEditor.ClaimAffectedContent(null, null, 
EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
 
        traversar.record = EvoUndoRedo.StartRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, increment ? "Indent" : 
"Outdent", null, null, EvoEditor.CLAIM_CONTENT_FLAG_USE_PARENT_BLOCK_NODE);
+       traversar.selectionUpdater = EvoSelection.CreateUpdaterObject();
 
        try {
                EvoEditor.ForeachChildInAffectedContent(affected, traversar);
@@ -1100,6 +1359,8 @@ EvoEditor.Indent = function(increment)
                        traversar.record.applyIncrement = increment;
                        traversar.record.apply = EvoEditor.applyIndent;
                }
+
+               traversar.selectionUpdater.restore();
        } finally {
                EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, increment ? "Indent" : "Outdent");
                EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
@@ -1163,8 +1424,10 @@ EvoEditor.applySetBodyFontName = function(record, isUndo)
 {
        EvoEditor.UpdateStyleSheet("x-evo-body-fontname", isUndo ? record.beforeCSS : record.afterCSS);
 
-       if (record.beforeStyle != record.afterStyle)
+       if (record.beforeStyle != record.afterStyle) {
                document.body.style.fontFamily = isUndo ? record.beforeStyle : record.afterStyle;
+               EvoEditor.removeEmptyStyleAttribute(body.document);
+       }
 }
 
 EvoEditor.SetBodyFontName = function(name)
@@ -1197,6 +1460,8 @@ EvoEditor.SetBodyFontName = function(name)
                        if (record.beforeCSS == record.afterCSS && record.beforeStyle == record.afterStyle)
                                record.ignore = true;
                }
+
+               EvoEditor.removeEmptyStyleAttribute(document.body);
        } finally {
                EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_CUSTOM, "setBodyFontName");
                EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_YES);
@@ -1238,6 +1503,7 @@ EvoEditor.convertParagraphs = function(parent, wrapWidth)
                if (child.tagName == "DIV") {
                        if (wrapWidth == -1) {
                                child.style.width = "";
+                               EvoEditor.removeEmptyStyleAttribute(child);
                        } else {
                                child.style.width = wrapWidth + "ch";
                        }
@@ -1253,6 +1519,7 @@ EvoEditor.convertParagraphs = function(parent, wrapWidth)
                } else if (child.tagName == "UL") {
                        if (wrapWidth == -1) {
                                child.style.width = "";
+                               EvoEditor.removeEmptyStyleAttribute(child);
                        } else {
                                var innerWrapWidth = wrapWidth;
 
@@ -1267,10 +1534,11 @@ EvoEditor.convertParagraphs = function(parent, wrapWidth)
                        if (wrapWidth == -1) {
                                child.style.width = "";
                                child.style.paddingInlineStart = "";
+                               EvoEditor.removeEmptyStyleAttribute(child);
                        } else {
                                var innerWrapWidth = wrapWidth, olNeedWidth;
 
-                               olNeedWidth = EvoEditor.GetOLMaxLetters(child.getAttribute("type"), 
child.children.length) + 2; // length of ". " suffix
+                               olNeedWidth = EvoConvert.GetOLMaxLetters(child.getAttribute("type"), 
child.children.length) + 2; // length of ". " suffix
 
                                if (olNeedWidth < EvoConvert.MIN_OL_WIDTH)
                                        olNeedWidth = EvoConvert.MIN_OL_WIDTH;
@@ -1339,28 +1607,15 @@ EvoEditor.applyFontReset = function(record, isUndo)
        if (record.changes) {
                var ii;
 
-               if (isUndo) {
-                       for (ii = record.changes.length - 1; ii >= 0; ii--) {
-                               var change = record.changes[ii];
-                               var parent = EvoSelection.FindElementByPath(document.body, change.parentPath);
-
-                               if (!parent) {
-                                       throw "EvoEditor.applyFontReset: Cannot find node at path " + 
change.path;
-                               }
+               for (ii = 0; ii < record.changes.length; ii++) {
+                       var change = record.changes[isUndo ? (record.changes.length - ii - 1) : ii];
+                       var parent = EvoSelection.FindElementByPath(document.body, change.parentPath);
 
-                               parent.innerHTML = change.htmlBefore;
+                       if (!parent) {
+                               throw "EvoEditor.applyFontReset: Cannot find node at path " + change.path;
                        }
-               } else {
-                       for (ii = 0; ii < record.changes.length; ii++) {
-                               var change = record.changes[ii];
-                               var parent = EvoSelection.FindElementByPath(document.body, change.parentPath);
 
-                               if (!parent) {
-                                       throw "EvoEditor.applyFontReset: Cannot find node at path " + 
change.path;
-                               }
-
-                               parent.innerHTML = change.htmlAfter;
-                       }
+                       parent.innerHTML = isUndo ? change.htmlBefore : change.htmlAfter;
                }
        }
 }
@@ -1485,6 +1740,8 @@ EvoEditor.SetFontName = function(name)
                EvoUndoRedo.StopRecord(EvoUndoRedo.RECORD_KIND_GROUP, "SetFontName");
                EvoEditor.maybeUpdateFormattingState(EvoEditor.FORCE_MAYBE);
                EvoEditor.EmitContentChanged();
+
+               EvoEditor.removeEmptyStyleAttribute(document.body);
        }
 }
 
@@ -1689,7 +1946,7 @@ EvoEditor.GetContent = function(flags, cid_uid_prefix)
                        content_data["to-send-html"] = EvoEditor.convertHtmlToSend();
 
                if ((flags & EvoEditor. E_CONTENT_EDITOR_GET_TO_SEND_PLAIN) != 0) {
-                       content_data["to-send-plain"] = EvoConvert.ToPlainText(document.body);
+                       content_data["to-send-plain"] = EvoConvert.ToPlainText(document.body, 
EvoEditor.NORMAL_PARAGRAPH_WIDTH);
                }
        } finally {
                try {
diff --git a/data/webkit/e-undo-redo.js b/data/webkit/e-undo-redo.js
index 8d907644e4..3f22f36d61 100644
--- a/data/webkit/e-undo-redo.js
+++ b/data/webkit/e-undo-redo.js
@@ -498,23 +498,13 @@ EvoUndoRedo.applyRecord = function(record, isUndo, withSelection)
                records = record.records;
 
                if (records && records.length) {
-                       if (isUndo) {
-                               for (ii = records.length - 1; ii >= 0; ii--) {
-                                       EvoUndoRedo.applyRecord(records[ii], isUndo, false);
-                               }
-                       } else {
-                               for (ii = 0; ii < records.length; ii++) {
-                                       EvoUndoRedo.applyRecord(records[ii], isUndo, false);
-                               }
+                       for (ii = 0; ii < records.length; ii++) {
+                               EvoUndoRedo.applyRecord(records[isUndo ? (records.length - ii - 1) : ii], 
isUndo, false);
                        }
                }
 
                if (withSelection) {
-                       if (isUndo) {
-                               EvoSelection.Restore(document, record.selectionBefore);
-                       } else {
-                               EvoSelection.Restore(document, record.selectionAfter);
-                       }
+                       EvoSelection.Restore(document, isUndo ? record.selectionBefore : 
record.selectionAfter);
                }
 
                return;
@@ -536,67 +526,18 @@ EvoUndoRedo.applyRecord = function(record, isUndo, withSelection)
                } else if (kind == EvoUndoRedo.RECORD_KIND_CUSTOM && record.apply != null) {
                        record.apply(record, isUndo);
                } else {
-                       var commonParent, first, last, ii;
+                       var commonParent;
 
                        commonParent = EvoSelection.FindElementByPath(document.body, record.path);
                        if (!commonParent) {
                                throw "EvoUndoRedo::applyRecord: Cannot find parent at path " + record.path;
                        }
 
-                       first = record.firstChildIndex;
-
-                       if (first == -1) {
-                               if (isUndo) {
-                                       commonParent.innerHTML = record.htmlBefore;
-                               } else {
-                                       commonParent.innerHTML = record.htmlAfter;
-                               }
-                       } else {
-                               // it can equal to the children.length, when the node had been removed
-                               if (first < 0 || first > commonParent.children.length) {
-                                       throw "EvoUndoRedo::applyRecord: firstChildIndex (" + first + ") out 
of bounds (" + commonParent.children.length + ")";
-                               }
-
-                               last = commonParent.children.length - record.restChildrenCount;
-                               if (last < 0 || last < first) {
-                                       throw "EvoUndoRedo::applyRecord: restChildrenCount (" + 
record.restChildrenCount + ") out of bounds (length:" +
-                                               commonParent.children.length + " first:" + first + " last:" + 
last + ")";
-                               }
-
-                               for (ii = last - 1; ii >= first; ii--) {
-                                       if (ii >= 0 && ii < commonParent.children.length) {
-                                               commonParent.removeChild(commonParent.children.item(ii));
-                                       }
-                               }
-
-                               var tmpNode = document.createElement("evo-tmp");
-
-                               if (isUndo) {
-                                       tmpNode.innerHTML = record.htmlBefore;
-                               } else {
-                                       tmpNode.innerHTML = record.htmlAfter;
-                               }
-
-                               if (first < commonParent.children.length) {
-                                       first = commonParent.children.item(first);
-
-                                       while(tmpNode.firstElementChild) {
-                                               commonParent.insertBefore(tmpNode.firstElementChild, first);
-                                       }
-                               } else {
-                                       while(tmpNode.children.length) {
-                                               commonParent.appendChild(tmpNode.children.item(0));
-                                       }
-                               }
-                       }
+                       EvoUndoRedo.RestoreChildren(record, commonParent, isUndo);
                }
 
                if (withSelection) {
-                       if (isUndo) {
-                               EvoSelection.Restore(document, record.selectionBefore);
-                       } else {
-                               EvoSelection.Restore(document, record.selectionAfter);
-                       }
+                       EvoSelection.Restore(document, isUndo ? record.selectionBefore : 
record.selectionAfter);
                }
        } finally {
                EvoUndoRedo.Enable();
@@ -647,6 +588,7 @@ EvoUndoRedo.StopRecord = function(kind, opType)
 
        var record = EvoUndoRedo.ongoingRecordings[EvoUndoRedo.ongoingRecordings.length - 1];
 
+       // Events can overlap sometimes, like when doing drag&drop inside web view
        if (record.kind != kind || record.opType != opType) {
                var ii;
 
@@ -688,7 +630,7 @@ EvoUndoRedo.StopRecord = function(kind, opType)
        if (kind == EvoUndoRedo.RECORD_KIND_DOCUMENT) {
                record.htmlAfter = document.documentElement.innerHTML;
        } else if (record.htmlBefore != window.undefined) {
-               var commonParent, first, last, ii, html = "";
+               var commonParent;
 
                commonParent = EvoSelection.FindElementByPath(document.body, record.path);
 
@@ -696,39 +638,16 @@ EvoUndoRedo.StopRecord = function(kind, opType)
                        throw "EvoUndoRedo.StopRecord:: Failed to stop '" + opType + "', cannot find common 
parent";
                }
 
-               first = record.firstChildIndex;
-
-               if (first == -1) {
-                       html = commonParent.innerHTML;
-               } else {
-                       // it can equal to the children.length, when the node had been removed
-                       if (first < 0 || first > commonParent.children.length) {
-                               throw "EvoUndoRedo::StopRecord: firstChildIndex (" + first + ") out of bounds 
(" + commonParent.children.length + ")";
-                       }
-
-                       last = commonParent.children.length - record.restChildrenCount;
-                       if (last < 0 || last < first) {
-                               throw "EvoUndoRedo::StopRecord: restChildrenCount (" + 
record.restChildrenCount + ") out of bounds (length:" +
-                                       commonParent.children.length + " first:" + first + " last:" + last + 
")";
-                       }
-
-                       for (ii = first; ii < last; ii++) {
-                               if (ii >= 0 && ii < commonParent.children.length) {
-                                       html += commonParent.children.item(ii).outerHTML;
-                               }
-                       }
-               }
+               EvoUndoRedo.BackupChildrenAfter(record, commonParent);
 
                // some formatting commands do not change HTML structure immediately, thus ignore those
-               if (kind == EvoUndoRedo.RECORD_KIND_EVENT && record.htmlBefore == html) {
+               if (kind == EvoUndoRedo.RECORD_KIND_EVENT && record.htmlBefore == record.htmlAfter) {
                        if (!EvoUndoRedo.ongoingRecordings.length && record.opType != "insertText") {
                                EvoUndoRedo.stack.maybeMergeInsertText(false);
                        }
 
                        return false;
                }
-
-               record.htmlAfter = html;
        }
 
        record.selectionAfter = EvoSelection.Store(document);
@@ -824,4 +743,136 @@ EvoUndoRedo.GroupTopRecords = function(nRecords, opType)
        }
 }
 
+/* Backs up all the children elements between firstChildIndex and lastChildIndex inclusive,
+   saving their HTML content into record.htmlBefore; it stores only element children,
+   not text or other nodes. Use also EvoUndoRedo.BackupChildrenAfter() to save all data
+   needed by EvoUndoRedo.RestoreChildren(), which is used to restore saved data.
+   The firstChildIndex can be -1, to back up parent's innerHTML.
+*/
+EvoUndoRedo.BackupChildrenBefore = function(record, parent, firstChildIndex, lastChildIndex)
+{
+       record.firstChildIndex = firstChildIndex;
+
+       if (firstChildIndex == -1) {
+               record.htmlBefore = parent.innerHTML;
+               return;
+       }
+
+       record.htmlBefore = "";
+
+       var ii;
+
+       for (ii = firstChildIndex; ii < parent.children.length; ii++) {
+               record.htmlBefore += parent.children[ii].outerHTML;
+
+               if (ii == lastChildIndex) {
+                       ii++;
+                       break;
+               }
+       }
+
+       record.restChildrenCount = parent.children.length - ii;
+}
+
+EvoUndoRedo.BackupChildrenAfter = function(record, parent)
+{
+       if (record.firstChildIndex == undefined)
+               throw "EvoUndoRedo.BackupChildrenAfter: 'record' doesn't contain 'firstChildIndex' property";
+       if (record.firstChildIndex != -1 && record.restChildrenCount == undefined)
+               throw "EvoUndoRedo.BackupChildrenAfter: 'record' doesn't contain 'restChildrenCount' 
property";
+       if (record.htmlBefore == undefined)
+               throw "EvoUndoRedo.BackupChildrenAfter: 'record' doesn't contain 'htmlBefore' property";
+
+       if (record.firstChildIndex == -1) {
+               record.htmlAfter = parent.innerHTML;
+               return;
+       }
+
+       record.htmlAfter = "";
+
+       var ii, first, last;
+
+       first = record.firstChildIndex;
+
+       // it can equal to the children.length, when the node had been removed
+       if (first < 0 || first > parent.children.length) {
+               throw "EvoUndoRedo.BackupChildrenAfter: firstChildIndex (" + first + ") out of bounds (" + 
parent.children.length + ")";
+       }
+
+       last = parent.children.length - record.restChildrenCount;
+       if (last < 0 || last < first) {
+               throw "EvoUndoRedo::BackupChildrenAfter: restChildrenCount (" + record.restChildrenCount + ") 
out of bounds (length:" +
+                       parent.children.length + " first:" + first + " last:" + last + ")";
+       }
+
+       for (ii = first; ii < last; ii++) {
+               if (ii >= 0 && ii < parent.children.length) {
+                       record.htmlAfter += parent.children[ii].outerHTML;
+               }
+       }
+}
+
+// restores content of 'parent' based on the information saved by EvoUndoRedo.BackupChildrenBefore()
+// and EvoUndoRedo.BackupChildrenAfter()
+EvoUndoRedo.RestoreChildren = function(record, parent, isUndo)
+{
+       var first, last, ii;
+
+       if (record.firstChildIndex == undefined)
+               throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'firstChildIndex' property";
+       if (record.firstChildIndex != -1 && record.restChildrenCount == undefined)
+               throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'restChildrenCount' property";
+       if (record.htmlBefore == undefined)
+               throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'htmlBefore' property";
+       if (record.htmlAfter == undefined)
+               throw "EvoUndoRedo.RestoreChildren: 'record' doesn't contain 'htmlAfter' property";
+
+       first = record.firstChildIndex;
+
+       if (first == -1) {
+               if (isUndo) {
+                       parent.innerHTML = record.htmlBefore;
+               } else {
+                       parent.innerHTML = record.htmlAfter;
+               }
+       } else {
+               // it can equal to the children.length, when the node had been removed
+               if (first < 0 || first > parent.children.length) {
+                       throw "EvoUndoRedo::RestoreChildren: firstChildIndex (" + first + ") out of bounds (" 
+ parent.children.length + ")";
+               }
+
+               last = parent.children.length - record.restChildrenCount;
+               if (last < 0 || last < first) {
+                       throw "EvoUndoRedo::RestoreChildren: restChildrenCount (" + record.restChildrenCount 
+ ") out of bounds (length:" +
+                               parent.children.length + " first:" + first + " last:" + last + ")";
+               }
+
+               for (ii = last - 1; ii >= first; ii--) {
+                       if (ii >= 0 && ii < parent.children.length) {
+                               parent.removeChild(parent.children[ii]);
+                       }
+               }
+
+               var tmpNode = document.createElement("evo-tmp");
+
+               if (isUndo) {
+                       tmpNode.innerHTML = record.htmlBefore;
+               } else {
+                       tmpNode.innerHTML = record.htmlAfter;
+               }
+
+               if (first < parent.children.length) {
+                       first = parent.children[first];
+
+                       while(tmpNode.firstElementChild) {
+                               parent.insertBefore(tmpNode.firstElementChild, first);
+                       }
+               } else {
+                       while(tmpNode.firstElementChild) {
+                               parent.appendChild(tmpNode.firstElementChild);
+                       }
+               }
+       }
+}
+
 EvoUndoRedo.Attach();
diff --git a/src/e-util/test-html-editor-units-utils.c b/src/e-util/test-html-editor-units-utils.c
index 609cfd0a56..03eae0de20 100644
--- a/src/e-util/test-html-editor-units-utils.c
+++ b/src/e-util/test-html-editor-units-utils.c
@@ -685,8 +685,8 @@ test_utils_html_equal (TestFixture *fixture,
                "       var elem1, elem2;\n"
                "       elem1 = document.createElement(\"testHtmlEqual\");\n"
                "       elem2 = document.createElement(\"testHtmlEqual\");\n"
-               "       elem1.innerHTML = html1.replace(\"&nbsp;\", \" \").replace(\" \", \" \");\n"
-               "       elem2.innerHTML = html2.replace(\"&nbsp;\", \" \").replace(\" \", \" \");\n"
+               "       elem1.innerHTML = html1.replace(/&nbsp;/g, \" \").replace(/ /g, \" \");\n"
+               "       elem2.innerHTML = html2.replace(/&nbsp;/g, \" \").replace(/ /g, \" \");\n"
                "       elem1.normalize();\n"
                "       elem2.normalize();\n"
                "       return elem1.isEqualNode(elem2);\n"
diff --git a/src/e-util/test-html-editor-units.c b/src/e-util/test-html-editor-units.c
index 41e4bb793b..734be71187 100644
--- a/src/e-util/test-html-editor-units.c
+++ b/src/e-util/test-html-editor-units.c
@@ -193,13 +193,14 @@ test_justify_selection (TestFixture *fixture)
                "seq:d\n"
                "action:justify-left\n",
                HTML_PREFIX
-                       "<div style=\"text-align: center\">center</div>"
-                       "<div style=\"text-align: right\">right</div>"
+                       "<div style=\"text-align: center;\">center</div>"
+                       "<div style=\"text-align: right;\">right</div>"
                        "<div>left</div><div><br></div>"
                HTML_SUFFIX,
                "                                center\n"
                "                                                                  right\n"
-               "left\n"))
+               "left\n"
+               "\n"))
                g_test_fail ();
 }
 
@@ -215,13 +216,14 @@ test_justify_typed (TestFixture *fixture)
                "action:justify-left\n"
                "type:left\\n\n",
                HTML_PREFIX
-                       "<div style=\"text-align: center\">center</div>"
-                       "<div style=\"text-align: right\">right</div>"
+                       "<div style=\"text-align: center;\">center</div>"
+                       "<div style=\"text-align: right;\">right</div>"
                        "<div>left</div><div><br></div>"
                HTML_SUFFIX,
                "                                center\n"
                "                                                                  right\n"
-               "left\n"))
+               "left\n"
+               "\n"))
                g_test_fail ();
 }
 
@@ -245,16 +247,16 @@ test_indent_selection (TestFixture *fixture)
                "action:unindent\n",
                HTML_PREFIX
                        "<div>level 0</div>"
-                       "<div style=\"margin-left: 3ch;\">"
-                               "<div>level 1</div>"
-                               "<div style=\"margin-left: 3ch;\"><div>level 2</div></div>"
-                               "<div>level 1</div>"
-                       "</div><div><br></div>"
+                       "<div style=\"margin-left: 3ch;\">level 1</div>"
+                       "<div style=\"margin-left: 6ch;\">level 2</div>"
+                       "<div style=\"margin-left: 3ch;\">level 1</div>"
+                       "<div><br></div>"
                HTML_SUFFIX,
                "level 0\n"
                "   level 1\n"
                "      level 2\n"
-               "   level 1\n"))
+               "   level 1\n"
+               "\n"))
                g_test_fail ();
 }
 
@@ -273,16 +275,16 @@ test_indent_typed (TestFixture *fixture)
                "action:unindent\n",
                HTML_PREFIX
                        "<div>level 0</div>"
-                       "<div style=\"margin-left: 3ch;\">"
-                               "<div>level 1</div>"
-                               "<div style=\"margin-left: 3ch;\"><div>level 2</div></div>"
-                               "<div>level 1</div>"
-                       "</div><div><br></div>"
+                       "<div style=\"margin-left: 3ch;\">level 1</div>"
+                       "<div style=\"margin-left: 6ch;\">level 2</div>"
+                       "<div style=\"margin-left: 3ch;\">level 1</div>"
+                       "<div><br></div>"
                HTML_SUFFIX,
                "level 0\n"
                "   level 1\n"
                "      level 2\n"
-               "   level 1\n"))
+               "   level 1\n"
+               "\n"))
                g_test_fail ();
 }
 
@@ -306,9 +308,9 @@ test_font_size_selection (TestFixture *fixture)
                "action:size-plus-three\n"
                "seq:rrCSrcs\n"
                "action:size-plus-four\n",
-               HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font 
size=\"4\">FontP1</font> "
+               HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> <font 
size=\"3\">Font0</font> <font size=\"4\">FontP1</font> "
                "<font size=\"5\">FontP2</font> <font size=\"6\">FontP3</font> <font 
size=\"7\">FontP4</font></div>" HTML_SUFFIX,
-               "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4"))
+               "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4\n"))
                g_test_fail ();
 }
 
@@ -343,9 +345,10 @@ test_font_size_typed (TestFixture *fixture)
                "action:size-plus-four\n"
                "type:FontP4\n"
                "action:size-plus-zero\n",
-               HTML_PREFIX "<div><font size=\"1\">FontM2</font> <font size=\"2\">FontM1</font> Font0 <font 
size=\"4\">FontP1</font> "
-               "<font size=\"5\">FontP2</font> <font size=\"6\">FontP3</font> <font 
size=\"7\">FontP4</font><br></div>" HTML_SUFFIX,
-               "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4"))
+               HTML_PREFIX "<div><font size=\"1\">FontM2</font><font size=\"3\"> </font><font 
size=\"2\">FontM1</font><font size=\"3\"> Font0 </font>"
+               "<font size=\"4\">FontP1</font><font size=\"3\"> </font><font size=\"5\">FontP2</font><font 
size=\"3\"> </font>"
+               "<font size=\"6\">FontP3</font><font size=\"3\"> </font><font size=\"7\">FontP4</font></div>" 
HTML_SUFFIX,
+               "FontM2 FontM1 Font0 FontP1 FontP2 FontP3 FontP4\n"))
                g_test_fail ();
 }
 
@@ -405,7 +408,7 @@ test_font_color_selection (TestFixture *fixture)
        if (!test_utils_run_simple_test (fixture, "",
                HTML_PREFIX "<div>default <font color=\"#ff0000\">red</font> <font 
color=\"#00ff00\">green</font> "
                "<font color=\"#0000ff\">blue</font></div>" HTML_SUFFIX,
-               "default red green blue"))
+               "default red green blue\n"))
                g_test_fail ();
 }
 
@@ -470,7 +473,7 @@ test_font_color_typed (TestFixture *fixture)
        if (!test_utils_run_simple_test (fixture, "",
                HTML_PREFIX "<div>default <font color=\"#ff0000\">red </font><font color=\"#00ff00\">green 
</font>"
                "<font color=\"#0000ff\">blue</font></div>" HTML_SUFFIX,
-               "default red green blue"))
+               "default red green blue\n"))
                g_test_fail ();
 }
 
@@ -489,7 +492,7 @@ test_list_bullet_plain (TestFixture *fixture)
                " * item 1\n"
                " * item 2\n"
                " * item 3\n"
-               "text"))
+               "text\n"))
                g_test_fail ();
 }
 
@@ -517,9 +520,9 @@ test_list_bullet_html (TestFixture *fixture)
                        "<div>text</div>"
                HTML_SUFFIX,
                " * item 1\n"
-               "    * item 2\n"
+               "    - item 2\n"
                " * item 3\n"
-               "text"))
+               "text\n"))
                g_test_fail ();
 }
 
@@ -531,7 +534,7 @@ test_list_bullet_change (TestFixture *fixture)
                "action:style-list-bullet\n"
                "action:style-list-number\n",
                NULL,
-               "   1. "))
+               "   1. \n"))
                g_test_fail ();
 }
 
@@ -559,7 +562,7 @@ test_list_bullet_html_from_block (TestFixture *fixture)
                " * item 1\n"
                " * item 2\n"
                " * item 3\n"
-               " * "))
+               " * \n"))
                g_test_fail ();
 }
 
@@ -589,7 +592,7 @@ test_list_alpha_html (TestFixture *fixture)
                "   A. item 1\n"
                "      A. item 2\n"
                "   B. item 3\n"
-               "text"))
+               "text\n"))
                g_test_fail ();
 }
 
@@ -610,7 +613,7 @@ test_list_alpha_plain (TestFixture *fixture)
                "   A. item 1\n"
                "      A. item 2\n"
                "   B. item 3\n"
-               "text"))
+               "text\n"))
                g_test_fail ();
 }
 
@@ -643,24 +646,24 @@ test_list_roman_html (TestFixture *fixture)
                "<li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li>"
                "<li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li>"
                "</ol>" HTML_SUFFIX,
-               "   I. 1\n"
-               "  II. 2\n"
-               " III. 3\n"
-               "  IV. 4\n"
-               "   V. 5\n"
-               "  VI. 6\n"
-               " VII. 7\n"
-               "VIII. 8\n"
-               "  IX. 9\n"
-               "   X. 10\n"
-               "  XI. 11\n"
-               " XII. 12\n"
-               "XIII. 13\n"
-               " XIV. 14\n"
-               "  XV. 15\n"
-               " XVI. 16\n"
-               "XVII. 17\n"
-               "XVIII. 18"))
+               "    I. 1\n"
+               "   II. 2\n"
+               "  III. 3\n"
+               "   IV. 4\n"
+               "    V. 5\n"
+               "   VI. 6\n"
+               "  VII. 7\n"
+               " VIII. 8\n"
+               "   IX. 9\n"
+               "    X. 10\n"
+               "   XI. 11\n"
+               "  XII. 12\n"
+               " XIII. 13\n"
+               "  XIV. 14\n"
+               "   XV. 15\n"
+               "  XVI. 16\n"
+               " XVII. 17\n"
+               "XVIII. 18\n"))
                g_test_fail ();
 }
 
@@ -689,24 +692,24 @@ test_list_roman_plain (TestFixture *fixture)
                "type:17\\n\n"
                "type:18\n",
                NULL,
-               "   I. 1\n"
-               "  II. 2\n"
-               " III. 3\n"
-               "  IV. 4\n"
-               "   V. 5\n"
-               "  VI. 6\n"
-               " VII. 7\n"
-               "VIII. 8\n"
-               "  IX. 9\n"
-               "   X. 10\n"
-               "  XI. 11\n"
-               " XII. 12\n"
-               "XIII. 13\n"
-               " XIV. 14\n"
-               "  XV. 15\n"
-               " XVI. 16\n"
-               "XVII. 17\n"
-               "XVIII. 18"))
+               "    I. 1\n"
+               "   II. 2\n"
+               "  III. 3\n"
+               "   IV. 4\n"
+               "    V. 5\n"
+               "   VI. 6\n"
+               "  VII. 7\n"
+               " VIII. 8\n"
+               "   IX. 9\n"
+               "    X. 10\n"
+               "   XI. 11\n"
+               "  XII. 12\n"
+               " XIII. 13\n"
+               "  XIV. 14\n"
+               "   XV. 15\n"
+               "  XVI. 16\n"
+               " XVII. 17\n"
+               "XVIII. 18\n"))
                g_test_fail ();
 }
 
@@ -737,7 +740,7 @@ test_list_multi_html (TestFixture *fixture)
                " * item 2\n"
                "   I. item 3\n"
                "  II. item 4\n"
-               " III. "))
+               " III. \n"))
                g_test_fail ();
 }
 
@@ -758,7 +761,7 @@ test_list_multi_plain (TestFixture *fixture)
                " * item 2\n"
                "   I. item 3\n"
                "  II. item 4\n"
-               " III. "))
+               " III. \n"))
                g_test_fail ();
 }
 
@@ -789,7 +792,7 @@ test_list_multi_change_html (TestFixture *fixture)
                "   2. item 2\n"
                "   3. item 3\n"
                "   4. item 4\n"
-               "   5. "))
+               "   5. \n"))
                g_test_fail ();
 }
 
diff --git a/src/modules/webkit-editor/e-webkit-editor.c b/src/modules/webkit-editor/e-webkit-editor.c
index 92c7692f91..a583fa8035 100644
--- a/src/modules/webkit-editor/e-webkit-editor.c
+++ b/src/modules/webkit-editor/e-webkit-editor.c
@@ -63,7 +63,9 @@ enum {
        PROP_STRIKETHROUGH,
        PROP_SUBSCRIPT,
        PROP_SUPERSCRIPT,
-       PROP_UNDERLINE
+       PROP_UNDERLINE,
+
+       PROP_NORMAL_PARAGRAPH_WIDTH
 };
 
 struct _EWebKitEditorPrivate {
@@ -73,7 +75,6 @@ struct _EWebKitEditorPrivate {
        GCancellable *cancellable;
        EWebExtensionContainer *container;
        GDBusProxy *web_extension_proxy;
-       guint web_extension_user_changed_default_colors_cb_id;
 
        gboolean html_mode;
        gboolean changed;
@@ -110,6 +111,7 @@ struct _EWebKitEditorPrivate {
        gchar *body_font_name;
 
        guint font_size;
+       gint normal_paragraph_width;
 
        EContentEditorBlockFormat block_format;
        EContentEditorAlignment alignment;
@@ -1056,7 +1058,7 @@ webkit_editor_update_styles (EContentEditor *editor)
                "  border-collapse: collapse;\n"
                "  width: %dch;\n"
                "}\n",
-               g_settings_get_int (wk_editor->priv->mail_settings, "composer-word-wrap-length"));
+               wk_editor->priv->normal_paragraph_width);
 
        g_string_append (
                stylesheet,
@@ -1085,7 +1087,7 @@ webkit_editor_update_styles (EContentEditor *editor)
                stylesheet,
                "body[data-evo-plain-text] ul > li::before "
                "{\n"
-               "  content: \"*"UNICODE_NBSP"\";\n"
+               "  content: \"*" UNICODE_NBSP "\";\n"
                "}\n");
 
        g_string_append_printf (
@@ -1123,27 +1125,6 @@ webkit_editor_update_styles (EContentEditor *editor)
                "  -webkit-padding-start: %dch; \n"
                "}\n", SPACES_PER_LIST_LEVEL);
 
-       g_string_append (
-               stylesheet,
-               ".-x-evo-align-left "
-               "{\n"
-               "  text-align: left; \n"
-               "}\n");
-
-       g_string_append (
-               stylesheet,
-               ".-x-evo-align-center "
-               "{\n"
-               "  text-align: center; \n"
-               "}\n");
-
-       g_string_append (
-               stylesheet,
-               ".-x-evo-align-right "
-               "{\n"
-               "  text-align: right; \n"
-               "}\n");
-
        g_string_append (
                stylesheet,
                "ol,ul "
@@ -2192,7 +2173,7 @@ webkit_editor_selection_indent (EContentEditor *editor)
        wk_editor = E_WEBKIT_EDITOR (editor);
 
        e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
-               "EvoEditor.Indent(+1);");
+               "EvoEditor.Indent(true);");
 }
 
 static void
@@ -2203,7 +2184,7 @@ webkit_editor_selection_unindent (EContentEditor *editor)
        wk_editor = E_WEBKIT_EDITOR (editor);
 
        e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
-               "EvoEditor.Indent(-1);");
+               "EvoEditor.Indent(false);");
 }
 
 static void
@@ -5144,6 +5125,31 @@ webkit_editor_process_uri_request_cb (WebKitURISchemeRequest *request,
                webkit_editor_uri_request_done_cb, g_object_ref (request));
 }
 
+static void
+webkit_editor_set_normal_paragraph_width (EWebKitEditor *wk_editor,
+                                         gint value)
+{
+       g_return_if_fail (E_IS_WEBKIT_EDITOR (wk_editor));
+
+       if (wk_editor->priv->normal_paragraph_width != value) {
+               wk_editor->priv->normal_paragraph_width = value;
+
+               e_web_view_jsc_run_script (WEBKIT_WEB_VIEW (wk_editor), wk_editor->priv->cancellable,
+                       "EvoEditor.SetNormalParagraphWidth(%d);",
+                       value);
+
+               g_object_notify (G_OBJECT (wk_editor), "normal-paragraph-width");
+       }
+}
+
+static gint
+webkit_editor_get_normal_paragraph_width (EWebKitEditor *wk_editor)
+{
+       g_return_val_if_fail (E_IS_WEBKIT_EDITOR (wk_editor), -1);
+
+       return wk_editor->priv->normal_paragraph_width;
+}
+
 static void
 e_webkit_editor_initialize_web_extensions_cb (WebKitWebContext *web_context,
                                              gpointer user_data)
@@ -5165,6 +5171,7 @@ webkit_editor_constructed (GObject *object)
        WebKitSettings *web_settings;
        WebKitWebView *web_view;
        WebKitUserContentManager *manager;
+       GSettings *settings;
 
        wk_editor = E_WEBKIT_EDITOR (object);
        web_view = WEBKIT_WEB_VIEW (wk_editor);
@@ -5211,6 +5218,13 @@ webkit_editor_constructed (GObject *object)
        webkit_settings_set_allow_file_access_from_file_urls (web_settings, TRUE);
        webkit_settings_set_enable_developer_extras (web_settings, e_util_get_webkit_developer_mode_enabled 
());
 
+       settings = e_util_ref_settings ("org.gnome.evolution.mail");
+       g_settings_bind (
+               settings, "composer-word-wrap-length",
+               wk_editor, "normal-paragraph-width",
+               G_SETTINGS_BIND_GET);
+       g_object_unref (settings);
+
        e_webkit_editor_load_data (wk_editor, "");
 }
 
@@ -5391,6 +5405,12 @@ webkit_editor_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
+               case PROP_NORMAL_PARAGRAPH_WIDTH:
+                       webkit_editor_set_normal_paragraph_width (
+                               E_WEBKIT_EDITOR (object),
+                               g_value_get_int (value));
+                       return;
+
                case PROP_ALIGNMENT:
                        webkit_editor_set_alignment (
                                E_WEBKIT_EDITOR (object),
@@ -5564,6 +5584,11 @@ webkit_editor_get_property (GObject *object,
                                E_WEBKIT_EDITOR (object)));
                        return;
 
+               case PROP_NORMAL_PARAGRAPH_WIDTH:
+                       g_value_set_int (value,
+                               webkit_editor_get_normal_paragraph_width (E_WEBKIT_EDITOR (object)));
+                       return;
+
                case PROP_ALIGNMENT:
                        g_value_set_enum (
                                value,
@@ -6438,6 +6463,20 @@ e_webkit_editor_class_init (EWebKitEditorClass *class)
                object_class, PROP_LAST_ERROR, "last-error");
        g_object_class_override_property (
                object_class, PROP_SPELL_CHECKER, "spell-checker");
+
+       g_object_class_install_property (
+               object_class,
+               PROP_NORMAL_PARAGRAPH_WIDTH,
+               g_param_spec_int (
+                       "normal-paragraph-width",
+                       NULL,
+                       NULL,
+                       G_MININT32,
+                       G_MAXINT32,
+                       71, /* Should be the same as e-editor.js:EvoEditor.NORMAL_PARAGRAPH_WIDTH */
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -6560,8 +6599,7 @@ e_webkit_editor_init (EWebKitEditor *wk_editor)
 
        wk_editor->priv->start_bottom = E_THREE_STATE_INCONSISTENT;
        wk_editor->priv->top_signature = E_THREE_STATE_INCONSISTENT;
-
-       wk_editor->priv->web_extension_user_changed_default_colors_cb_id = 0;
+       wk_editor->priv->normal_paragraph_width = 71; /* Should be the same as 
e-editor.js:EvoEditor.NORMAL_PARAGRAPH_WIDTH */
 }
 
 static void



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