Update SVG-Edit

This commit is contained in:
Jacques Distler 2011-02-03 11:13:18 -06:00
parent a12a778c5a
commit 1bef71bbf1
9 changed files with 277 additions and 192 deletions

View file

@ -85,6 +85,17 @@ var supportsTextCharPos_ = (function() {
return retValue;
})();
var supportsPathBBox_ = (function() {
var svgcontent = document.createElementNS(svgns, 'svg');
document.documentElement.appendChild(svgcontent);
var path = document.createElementNS(svgns, 'path');
path.setAttribute('d','M0,0 C0,0 10,10 10,0');
svgcontent.appendChild(path);
var bbox = path.getBBox();
document.documentElement.removeChild(svgcontent);
return (bbox.height > 4 && bbox.height < 5);
})();
var supportsEditableText_ = (function() {
// TODO: Find better way to check support for this
return isOpera_;
@ -129,6 +140,7 @@ svgedit.browser.supportsXpath = function() { return supportsXpath_; }
svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; }
svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; }
svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; }
svgedit.browser.supportsTextCharPos = function() { return supportsTextCharPos_; }
svgedit.browser.supportsEditableText = function() { return supportsEditableText_; }
svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; }

View file

@ -23,6 +23,13 @@ var svg_ns = "http://www.w3.org/2000/svg";
var se_ns = "http://svg-edit.googlecode.com";
var xmlns_ns = "http://www.w3.org/2000/xmlns/";
var RandomizeModes = {
LET_DOCUMENT_DECIDE: 0,
ALWAYS_RANDOMIZE: 1,
NEVER_RANDOMIZE: 2
};
var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE;
/**
* This class encapsulates the concept of a layer in the drawing
* @param name {String} Layer name
@ -42,6 +49,23 @@ svgedit.draw.Layer.prototype.getGroup = function() {
};
// Called to ensure that drawings will or will not have randomized ids.
// The current_drawing will have its nonce set if it doesn't already.
//
// Params:
// enableRandomization - flag indicating if documents should have randomized ids
svgedit.draw.randomizeIds = function(enableRandomization, current_drawing) {
randomize_ids = enableRandomization == false ?
RandomizeModes.NEVER_RANDOMIZE :
RandomizeModes.ALWAYS_RANDOMIZE;
if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !current_drawing.getNonce()) {
current_drawing.setNonce(Math.floor(Math.random() * 100001));
} else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && current_drawing.getNonce()) {
current_drawing.clearNonce();
}
};
/**
* This class encapsulates the concept of a SVG-edit drawing
*
@ -100,7 +124,15 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
* The nonce to use to uniquely identify elements across drawings.
* @type {!String}
*/
this.nonce_ = this.svgElem_.getAttributeNS(se_ns, 'nonce') || "";
this.nonce_ = "";
var n = this.svgElem_.getAttributeNS(se_ns, 'nonce');
// If already set in the DOM, use the nonce throughout the document
// else, if randomizeIds(true) has been called, create and set the nonce.
if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) {
this.nonce_ = n;
} else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) {
this.setNonce(Math.floor(Math.random() * 100001));
}
};
svgedit.draw.Drawing.prototype.getElem_ = function(id) {
@ -121,10 +153,16 @@ svgedit.draw.Drawing.prototype.getNonce = function() {
return this.nonce_;
};
svgedit.draw.Drawing.prototype.setNonce = function(nonce) {
this.nonce_ = nonce;
svgedit.draw.Drawing.prototype.setNonce = function(n) {
this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns);
this.svgElem_.setAttributeNS(se_ns, 'se:nonce', nonce);
this.svgElem_.setAttributeNS(se_ns, 'se:nonce', n);
this.nonce_ = n;
};
svgedit.draw.Drawing.prototype.clearNonce = function() {
// We deliberately leave any se:nonce attributes alone,
// we just don't use it to randomize ids.
this.nonce_ = "";
};
/**

View file

@ -15,8 +15,8 @@ svgEditor.addExtension("Arrows", function(S) {
randomize_ids = S.randomize_ids,
selElems;
svgCanvas.bind('setarrownonce', setArrowNonce);
svgCanvas.bind('unsetsetarrownonce', unsetArrowNonce);
svgCanvas.bind('setnonce', setArrowNonce);
svgCanvas.bind('unsetnonce', unsetArrowNonce);
var lang_list = {
"en":[

View file

@ -36,13 +36,23 @@ var removedElements = {};
* An interface that all command objects must implement.
*
* interface svgedit.history.HistoryCommand {
* void apply();
* void unapply();
* void apply(svgedit.history.HistoryEventHandler);
* void unapply(svgedit.history.HistoryEventHandler);
* Element[] elements();
* String getText();
*
* static String type();
* }
*
* Interface: svgedit.history.HistoryEventHandler
* An interface for objects that will handle history events.
*
* interface svgedit.history.HistoryEventHandler {
* void handleHistoryEvent(eventType, command);
* }
*
* eventType is a string conforming to one of the HistoryEvent types.
* command is an object fulfilling the HistoryCommand interface.
*/
// Class: svgedit.history.MoveElementCommand
@ -213,8 +223,12 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
}
svgedit.transformlist.removeElementFromListMap(this.elem);
if(this.nextSibling == null) {
console.log('Error: reference element was lost');
}
this.parent.insertBefore(this.elem, this.nextSibling);
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
}
@ -443,18 +457,6 @@ svgedit.history.BatchCommand.prototype.isEmpty = function() {
};
/**
* Interface: svgedit.history.HistoryEventHandler
* An interface for objects that will handle history events.
*
* interface svgedit.history.HistoryEventHandler {
* void handleHistoryEvent(eventType, command);
* }
*
* eventType is a string conforming to one of the HistoryEvent types (see above).
* command is an object fulfilling the HistoryCommand interface (see above).
*/
// Class: svgedit.history.UndoManager
// Parameters:
// historyEventHandler - an object that conforms to the HistoryEventHandler interface

