Skip to content

Commit

Permalink
Operations for merging and splitting lists
Browse files Browse the repository at this point in the history
  • Loading branch information
Satvik Kumar committed Sep 16, 2014
1 parent c9346f2 commit a4b34bb
Show file tree
Hide file tree
Showing 6 changed files with 318 additions and 1 deletion.
9 changes: 9 additions & 0 deletions webodf/lib/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,9 @@
"ops.OpInsertText": [
"ops.OdtDocument"
],
"ops.OpMergeList": [
"ops.OdtDocument"
],
"ops.OpMergeParagraph": [
"odf.CollapsingRules",
"ops.OdtDocument"
Expand Down Expand Up @@ -482,6 +485,10 @@
"ops.OpSetParagraphStyle": [
"ops.OdtDocument"
],
"ops.OpSplitList": [
"odf.CollapsingRules",
"ops.OdtDocument"
],
"ops.OpSplitParagraph": [
"ops.OdtDocument"
],
Expand Down Expand Up @@ -509,6 +516,7 @@
"ops.OpInsertImage",
"ops.OpInsertTable",
"ops.OpInsertText",
"ops.OpMergeList",
"ops.OpMergeParagraph",
"ops.OpMoveCursor",
"ops.OpRemoveAnnotation",
Expand All @@ -521,6 +529,7 @@
"ops.OpRemoveText",
"ops.OpSetBlob",
"ops.OpSetParagraphStyle",
"ops.OpSplitList",
"ops.OpSplitParagraph",
"ops.OpUpdateMember",
"ops.OpUpdateMetadata",
Expand Down
110 changes: 110 additions & 0 deletions webodf/lib/ops/OpMergeList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Copyright (C) 2010-2014 KO GmbH <[email protected]>
*
* @licstart
* This file is part of WebODF.
*
* WebODF is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License (GNU AGPL)
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* WebODF is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
* @licend
*
* @source: http://www.webodf.org/
* @source: https://github.com/kogmbh/WebODF/
*/

/*global ops, runtime, odf, core */

/**
*
* @constructor
* @implements ops.Operation
*/
ops.OpMergeList = function OpMergeList() {
"use strict";

var memberid,
timestamp,
/**@type{!number}*/
sourceStartPosition,
/**@type{!number}*/
destinationStartPosition,
odfUtils = odf.OdfUtils;

/**
* @param {!ops.OpMergeList.InitSpec} data
*/
this.init = function (data) {
memberid = data.memberid;
timestamp = data.timestamp;
sourceStartPosition = data.sourceStartPosition;
destinationStartPosition = data.destinationStartPosition;
};

this.isEdit = true;
this.group = undefined;

/**
* @return {!ops.OpMergeList.Spec}
*/
this.spec = function () {
return {
optype: "MergeList",
memberid: memberid,
timestamp: timestamp,
sourceStartPosition: sourceStartPosition,
destinationStartPosition: destinationStartPosition
};
};

/**
* @param {!ops.Document} document
*/
this.execute = function (document) {
var odtDocument = /**@type{ops.OdtDocument}*/(document),
rootNode = odtDocument.getRootNode(),
sourceDomPosition = odtDocument.convertCursorStepToDomPoint(sourceStartPosition),
destinationDomPosition = odtDocument.convertCursorStepToDomPoint(destinationStartPosition),
sourceList,
destinationList,
childListItem;

sourceList = odfUtils.getTopLevelListElement(sourceDomPosition.node, rootNode);
destinationList = odfUtils.getTopLevelListElement(destinationDomPosition.node, rootNode);
childListItem = sourceList.firstElementChild;

while (childListItem) {
destinationList.appendChild(childListItem);
childListItem = sourceList.firstElementChild;
}

sourceList.parentNode.removeChild(sourceList);
return true;
};
};

/**@typedef{{
optype: !string,
memberid: !string,
timestamp: !number,
sourceStartPosition: !number,
destinationStartPosition: !number
}}*/
ops.OpMergeList.Spec;

/**@typedef{{
memberid: !string,
timestamp:(!number|undefined),
sourceStartPosition: !number,
destinationStartPosition: !number
}}*/
ops.OpMergeList.InitSpec;
132 changes: 132 additions & 0 deletions webodf/lib/ops/OpSplitList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/**
* Copyright (C) 2010-2014 KO GmbH <[email protected]>
*
* @licstart
* This file is part of WebODF.
*
* WebODF is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License (GNU AGPL)
* as published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* WebODF is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with WebODF. If not, see <http://www.gnu.org/licenses/>.
* @licend
*
* @source: http://www.webodf.org/
* @source: https://github.com/kogmbh/WebODF/
*/

/*global ops, runtime, odf, core, Range*/

/**
*
* @constructor
* @implements ops.Operation
*/
ops.OpSplitList = function OpSplitList() {
"use strict";

var memberid,
timestamp,
/**@type{!number}*/
sourceStartPosition,
/**@type{!number}*/
splitPosition,
odfUtils = odf.OdfUtils,
/**@const*/
xmlns = odf.Namespaces.xmlns;

/**
* @param {!ops.OpSplitList.InitSpec} data
*/
this.init = function (data) {
memberid = data.memberid;
timestamp = data.timestamp;
sourceStartPosition = data.sourceStartPosition;
splitPosition = data.splitPosition;
};

this.isEdit = true;
this.group = undefined;

/**
* @return {!ops.OpSplitList.Spec}
*/
this.spec = function () {
return {
optype: "SplitList",
memberid: memberid,
timestamp: timestamp,
sourceStartPosition: sourceStartPosition,
splitPosition: splitPosition
};
};

/**
* @param {!ops.Document} document
*/
this.execute = function (document) {
var odtDocument = /**@type{ops.OdtDocument}*/(document),
ownerDocument = odtDocument.getDOMDocument(),
rootNode = odtDocument.getRootNode(),
collapseRules = new odf.CollapsingRules(rootNode),
sourceDomPosition = odtDocument.convertCursorStepToDomPoint(sourceStartPosition),
splitDomPosition = odtDocument.convertCursorStepToDomPoint(splitPosition),
sourceParagraph = /**@type{!Element}*/(odfUtils.getParagraphElement(sourceDomPosition.node, sourceDomPosition.offset)),
splitParagraph = /**@type{!Element}*/(odfUtils.getParagraphElement(splitDomPosition.node, splitDomPosition.offset)),
sourceList = odfUtils.getTopLevelListElement(sourceParagraph, rootNode),
destinationList,
splitPositionParentList,
range = ownerDocument.createRange(),
fragment;

if (!sourceList || !splitParagraph) {
return false;
}

destinationList = sourceList.cloneNode(false);
destinationList.removeAttributeNS(xmlns, "id");

// create a range starting at before the list item element we split at and
// ending at just after the last list item in the list
range.setStartBefore(splitParagraph.parentNode);
range.setEndAfter(sourceList.lastElementChild);

// extract the range to get all list items from the split position to the end of the list
// then collapse any empty nodes at the parent text:list element of the paragraph at the split position
splitPositionParentList = /**@type{!Node}*/(splitParagraph.parentNode.parentNode);
fragment = range.extractContents();

// don't collapse nodes if its the top level list
if (splitPositionParentList !== sourceList) {
collapseRules.mergeChildrenIntoParent(splitPositionParentList);
}

destinationList.appendChild(fragment);
sourceList.parentNode.insertBefore(destinationList, sourceList.nextElementSibling);
return true;
};
};

/**@typedef{{
optype: !string,
memberid: !string,
timestamp: !number,
sourceStartPosition: !number,
splitPosition: !number
}}*/
ops.OpSplitList.Spec;

/**@typedef{{
memberid: !string,
timestamp:(number|undefined),
sourceStartPosition: !number,
splitPosition: !number
}}*/
ops.OpSplitList.InitSpec;
4 changes: 3 additions & 1 deletion webodf/lib/ops/OperationFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,9 @@ ops.OperationFactory = function OperationFactory() {
RemoveHyperlink: construct(ops.OpRemoveHyperlink),
AddList: construct(ops.OpAddList),
RemoveList: construct(ops.OpRemoveList),
AddListStyle: construct(ops.OpAddListStyle)
AddListStyle: construct(ops.OpAddListStyle),
MergeList: construct(ops.OpMergeList),
SplitList: construct(ops.OpSplitList)
};
}

