node-webodf-ilkkah
Version:
WebODF - JavaScript Document Engine http://webodf.org/
319 lines (281 loc) • 12.5 kB
JavaScript
/**
* Copyright (C) 2014 KO GmbH <copyright@kogmbh.com>
*
* @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 runtime, core, gui, odf, ops*/
/**
* @constructor
* @param {core.UnitTestRunner} runner
* @implements {core.UnitTest}
*/
gui.DirectFormattingControllerTests = function DirectFormattingControllerTests(runner) {
"use strict";
var r = runner,
t,
testarea,
officens = odf.Namespaces.officens,
utils = new core.Utils(),
domUtils = core.DomUtils,
inputMemberId = "Joe";
/**
* @constructor
* @extends {odf.OdfContainer}
* @param {!Element} node
*/
function MockOdfContainer(node) {
// OdfContainer maps the following properties onto the rootElement
node.styles = node.getElementsByTagNameNS(odf.Namespaces.officens, "styles")[0];
node.automaticStyles = node.getElementsByTagNameNS(odf.Namespaces.officens, "automatic-styles")[0];
this.rootElement = /**@type{!odf.ODFDocumentElement}*/(node);
this.getContentElement = function () { return node.getElementsByTagNameNS(officens, 'text')[0]; };
}
/**
* Trying to avoid having to load a complete document for these tests. Mocking ODF
* canvas allows some simplification in the testing setup
* @constructor
* @extends {odf.OdfCanvas} Well.... we don't really, but please shut your face closure compiler :)
* @param {!Element} node
*/
/*jslint emptyblock:true*/
function MockOdfCanvas(node) {
var container = new MockOdfContainer(node),
formatting = new odf.Formatting();
formatting.setOdfContainer(container);
this.getFormatting = function() { return formatting; };
this.odfContainer = function () { return container; };
this.getElement = function () { return node; };
this.refreshSize = function() { };
this.rerenderAnnotations = function() { };
}
/*jslint emptyblock:false*/
/**
* @param {!ops.OdtDocument} odtDocument
* @extends {ops.Session} Don't mind me... I'm just lying to closure compiler again!
* @constructor
*/
function MockSession(odtDocument) {
var self = this;
this.operations = [];
this.getOdtDocument = function() {
return odtDocument;
};
this.enqueue = function(ops) {
self.operations.push.apply(self.operations, ops);
ops.forEach(function(op) { op.execute(odtDocument); });
};
this.reset = function() {
self.operations.length = 0;
};
}
/**
* Create a new ODT document with the specified text body
* @param {!string} styles
* @param {!string} xml
* @return {!Element} Root document node
*/
function createOdtDocument(styles, xml) {
var domDocument = testarea.ownerDocument,
testns = "urn:webodf:textcontrollertest",
namespaceMap = utils.mergeObjects(odf.Namespaces.namespaceMap, {"test": testns}),
doc,
node,
mock,
range;
xml = xml.replace("[", "<test:start/>").replace("]", "<test:end/>");
doc = core.UnitTest.createOdtDocument("<office:styles>" + styles + "</office:styles>" +
"<office:automatic-styles></office:automatic-styles>" +
"<office:text>" + xml + "</office:text>", namespaceMap);
node = /**@type{!Element}*/(domDocument.importNode(doc.documentElement, true));
testarea.appendChild(node);
mock = new MockOdfCanvas(node);
t.odtDocument = new ops.OdtDocument(mock);
t.session = new MockSession(t.odtDocument);
t.sessionConstraints = new gui.SessionConstraints();
t.sessionContext = new gui.SessionContext(t.session, inputMemberId);
t.formattingController = new gui.DirectFormattingController(t.session, t.sessionConstraints, t.sessionContext,
inputMemberId,
new odf.ObjectNameGenerator(mock.odfContainer(), inputMemberId),
true, true);
t.cursor = new ops.OdtCursor(inputMemberId, t.odtDocument);
t.odtDocument.addCursor(t.cursor);
if (node.getElementsByTagNameNS(testns, "start")[0]) {
range = node.ownerDocument.createRange();
range.setStartAfter(node.getElementsByTagNameNS(testns, "start")[0]);
range.setEndAfter(node.getElementsByTagNameNS(testns, "end")[0]);
t.cursor.setSelectedRange(range, true);
// Clean up the test anchors after the selection has been set
domUtils.getElementsByTagNameNS(node, testns, '*').forEach(function(node) {
node.parentNode.removeChild(node);
});
t.odtDocument.emit(ops.Document.signalCursorMoved, t.cursor);
}
return node;
}
this.setUp = function () {
testarea = core.UnitTest.provideTestAreaDiv();
t = { doc: testarea.ownerDocument };
};
this.tearDown = function () {
core.UnitTest.cleanupTestAreaDiv();
t = {};
};
function getSelectionInfo_ReportedStyleSummaryIncludesCursorStyling() {
createOdtDocument(
"<style:style style:name='simple' style:family='paragraph'>" +
"<style:text-properties fo:font-weight='bold'/>" +
"</style:style>",
"<text:p text:style-name='simple'>[]</text:p>");
t.formattingController.setBold(false);
t.isBold = t.formattingController.isBold();
r.shouldBe(t, "t.isBold", "false");
}
function getSelectionInfo_ReportedStyleSummaryStaysInAnnotationScope() {
createOdtDocument(
"<style:style style:name='simple' style:family='paragraph'>" +
"<style:text-properties fo:font-weight='bold'/>" +
"</style:style>",
"<text:p text:style-name='simple'><office:annotation office:name=\"alice_1\">" +
"<text:list><text:list-item><text:p>[]</text:p></text:list-item></text:list>" +
"</office:annotation></text:p>");
t.isBold = t.formattingController.isBold();
r.shouldBe(t, "t.isBold", "false");
t.formattingController.setBold(true);
t.isBold = t.formattingController.isBold();
r.shouldBe(t, "t.isBold", "true");
}
function createCursorStyleOp_UseCachedStyle_ReturnsSetOpForCachedStyle() {
createOdtDocument(
"<style:style style:name='simple' style:family='paragraph'>" +
"<style:text-properties fo:font-weight='bold'/>" +
"</style:style>",
"<text:p text:style-name='simple'>[]</text:p>");
t.operation = t.formattingController.createCursorStyleOp(0, 0, true);
t.expectedOperation = {
optype: "ApplyDirectStyling",
timestamp: undefined,
memberid: inputMemberId,
position: 0,
length: 0,
setProperties: {
'style:text-properties': {
'fo:font-weight': 'bold'
}
}
};
r.shouldBe(t, "t.operation.spec()", "t.expectedOperation");
}
function createParagraphStyleOp_OnLastStepInParagraph_CreatesParagraphStyleForNewParagraph() {
createOdtDocument(
"<style:style style:name='simple' style:family='paragraph'>" +
"<style:text-properties fo:font-weight='normal'/>" +
"</style:style>" +
"<style:style style:name='bold' style:family='text'>" +
"<style:text-properties fo:font-weight='bold'/>" +
"</style:style>",
"<text:p text:style-name='simple'><text:span text:style-name='bold'>[a]</text:span></text:p>");
t.operations = t.formattingController.createParagraphStyleOps(1);
t.expectedOperation0 = {
optype: "AddStyle",
timestamp: undefined,
memberid: inputMemberId,
styleName: 'auto74656_0',
styleFamily: 'paragraph',
isAutomaticStyle: true,
setProperties: {
'style:parent-style-name': 'simple',
'style:family': 'paragraph',
'style:text-properties': {
'fo:font-weight': 'bold'
}
}
};
r.shouldBe(t, "t.operations.shift().spec()", "t.expectedOperation0");
t.expectedOperation1 = {
optype: "SetParagraphStyle",
timestamp: undefined,
memberid: inputMemberId,
styleName: 'auto74656_0',
position: 1
};
r.shouldBe(t, "t.operations.shift().spec()", "t.expectedOperation1");
r.shouldBe(t, "t.operations.shift()", "undefined");
}
function createParagraphStyleOp_NoSelectedText_ReturnsEmptyArray() {
createOdtDocument("", "<text:p>a[</text:p><text:p>]</text:p>");
t.operations = t.formattingController.createParagraphStyleOps(1);
r.shouldBe(t, "t.operations.shift()", "undefined");
}
function createParagraphStyleOp_NoSelectedText_UsesStyleBeforeSelection() {
createOdtDocument(
"<style:style style:name='simple' style:family='paragraph'>" +
"<style:text-properties fo:font-weight='normal'/>" +
"</style:style>" +
"<style:style style:name='bold' style:family='text'>" +
"<style:text-properties fo:font-weight='bold'/>" +
"</style:style>",
"<text:p text:style-name='simple'><text:span text:style-name='bold'>a[</text:span></text:p><text:p>]</text:p>");
t.operations = t.formattingController.createParagraphStyleOps(1);
t.expectedOperation0 = {
optype: "AddStyle",
timestamp: undefined,
memberid: inputMemberId,
styleName: 'auto74656_0',
styleFamily: 'paragraph',
isAutomaticStyle: true,
setProperties: {
'style:parent-style-name': 'simple',
'style:family': 'paragraph',
'style:text-properties': {
'fo:font-weight': 'bold'
}
}
};
r.shouldBe(t, "t.operations.shift().spec()", "t.expectedOperation0");
t.expectedOperation1 = {
optype: "SetParagraphStyle",
timestamp: undefined,
memberid: inputMemberId,
styleName: 'auto74656_0',
position: 1
};
r.shouldBe(t, "t.operations.shift().spec()", "t.expectedOperation1");
r.shouldBe(t, "t.operations.shift()", "undefined");
}
this.tests = function () {
return r.name([
getSelectionInfo_ReportedStyleSummaryIncludesCursorStyling,
getSelectionInfo_ReportedStyleSummaryStaysInAnnotationScope,
createCursorStyleOp_UseCachedStyle_ReturnsSetOpForCachedStyle,
createParagraphStyleOp_OnLastStepInParagraph_CreatesParagraphStyleForNewParagraph,
createParagraphStyleOp_NoSelectedText_ReturnsEmptyArray,
createParagraphStyleOp_NoSelectedText_UsesStyleBeforeSelection
]);
};
this.asyncTests = function () {
return [
];
};
};
gui.DirectFormattingControllerTests.prototype.description = function () {
"use strict";
return "Test the DirectFormattingController class.";
};