View file

@ -532,7 +532,7 @@
position: absolute;
top: 77px;
left: 40px;
right: -2px;
right: 0;
line-height: 22px;
overflow: auto;
border: 1px solid #777;

View file

@ -1535,8 +1535,8 @@
}
if(unit) {
x = svgCanvas.convertUnit(x);
y = svgCanvas.convertUnit(y);
x = svgedit.units.convertUnit(x);
y = svgedit.units.convertUnit(y);
}
$('#selected_x').val(x || 0);
@ -1560,8 +1560,8 @@
if(point) {
var seg_type = $('#seg_type');
if(unit) {
point.x = svgCanvas.convertUnit(point.x);
point.y = svgCanvas.convertUnit(point.y);
point.x = svgedit.units.convertUnit(point.x);
point.y = svgedit.units.convertUnit(point.y);
}
$('#path_node_x').val(point.x);
$('#path_node_y').val(point.y);
@ -1622,7 +1622,7 @@
var attrVal = elem.getAttribute(item);
if(curConfig.baseUnit !== 'px' && elem[item]) {
var bv = elem[item].baseVal.value;
attrVal = svgCanvas.convertUnit(bv);
attrVal = svgedit.units.convertUnit(bv);
}
$('#' + el_name + '_' + item).val(attrVal || 0);
@ -2734,8 +2734,8 @@
// update resolution option with actual resolution
var res = svgCanvas.getResolution();
if(curConfig.baseUnit !== "px") {
res.w = svgCanvas.convertUnit(res.w) + curConfig.baseUnit;
res.h = svgCanvas.convertUnit(res.h) + curConfig.baseUnit;
res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit;
res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit;
}
$('#canvas_width').val(res.w);
@ -4583,7 +4583,7 @@
updateCanvas(true);
// });
// var revnums = "svg-editor.js ($Rev: 1956 $) ";
// var revnums = "svg-editor.js ($Rev: 1973 $) ";
// revnums += svgCanvas.getVersion();
// $('#copyright')[0].setAttribute("title", revnums);
@ -4721,6 +4721,13 @@
});
};
Editor.disableUI = function(featList) {
// $(function() {
// $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove();
// $('#tools_top').css('left', 5);
// });
};
Editor.loadFromURL = function(url, opts) {
if(!opts) opts = {};

View file

@ -151,17 +151,29 @@ container.appendChild(svgroot);
// The actual element that represents the final output SVG element
var svgcontent = svgdoc.createElementNS(svgns, "svg");
$(svgcontent).attr({
id: 'svgcontent',
width: dimensions[0],
height: dimensions[1],
x: dimensions[0],
y: dimensions[1],
overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden',
xmlns: svgns,
"xmlns:se": se_ns,
"xmlns:xlink": xlinkns
}).appendTo(svgroot);
// This function resets the svgcontent element while keeping it in the DOM.
var clearSvgContentElement = canvas.clearSvgContentElement = function() {
while (svgcontent.firstChild) { svgcontent.removeChild(svgcontent.firstChild); }
// TODO: Clear out all other attributes first?
$(svgcontent).attr({
id: 'svgcontent',
width: dimensions[0],
height: dimensions[1],
x: dimensions[0],
y: dimensions[1],
overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden',
xmlns: svgns,
"xmlns:se": se_ns,
"xmlns:xlink": xlinkns
}).appendTo(svgroot);
// TODO: make this string optional and set by the client
var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");
// Lead to invalid content with Instiki's Sanitizer
// svgcontent.appendChild(comment);
};
clearSvgContentElement();
// Prefix string for element IDs
var idprefix = "svg_";
@ -177,27 +189,15 @@ canvas.setIdPrefix = function(p) {
// Current svgedit.draw.Drawing object
// @type {svgedit.draw.Drawing}
var current_drawing = new svgedit.draw.Drawing(svgcontent, idprefix);
canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix);
// Function: getCurrentDrawing
// Returns the current Drawing.
// @return {svgedit.draw.Drawing}
var getCurrentDrawing = canvas.getCurrentDrawing = function() {
return current_drawing;
return canvas.current_drawing_;
};
// nonce to uniquify id's
var nonce = Math.floor(Math.random() * 100001);
// Boolean to indicate whether or not IDs given to elements should be random
var randomize_ids = false;
// Set nonce if randomize_ids = true
// TODO: Remove this? Given randomize_ids is set to false above, it seems useless.
if (randomize_ids) {
getCurrentDrawing().setNonce(nonce);
}
// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc)
var current_zoom = 1;
@ -386,7 +386,8 @@ svgedit.units.init({
getBaseUnit: function() { return curConfig.baseUnit; },
getElement: getElem,
getHeight: function() { return svgcontent.getAttribute("height")/current_zoom; },
getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; }
getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; },
getRoundDigits: function() { return save_options.round_digits; }
});
// import from units.js
var convertToNum = canvas.convertToNum = svgedit.units.convertToNum;
@ -426,7 +427,7 @@ canvas.undoMgr = new svgedit.history.UndoManager({
call("changed", elems);
var cmdType = cmd.type();
var isApply = eventType == EventTypes.AFTER_APPLY;
var isApply = (eventType == EventTypes.AFTER_APPLY);
if (cmdType == MoveElementCommand.type()) {
var parent = isApply ? cmd.newParent : cmd.oldParent;
if (parent == svgcontent) {
@ -442,6 +443,10 @@ canvas.undoMgr = new svgedit.history.UndoManager({
} else {
if (!isApply) restoreRefElems(cmd.elem);
}
if(cmd.elem.tagName === 'use') {
setUseData(cmd.elem);
}
} else if (cmdType == ChangeElementCommand.type()) {
// if we are changing layer names, re-identify all layers
if (cmd.elem.tagName == "title" && cmd.elem.parentNode.parentNode == svgcontent) {
@ -524,14 +529,17 @@ var restoreRefElems = function(elem) {
}
}
}
var childs = elem.getElementsByTagName('*');
if(childs.length) {
for(var i = 0, l = childs.length; i < l; i++) {
restoreRefElems(childs[i]);
}
}
};
(function() {
// TODO: make this string optional and set by the client
var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");
// Lead to invalid content with Instiki's Sanitizer
// svgcontent.appendChild(comment);
// TODO For Issue 208: this is a start on a thumbnail
// var svgthumb = svgdoc.createElementNS(svgns, "use");
// svgthumb.setAttribute('width', '100');
@ -628,7 +636,7 @@ this.addExtension = function(name, ext_func) {
var ext = ext_func($.extend(canvas.getPrivateMethods(), {
svgroot: svgroot,
svgcontent: svgcontent,
nonce: nonce,
nonce: getCurrentDrawing().getNonce(),
selectorManager: selectorManager
}));
} else {
@ -641,32 +649,6 @@ this.addExtension = function(name, ext_func) {
}
};
// Function: shortFloat
// Rounds a given value to a float with number of digits defined in save_options
//
// Parameters:
// val - The value as a String, Number or Array of two numbers to be rounded
//
// Returns:
// If a string/number was given, returns a Float. If an array, return a string
// with comma-seperated floats
var shortFloat = function(val) {
var digits = save_options.round_digits;
if(!isNaN(val)) {
// Note that + converts to Number
return +((+val).toFixed(digits));
} else if($.isArray(val)) {
return shortFloat(val[0]) + ',' + shortFloat(val[1]);
} else {
return parseFloat(val).toFixed(digits) - 0;
}
}
this.convertUnit = function(val, unit) {
return shortFloat(svgedit.units.convertUnit(val, unit));
};
// This method rounds the incoming value to the nearest value based on the current_zoom
var round = this.round = function(val) {
return parseInt(val*current_zoom)/current_zoom;
@ -1547,6 +1529,23 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
}
}
// If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned).
switch ( selected.tagName ) {
// Ignore these elements, as they can absorb the [M]
case 'line':
case 'polyline':
case 'polygon':
case 'path':
break;
default:
if(
(tlist.numberOfItems === 1 && tlist.getItem(0).type === 1)
|| (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4)
) {
return null;
}
}
// Grouped SVG element
var gsvg = $(selected).data('gsvg');
@ -2184,6 +2183,7 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) {
if (tlist.numberOfItems == 0) {
selected.removeAttribute("transform");
}
batchCmd.addSubCommand(new ChangeElementCommand(selected, initial));
return batchCmd;
@ -5832,9 +5832,9 @@ var pathActions = canvas.pathActions = function() {
var addToD = function(pnts, more, last) {
var str = '';
var more = more?' '+more.join(' '):'';
var last = last?' '+shortFloat(last):'';
var last = last?' '+svgedit.units.shortFloat(last):'';
$.each(pnts, function(i, pnt) {
pnts[i] = shortFloat(pnt);
pnts[i] = svgedit.units.shortFloat(pnt);
});
d += letter + pnts.join(' ') + more + last;
}
@ -5984,6 +5984,8 @@ var removeUnusedDefElems = this.removeUnusedDefElems = function() {
var defs = svgcontent.getElementsByTagNameNS(svgns, "defs");
if(!defs || !defs.length) return 0;
// if(!defs.firstChild) return;
var defelem_uses = [],
numRemoved = 0;
var attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end'];
@ -5996,7 +5998,9 @@ var removeUnusedDefElems = this.removeUnusedDefElems = function() {
var el = all_els[i];
for(var j = 0; j < alen; j++) {
var ref = getUrlFromAttr(el.getAttribute(attrs[j]));
if(ref) defelem_uses.push(ref.substr(1));
if(ref) {
defelem_uses.push(ref.substr(1));
}
}
// gradients can refer to other gradients
@ -6020,15 +6024,6 @@ var removeUnusedDefElems = this.removeUnusedDefElems = function() {
}
}
// Remove defs if empty
var i = defs.length;
while (i--) {
var def = defs[i];
if(!def.getElementsByTagNameNS(svgns,'*').length) {
def.parentNode.removeChild(def);
}
}
return numRemoved;
}
@ -6119,16 +6114,16 @@ this.svgToString = function(elem, indent) {
// if(curConfig.baseUnit !== "px") {
// var unit = curConfig.baseUnit;
// var unit_m = svgedit.units.getTypeMap()[unit];
// res.w = shortFloat(res.w / unit_m)
// res.h = shortFloat(res.h / unit_m)
// res.w = svgedit.units.shortFloat(res.w / unit_m)
// res.h = svgedit.units.shortFloat(res.h / unit_m)
// vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"';
// res.w += unit;
// res.h += unit;
// }
if(unit !== "px") {
res.w = this.convertUnit(res.w, unit) + unit;
res.h = this.convertUnit(res.h, unit) + unit;
res.w = svgedit.units.convertUnit(res.w, unit) + unit;
res.h = svgedit.units.convertUnit(res.h, unit) + unit;
}
out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="'+svgns+'"');
@ -6168,6 +6163,9 @@ this.svgToString = function(elem, indent) {
}
}
} else {
// Skip empty defs
if(elem.nodeName === 'defs' && !elem.firstChild) return;
var moz_attrs = ['-moz-math-font-style', '_moz-math-font-style'];
for (var i=attrs.length-1; i>=0; i--) {
attr = attrs.item(i);
@ -6180,9 +6178,9 @@ this.svgToString = function(elem, indent) {
out.push(" ");
if(attr.localName === 'd') attrVal = pathActions.convertPath(elem, true);
if(!isNaN(attrVal)) {
attrVal = shortFloat(attrVal);
attrVal = svgedit.units.shortFloat(attrVal);
} else if(unit_re.test(attrVal)) {
attrVal = shortFloat(attrVal) + unit;
attrVal = svgedit.units.shortFloat(attrVal) + unit;
}
// Embed images when saving
@ -6350,9 +6348,9 @@ this.getSvgString = function() {
return this.svgCanvasToString();
};
//function randomizeIds
// This function determines whether to add a nonce to the prefix, when
// generating IDs in SVG-Edit
// Function: randomizeIds
// This function determines whether to use a nonce in the prefix, when
// generating IDs for future documents in SVG-Edit.
//
// Parameters:
// an opional boolean, which, if true, adds a nonce to the prefix. Thus
@ -6363,17 +6361,11 @@ this.getSvgString = function() {
//
this.randomizeIds = function() {
if (arguments.length > 0 && arguments[0] == false) {
randomize_ids = false;
if (extensions["Arrows"]) call("unsetarrownonce") ;
svgedit.draw.randomizeIds(false, getCurrentDrawing());
} else {
randomize_ids = true;
var drawing = getCurrentDrawing();
if (!drawing.getSvgElem().getAttributeNS(se_ns, 'nonce')) {
drawing.setNonce(nonce);
if (extensions["Arrows"]) call("setarrownonce", nonce);
}
svgedit.draw.randomizeIds(true, getCurrentDrawing());
}
}
};
// Function: uniquifyElems
// Ensure each element has a unique ID
@ -6472,9 +6464,16 @@ var uniquifyElems = this.uniquifyElems = function(g) {
// Function setUseData
// Assigns reference data for each use element
var setUseData = this.setUseData = function(parent) {
$(parent).find('use').each(function() {
var elems = $(parent);
if(parent.tagName !== 'use') {
elems = elems.find('use');
}
elems.each(function() {
var id = getHref(this).substr(1);
var ref_elem = getElem(id);
if(!ref_elem) return;
$(this).data('ref', ref_elem);
if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') {
$(this).data('symbol', ref_elem);
@ -6669,8 +6668,11 @@ var convertToGroup = this.convertToGroup = function(elem) {
selectOnly([g]);
batchCmd.addSubCommand(pushGroupProperties(g, true));
//
var cm = pushGroupProperties(g, true);
if(cm) {
batchCmd.addSubCommand(cm);
}
addCommandToHistory(batchCmd);
} else {
@ -6706,17 +6708,14 @@ this.setSvgString = function(xmlString) {
var content = $(svgcontent);
current_drawing = new svgedit.draw.Drawing(svgcontent, idprefix);
canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix);
// retrieve or set the nonce
n = svgcontent.getAttributeNS(se_ns, 'nonce');
if (n) {
randomize_ids = true;
nonce = n;
if (extensions["Arrows"]) call("setarrownonce", n) ;
} else if (randomize_ids) {
current_drawing.setNonce(nonce);
if (extensions["Arrows"]) call("setarrownonce", nonce) ;
var nonce = getCurrentDrawing().getNonce();
if (nonce) {
call("setnonce", nonce);
} else {
call("unsetnonce");
}
// change image href vals if possible
@ -7042,10 +7041,10 @@ this.cloneLayer = function(name) {
// Deletes the current layer from the drawing and then clears the selection. This function
// then calls the 'changed' handler. This is an undoable action.
this.deleteCurrentLayer = function() {
var current_layer = current_drawing.getCurrentLayer();
var current_layer = getCurrentDrawing().getCurrentLayer();
var nextSibling = current_layer.nextSibling;
var parent = current_layer.parentNode;
current_layer = current_drawing.deleteCurrentLayer();
current_layer = getCurrentDrawing().deleteCurrentLayer();
if (current_layer) {
var batchCmd = new BatchCommand("Delete Layer");
// store in our Undo History
@ -7086,18 +7085,19 @@ this.setCurrentLayer = function(name) {
// Returns:
// true if the rename succeeded, false otherwise.
this.renameCurrentLayer = function(newname) {
if (current_drawing.current_layer) {
var oldLayer = current_drawing.current_layer;
var drawing = getCurrentDrawing();
if (drawing.current_layer) {
var oldLayer = drawing.current_layer;
// setCurrentLayer will return false if the name doesn't already exist
// this means we are free to rename our oldLayer
if (!canvas.setCurrentLayer(newname)) {
var batchCmd = new BatchCommand("Rename Layer");
// find the index of the layer
for (var i = 0; i < current_drawing.getNumLayers(); ++i) {
if (current_drawing.all_layers[i][1] == oldLayer) break;
for (var i = 0; i < drawing.getNumLayers(); ++i) {
if (drawing.all_layers[i][1] == oldLayer) break;
}
var oldname = current_drawing.getLayerName(i);
current_drawing.all_layers[i][0] = svgedit.utilities.toXml(newname);
var oldname = drawing.getLayerName(i);
drawing.all_layers[i][0] = svgedit.utilities.toXml(newname);
// now change the underlying title element contents
var len = oldLayer.childNodes.length;
@ -7116,7 +7116,7 @@ this.renameCurrentLayer = function(newname) {
}
}
}
current_drawing.current_layer = oldLayer;
drawing.current_layer = oldLayer;
}
return false;
};
@ -7133,31 +7133,32 @@ this.renameCurrentLayer = function(newname) {
// Returns:
// true if the current layer position was changed, false otherwise.
this.setCurrentLayerPosition = function(newpos) {
if (current_drawing.current_layer && newpos >= 0 && newpos < current_drawing.getNumLayers()) {
for (var oldpos = 0; oldpos < current_drawing.getNumLayers(); ++oldpos) {
if (current_drawing.all_layers[oldpos][1] == current_drawing.current_layer) break;
var drawing = getCurrentDrawing();
if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) {
for (var oldpos = 0; oldpos < drawing.getNumLayers(); ++oldpos) {
if (drawing.all_layers[oldpos][1] == drawing.current_layer) break;
}
// some unknown error condition (current_layer not in all_layers)
if (oldpos == current_drawing.getNumLayers()) { return false; }
if (oldpos == drawing.getNumLayers()) { return false; }
if (oldpos != newpos) {
// if our new position is below us, we need to insert before the node after newpos
var refLayer = null;
var oldNextSibling = current_drawing.current_layer.nextSibling;
var oldNextSibling = drawing.current_layer.nextSibling;
if (newpos > oldpos ) {
if (newpos < current_drawing.getNumLayers()-1) {
refLayer = current_drawing.all_layers[newpos+1][1];
if (newpos < drawing.getNumLayers()-1) {
refLayer = drawing.all_layers[newpos+1][1];
}
}
// if our new position is above us, we need to insert before the node at newpos
else {
refLayer = current_drawing.all_layers[newpos][1];
refLayer = drawing.all_layers[newpos][1];
}
svgcontent.insertBefore(current_drawing.current_layer, refLayer);
addCommandToHistory(new MoveElementCommand(current_drawing.current_layer, oldNextSibling, svgcontent));
svgcontent.insertBefore(drawing.current_layer, refLayer);
addCommandToHistory(new MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent));
identifyLayers();
canvas.setCurrentLayer(current_drawing.getLayerName(newpos));
canvas.setCurrentLayer(drawing.getLayerName(newpos));
return true;
}
@ -7207,9 +7208,10 @@ this.setLayerVisibility = function(layername, bVisible) {
this.moveSelectedToLayer = function(layername) {
// find the layer
var layer = null;
for (var i = 0; i < current_drawing.getNumLayers(); ++i) {
if (current_drawing.getLayerName(i) == layername) {
layer = current_drawing.all_layers[i][1];
var drawing = getCurrentDrawing();
for (var i = 0; i < drawing.getNumLayers(); ++i) {
if (drawing.getLayerName(i) == layername) {
layer = drawing.all_layers[i][1];
break;
}
}
@ -7237,28 +7239,29 @@ this.moveSelectedToLayer = function(layername) {
this.mergeLayer = function(skipHistory) {
var batchCmd = new BatchCommand("Merge Layer");
var prev = $(current_drawing.current_layer).prev()[0];
var drawing = getCurrentDrawing();
var prev = $(drawing.current_layer).prev()[0];
if(!prev) return;
var childs = current_drawing.current_layer.childNodes;
var childs = drawing.current_layer.childNodes;
var len = childs.length;
var layerNextSibling = current_drawing.current_layer.nextSibling;
batchCmd.addSubCommand(new RemoveElementCommand(current_drawing.current_layer, layerNextSibling, svgcontent));
var layerNextSibling = drawing.current_layer.nextSibling;
batchCmd.addSubCommand(new RemoveElementCommand(drawing.current_layer, layerNextSibling, svgcontent));
while(current_drawing.current_layer.firstChild) {
var ch = current_drawing.current_layer.firstChild;
while(drawing.current_layer.firstChild) {
var ch = drawing.current_layer.firstChild;
if(ch.localName == 'title') {
var chNextSibling = ch.nextSibling;
batchCmd.addSubCommand(new RemoveElementCommand(ch, chNextSibling, current_drawing.current_layer));
current_drawing.current_layer.removeChild(ch);
batchCmd.addSubCommand(new RemoveElementCommand(ch, chNextSibling, drawing.current_layer));
drawing.current_layer.removeChild(ch);
continue;
}
var oldNextSibling = ch.nextSibling;
prev.appendChild(ch);
batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, current_drawing.current_layer));
batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, drawing.current_layer));
}
// Remove current layer
svgcontent.removeChild(current_drawing.current_layer);
svgcontent.removeChild(drawing.current_layer);
if(!skipHistory) {
clearSelection();
@ -7269,13 +7272,14 @@ this.mergeLayer = function(skipHistory) {
addCommandToHistory(batchCmd);
}
current_drawing.current_layer = prev;
drawing.current_layer = prev;
return batchCmd;
}
this.mergeAllLayers = function() {
var batchCmd = new BatchCommand("Merge all Layers");
current_drawing.current_layer = current_drawing.all_layers[current_drawing.getNumLayers()-1][1];
var drawing = getCurrentDrawing();
drawing.current_layer = drawing.all_layers[drawing.getNumLayers()-1][1];
while($(svgcontent).children('g').length > 1) {
batchCmd.addSubCommand(canvas.mergeLayer(true));
}
@ -7342,29 +7346,26 @@ var setContext = this.setContext = function(elem) {
this.clear = function() {
pathActions.clear();
// clear the svgcontent node
var nodes = svgcontent.childNodes;
var len = svgcontent.childNodes.length;
var i = 0;
clearSelection();
for(var rep = 0; rep < len; rep++){
if (nodes[i].nodeType == 1) { // element node
svgcontent.removeChild(nodes[i]);
} else {
i++;
}
}
// create empty first layer
current_drawing.all_layers = [];
// clear the svgcontent node
canvas.clearSvgContentElement();
// create new document
canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent);
// create empty first layer
canvas.createLayer("Layer 1");
// clear the undo stack
canvas.undoMgr.resetUndoStack();
// reset the selector manager
selectorManager.initGroup();
// reset the rubber band box
rubberBox = selectorManager.getRubberBandBox();
call("cleared");
};
@ -7407,7 +7408,7 @@ this.getZoom = function(){return current_zoom;};
// Function: getVersion
// Returns a string which describes the revision number of SvgCanvas.
this.getVersion = function() {
return "svgcanvas.js ($Rev: 1961 $)";
return "svgcanvas.js ($Rev: 1972 $)";
};
// Function: setUiStrings
@ -8730,8 +8731,8 @@ var changeSelectedAttributeNoUndo = function(attr, newValue, elems) {
selectedBBoxes[i] = getBBox(elem);
// Use the Firefox ffClone hack for text elements with gradients or
// where other text attributes are changed.
if(elem.nodeName == 'text') {
if((newValue+'').indexOf('url') == 0 || ['font-size','font-family','x','y'].indexOf(attr) >= 0 && elem.textContent) {
if(svgedit.browser.isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) {
if((newValue+'').indexOf('url') === 0 || ['font-size','font-family','x','y'].indexOf(attr) >= 0 && elem.textContent) {
elem = ffClone(elem);
}
}
@ -9015,6 +9016,8 @@ var pushGroupProperties = this.pushGroupProperties = function(g, undoable) {
for(var i = 0; i < len; i++) {
var elem = children[i];
if(elem.nodeType !== 1) continue;
if(gattrs.opacity !== null && gattrs.opacity !== 1) {
var c_opac = elem.getAttribute('opacity') || 1;
var new_opac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100)/100;
@ -9149,7 +9152,8 @@ var pushGroupProperties = this.pushGroupProperties = function(g, undoable) {
newxform.setMatrix(gm);
chtlist.appendItem(newxform);
}
batchCmd.addSubCommand(recalculateDimensions(elem));
var cmd = recalculateDimensions(elem);
if(cmd) batchCmd.addSubCommand(cmd);
}
}
@ -9670,7 +9674,6 @@ this.getPrivateMethods = function() {
round: round,
runExtensions: runExtensions,
sanitizeSvg: sanitizeSvg,
shortFloat: shortFloat,
SVGEditTransformList: svgedit.transformlist.SVGTransformList,
toString: toString,
transformBox: svgedit.math.transformBox,

View file

@ -186,7 +186,7 @@ svgedit.utilities.convertToXMLReferences = function(input) {
return output;
};
// Function: text2xml
// Function: svgedit.utilities.text2xml
// Cross-browser compatible method of converting a string to an XML tree
// found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f
svgedit.utilities.text2xml = function(sXML) {
@ -209,7 +209,7 @@ svgedit.utilities.text2xml = function(sXML) {
return out;
};
// Function: bboxToObj
// Function: svgedit.utilities.bboxToObj
// Converts a SVGRect into an object.
//
// Parameters:
@ -226,7 +226,7 @@ svgedit.utilities.bboxToObj = function(bbox) {
}
};
// Function: walkTree
// Function: svgedit.utilities.walkTree
// Walks the tree and executes the callback on each element in a top-down fashion
//
// Parameters:
@ -242,7 +242,7 @@ svgedit.utilities.walkTree = function(elem, cbFn){
}
};
// Function: walkTreePost
// Function: svgedit.utilities.walkTreePost
// Walks the tree and executes the callback on each element in a depth-first fashion
// TODO: FIXME: Shouldn't this be calling walkTreePost?
//
@ -418,7 +418,7 @@ svgedit.utilities.getBBox = function(elem) {
selected.textContent = 'a'; // Some character needed for the selector to use.
ret = selected.getBBox();
selected.textContent = '';
} else if(elname === 'path' && svgedit.browser.isWebkit()) {
} else if(elname === 'path' && !svgedit.browser.supportsPathBBox()) {
ret = svgedit.utilities.getPathBBox(selected);
} else if(elname === 'use' && !svgedit.browser.isWebkit() || elname === 'foreignObject') {
ret = selected.getBBox();

View file

@ -51,6 +51,7 @@ var typeMap_ = {px: 1};
* function getElement() - returns an element in the container given an id
* function getHeight() - returns the container's height
* function getWidth() - returns the container's width
* function getRoundDigits() - returns the number of digits number should be rounded to
*/
/**
@ -95,6 +96,26 @@ svgedit.units.getTypeMap = function() {
return typeMap_;
};
// Function: svgedit.units.shortFloat
// Rounds a given value to a float with number of digits defined in save_options
//
// Parameters:
// val - The value as a String, Number or Array of two numbers to be rounded
//
// Returns:
// If a string/number was given, returns a Float. If an array, return a string
// with comma-seperated floats
svgedit.units.shortFloat = function(val) {
var digits = elementContainer_.getRoundDigits();
if(!isNaN(val)) {
// Note that + converts to Number
return +((+val).toFixed(digits));
} else if($.isArray(val)) {
return svgedit.units.shortFloat(val[0]) + ',' + svgedit.units.shortFloat(val[1]);
}
return parseFloat(val).toFixed(digits) - 0;
};
// Function: svgedit.units.convertUnit
// Converts the number to given unit or baseUnit
svgedit.units.convertUnit = function(val, unit) {
@ -102,7 +123,7 @@ svgedit.units.convertUnit = function(val, unit) {
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
// var val = baseVal.valueInSpecifiedUnits;
// baseVal.convertToSpecifiedUnits(1);
return val / typeMap_[unit];
return svgedit.unit.shortFloat(val / typeMap_[unit]);
};
// Function: svgedit.units.setUnitAttr
@ -249,7 +270,9 @@ svgedit.units.isValidUnit = function(attr, val) {
result = (elem == null);
} catch(e) {}
return result;
} else valid = true;
} else {
valid = true;
}
return valid;
};