Expand Down
62 changes: 62 additions & 0 deletions webodf/tests/ops/operationtests.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2205,4 +2205,66 @@
</ops>
<after><office:text><text:p><foreign:foo foreign:baz="bar"/>Sample Text</text:p></office:text></after>
</test>
<test name="MergeList_Simple">
<before>
<office:text>
<text:list>
<text:list-item>
<text:p>SampleText1</text:p>
</text:list-item>
</text:list>
<text:list>
<text:list-item>
<text:p>SampleText2</text:p>
</text:list-item>
</text:list>
</office:text>
</before>
<ops>
<op optype="MergeList" destinationStartPosition="0" sourceStartPosition="12" />
</ops>
<after>
<office:text>
<text:list>
<text:list-item>
<text:p>SampleText1</text:p>
</text:list-item>
<text:list-item>
<text:p>SampleText2</text:p>
</text:list-item>
</text:list>
</office:text>
</after>
</test>
<test name="SplitList_Simple">
<before>
<office:text>
<text:list>
<text:list-item>
<text:p>SampleText1</text:p>
</text:list-item>
<text:list-item>
<text:p>SampleText2</text:p>
</text:list-item>
</text:list>
</office:text>
</before>
<ops>
<op optype="SplitList" sourceStartPosition="0" splitPosition="12" />
</ops>
<after>
<office:text>
<text:list>
<text:list-item>
<text:p>SampleText1</text:p>
</text:list-item>
</text:list>
<text:list>
<text:list-item>
<text:p>SampleText2</text:p>
</text:list-item>
</text:list>
</office:text>
</after>
</test>
</tests>
2 changes: 2 additions & 0 deletions webodf/tools/karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ module.exports = function (config) {
'lib/ops/OpInsertImage.js',
'lib/ops/OpInsertTable.js',
'lib/ops/OpInsertText.js',
'lib/ops/OpMergeList.js',
'lib/odf/CollapsingRules.js',
'lib/ops/OpMergeParagraph.js',
'lib/ops/OpMoveCursor.js',
Expand All @@ -106,6 +107,7 @@ module.exports = function (config) {
'lib/ops/OpRemoveText.js',
'lib/ops/OpSetBlob.js',
'lib/ops/OpSetParagraphStyle.js',
'lib/ops/OpSplitList.js',
'lib/ops/OpSplitParagraph.js',
'lib/ops/OpUpdateMember.js',
'lib/ops/OpUpdateMetadata.js',
Expand Down

0 comments on commit a4b34bb

Please sign in to comment.