From ccb1f2b3f553477dae0e3a8316fe1e54be6f7462 Mon Sep 17 00:00:00 2001 From: Satvik Kumar Date: Wed, 13 Aug 2014 01:03:16 +1000 Subject: [PATCH] Default styles for numbered and bulleted lists --- webodf/lib/gui/DefaultStyles.js | 370 +++++++++++++++++++++ webodf/lib/gui/ListController.js | 75 ++++- webodf/lib/manifest.json | 9 + webodf/lib/ops/OpAddListStyle.js | 130 ++++++++ webodf/lib/ops/OperationFactory.js | 3 +- webodf/lib/ops/OperationTransformMatrix.js | 37 +++ webodf/tests/ops/OperationTests.js | 4 + webodf/tools/karma.conf.js | 2 + 8 files changed, 620 insertions(+), 10 deletions(-) create mode 100644 webodf/lib/gui/DefaultStyles.js create mode 100644 webodf/lib/ops/OpAddListStyle.js diff --git a/webodf/lib/gui/DefaultStyles.js b/webodf/lib/gui/DefaultStyles.js new file mode 100644 index 000000000..957b9eb0e --- /dev/null +++ b/webodf/lib/gui/DefaultStyles.js @@ -0,0 +1,370 @@ +/** + * Copyright (C) 2010-2014 KO GmbH + * + * @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 . + * @licend + * + * @source: http://www.webodf.org/ + * @source: https://github.com/kogmbh/WebODF/ + */ + +/*global gui */ + +/** + * This file contains the default styles for numbered and bulleted lists created by WebODF + * It is used by the list controller to create the corresponding text:list-style nodes in + * the document. The list controller decides which of these default styles to use based on user input. + * Both of these default styles are based off the default numbered and bulleted list styles provided + * by LibreOffice + */ + +/** + * This is the default style for numbered lists created by WebODF. + * This has been modified from the LibreOffice style by enabling multi-level list numbering + * by adding the text:display-level attribute to each styleProperties object. + * @const + * @type {!ops.OpAddListStyle.ListStyle} + */ +gui.DefaultNumberedListStyle = [ + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "1", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "1.27cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "2", + "text:display-levels": "2", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "1.905cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "3", + "text:display-levels": "3", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "2.54cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "4", + "text:display-levels": "4", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "3.175cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "5", + "text:display-levels": "5", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "3.81cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "6", + "text:display-levels": "6", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "4.445cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "7", + "text:display-levels": "7", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "5.08cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "8", + "text:display-levels": "8", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "5.715cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "9", + "text:display-levels": "9", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "6.35cm" + } + } + } + }, + { + styleType: "text:list-level-style-number", + styleProperties: { + "text:level": "10", + "text:display-levels": "10", + "style:num-format": "1", + "style:num-suffix": ".", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "6.985cm" + } + } + } + } +]; + +/** + * This is the default style for bulleted lists created by WebODF. + * @const + * @type {!ops.OpAddListStyle.ListStyle} + */ +gui.DefaultBulletedListStyle = [ + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "1", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "1.27cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "2", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "1.905cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "3", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "2.54cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "4", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "3.175cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "5", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "3.81cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "6", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "4.445cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "7", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "5.08cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "8", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "5.715cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "9", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "6.35cm" + } + } + } + }, + { + styleType: "text:list-level-style-bullet", + styleProperties: { + "text:level": "10", + "text:bullet-char": "•", + "style:list-level-properties": { + "text:list-level-position-and-space-mode": "label-alignment", + "style:list-level-label-alignment": { + "text:label-followed-by": "space", + "fo:text-indent": "-0.635cm", + "fo:margin-left": "6.985cm" + } + } + } + } +]; \ No newline at end of file diff --git a/webodf/lib/gui/ListController.js b/webodf/lib/gui/ListController.js index 1a9668b24..95ec5568b 100644 --- a/webodf/lib/gui/ListController.js +++ b/webodf/lib/gui/ListController.js @@ -46,7 +46,11 @@ gui.ListController = function ListController(session, sessionConstraints, sessio /**@type{!core.LazyProperty.}*/ cachedSelectionInfo, /**@const*/ - NEXT = core.StepDirection.NEXT; + NEXT = core.StepDirection.NEXT, + /**@const*/ + DEFAULT_NUMBERING_STYLE = "WebODF-Numbering", + /**@const*/ + DEFAULT_BULLETED_STYLE = "WebODF-Bulleted"; /** * @param {!ops.OdtCursor|!string} cursorOrId @@ -193,13 +197,38 @@ gui.ListController = function ListController(session, sessionConstraints, sessio }; } + /** + * @param {!string} styleName + * @return {!ops.OpAddListStyle} + */ + function createDefaultListStyleOp(styleName) { + var op = new ops.OpAddListStyle(), + defaultListStyle; + + if (styleName === DEFAULT_NUMBERING_STYLE) { + defaultListStyle = gui.DefaultNumberedListStyle; + } else { + defaultListStyle = gui.DefaultBulletedListStyle; + } + + op.init({ + memberid: inputMemberId, + styleName: styleName, + isAutomaticStyle: true, + listStyle: defaultListStyle + }); + + return op; + } + /** * Takes all the paragraph elements in the current selection and breaks * them into add list operations based on their common ancestors. Paragraph elements * with the same common ancestor will be grouped into the same operation + * @param {!string=} styleName * @return {!Array.} */ - function determineOpsForAddingLists() { + function determineOpsForAddingLists(styleName) { var paragraphElements, /**@type{!Array.}*/ paragraphGroups = [], @@ -213,6 +242,7 @@ gui.ListController = function ListController(session, sessionConstraints, sessio paragraphParent = paragraphElements[i].parentNode; //TODO: handle selections that intersect with existing lists + // This also needs to handle converting a list between numbering or bullets which MUST preserve the list structure if (odfUtils.isListItemElement(paragraphParent)) { runtime.log("DEBUG: Current selection intersects with an existing list which is not supported at this time"); paragraphGroups.length = 0; @@ -238,7 +268,8 @@ gui.ListController = function ListController(session, sessionConstraints, sessio newOp.init({ memberid: inputMemberId, startParagraphPosition: odtDocument.convertDomPointToCursorStep(group.startParagraph, 0, NEXT), - endParagraphPosition: odtDocument.convertDomPointToCursorStep(group.endParagraph, 0, NEXT) + endParagraphPosition: odtDocument.convertDomPointToCursorStep(group.endParagraph, 0, NEXT), + styleName: styleName }); return newOp; }); @@ -320,13 +351,39 @@ gui.ListController = function ListController(session, sessionConstraints, sessio }; /** + * @param {!string=} styleName * @return {!boolean} */ - function makeList() { - return executeListOperations(determineOpsForAddingLists); - } + function makeList(styleName) { + var /**@type{!boolean}*/ + isExistingStyle, + /**@type{!boolean}*/ + isDefaultStyle; + + // check if the style name passed in exists in the document or is a WebODF default numbered or bulleted style. + // If no style name is passed in then the created list will have a style applied as described here: + // http://docs.oasis-open.org/office/v1.2/os/OpenDocument-v1.2-os-part1.html#__RefHeading__1419242_253892949 + if (styleName) { + isExistingStyle = Boolean(odtDocument.getFormatting().getStyleElement(styleName, "list-style")); + isDefaultStyle = styleName === DEFAULT_NUMBERING_STYLE || styleName === DEFAULT_BULLETED_STYLE; + + // if the style doesn't exist in the document and isn't a WebODF default style then we can't continue + if (!isExistingStyle && !isDefaultStyle) { + runtime.log("DEBUG: Could not create a list with the style name: " + styleName + " as it does not exist in the document"); + return false; + } + } - this.makeList = makeList; + return executeListOperations(function () { + var newOps = determineOpsForAddingLists(styleName); + + // this will only create an add list style op for WebODF default styles and only when they don't exist already + if (newOps.length > 0 && isDefaultStyle && !isExistingStyle) { + newOps.unshift(createDefaultListStyleOp(/**@type{!string}*/(styleName))); + } + return newOps; + }); + } /** * @return {!boolean} @@ -343,7 +400,7 @@ gui.ListController = function ListController(session, sessionConstraints, sessio */ this.setNumberedList = function (checked) { if (checked) { - return makeList(); + return makeList(DEFAULT_NUMBERING_STYLE); } return removeList(); @@ -355,7 +412,7 @@ gui.ListController = function ListController(session, sessionConstraints, sessio */ this.setBulletedList = function (checked) { if (checked) { - return makeList(); + return makeList(DEFAULT_BULLETED_STYLE); } return removeList(); }; diff --git a/webodf/lib/manifest.json b/webodf/lib/manifest.json index 47789d1a0..d86b039b2 100644 --- a/webodf/lib/manifest.json +++ b/webodf/lib/manifest.json @@ -97,6 +97,9 @@ ], "gui.CommonConstraints": [ ], + "gui.DefaultStyles": [ + "ops.OpAddListStyle" + ], "gui.DirectFormattingController": [ "core.LazyProperty", "gui.CommonConstraints", @@ -156,6 +159,7 @@ "gui.ListController": [ "core.LazyProperty", "gui.CommonConstraints", + "gui.DefaultStyles", "gui.ListStyleSummary", "gui.SessionConstraints", "gui.SessionContext" @@ -418,6 +422,9 @@ "ops.OpAddList": [ "ops.OdtDocument" ], + "ops.OpAddListStyle": [ + "ops.OdtDocument" + ], "ops.OpAddMember": [ "ops.OdtDocument" ], @@ -497,6 +504,7 @@ "ops.OpAddAnnotation", "ops.OpAddCursor", "ops.OpAddList", + "ops.OpAddListStyle", "ops.OpAddMember", "ops.OpAddStyle", "ops.OpApplyDirectStyling", @@ -526,6 +534,7 @@ ], "ops.OperationTransformMatrix": [ "ops.OpAddList", + "ops.OpAddListStyle", "ops.OpAddStyle", "ops.OpApplyDirectStyling", "ops.OpInsertText", diff --git a/webodf/lib/ops/OpAddListStyle.js b/webodf/lib/ops/OpAddListStyle.js new file mode 100644 index 000000000..80a5b88d6 --- /dev/null +++ b/webodf/lib/ops/OpAddListStyle.js @@ -0,0 +1,130 @@ +/** + * Copyright (C) 2010-2014 KO GmbH + * + * @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 . + * @licend + * + * @source: http://www.webodf.org/ + * @source: https://github.com/kogmbh/WebODF/ + */ + +/*global ops, runtime, odf, core*/ + +/** + * + * @constructor + * @implements ops.Operation + */ +ops.OpAddListStyle = function OpAddListStyle() { + "use strict"; + + var memberid, + timestamp, + isAutomaticStyle, + styleName, + /**@type{!ops.OpAddListStyle.ListStyle}*/ + listStyle, + /**@const*/ + textns = odf.Namespaces.textns, + /**@const*/ + stylens = odf.Namespaces.stylens; + + /** + * @param {!ops.OpAddListStyle.InitSpec} data + */ + this.init = function (data) { + memberid = data.memberid; + timestamp = data.timestamp; + isAutomaticStyle = data.isAutomaticStyle; + styleName = data.styleName; + listStyle = data.listStyle; + }; + + this.isEdit = true; + this.group = undefined; + + /** + * @return {!ops.OpAddListStyle.Spec} + */ + this.spec = function () { + return { + optype: "AddListStyle", + memberid: memberid, + timestamp: timestamp, + isAutomaticStyle: isAutomaticStyle, + styleName: styleName, + listStyle: listStyle + }; + }; + + /** + * @param {!ops.Document} document + */ + this.execute = function (document) { + var odtDocument = /**@type{!ops.OdtDocument}*/(document), + odfContainer = odtDocument.getOdfCanvas().odfContainer(), + ownerDocument = odtDocument.getDOMDocument(), + formatting = odtDocument.getFormatting(), + styleNode = ownerDocument.createElementNS(textns, "text:list-style"); + + if(!styleNode) { + return false; + } + + listStyle.forEach(function (listLevelStyle) { + var newListLevelNode = ownerDocument.createElementNS(textns, listLevelStyle.styleType); + formatting.updateStyle(newListLevelNode, listLevelStyle.styleProperties); + styleNode.appendChild(newListLevelNode); + }); + + styleNode.setAttributeNS(stylens, 'style:name', styleName); + + if (isAutomaticStyle) { + odfContainer.rootElement.automaticStyles.appendChild(styleNode); + } else { + odfContainer.rootElement.styles.appendChild(styleNode); + } + + odtDocument.getOdfCanvas().refreshCSS(); + if (!isAutomaticStyle) { + odtDocument.emit(ops.OdtDocument.signalCommonStyleCreated, {name: styleName, family: "list-style"}); + } + return true; + }; +}; + +/**@typedef{{ + optype: !string, + memberid: !string, + timestamp: !number, + isAutomaticStyle: !boolean, + styleName: !string, + listStyle: !ops.OpAddListStyle.ListStyle +}}*/ +ops.OpAddListStyle.Spec; + +/**@typedef{{ + memberid: !string, + timestamp:(!number|undefined), + isAutomaticStyle: !boolean, + styleName: !string, + listStyle: !ops.OpAddListStyle.ListStyle +}}*/ +ops.OpAddListStyle.InitSpec; + +/**@typedef{!Array.<{styleType: !string, styleProperties: !Object}>}*/ +ops.OpAddListStyle.ListStyle; \ No newline at end of file diff --git a/webodf/lib/ops/OperationFactory.js b/webodf/lib/ops/OperationFactory.js index 9d6e8bb91..af2911de9 100644 --- a/webodf/lib/ops/OperationFactory.js +++ b/webodf/lib/ops/OperationFactory.js @@ -102,7 +102,8 @@ ops.OperationFactory = function OperationFactory() { ApplyHyperlink: construct(ops.OpApplyHyperlink), RemoveHyperlink: construct(ops.OpRemoveHyperlink), AddList: construct(ops.OpAddList), - RemoveList: construct(ops.OpRemoveList) + RemoveList: construct(ops.OpRemoveList), + AddListStyle: construct(ops.OpAddListStyle) }; } diff --git a/webodf/lib/ops/OperationTransformMatrix.js b/webodf/lib/ops/OperationTransformMatrix.js index 86cc3c317..9696e1aa0 100644 --- a/webodf/lib/ops/OperationTransformMatrix.js +++ b/webodf/lib/ops/OperationTransformMatrix.js @@ -441,6 +441,22 @@ ops.OperationTransformMatrix = function OperationTransformMatrix() { }; } + /** + * @param {!ops.OpAddListStyle.Spec} addListStyleSpecA + * @param {!ops.OpAddListStyle.Spec} addListStyleSpecB + */ + function transformAddListStyleAddListStyle(addListStyleSpecA, addListStyleSpecB) { + //TODO: handle list style conflicts + if(addListStyleSpecA.styleName === addListStyleSpecB.styleName) { + return null; + } + + return { + opSpecsA: [addListStyleSpecA], + opSpecsB: [addListStyleSpecB] + }; + } + /** * @param {!ops.OpAddStyle.Spec} addStyleSpec * @param {!ops.OpRemoveStyle.Spec} removeStyleSpec @@ -1748,6 +1764,7 @@ ops.OperationTransformMatrix = function OperationTransformMatrix() { "AddCursor": { "AddCursor": passUnchanged, "AddList": passUnchanged, + "AddListStyle": passUnchanged, "AddMember": passUnchanged, "AddStyle": passUnchanged, "ApplyDirectStyling": passUnchanged, @@ -1767,6 +1784,7 @@ ops.OperationTransformMatrix = function OperationTransformMatrix() { }, "AddList": { "AddList": transformAddListAddList, + "AddListStyle": passUnchanged, "AddMember": passUnchanged, "AddStyle": passUnchanged, "ApplyDirectStyling": passUnchanged, @@ -1784,6 +1802,25 @@ ops.OperationTransformMatrix = function OperationTransformMatrix() { "UpdateMetadata": passUnchanged, "UpdateParagraphStyle": passUnchanged }, + "AddListStyle": { + "AddListStyle": transformAddListStyleAddListStyle, + "AddMember": passUnchanged, + "AddStyle": passUnchanged, + "ApplyDirectStyling": passUnchanged, + "InsertText": passUnchanged, + "MergeParagraph": passUnchanged, + "MoveCursor": passUnchanged, + "RemoveCursor": passUnchanged, + "RemoveList": passUnchanged, + "RemoveMember": passUnchanged, + "RemoveStyle": passUnchanged, + "RemoveText": passUnchanged, + "SetParagraphStyle": passUnchanged, + "SplitParagraph": passUnchanged, + "UpdateMember": passUnchanged, + "UpdateMetadata": passUnchanged, + "UpdateParagraphStyle": passUnchanged + }, "AddMember": { "AddStyle": passUnchanged, "ApplyDirectStyling": passUnchanged, diff --git a/webodf/tests/ops/OperationTests.js b/webodf/tests/ops/OperationTests.js index 37e8a7235..99e0eb6cb 100644 --- a/webodf/tests/ops/OperationTests.js +++ b/webodf/tests/ops/OperationTests.js @@ -106,6 +106,10 @@ ops.OperationTests = function OperationTests(runner) { if (/(length|position)/i.test(att.localName)) { value = parseInt(value, 10); } + // find boolean values + if (/^(is|moveCursor)/.test(att.localName)) { + value = JSON.parse(value); + } op[att.nodeName] = value; } // read complex data by childs diff --git a/webodf/tools/karma.conf.js b/webodf/tools/karma.conf.js index 77570b36a..0fbe73f16 100644 --- a/webodf/tools/karma.conf.js +++ b/webodf/tools/karma.conf.js @@ -83,6 +83,7 @@ module.exports = function (config) { 'lib/ops/OpAddAnnotation.js', 'lib/ops/OpAddCursor.js', 'lib/ops/OpAddList.js', + 'lib/ops/OpAddListStyle.js', 'lib/ops/OpAddMember.js', 'lib/ops/OpAddStyle.js', 'lib/odf/ObjectNameGenerator.js', @@ -132,6 +133,7 @@ module.exports = function (config) { 'lib/gui/ImageController.js', 'lib/gui/ImageSelector.js', 'lib/gui/InputMethodEditor.js', + 'lib/gui/DefaultStyles.js', 'lib/gui/ListStyleSummary.js', 'lib/gui/ListController.js', 'lib/gui/MetadataController.js',