Fix merge/cloneLayer. Migrate more Canvas functions to Draw. Tests.

Fixed recently introduced bugs in mergeLayer, cloneLayer.
More Draw unit tests.
Migrating Canvas methods to Draw, Layer, and utilities: copyElem,
pathActions.convertPath, cloneLayer, mergeLayer, and mergeAllLayers.
Canvas API is unchanged for backwards compatibility (i.e. previous
functions forward to new functions).
This commit is contained in:
Flint O'Brien
2016-05-04 09:38:29 -04:00
parent 14d372c084
commit 87e25e9d2c
5 changed files with 624 additions and 297 deletions

View File

@@ -8,10 +8,13 @@
<script src='../editor/svgedit.js'></script>
<script src='../editor/pathseg.js'></script>
<script src='../editor/browser.js'></script>
<script src='../editor/units.js'></script>
<script src='../editor/svgutils.js'></script>
<script src='../editor/draw.js'></script>
<script src='../editor/layer.js'></script>
<script src='qunit/qunit.js'></script>
<script src="sinon/sinon-1.17.3.js"></script>
<script src="sinon/sinon-qunit-1.0.0.js"></script>
<script>
$(function() {
// log function
@@ -26,6 +29,15 @@
var LAYER1 = 'Layer 1';
var LAYER2 = 'Layer 2';
var LAYER3 = 'Layer 3';
var PATH_ATTR = {
// clone will convert relative to absolute, so the test for equality fails.
//'d': 'm7.38867,57.38867c0,-27.62431 22.37569,-50 50,-50c27.62431,0 50,22.37569 50,50c0,27.62431 -22.37569,50 -50,50c-27.62431,0 -50,-22.37569 -50,-50z',
'd': 'M7.389,57.389C7.389,29.764 29.764,7.389 57.389,7.389C85.013,7.389 107.389,29.764 107.389,57.389C107.389,85.013 85.013,107.389 57.389,107.389C29.764,107.389 7.389,85.013 7.389,57.389z',
'transform': 'rotate(45 57.388671875000036,57.388671874999986) ',
'stroke-width': '5',
'stroke': '#660000',
'fill':'#ff0000'
};
var svg = document.createElementNS(NS.SVG, 'svg');
var sandbox = document.getElementById('sandbox');
@@ -37,6 +49,19 @@
svg_n.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
svg_n.setAttributeNS(NS.SE, 'se:nonce', NONCE);
svgedit.units.init({
// used by svgedit.units.shortFloat - call path: cloneLayer -> copyElem -> convertPath -> pathDSegment -> shortFloat
getRoundDigits: function() { return 3; }
});
function createSVGElement(jsonMap) {
var elem = document.createElementNS(svgedit.NS.SVG, jsonMap['element']);
for (var attr in jsonMap['attr']) {
elem.setAttribute(attr, jsonMap['attr'][attr]);
}
return elem;
}
var setupSvgWith3Layers = function(svgElem) {
var layer1 = document.createElementNS(NS.SVG, 'g');
var layer1_title = document.createElementNS(NS.SVG, 'title');
@@ -55,12 +80,51 @@
layer3_title.appendChild(document.createTextNode(LAYER3));
layer3.appendChild(layer3_title);
svgElem.appendChild(layer3);
return [layer1, layer2, layer3];
};
var createSomeElementsInGroup = function(group) {
group.appendChild(createSVGElement({
'element': 'path',
'attr': PATH_ATTR
}));
// group.appendChild(createSVGElement({
// 'element': 'path',
// 'attr': {'d': 'M0,1L2,3'}
// }));
group.appendChild(createSVGElement({
'element': 'rect',
'attr': {'x': '0', 'y': '1', 'width': '5', 'height': '10'}
}));
group.appendChild(createSVGElement({
'element': 'line',
'attr': {'x1': '0', 'y1': '1', 'x2': '5', 'y2': '6'}
}));
var g = createSVGElement({
'element': 'g',
'attr': {}
});
g.appendChild(createSVGElement({
'element': 'rect',
'attr': {'x': '0', 'y': '1', 'width': '5', 'height': '10'}
}));
group.appendChild(g);
return 4;
};
var cleanupSvg = function(svgElem) {
while(svgElem.firstChild) {svgElem.removeChild(svgElem.firstChild);}
};
module('svgedit.draw.Drawing', {
setup: function() {
},
teardown: function() {
}
});
test('Test draw module', function() {
expect(4);
@@ -389,11 +453,8 @@
test('Test setCurrentLayerName()', function() {
var mockHrService = {
changeElement: function(elem, attrs){
mockHrService.elem = elem;
mockHrService.attrs = attrs;
}
}
changeElement: this.spy()
};
var drawing = new svgedit.draw.Drawing(svg);
setupSvgWith3Layers(svg);
@@ -413,14 +474,21 @@
equals( drawing.layer_map[oldName], undefined);
equals( drawing.layer_map[newName], drawing.current_layer);
// Was mockHrService called?
equals( oldName, mockHrService.attrs['#text']);
equals( newName, mockHrService.elem.textContent);
ok( mockHrService.changeElement.calledOnce);
equals( oldName, mockHrService.changeElement.getCall(0).args[1]['#text']);
equals( newName, mockHrService.changeElement.getCall(0).args[0].textContent);
cleanupSvg(svg);
});
test('Test createLayer()', function() {
expect(7);
expect(10);
var mockHrService = {
startBatchCommand: this.spy(),
endBatchCommand: this.spy(),
insertElement: this.spy()
};
var drawing = new svgedit.draw.Drawing(svg);
setupSvgWith3Layers(svg);
@@ -430,13 +498,178 @@
equals(typeof drawing.createLayer, typeof function(){});
var NEW_LAYER_NAME = 'Layer A';
var layer_g = drawing.createLayer(NEW_LAYER_NAME);
var layer_g = drawing.createLayer(NEW_LAYER_NAME, mockHrService);
equals(drawing.getNumLayers(), 4);
equals(layer_g, drawing.getCurrentLayer());
equals(layer_g.getAttribute('class'), LAYER_CLASS);
equals(NEW_LAYER_NAME, drawing.getCurrentLayerName());
equals(NEW_LAYER_NAME, drawing.getLayerName(3));
equals(layer_g, mockHrService.insertElement.getCall(0).args[0]);
ok( mockHrService.startBatchCommand.calledOnce);
ok( mockHrService.endBatchCommand.calledOnce);
cleanupSvg(svg);
});
test('Test mergeLayer()', function() {
var mockHrService = {
startBatchCommand: this.spy(),
endBatchCommand: this.spy(),
moveElement: this.spy(),
removeElement: this.spy()
};
var drawing = new svgedit.draw.Drawing(svg);
var layers = setupSvgWith3Layers(svg);
var elementCount = createSomeElementsInGroup(layers[2]) + 1; // +1 for title element
equals(layers[1].childElementCount, 1);
equals(layers[2].childElementCount, elementCount);
drawing.identifyLayers();
equals(drawing.getCurrentLayer(), layers[2])
ok(drawing.mergeLayer);
equals(typeof drawing.mergeLayer, typeof function(){});
drawing.mergeLayer(mockHrService);
equals(drawing.getNumLayers(), 2);
equals(svg.childElementCount, 2);
equals(drawing.getCurrentLayer(), layers[1]);
equals(layers[1].childElementCount, elementCount);
// check history record
ok( mockHrService.startBatchCommand.calledOnce);
ok( mockHrService.endBatchCommand.calledOnce);
equals(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge Layer');
equals(mockHrService.moveElement.callCount, elementCount - 1); // -1 because the title was not moved.
equals(mockHrService.removeElement.callCount, 2); // remove group and title.
cleanupSvg(svg);
});
test('Test mergeLayer() when no previous layer to merge', function() {
var mockHrService = {
startBatchCommand: this.spy(),
endBatchCommand: this.spy(),
moveElement: this.spy(),
removeElement: this.spy()
};
var drawing = new svgedit.draw.Drawing(svg);
var layers = setupSvgWith3Layers(svg);
drawing.identifyLayers();
drawing.setCurrentLayer(LAYER1);
equals(drawing.getCurrentLayer(), layers[0]);
drawing.mergeLayer(mockHrService);
equals(drawing.getNumLayers(), 3);
equals(svg.childElementCount, 3);
equals(drawing.getCurrentLayer(), layers[0]);
equals(layers[0].childElementCount, 1);
equals(layers[1].childElementCount, 1);
equals(layers[2].childElementCount, 1);
// check history record
equals(mockHrService.startBatchCommand.callCount, 0);
equals(mockHrService.endBatchCommand.callCount, 0);
equals(mockHrService.moveElement.callCount, 0);
equals(mockHrService.removeElement.callCount, 0);
cleanupSvg(svg);
});
test('Test mergeAllLayers()', function() {
var mockHrService = {
startBatchCommand: this.spy(),
endBatchCommand: this.spy(),
moveElement: this.spy(),
removeElement: this.spy()
};
var drawing = new svgedit.draw.Drawing(svg);
var layers = setupSvgWith3Layers(svg);
var elementCount = createSomeElementsInGroup(layers[0]) + 1; // +1 for title element
createSomeElementsInGroup(layers[1]);
createSomeElementsInGroup(layers[2]);
equals(layers[0].childElementCount, elementCount);
equals(layers[1].childElementCount, elementCount);
equals(layers[2].childElementCount, elementCount);
drawing.identifyLayers();
ok(drawing.mergeAllLayers);
equals(typeof drawing.mergeAllLayers, typeof function(){});
drawing.mergeAllLayers(mockHrService);
equals(drawing.getNumLayers(), 1);
equals(svg.childElementCount, 1);
equals(drawing.getCurrentLayer(), layers[0]);
equals(layers[0].childElementCount, elementCount * 3 - 2); // -2 because two titles were deleted.
// check history record
equals( mockHrService.startBatchCommand.callCount, 3); // mergeAllLayers + 2 * mergeLayer
equals( mockHrService.endBatchCommand.callCount, 3);
equals(mockHrService.startBatchCommand.getCall(0).args[0], 'Merge all Layers');
equals(mockHrService.startBatchCommand.getCall(1).args[0], 'Merge Layer');
equals(mockHrService.startBatchCommand.getCall(2).args[0], 'Merge Layer');
// moveElement count is times 3 instead of 2, because one layer's elements were moved twice.
// moveElement count is minus 3 because the three titles were not moved.
equals(mockHrService.moveElement.callCount, elementCount * 3 - 3);
equals(mockHrService.removeElement.callCount, 2 * 2); // remove group and title twice.
cleanupSvg(svg);
});
test('Test cloneLayer()', function() {
var mockHrService = {
startBatchCommand: this.spy(),
endBatchCommand: this.spy(),
insertElement: this.spy()
};
var drawing = new svgedit.draw.Drawing(svg);
var layers = setupSvgWith3Layers(svg);
var layer3 = layers[2];
var elementCount = createSomeElementsInGroup(layer3) + 1; // +1 for title element
equals(layer3.childElementCount, elementCount);
drawing.identifyLayers();
ok(drawing.cloneLayer);
equals(typeof drawing.cloneLayer, typeof function(){});
var clone = drawing.cloneLayer('clone', mockHrService);
equals(drawing.getNumLayers(), 4);
equals(svg.childElementCount, 4);
equals(drawing.getCurrentLayer(), clone);
equals(clone.childElementCount, elementCount);
// check history record
ok( mockHrService.startBatchCommand.calledOnce); // mergeAllLayers + 2 * mergeLayer
ok( mockHrService.endBatchCommand.calledOnce);
equals(mockHrService.startBatchCommand.getCall(0).args[0], 'Duplicate Layer');
equals(mockHrService.insertElement.callCount, 1);
equals(mockHrService.insertElement.getCall(0).args[0], clone);
// check that path is cloned properly
equals(clone.childNodes.length, elementCount);
var path = clone.childNodes[1]
equals(path.id, 'svg_1');
equals(path.getAttribute('d'), PATH_ATTR.d);
equals(path.getAttribute('transform'), PATH_ATTR.transform);
equals(path.getAttribute('fill'), PATH_ATTR.fill);
equals(path.getAttribute('stroke'), PATH_ATTR.stroke);
equals(path.getAttribute('stroke-width'), PATH_ATTR['stroke-width']);
// check that g is cloned properly
var g = clone.childNodes[4]
equals(g.childNodes.length, 1);
equals(g.id, 'svg_4');
cleanupSvg(svg);
});