Skip to content

Commit ca7d2e6

Browse files
author
Friedrich
committed
Merge pull request #877 from kossebau/fixOpMergeParagraphAndEmptyAnnotations
Fix OpMergeParagraph merging paragraphs with empty annotations
2 parents a79eeac + 45726eb commit ca7d2e6

6 files changed

Lines changed: 89 additions & 17 deletions

File tree

ChangeLog.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# Changes between 0.5.6 and 0.5.7
2+
3+
## WebODF
4+
5+
### Fixes
6+
7+
* Fix breaking all empty annotations on merging the paragraph they are contained in with the one before ([#877](https://github.com/kogmbh/WebODF/pull/877)))
8+
9+
110
# Changes between 0.5.5 and 0.5.6
211

312
## WebODF

webodf/lib/core/DomUtils.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,20 +579,29 @@
579579

580580
/**
581581
* Removes all unwanted nodes from targetNode includes itself.
582+
* The nodeFilter defines which nodes should be removed (NodeFilter.FILTER_REJECT),
583+
* should be skipped including the subtree (NodeFilter.FILTER_SKIP) or should be kept
584+
* and their subtree checked further (NodeFilter.FILTER_ACCEPT).
582585
* @param {!Node} targetNode
583-
* @param {function(!Node):!boolean} shouldRemove check whether a node should be removed or not
586+
* @param {!function(!Node) : !number} nodeFilter
584587
* @return {?Node} parent of targetNode
585588
*/
586-
function removeUnwantedNodes(targetNode, shouldRemove) {
589+
function removeUnwantedNodes(targetNode, nodeFilter) {
587590
var parent = targetNode.parentNode,
588591
node = targetNode.firstChild,
592+
filterResult = nodeFilter(targetNode),
589593
next;
594+
595+
if (filterResult === NodeFilter.FILTER_SKIP) {
596+
return parent;
597+
}
598+
590599
while (node) {
591600
next = node.nextSibling;
592-
removeUnwantedNodes(node, shouldRemove);
601+
removeUnwantedNodes(node, nodeFilter);
593602
node = next;
594603
}
595-
if (parent && shouldRemove(targetNode)) {
604+
if (parent && (filterResult === NodeFilter.FILTER_REJECT)) {
596605
mergeIntoParent(targetNode);
597606
}
598607
return parent;

webodf/lib/odf/CollapsingRules.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* @source: https://github.com/kogmbh/WebODF/
2323
*/
2424

25-
/*global odf, core, Node*/
25+
/*global odf, core, Node, NodeFilter*/
2626

2727
/**
2828
* Defines a set of rules for how elements can be collapsed based on whether they contain ODT content (e.g.,
@@ -36,14 +36,15 @@ odf.CollapsingRules = function CollapsingRules(rootNode) {
3636
domUtils = core.DomUtils;
3737

3838
/**
39-
* Returns true if a given node is odf node or a text node that has a odf parent.
39+
* Returns NodeFilter value if a given node is odf node or a text node that has a odf parent.
4040
* @param {!Node} node
41-
* @return {!boolean}
41+
* @return {!number}
4242
*/
43-
function shouldRemove(node) {
44-
return odfUtils.isODFNode(node)
43+
function filterOdfNodesToRemove(node) {
44+
var isToRemove = odfUtils.isODFNode(node)
4545
|| (node.localName === "br" && odfUtils.isLineBreak(node.parentNode))
4646
|| (node.nodeType === Node.TEXT_NODE && odfUtils.isODFNode(/** @type {!Node}*/(node.parentNode)));
47+
return isToRemove ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
4748
}
4849

4950
/**
@@ -69,7 +70,7 @@ odf.CollapsingRules = function CollapsingRules(rootNode) {
6970
parent.removeChild(targetNode);
7071
} else {
7172
// removes all odf nodes
72-
parent = domUtils.removeUnwantedNodes(targetNode, shouldRemove);
73+
parent = domUtils.removeUnwantedNodes(targetNode, filterOdfNodesToRemove);
7374
}
7475
if (parent && isCollapsibleContainer(parent)) {
7576
return mergeChildrenIntoParent(parent);

webodf/lib/ops/OpMergeParagraph.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* @source: https://github.com/kogmbh/WebODF/
2323
*/
2424

25-
/*global ops, runtime, odf, core, Node*/
25+
/*global ops, runtime, odf, core, Node, NodeFilter*/
2626

2727
/**
2828
* Merges two adjacent paragraphs together into the first paragraph. The destination paragraph
@@ -68,10 +68,13 @@ ops.OpMergeParagraph = function OpMergeParagraph() {
6868
/**
6969
* Returns true if the supplied node is an ODF grouping element with no content
7070
* @param {!Node} element
71-
* @return {!boolean}
71+
* @return {!number}
7272
*/
73-
function isEmptyGroupingElement(element) {
74-
return odfUtils.isGroupingElement(element) && odfUtils.hasNoODFContent(element);
73+
function filterEmptyGroupingElementToRemove(element) {
74+
if (odf.OdfUtils.isInlineRoot(element)) {
75+
return NodeFilter.FILTER_SKIP;
76+
}
77+
return odfUtils.isGroupingElement(element) && odfUtils.hasNoODFContent(element) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
7578
}
7679

7780
/**
@@ -93,7 +96,7 @@ ops.OpMergeParagraph = function OpMergeParagraph() {
9396
// Empty spans need to be cleaned up on merge, as remove text only removes things that contain text content
9497
// Child is moved across before collapsing so any foreign sub-elements are collapsed up the chain next to
9598
// the destination location
96-
domUtils.removeUnwantedNodes(child, isEmptyGroupingElement);
99+
domUtils.removeUnwantedNodes(child, filterEmptyGroupingElementToRemove);
97100
}
98101
child = source.firstChild;
99102
}

webodf/tests/core/DomUtilsTests.js

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ core.DomUtilsTests = function DomUtilsTests(runner) {
515515
p.appendChild(span3);
516516
t.doc.appendChild(p);
517517
t.parent = t.utils.removeUnwantedNodes(p, function (node) {
518-
return node !== null;
518+
return (node !== null) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
519519
});
520520
r.shouldBe(t, "t.parent", "t.doc");
521521
r.shouldBe(t, "t.parent.childNodes.length", "0");
@@ -536,7 +536,7 @@ core.DomUtilsTests = function DomUtilsTests(runner) {
536536
p.appendChild(span3);
537537
t.doc.appendChild(p);
538538
t.parent = t.utils.removeUnwantedNodes(p, function (node) {
539-
return node.localName === 'span';
539+
return node.localName === 'span' ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
540540
});
541541
r.shouldBe(t, "t.parent", "t.doc");
542542
r.shouldBe(t, "t.parent.firstChild.localName", "'p'");
@@ -546,6 +546,32 @@ core.DomUtilsTests = function DomUtilsTests(runner) {
546546
r.shouldBe(t, "t.parent.firstChild.childNodes[2].firstChild.textContent", "'test'");
547547
}
548548

549+
function removeUnwantedNodes_SkipDiv() {
550+
var p = document.createElement("p"),
551+
span1 = document.createElement("span"),
552+
div = document.createElement("div"),
553+
divspan = document.createElement("span"),
554+
span3 = document.createElement("span"),
555+
b = document.createElement("b");
556+
b.textContent = "test";
557+
span1.textContent = "hello";
558+
divspan.textContent = "world";
559+
span3.appendChild(b);
560+
p.appendChild(span1);
561+
p.appendChild(div);
562+
div.appendChild(divspan);
563+
p.appendChild(span3);
564+
t.doc.appendChild(p);
565+
t.parent = t.utils.removeUnwantedNodes(p, function (node) {
566+
return (node.localName === "div") ? NodeFilter.FILTER_SKIP : NodeFilter.FILTER_REJECT;
567+
});
568+
r.shouldBe(t, "t.parent", "t.doc");
569+
r.shouldBe(t, "t.parent.childNodes.length", "1");
570+
r.shouldBe(t, "t.parent.firstChild.localName", "'div'");
571+
r.shouldBe(t, "t.parent.firstChild.childNodes.length", "1");
572+
r.shouldBe(t, "t.parent.firstChild.firstChild.localName", "'span'");
573+
}
574+
549575
function removeAllChildNodes_None() {
550576
var p = document.createElement("p");
551577
t.doc.appendChild(p);
@@ -818,6 +844,7 @@ core.DomUtilsTests = function DomUtilsTests(runner) {
818844

819845
removeUnwantedNodes_DiscardAll,
820846
removeUnwantedNodes_DiscardSpanOnly,
847+
removeUnwantedNodes_SkipDiv,
821848

822849
removeAllChildNodes_None,
823850
removeAllChildNodes_ElementAndTextNodes,

webodf/tests/ops/operationtests.xml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,29 @@
528528
</ops>
529529
<after><office:text><text:p text:style-name="A">abcdefgh</text:p></office:text></after>
530530
</test>
531+
<test name="MergeParagraphWithEmptyAnnotationText inside">
532+
<before><office:text><text:p text:style-name="A">ab</text:p><text:p text:style-name="B">c<office:annotation office:name="alice_1">
533+
<dc:creator e:memberid="Alice">Alice</dc:creator>
534+
<dc:date>2013-08-05T12:34:07.061Z</dc:date>
535+
<text:list>
536+
<text:list-item>
537+
<text:p></text:p>
538+
</text:list-item>
539+
</text:list>
540+
</office:annotation>d</text:p></office:text></before>
541+
<ops>
542+
<op optype="MergeParagraph" destinationStartPosition="0" sourceStartPosition="3" paragraphStyleName="A"/>
543+
</ops>
544+
<after><office:text><text:p text:style-name="A">abc<office:annotation office:name="alice_1">
545+
<dc:creator e:memberid="Alice">Alice</dc:creator>
546+
<dc:date>2013-08-05T12:34:07.061Z</dc:date>
547+
<text:list>
548+
<text:list-item>
549+
<text:p></text:p>
550+
</text:list-item>
551+
</text:list>
552+
</office:annotation>d</text:p></office:text></after>
553+
</test>
531554
<test name="RemoveAndMerge">
532555
<before><office:text><text:p text:style-name="A">abc<text:span text:style-name="B">d</text:span></text:p><text:p text:style-name="C"><text:span text:style-name="D">efgh</text:span></text:p></office:text></before>
533556
<ops>

0 commit comments

Comments
 (0)