Merge pull request #109 from gec/layerTests
Fix rename layer, merge/cloneLayer. Migrate functions from Canvas to Draw. Tests.master
commit
e35413c5ad
|
@ -300,10 +300,20 @@ svgedit.draw.Drawing.prototype.getCurrentLayerName = function () {
|
|||
/**
|
||||
* Set the current layer's name.
|
||||
* @param {string} name - The new name.
|
||||
* @returns {Object} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null.
|
||||
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
|
||||
* @returns {string|null} The new name if changed; otherwise, null.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.setCurrentLayerName = function (name) {
|
||||
return this.current_layer ? this.current_layer.setName(name) : null;
|
||||
svgedit.draw.Drawing.prototype.setCurrentLayerName = function (name, hrService) {
|
||||
var finalName = null;
|
||||
if (this.current_layer) {
|
||||
var oldName = this.current_layer.getName();
|
||||
finalName = this.current_layer.setName(name, hrService);
|
||||
if (finalName) {
|
||||
delete this.layer_map[oldName];
|
||||
this.layer_map[finalName] = this.current_layer;
|
||||
}
|
||||
}
|
||||
return finalName;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -354,7 +364,7 @@ svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) {
|
|||
svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
|
||||
var current_group = this.current_layer.getGroup();
|
||||
var prevGroup = $(current_group).prev()[0];
|
||||
if (!prevGroup) {return null;}
|
||||
if (!prevGroup) {return;}
|
||||
|
||||
hrService.startBatchCommand('Merge Layer');
|
||||
|
||||
|
@ -509,12 +519,13 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
|
|||
|
||||
/**
|
||||
* Creates a new top-level layer in the drawing with the given name and
|
||||
* sets the current layer to it.
|
||||
* makes it the current layer.
|
||||
* @param {string} name - The given name. If the layer name exists, a new name will be generated.
|
||||
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
|
||||
* @returns {SVGGElement} The SVGGElement of the new layer, which is
|
||||
* also the current layer of this drawing.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.createLayer = function(name) {
|
||||
svgedit.draw.Drawing.prototype.createLayer = function(name, hrService) {
|
||||
if (this.current_layer) {
|
||||
this.current_layer.deactivate();
|
||||
}
|
||||
|
@ -522,13 +533,69 @@ svgedit.draw.Drawing.prototype.createLayer = function(name) {
|
|||
if (name === undefined || name === null || name === '' || this.layer_map[name]) {
|
||||
name = getNewLayerName(Object.keys(this.layer_map));
|
||||
}
|
||||
|
||||
// Crate new layer and add to DOM as last layer
|
||||
var layer = new svgedit.draw.Layer(name, null, this.svgElem_);
|
||||
// Like to assume hrService exists, but this is backwards compatible with old version of createLayer.
|
||||
if (hrService) {
|
||||
hrService.startBatchCommand('Create Layer');
|
||||
hrService.insertElement(layer.getGroup());
|
||||
hrService.endBatchCommand();
|
||||
}
|
||||
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
this.current_layer = layer;
|
||||
return layer.getGroup();
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a copy of the current layer with the given name and makes it the current layer.
|
||||
* @param {string} name - The given name. If the layer name exists, a new name will be generated.
|
||||
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
|
||||
* @returns {SVGGElement} The SVGGElement of the new layer, which is
|
||||
* also the current layer of this drawing.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.cloneLayer = function(name, hrService) {
|
||||
if (!this.current_layer) {return null;}
|
||||
this.current_layer.deactivate();
|
||||
// Check for duplicate name.
|
||||
if (name === undefined || name === null || name === '' || this.layer_map[name]) {
|
||||
name = getNewLayerName(Object.keys(this.layer_map));
|
||||
}
|
||||
|
||||
// Create new group and add to DOM just after current_layer
|
||||
var currentGroup = this.current_layer.getGroup();
|
||||
var layer = new svgedit.draw.Layer(name, currentGroup, this.svgElem_);
|
||||
var group = layer.getGroup();
|
||||
|
||||
// Clone children
|
||||
var children = currentGroup.childNodes;
|
||||
var index;
|
||||
for (index = 0; index < children.length; index++) {
|
||||
var ch = children[index];
|
||||
if (ch.localName == 'title') {continue;}
|
||||
group.appendChild(this.copyElem(ch));
|
||||
}
|
||||
|
||||
if (hrService) {
|
||||
hrService.startBatchCommand('Duplicate Layer');
|
||||
hrService.insertElement(group);
|
||||
hrService.endBatchCommand();
|
||||
}
|
||||
|
||||
// Update layer containers and current_layer.
|
||||
index = this.all_layers.indexOf(this.current_layer);
|
||||
if (index >= 0) {
|
||||
this.all_layers.splice(index + 1, 0, layer);
|
||||
} else {
|
||||
this.all_layers.push(layer);
|
||||
}
|
||||
this.layer_map[name] = layer;
|
||||
this.current_layer = layer;
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns whether the layer is visible. If the layer name is not valid,
|
||||
* then this function returns false.
|
||||
|
@ -589,4 +656,16 @@ svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of an element, updating its ID and its children's IDs when needed
|
||||
* @param {Element} el - DOM element to clone
|
||||
* @returns {Element}
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.copyElem = function(el) {
|
||||
var self = this;
|
||||
var getNextIdClosure = function() { return self.getNextId();}
|
||||
return svgedit.utilities.copyElem(el, getNextIdClosure)
|
||||
}
|
||||
|
||||
|
||||
}());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*globals svgedit*/
|
||||
/*globals $ svgedit*/
|
||||
/*jslint vars: true, eqeq: true */
|
||||
/**
|
||||
* Package: svgedit.history
|
||||
|
@ -25,24 +25,37 @@ var NS = svgedit.NS;
|
|||
/**
|
||||
* This class encapsulates the concept of a layer in the drawing. It can be constructed with
|
||||
* an existing group element or, with three parameters, will create a new layer group element.
|
||||
*
|
||||
* Usage:
|
||||
* new Layer'name', group) // Use the existing group for this layer.
|
||||
* new Layer('name', group, svgElem) // Create a new group and add it to the DOM after group.
|
||||
* new Layer('name', null, svgElem) // Create a new group and add it to the DOM as the last layer.
|
||||
*
|
||||
* @param {string} name - Layer name
|
||||
* @param {SVGGElement} group - SVG group element that constitutes the layer or null if a group should be created and added to the DOM..
|
||||
* @param {SVGGElement} svgElem - The SVG DOM element. If defined, use this to add
|
||||
* @param {SVGGElement|null} group - An existing SVG group element or null.
|
||||
* If group and no svgElem, use group for this layer.
|
||||
* If group and svgElem, create a new group element and insert it in the DOM after group.
|
||||
* If no group and svgElem, create a new group element and insert it in the DOM as the last layer.
|
||||
* @param {SVGGElement=} svgElem - The SVG DOM element. If defined, use this to add
|
||||
* a new layer to the document.
|
||||
*/
|
||||
var Layer = svgedit.draw.Layer = function(name, group, svgElem) {
|
||||
this.name_ = name;
|
||||
this.group_ = group;
|
||||
this.group_ = svgElem ? null : group;
|
||||
|
||||
if (!group) {
|
||||
if (svgElem) {
|
||||
// Create a group element with title and add it to the DOM.
|
||||
var svgdoc = svgElem.ownerDocument;
|
||||
this.group_ = svgdoc.createElementNS(NS.SVG, "g");
|
||||
var layer_title = svgdoc.createElementNS(NS.SVG, "title");
|
||||
layer_title.textContent = name;
|
||||
this.group_.appendChild(layer_title);
|
||||
if (group) {
|
||||
$(group).after(this.group_);
|
||||
} else {
|
||||
svgElem.appendChild(this.group_);
|
||||
}
|
||||
}
|
||||
|
||||
addLayerClass(this.group_);
|
||||
svgedit.utilities.walkTree(this.group_, function(e){e.setAttribute("style", "pointer-events:inherit");});
|
||||
|
@ -155,7 +168,13 @@ Layer.prototype.getTitleElement = function() {
|
|||
return null;
|
||||
};
|
||||
|
||||
Layer.prototype.setName = function(name) {
|
||||
/**
|
||||
* Set the name of this layer.
|
||||
* @param {string} name - The new name.
|
||||
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
|
||||
* @returns {string|null} The new name if changed; otherwise, null.
|
||||
*/
|
||||
Layer.prototype.setName = function(name, hrService) {
|
||||
var previousName = this.name_;
|
||||
name = svgedit.utilities.toXml(name);
|
||||
// now change the underlying title element contents
|
||||
|
@ -164,7 +183,10 @@ Layer.prototype.setName = function(name) {
|
|||
while (title.firstChild) { title.removeChild(title.firstChild); }
|
||||
title.textContent = name;
|
||||
this.name_ = name;
|
||||
return {title: title, previousName: previousName};
|
||||
if (hrService) {
|
||||
hrService.changeElement(title, {'#text':previousName});
|
||||
}
|
||||
return this.name_;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
|
|
@ -355,6 +355,15 @@ var addCommandToHistory = function(cmd) {
|
|||
canvas.undoMgr.addCommandToHistory(cmd);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get a HistoryRecordingService.
|
||||
* @param {svgedit.history.HistoryRecordingService=} hrService - if exists, return it instead of creating a new service.
|
||||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
function historyRecordingService(hrService) {
|
||||
return hrService ? hrService : new svgedit.history.HistoryRecordingService(canvas.undoMgr);
|
||||
}
|
||||
|
||||
// import from select.js
|
||||
svgedit.select.init(curConfig, {
|
||||
createSVGElement: function(jsonMap) { return canvas.addSvgElementFromJson(jsonMap); },
|
||||
|
@ -666,56 +675,6 @@ var groupSvgElem = this.groupSvgElem = function(elem) {
|
|||
$(g).append(elem).data('gsvg', elem)[0].id = getNextId();
|
||||
};
|
||||
|
||||
// Function: copyElem
|
||||
// Create a clone of an element, updating its ID and its children's IDs when needed
|
||||
//
|
||||
// Parameters:
|
||||
// el - DOM element to clone
|
||||
//
|
||||
// Returns: The cloned element
|
||||
var copyElem = function(el) {
|
||||
// manually create a copy of the element
|
||||
var new_el = document.createElementNS(el.namespaceURI, el.nodeName);
|
||||
$.each(el.attributes, function(i, attr) {
|
||||
if (attr.localName != '-moz-math-font-style') {
|
||||
new_el.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value);
|
||||
}
|
||||
});
|
||||
// set the copied element's new id
|
||||
new_el.removeAttribute('id');
|
||||
new_el.id = getNextId();
|
||||
|
||||
// Opera's "d" value needs to be reset for Opera/Win/non-EN
|
||||
// Also needed for webkit (else does not keep curved segments on clone)
|
||||
if (svgedit.browser.isWebkit() && el.nodeName == 'path') {
|
||||
var fixed_d = pathActions.convertPath(el);
|
||||
new_el.setAttribute('d', fixed_d);
|
||||
}
|
||||
|
||||
// now create copies of all children
|
||||
$.each(el.childNodes, function(i, child) {
|
||||
switch(child.nodeType) {
|
||||
case 1: // element node
|
||||
new_el.appendChild(copyElem(child));
|
||||
break;
|
||||
case 3: // text node
|
||||
new_el.textContent = child.nodeValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if ($(el).data('gsvg')) {
|
||||
$(new_el).data('gsvg', new_el.firstChild);
|
||||
} else if ($(el).data('symbol')) {
|
||||
var ref = $(el).data('symbol');
|
||||
$(new_el).data('ref', ref).data('symbol', ref);
|
||||
} else if (new_el.tagName == 'image') {
|
||||
preventClickDefault(new_el);
|
||||
}
|
||||
return new_el;
|
||||
};
|
||||
|
||||
// Set scope for these functions
|
||||
var getId, getNextId;
|
||||
|
@ -882,9 +841,6 @@ var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = f
|
|||
}
|
||||
};
|
||||
|
||||
// this is how we map paths to our preferred relative segment types
|
||||
var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
|
||||
'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
|
||||
|
||||
// Debug tool to easily see the current matrix in the browser's console
|
||||
var logMatrix = function(m) {
|
||||
|
@ -1404,7 +1360,7 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
|
|||
}
|
||||
});
|
||||
setHref(newImage, last_good_img_url);
|
||||
preventClickDefault(newImage);
|
||||
svgedit.utilities.preventClickDefault(newImage);
|
||||
break;
|
||||
case 'square':
|
||||
// FIXME: once we create the rect, we lose information that this was a square
|
||||
|
@ -2353,14 +2309,6 @@ var getMouseTarget = this.getMouseTarget = function(evt) {
|
|||
|
||||
}());
|
||||
|
||||
// Function: preventClickDefault
|
||||
// Prevents default browser click behaviour on the given element
|
||||
//
|
||||
// Parameters:
|
||||
// img - The DOM element to prevent the cilck on
|
||||
var preventClickDefault = function(img) {
|
||||
$(img).click(function(e){e.preventDefault();});
|
||||
};
|
||||
|
||||
// Group: Text edit functions
|
||||
// Functions relating to editing text elements
|
||||
|
@ -3684,165 +3632,7 @@ pathActions = canvas.pathActions = function() {
|
|||
if (svgedit.browser.isWebkit()) {resetD(elem);}
|
||||
},
|
||||
// Convert a path to one with only absolute or relative values
|
||||
convertPath: function(path, toRel) {
|
||||
var i;
|
||||
var segList = path.pathSegList;
|
||||
var len = segList.numberOfItems;
|
||||
var curx = 0, cury = 0;
|
||||
var d = '';
|
||||
var last_m = null;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
var seg = segList.getItem(i);
|
||||
// if these properties are not in the segment, set them to zero
|
||||
var x = seg.x || 0,
|
||||
y = seg.y || 0,
|
||||
x1 = seg.x1 || 0,
|
||||
y1 = seg.y1 || 0,
|
||||
x2 = seg.x2 || 0,
|
||||
y2 = seg.y2 || 0;
|
||||
|
||||
var type = seg.pathSegType;
|
||||
var letter = pathMap[type]['to'+(toRel?'Lower':'Upper')+'Case']();
|
||||
|
||||
var addToD = function(pnts, more, last) {
|
||||
var str = '';
|
||||
more = more ? ' ' + more.join(' ') : '';
|
||||
last = last ? ' ' + svgedit.units.shortFloat(last) : '';
|
||||
$.each(pnts, function(i, pnt) {
|
||||
pnts[i] = svgedit.units.shortFloat(pnt);
|
||||
});
|
||||
d += letter + pnts.join(' ') + more + last;
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case 1: // z,Z closepath (Z/z)
|
||||
d += 'z';
|
||||
break;
|
||||
case 12: // absolute horizontal line (H)
|
||||
x -= curx;
|
||||
case 13: // relative horizontal line (h)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
letter = 'l';
|
||||
} else {
|
||||
x += curx;
|
||||
curx = x;
|
||||
letter = 'L';
|
||||
}
|
||||
// Convert to "line" for easier editing
|
||||
addToD([[x, cury]]);
|
||||
break;
|
||||
case 14: // absolute vertical line (V)
|
||||
y -= cury;
|
||||
case 15: // relative vertical line (v)
|
||||
if (toRel) {
|
||||
cury += y;
|
||||
letter = 'l';
|
||||
} else {
|
||||
y += cury;
|
||||
cury = y;
|
||||
letter = 'L';
|
||||
}
|
||||
// Convert to "line" for easier editing
|
||||
addToD([[curx, y]]);
|
||||
break;
|
||||
case 2: // absolute move (M)
|
||||
case 4: // absolute line (L)
|
||||
case 18: // absolute smooth quad (T)
|
||||
x -= curx;
|
||||
y -= cury;
|
||||
case 5: // relative line (l)
|
||||
case 3: // relative move (m)
|
||||
// If the last segment was a "z", this must be relative to
|
||||
if (last_m && segList.getItem(i-1).pathSegType === 1 && !toRel) {
|
||||
curx = last_m[0];
|
||||
cury = last_m[1];
|
||||
}
|
||||
|
||||
case 19: // relative smooth quad (t)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx;
|
||||
y += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
if (type === 3) {last_m = [curx, cury];}
|
||||
|
||||
addToD([[x, y]]);
|
||||
break;
|
||||
case 6: // absolute cubic (C)
|
||||
x -= curx; x1 -= curx; x2 -= curx;
|
||||
y -= cury; y1 -= cury; y2 -= cury;
|
||||
case 7: // relative cubic (c)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx; x1 += curx; x2 += curx;
|
||||
y += cury; y1 += cury; y2 += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
addToD([[x1, y1], [x2, y2], [x, y]]);
|
||||
break;
|
||||
case 8: // absolute quad (Q)
|
||||
x -= curx; x1 -= curx;
|
||||
y -= cury; y1 -= cury;
|
||||
case 9: // relative quad (q)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx; x1 += curx;
|
||||
y += cury; y1 += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
addToD([[x1, y1],[x, y]]);
|
||||
break;
|
||||
case 10: // absolute elliptical arc (A)
|
||||
x -= curx;
|
||||
y -= cury;
|
||||
case 11: // relative elliptical arc (a)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx;
|
||||
y += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
addToD([[seg.r1, seg.r2]], [
|
||||
seg.angle,
|
||||
(seg.largeArcFlag ? 1 : 0),
|
||||
(seg.sweepFlag ? 1 : 0)
|
||||
], [x, y]
|
||||
);
|
||||
break;
|
||||
case 16: // absolute smooth cubic (S)
|
||||
x -= curx; x2 -= curx;
|
||||
y -= cury; y2 -= cury;
|
||||
case 17: // relative smooth cubic (s)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx; x2 += curx;
|
||||
y += cury; y2 += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
addToD([[x2, y2],[x, y]]);
|
||||
break;
|
||||
} // switch on path segment type
|
||||
} // for each segment
|
||||
return d;
|
||||
}
|
||||
convertPath: svgedit.utilities.convertPath
|
||||
};
|
||||
}();
|
||||
// end pathActions
|
||||
|
@ -4676,7 +4466,7 @@ this.setSvgString = function(xmlString) {
|
|||
// change image href vals if possible
|
||||
content.find('image').each(function() {
|
||||
var image = this;
|
||||
preventClickDefault(image);
|
||||
svgedit.utilities.preventClickDefault(image);
|
||||
var val = getHref(this);
|
||||
if (val) {
|
||||
if (val.indexOf('data:') === 0) {
|
||||
|
@ -4966,44 +4756,25 @@ var identifyLayers = canvas.identifyLayers = function() {
|
|||
//
|
||||
// Parameters:
|
||||
// name - The given name
|
||||
this.createLayer = function(name) {
|
||||
var batchCmd = new svgedit.history.BatchCommand('Create Layer');
|
||||
var new_layer = getCurrentDrawing().createLayer(name);
|
||||
batchCmd.addSubCommand(new svgedit.history.InsertElementCommand(new_layer));
|
||||
addCommandToHistory(batchCmd);
|
||||
this.createLayer = function(name, hrService) {
|
||||
var new_layer = getCurrentDrawing().createLayer(name, historyRecordingService(hrService));
|
||||
clearSelection();
|
||||
call('changed', [new_layer]);
|
||||
};
|
||||
|
||||
// Function: cloneLayer
|
||||
// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents
|
||||
// to it, and then clears the selection. This function then calls the 'changed' handler.
|
||||
// This is an undoable action.
|
||||
//
|
||||
// Parameters:
|
||||
// name - The given name
|
||||
this.cloneLayer = function(name) {
|
||||
var batchCmd = new svgedit.history.BatchCommand('Duplicate Layer');
|
||||
var new_layer = svgdoc.createElementNS(NS.SVG, 'g');
|
||||
var layer_title = svgdoc.createElementNS(NS.SVG, 'title');
|
||||
layer_title.textContent = name;
|
||||
new_layer.appendChild(layer_title);
|
||||
var current_layer = getCurrentDrawing().getCurrentLayer();
|
||||
$(current_layer).after(new_layer);
|
||||
var childs = current_layer.childNodes;
|
||||
var i;
|
||||
for (i = 0; i < childs.length; i++) {
|
||||
var ch = childs[i];
|
||||
if (ch.localName == 'title') {continue;}
|
||||
new_layer.appendChild(copyElem(ch));
|
||||
}
|
||||
/**
|
||||
* Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents
|
||||
* to it, and then clears the selection. This function then calls the 'changed' handler.
|
||||
* This is an undoable action.
|
||||
* @param {string} name - The given name. If the layer name exists, a new name will be generated.
|
||||
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
|
||||
*/
|
||||
this.cloneLayer = function(name, hrService) {
|
||||
// Clone the current layer and make the cloned layer the new current layer
|
||||
var new_layer = getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService));
|
||||
|
||||
clearSelection();
|
||||
identifyLayers();
|
||||
|
||||
batchCmd.addSubCommand(new svgedit.history.InsertElementCommand(new_layer));
|
||||
addCommandToHistory(batchCmd);
|
||||
canvas.setCurrentLayer(name);
|
||||
leaveContext();
|
||||
call('changed', [new_layer]);
|
||||
};
|
||||
|
||||
|
@ -5058,11 +4829,8 @@ this.renameCurrentLayer = function(newname) {
|
|||
var drawing = getCurrentDrawing();
|
||||
var layer = drawing.getCurrentLayer();
|
||||
if (layer) {
|
||||
var result = drawing.setCurrentLayerName( newname);
|
||||
var result = drawing.setCurrentLayerName(newname, historyRecordingService());
|
||||
if (result) {
|
||||
var batchCmd = new svgedit.history.BatchCommand('Rename Layer');
|
||||
batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(result.title, {'#text':result.previousName}));
|
||||
addCommandToHistory(batchCmd);
|
||||
call('changed', [layer]);
|
||||
return true;
|
||||
}
|
||||
|
@ -5158,20 +4926,14 @@ this.moveSelectedToLayer = function(layername) {
|
|||
|
||||
|
||||
this.mergeLayer = function(hrService) {
|
||||
if (!hrService) {
|
||||
hrService = new svgedit.history.HistoryRecordingService(this.undoMgr);
|
||||
}
|
||||
getCurrentDrawing().mergeLayer(hrService);
|
||||
getCurrentDrawing().mergeLayer(historyRecordingService(hrService));
|
||||
clearSelection();
|
||||
leaveContext();
|
||||
call('changed', [svgcontent]);
|
||||
};
|
||||
|
||||
this.mergeAllLayers = function(hrService) {
|
||||
if (!hrService) {
|
||||
hrService = new svgedit.history.HistoryRecordingService(this.undoMgr);
|
||||
}
|
||||
getCurrentDrawing().mergeAllLayers(hrService);
|
||||
getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService));
|
||||
clearSelection();
|
||||
leaveContext();
|
||||
call('changed', [svgcontent]);
|
||||
|
@ -6622,19 +6384,19 @@ this.pasteElements = function(type, x, y) {
|
|||
|
||||
var pasted = [];
|
||||
var batchCmd = new svgedit.history.BatchCommand('Paste elements');
|
||||
var drawing = getCurrentDrawing();
|
||||
|
||||
// Move elements to lastClickPoint
|
||||
|
||||
while (len--) {
|
||||
var elem = cb[len];
|
||||
if (!elem) {continue;}
|
||||
var copy = copyElem(elem);
|
||||
var copy = drawing.copyElem(elem);
|
||||
|
||||
// See if elem with elem ID is in the DOM already
|
||||
if (!svgedit.utilities.getElem(elem.id)) {copy.id = elem.id;}
|
||||
|
||||
pasted.push(copy);
|
||||
(current_group || getCurrentDrawing().getCurrentLayer()).appendChild(copy);
|
||||
(current_group || drawing.getCurrentLayer()).appendChild(copy);
|
||||
batchCmd.addSubCommand(new svgedit.history.InsertElementCommand(copy));
|
||||
|
||||
restoreRefElems(copy);
|
||||
|
@ -6758,6 +6520,7 @@ var pushGroupProperties = this.pushGroupProperties = function(g, undoable) {
|
|||
|
||||
var gattrs = $(g).attr(['filter', 'opacity']);
|
||||
var gfilter, gblur, changes;
|
||||
var drawing = getCurrentDrawing();
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
var elem = children[i];
|
||||
|
@ -6788,7 +6551,7 @@ var pushGroupProperties = this.pushGroupProperties = function(g, undoable) {
|
|||
gfilter = svgedit.utilities.getRefElem(gattrs.filter);
|
||||
} else {
|
||||
// Clone the group's filter
|
||||
gfilter = copyElem(gfilter);
|
||||
gfilter = drawing.copyElem(gfilter);
|
||||
svgedit.utilities.findDefs().appendChild(gfilter);
|
||||
}
|
||||
} else {
|
||||
|
@ -7167,11 +6930,12 @@ this.cloneSelectedElements = function(x, y) {
|
|||
this.clearSelection(true);
|
||||
// note that we loop in the reverse way because of the way elements are added
|
||||
// to the selectedElements array (top-first)
|
||||
var drawing = getCurrentDrawing();
|
||||
i = copiedElements.length;
|
||||
while (i--) {
|
||||
// clone each element and replace it within copiedElements
|
||||
elem = copiedElements[i] = copyElem(copiedElements[i]);
|
||||
(current_group || getCurrentDrawing().getCurrentLayer()).appendChild(elem);
|
||||
elem = copiedElements[i] = drawing.copyElem(copiedElements[i]);
|
||||
(current_group || drawing.getCurrentLayer()).appendChild(elem);
|
||||
batchCmd.addSubCommand(new svgedit.history.InsertElementCommand(elem));
|
||||
}
|
||||
|
||||
|
@ -7410,7 +7174,7 @@ this.getPrivateMethods = function() {
|
|||
BatchCommand: BatchCommand,
|
||||
call: call,
|
||||
ChangeElementCommand: ChangeElementCommand,
|
||||
copyElem: copyElem,
|
||||
copyElem: function(elem) {return getCurrentDrawing().copyElem(elem)},
|
||||
ffClone: ffClone,
|
||||
findDefs: findDefs,
|
||||
findDuplicateGradient: findDuplicateGradient,
|
||||
|
@ -7428,7 +7192,7 @@ this.getPrivateMethods = function() {
|
|||
logMatrix: logMatrix,
|
||||
matrixMultiply: matrixMultiply,
|
||||
MoveElementCommand: MoveElementCommand,
|
||||
preventClickDefault: preventClickDefault,
|
||||
preventClickDefault: svgedit.utilities.preventClickDefault,
|
||||
recalculateAllSelectedDimensions: recalculateAllSelectedDimensions,
|
||||
recalculateDimensions: recalculateDimensions,
|
||||
remapElement: remapElement,
|
||||
|
|
|
@ -1137,4 +1137,250 @@ svgedit.utilities.buildJSPDFCallback = function (callJSPDF) {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Prevents default browser click behaviour on the given element
|
||||
* @param img - The DOM element to prevent the click on
|
||||
*/
|
||||
svgedit.utilities.preventClickDefault = function(img) {
|
||||
$(img).click(function(e){e.preventDefault();});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of an element, updating its ID and its children's IDs when needed
|
||||
* @param {Element} el - DOM element to clone
|
||||
* @param {function()} getNextId - function the get the next unique ID.
|
||||
* @returns {Element}
|
||||
*/
|
||||
svgedit.utilities.copyElem = function(el, getNextId) {
|
||||
// manually create a copy of the element
|
||||
var new_el = document.createElementNS(el.namespaceURI, el.nodeName);
|
||||
$.each(el.attributes, function(i, attr) {
|
||||
if (attr.localName != '-moz-math-font-style') {
|
||||
new_el.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value);
|
||||
}
|
||||
});
|
||||
// set the copied element's new id
|
||||
new_el.removeAttribute('id');
|
||||
new_el.id = getNextId();
|
||||
|
||||
// Opera's "d" value needs to be reset for Opera/Win/non-EN
|
||||
// Also needed for webkit (else does not keep curved segments on clone)
|
||||
if (svgedit.browser.isWebkit() && el.nodeName == 'path') {
|
||||
var fixed_d = svgedit.utilities.convertPath(el);
|
||||
new_el.setAttribute('d', fixed_d);
|
||||
}
|
||||
|
||||
// now create copies of all children
|
||||
$.each(el.childNodes, function(i, child) {
|
||||
switch(child.nodeType) {
|
||||
case 1: // element node
|
||||
new_el.appendChild(svgedit.utilities.copyElem(child, getNextId));
|
||||
break;
|
||||
case 3: // text node
|
||||
new_el.textContent = child.nodeValue;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
if ($(el).data('gsvg')) {
|
||||
$(new_el).data('gsvg', new_el.firstChild);
|
||||
} else if ($(el).data('symbol')) {
|
||||
var ref = $(el).data('symbol');
|
||||
$(new_el).data('ref', ref).data('symbol', ref);
|
||||
} else if (new_el.tagName == 'image') {
|
||||
preventClickDefault(new_el);
|
||||
}
|
||||
return new_el;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* TODO: refactor callers in convertPath to use getPathDFromSegments instead of this function.
|
||||
* Legacy code refactored from svgcanvas.pathActions.convertPath
|
||||
* @param letter - path segment command
|
||||
* @param {Array.<Array.<number>>} points - x,y points.
|
||||
* @param {Array.<Array.<number>>=} morePoints - x,y points
|
||||
* @param {Array.<number>=}lastPoint - x,y point
|
||||
* @returns {string}
|
||||
*/
|
||||
function pathDSegment(letter, points, morePoints, lastPoint) {
|
||||
$.each(points, function(i, pnt) {
|
||||
points[i] = svgedit.units.shortFloat(pnt);
|
||||
});
|
||||
var segment = letter + points.join(' ');
|
||||
if (morePoints) {
|
||||
segment += ' ' + morePoints.join(' ');
|
||||
}
|
||||
if (lastPoint) {
|
||||
segment += ' ' + svgedit.units.shortFloat(lastPoint);
|
||||
}
|
||||
return segment;
|
||||
}
|
||||
|
||||
// this is how we map paths to our preferred relative segment types
|
||||
var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
|
||||
'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
|
||||
|
||||
|
||||
/**
|
||||
* TODO: move to pathActions.js when migrating rest of pathActions out of svgcanvas.js
|
||||
* Convert a path to one with only absolute or relative values
|
||||
* @param {Object} path - the path to convert
|
||||
* @param {boolean} toRel - true of convert to relative
|
||||
* @returns {string}
|
||||
*/
|
||||
svgedit.utilities.convertPath = function(path, toRel) {
|
||||
var i;
|
||||
var segList = path.pathSegList;
|
||||
var len = segList.numberOfItems;
|
||||
var curx = 0, cury = 0;
|
||||
var d = '';
|
||||
var last_m = null;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
var seg = segList.getItem(i);
|
||||
// if these properties are not in the segment, set them to zero
|
||||
var x = seg.x || 0,
|
||||
y = seg.y || 0,
|
||||
x1 = seg.x1 || 0,
|
||||
y1 = seg.y1 || 0,
|
||||
x2 = seg.x2 || 0,
|
||||
y2 = seg.y2 || 0;
|
||||
|
||||
var type = seg.pathSegType;
|
||||
var letter = pathMap[type]['to'+(toRel?'Lower':'Upper')+'Case']();
|
||||
|
||||
switch (type) {
|
||||
case 1: // z,Z closepath (Z/z)
|
||||
d += 'z';
|
||||
break;
|
||||
case 12: // absolute horizontal line (H)
|
||||
x -= curx;
|
||||
case 13: // relative horizontal line (h)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
letter = 'l';
|
||||
} else {
|
||||
x += curx;
|
||||
curx = x;
|
||||
letter = 'L';
|
||||
}
|
||||
// Convert to "line" for easier editing
|
||||
d += pathDSegment(letter,[[x, cury]]);
|
||||
break;
|
||||
case 14: // absolute vertical line (V)
|
||||
y -= cury;
|
||||
case 15: // relative vertical line (v)
|
||||
if (toRel) {
|
||||
cury += y;
|
||||
letter = 'l';
|
||||
} else {
|
||||
y += cury;
|
||||
cury = y;
|
||||
letter = 'L';
|
||||
}
|
||||
// Convert to "line" for easier editing
|
||||
d += pathDSegment(letter,[[curx, y]]);
|
||||
break;
|
||||
case 2: // absolute move (M)
|
||||
case 4: // absolute line (L)
|
||||
case 18: // absolute smooth quad (T)
|
||||
x -= curx;
|
||||
y -= cury;
|
||||
case 5: // relative line (l)
|
||||
case 3: // relative move (m)
|
||||
// If the last segment was a "z", this must be relative to
|
||||
if (last_m && segList.getItem(i-1).pathSegType === 1 && !toRel) {
|
||||
curx = last_m[0];
|
||||
cury = last_m[1];
|
||||
}
|
||||
|
||||
case 19: // relative smooth quad (t)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx;
|
||||
y += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
if (type === 3) {last_m = [curx, cury];}
|
||||
|
||||
d += pathDSegment(letter,[[x, y]]);
|
||||
break;
|
||||
case 6: // absolute cubic (C)
|
||||
x -= curx; x1 -= curx; x2 -= curx;
|
||||
y -= cury; y1 -= cury; y2 -= cury;
|
||||
case 7: // relative cubic (c)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx; x1 += curx; x2 += curx;
|
||||
y += cury; y1 += cury; y2 += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
d += pathDSegment(letter,[[x1, y1], [x2, y2], [x, y]]);
|
||||
break;
|
||||
case 8: // absolute quad (Q)
|
||||
x -= curx; x1 -= curx;
|
||||
y -= cury; y1 -= cury;
|
||||
case 9: // relative quad (q)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx; x1 += curx;
|
||||
y += cury; y1 += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
d += pathDSegment(letter,[[x1, y1],[x, y]]);
|
||||
break;
|
||||
case 10: // absolute elliptical arc (A)
|
||||
x -= curx;
|
||||
y -= cury;
|
||||
case 11: // relative elliptical arc (a)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx;
|
||||
y += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
d += pathDSegment(letter,[[seg.r1, seg.r2]], [
|
||||
seg.angle,
|
||||
(seg.largeArcFlag ? 1 : 0),
|
||||
(seg.sweepFlag ? 1 : 0)
|
||||
], [x, y]
|
||||
);
|
||||
break;
|
||||
case 16: // absolute smooth cubic (S)
|
||||
x -= curx; x2 -= curx;
|
||||
y -= cury; y2 -= cury;
|
||||
case 17: // relative smooth cubic (s)
|
||||
if (toRel) {
|
||||
curx += x;
|
||||
cury += y;
|
||||
} else {
|
||||
x += curx; x2 += curx;
|
||||
y += cury; y2 += cury;
|
||||
curx = x;
|
||||
cury = y;
|
||||
}
|
||||
d += pathDSegment(letter,[[x2, y2],[x, y]]);
|
||||
break;
|
||||
} // switch on path segment type
|
||||
} // for each segment
|
||||
return d;
|
||||
};
|
||||
|
||||
|
||||
}());
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -376,18 +440,55 @@
|
|||
equals(typeof drawing.setCurrentLayer, typeof function(){});
|
||||
|
||||
drawing.setCurrentLayer(LAYER2);
|
||||
equals(drawing.getCurrentLayerName(LAYER2), LAYER2);
|
||||
equals(drawing.getCurrentLayerName(), LAYER2);
|
||||
equals(drawing.getCurrentLayer(), drawing.all_layers[1].getGroup());
|
||||
|
||||
drawing.setCurrentLayer(LAYER3);
|
||||
equals(drawing.getCurrentLayerName(LAYER3), LAYER3);
|
||||
equals(drawing.getCurrentLayerName(), LAYER3);
|
||||
equals(drawing.getCurrentLayer(), drawing.all_layers[2].getGroup());
|
||||
|
||||
cleanupSvg(svg);
|
||||
});
|
||||
|
||||
test('Test setCurrentLayerName()', function() {
|
||||
|
||||
var mockHrService = {
|
||||
changeElement: this.spy()
|
||||
};
|
||||
|
||||
var drawing = new svgedit.draw.Drawing(svg);
|
||||
setupSvgWith3Layers(svg);
|
||||
drawing.identifyLayers();
|
||||
|
||||
ok(drawing.setCurrentLayerName);
|
||||
equals(typeof drawing.setCurrentLayerName, typeof function(){});
|
||||
|
||||
var oldName = drawing.getCurrentLayerName();
|
||||
var newName = 'New Name'
|
||||
ok(drawing.layer_map[oldName]);
|
||||
equals(drawing.layer_map[newName], undefined); // newName shouldn't exist.
|
||||
var result = drawing.setCurrentLayerName(newName, mockHrService);
|
||||
equals(result, newName);
|
||||
equals(drawing.getCurrentLayerName(), newName);
|
||||
// Was the map updated?
|
||||
equals(drawing.layer_map[oldName], undefined);
|
||||
equals(drawing.layer_map[newName], drawing.current_layer);
|
||||
// Was mockHrService called?
|
||||
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);
|
||||
|
@ -397,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);
|
||||
});
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* sinon-qunit 1.0.0, 2010/12/09
|
||||
*
|
||||
* @author Christian Johansen (christian@cjohansen.no)
|
||||
*
|
||||
* (The BSD License)
|
||||
*
|
||||
* Copyright (c) 2010-2011, Christian Johansen, christian@cjohansen.no
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* * Neither the name of Christian Johansen nor the names of his contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*global sinon, QUnit, test*/
|
||||
sinon.assert.fail = function (msg) {
|
||||
QUnit.ok(false, msg);
|
||||
};
|
||||
|
||||
sinon.assert.pass = function (assertion) {
|
||||
QUnit.ok(true, assertion);
|
||||
};
|
||||
|
||||
sinon.config = {
|
||||
injectIntoThis: true,
|
||||
injectInto: null,
|
||||
properties: ["spy", "stub", "mock", "clock", "sandbox"],
|
||||
useFakeTimers: true,
|
||||
useFakeServer: false
|
||||
};
|
||||
|
||||
(function (global) {
|
||||
var qTest = QUnit.test;
|
||||
|
||||
QUnit.test = global.test = function (testName, expected, callback, async) {
|
||||
if (arguments.length === 2) {
|
||||
callback = expected;
|
||||
expected = null;
|
||||
}
|
||||
|
||||
return qTest(testName, expected, sinon.test(callback), async);
|
||||
};
|
||||
}(this));
|
Loading…
Reference in New Issue