Fix Issue 770: Trouncing the nonce. Restructured how random ids are produced. Updated how new documents are created.

git-svn-id: http://svg-edit.googlecode.com/svn/trunk@1962 eee81c28-f429-11dd-99c0-75d572ba1ddd
master
Jeff Schiller 2011-02-01 07:22:18 +00:00
parent 846ee8eca1
commit 9c8ba2361f
4 changed files with 124 additions and 104 deletions

View File

@ -21,6 +21,9 @@ if (!svgedit.draw) {
var svg_ns = "http://www.w3.org/2000/svg"; var svg_ns = "http://www.w3.org/2000/svg";
var se_ns = "http://svg-edit.googlecode.com"; var se_ns = "http://svg-edit.googlecode.com";
var xmlns_ns = "http://www.w3.org/2000/xmlns/";
var randomize_ids = false;
/** /**
* This class encapsulates the concept of a layer in the drawing * This class encapsulates the concept of a layer in the drawing
@ -41,6 +44,12 @@ svgedit.draw.Layer.prototype.getGroup = function() {
}; };
// Called to ensure that drawings will or will not have
// randomized ids.
svgedit.draw.randomizeIds = function(enableRandomization) {
randomize_ids = enableRandomization;
};
/** /**
* This class encapsulates the concept of a SVG-edit drawing * This class encapsulates the concept of a SVG-edit drawing
* *
@ -99,7 +108,17 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
* The nonce to use to uniquely identify elements across drawings. * The nonce to use to uniquely identify elements across drawings.
* @type {!String} * @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) {
this.nonce_ = n;
} else if (randomize_ids) {
this.nonce_ = Math.floor(Math.random() * 100001);
this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns);
this.svgElem_.setAttributeNS(se_ns, 'se:nonce', this.nonce_);
}
}; };
svgedit.draw.Drawing.prototype.getElem_ = function(id) { svgedit.draw.Drawing.prototype.getElem_ = function(id) {

View File

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

View File

@ -151,7 +151,12 @@ container.appendChild(svgroot);
// The actual element that represents the final output SVG element // The actual element that represents the final output SVG element
var svgcontent = svgdoc.createElementNS(svgns, "svg"); var svgcontent = svgdoc.createElementNS(svgns, "svg");
$(svgcontent).attr({ // 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', id: 'svgcontent',
width: dimensions[0], width: dimensions[0],
height: dimensions[1], height: dimensions[1],
@ -161,7 +166,13 @@ $(svgcontent).attr({
xmlns: svgns, xmlns: svgns,
"xmlns:se": se_ns, "xmlns:se": se_ns,
"xmlns:xlink": xlinkns "xmlns:xlink": xlinkns
}).appendTo(svgroot); }).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/ ");
svgcontent.appendChild(comment);
};
clearSvgContentElement();
// Prefix string for element IDs // Prefix string for element IDs
var idprefix = "svg_"; var idprefix = "svg_";
@ -175,24 +186,15 @@ canvas.setIdPrefix = function(p) {
idprefix = p; idprefix = p;
}; };
// 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
if (randomize_ids) svgcontent.setAttributeNS(se_ns, 'se:nonce', nonce);
// Current svgedit.draw.Drawing object // Current svgedit.draw.Drawing object
// @type {svgedit.draw.Drawing} // @type {svgedit.draw.Drawing}
var current_drawing = new svgedit.draw.Drawing(svgcontent, idprefix); canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix);
// Function: getCurrentDrawing // Function: getCurrentDrawing
// Returns the current Drawing. // Returns the current Drawing.
// @return {svgedit.draw.Drawing} // @return {svgedit.draw.Drawing}
var getCurrentDrawing = canvas.getCurrentDrawing = function() { var getCurrentDrawing = canvas.getCurrentDrawing = function() {
return current_drawing; return canvas.current_drawing_;
}; };
// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc) // Float displaying the current zoom level (1 = 100%, .5 = 50%, etc)
@ -524,10 +526,6 @@ var restoreRefElems = function(elem) {
}; };
(function() { (function() {
// TODO: make this string optional and set by the client
var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");
svgcontent.appendChild(comment);
// TODO For Issue 208: this is a start on a thumbnail // TODO For Issue 208: this is a start on a thumbnail
// var svgthumb = svgdoc.createElementNS(svgns, "use"); // var svgthumb = svgdoc.createElementNS(svgns, "use");
// svgthumb.setAttribute('width', '100'); // svgthumb.setAttribute('width', '100');
@ -624,7 +622,7 @@ this.addExtension = function(name, ext_func) {
var ext = ext_func($.extend(canvas.getPrivateMethods(), { var ext = ext_func($.extend(canvas.getPrivateMethods(), {
svgroot: svgroot, svgroot: svgroot,
svgcontent: svgcontent, svgcontent: svgcontent,
nonce: nonce, nonce: getCurrentDrawing().getNonce(),
selectorManager: selectorManager selectorManager: selectorManager
})); }));
} else { } else {
@ -6346,9 +6344,9 @@ this.getSvgString = function() {
return this.svgCanvasToString(); return this.svgCanvasToString();
}; };
//function randomizeIds // Function: randomizeIds
// This function determines whether to add a nonce to the prefix, when // This function determines whether to use a nonce in the prefix, when
// generating IDs in SVG-Edit // generating IDs for future documents in SVG-Edit.
// //
// Parameters: // Parameters:
// an opional boolean, which, if true, adds a nonce to the prefix. Thus // an opional boolean, which, if true, adds a nonce to the prefix. Thus
@ -6359,16 +6357,11 @@ this.getSvgString = function() {
// //
this.randomizeIds = function() { this.randomizeIds = function() {
if (arguments.length > 0 && arguments[0] == false) { if (arguments.length > 0 && arguments[0] == false) {
randomize_ids = false; svgedit.draw.randomizeIds(false);
if (extensions["Arrows"]) call("unsetarrownonce") ;
} else { } else {
randomize_ids = true; svgedit.draw.randomizeIds(true);
if (!svgcontent.getAttributeNS(se_ns, 'nonce')) {
svgcontent.setAttributeNS(se_ns, 'se:nonce', nonce);
if (extensions["Arrows"]) call("setarrownonce", nonce) ;
} }
} };
}
// Function: uniquifyElems // Function: uniquifyElems
// Ensure each element has a unique ID // Ensure each element has a unique ID
@ -6701,19 +6694,15 @@ this.setSvgString = function(xmlString) {
var content = $(svgcontent); var content = $(svgcontent);
// retrieve or set the nonce canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix);
n = svgcontent.getAttributeNS(se_ns, 'nonce');
if (n) {
randomize_ids = true;
nonce = n;
if (extensions["Arrows"]) call("setarrownonce", n) ;
} else if (randomize_ids) {
svgcontent.setAttributeNS(xmlnsns, 'xmlns:se', se_ns);
svgcontent.setAttributeNS(se_ns, 'se:nonce', nonce);
if (extensions["Arrows"]) call("setarrownonce", nonce) ;
}
current_drawing = new svgedit.draw.Drawing(svgcontent, idprefix); // retrieve or set the nonce
var nonce = getCurrentDrawing().getNonce();
if (nonce) {
call("setnonce", nonce);
} else {
call("unsetnonce");
}
// change image href vals if possible // change image href vals if possible
content.find('image').each(function() { content.find('image').each(function() {
@ -7038,10 +7027,10 @@ this.cloneLayer = function(name) {
// Deletes the current layer from the drawing and then clears the selection. This function // Deletes the current layer from the drawing and then clears the selection. This function
// then calls the 'changed' handler. This is an undoable action. // then calls the 'changed' handler. This is an undoable action.
this.deleteCurrentLayer = function() { this.deleteCurrentLayer = function() {
var current_layer = current_drawing.getCurrentLayer(); var current_layer = getCurrentDrawing().getCurrentLayer();
var nextSibling = current_layer.nextSibling; var nextSibling = current_layer.nextSibling;
var parent = current_layer.parentNode; var parent = current_layer.parentNode;
current_layer = current_drawing.deleteCurrentLayer(); current_layer = getCurrentDrawing().deleteCurrentLayer();
if (current_layer) { if (current_layer) {
var batchCmd = new BatchCommand("Delete Layer"); var batchCmd = new BatchCommand("Delete Layer");
// store in our Undo History // store in our Undo History
@ -7082,18 +7071,19 @@ this.setCurrentLayer = function(name) {
// Returns: // Returns:
// true if the rename succeeded, false otherwise. // true if the rename succeeded, false otherwise.
this.renameCurrentLayer = function(newname) { this.renameCurrentLayer = function(newname) {
if (current_drawing.current_layer) { var drawing = getCurrentDrawing();
var oldLayer = current_drawing.current_layer; if (drawing.current_layer) {
var oldLayer = drawing.current_layer;
// setCurrentLayer will return false if the name doesn't already exist // setCurrentLayer will return false if the name doesn't already exist
// this means we are free to rename our oldLayer // this means we are free to rename our oldLayer
if (!canvas.setCurrentLayer(newname)) { if (!canvas.setCurrentLayer(newname)) {
var batchCmd = new BatchCommand("Rename Layer"); var batchCmd = new BatchCommand("Rename Layer");
// find the index of the layer // find the index of the layer
for (var i = 0; i < current_drawing.getNumLayers(); ++i) { for (var i = 0; i < drawing.getNumLayers(); ++i) {
if (current_drawing.all_layers[i][1] == oldLayer) break; if (drawing.all_layers[i][1] == oldLayer) break;
} }
var oldname = current_drawing.getLayerName(i); var oldname = drawing.getLayerName(i);
current_drawing.all_layers[i][0] = svgedit.utilities.toXml(newname); drawing.all_layers[i][0] = svgedit.utilities.toXml(newname);
// now change the underlying title element contents // now change the underlying title element contents
var len = oldLayer.childNodes.length; var len = oldLayer.childNodes.length;
@ -7112,7 +7102,7 @@ this.renameCurrentLayer = function(newname) {
} }
} }
} }
current_drawing.current_layer = oldLayer; drawing.current_layer = oldLayer;
} }
return false; return false;
}; };
@ -7129,31 +7119,32 @@ this.renameCurrentLayer = function(newname) {
// Returns: // Returns:
// true if the current layer position was changed, false otherwise. // true if the current layer position was changed, false otherwise.
this.setCurrentLayerPosition = function(newpos) { this.setCurrentLayerPosition = function(newpos) {
if (current_drawing.current_layer && newpos >= 0 && newpos < current_drawing.getNumLayers()) { var drawing = getCurrentDrawing();
for (var oldpos = 0; oldpos < current_drawing.getNumLayers(); ++oldpos) { if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) {
if (current_drawing.all_layers[oldpos][1] == current_drawing.current_layer) break; 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) // 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 (oldpos != newpos) {
// if our new position is below us, we need to insert before the node after newpos // if our new position is below us, we need to insert before the node after newpos
var refLayer = null; var refLayer = null;
var oldNextSibling = current_drawing.current_layer.nextSibling; var oldNextSibling = drawing.current_layer.nextSibling;
if (newpos > oldpos ) { if (newpos > oldpos ) {
if (newpos < current_drawing.getNumLayers()-1) { if (newpos < drawing.getNumLayers()-1) {
refLayer = current_drawing.all_layers[newpos+1][1]; refLayer = drawing.all_layers[newpos+1][1];
} }
} }
// if our new position is above us, we need to insert before the node at newpos // if our new position is above us, we need to insert before the node at newpos
else { else {
refLayer = current_drawing.all_layers[newpos][1]; refLayer = drawing.all_layers[newpos][1];
} }
svgcontent.insertBefore(current_drawing.current_layer, refLayer); svgcontent.insertBefore(drawing.current_layer, refLayer);
addCommandToHistory(new MoveElementCommand(current_drawing.current_layer, oldNextSibling, svgcontent)); addCommandToHistory(new MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent));
identifyLayers(); identifyLayers();
canvas.setCurrentLayer(current_drawing.getLayerName(newpos)); canvas.setCurrentLayer(drawing.getLayerName(newpos));
return true; return true;
} }
@ -7203,9 +7194,10 @@ this.setLayerVisibility = function(layername, bVisible) {
this.moveSelectedToLayer = function(layername) { this.moveSelectedToLayer = function(layername) {
// find the layer // find the layer
var layer = null; var layer = null;
for (var i = 0; i < current_drawing.getNumLayers(); ++i) { var drawing = getCurrentDrawing();
if (current_drawing.getLayerName(i) == layername) { for (var i = 0; i < drawing.getNumLayers(); ++i) {
layer = current_drawing.all_layers[i][1]; if (drawing.getLayerName(i) == layername) {
layer = drawing.all_layers[i][1];
break; break;
} }
} }
@ -7233,28 +7225,29 @@ this.moveSelectedToLayer = function(layername) {
this.mergeLayer = function(skipHistory) { this.mergeLayer = function(skipHistory) {
var batchCmd = new BatchCommand("Merge Layer"); 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; if(!prev) return;
var childs = current_drawing.current_layer.childNodes; var childs = drawing.current_layer.childNodes;
var len = childs.length; var len = childs.length;
var layerNextSibling = current_drawing.current_layer.nextSibling; var layerNextSibling = drawing.current_layer.nextSibling;
batchCmd.addSubCommand(new RemoveElementCommand(current_drawing.current_layer, layerNextSibling, svgcontent)); batchCmd.addSubCommand(new RemoveElementCommand(drawing.current_layer, layerNextSibling, svgcontent));
while(current_drawing.current_layer.firstChild) { while(drawing.current_layer.firstChild) {
var ch = current_drawing.current_layer.firstChild; var ch = drawing.current_layer.firstChild;
if(ch.localName == 'title') { if(ch.localName == 'title') {
var chNextSibling = ch.nextSibling; var chNextSibling = ch.nextSibling;
batchCmd.addSubCommand(new RemoveElementCommand(ch, chNextSibling, current_drawing.current_layer)); batchCmd.addSubCommand(new RemoveElementCommand(ch, chNextSibling, drawing.current_layer));
current_drawing.current_layer.removeChild(ch); drawing.current_layer.removeChild(ch);
continue; continue;
} }
var oldNextSibling = ch.nextSibling; var oldNextSibling = ch.nextSibling;
prev.appendChild(ch); 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 // Remove current layer
svgcontent.removeChild(current_drawing.current_layer); svgcontent.removeChild(drawing.current_layer);
if(!skipHistory) { if(!skipHistory) {
clearSelection(); clearSelection();
@ -7265,13 +7258,14 @@ this.mergeLayer = function(skipHistory) {
addCommandToHistory(batchCmd); addCommandToHistory(batchCmd);
} }
current_drawing.current_layer = prev; drawing.current_layer = prev;
return batchCmd; return batchCmd;
} }
this.mergeAllLayers = function() { this.mergeAllLayers = function() {
var batchCmd = new BatchCommand("Merge all Layers"); 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) { while($(svgcontent).children('g').length > 1) {
batchCmd.addSubCommand(canvas.mergeLayer(true)); batchCmd.addSubCommand(canvas.mergeLayer(true));
} }
@ -7339,28 +7333,23 @@ this.clear = function() {
pathActions.clear(); pathActions.clear();
// clear the svgcontent node // clear the svgcontent node
var nodes = svgcontent.childNodes; canvas.clearSvgContentElement();
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 = [];
// create new document
canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent);
// create empty first layer
canvas.createLayer("Layer 1"); canvas.createLayer("Layer 1");
// clear the undo stack // clear the undo stack
canvas.undoMgr.resetUndoStack(); canvas.undoMgr.resetUndoStack();
// reset the selector manager // reset the selector manager
selectorManager.initGroup(); selectorManager.initGroup();
// reset the rubber band box // reset the rubber band box
rubberBox = selectorManager.getRubberBandBox(); rubberBox = selectorManager.getRubberBandBox();
call("cleared"); call("cleared");
}; };

View File

@ -480,6 +480,18 @@
equals(drawing.getCurrentLayer(), drawing.all_layers[1][1]); equals(drawing.getCurrentLayer(), drawing.all_layers[1][1]);
}); });
test('Test svgedit.draw.randomizeIds()', function() {
expect(2);
svgedit.draw.randomizeIds(true);
var drawing = new svgedit.draw.Drawing(svg.cloneNode(true));
ok(!!drawing.getNonce());
svgedit.draw.randomizeIds(false);
var drawing = new svgedit.draw.Drawing(svg);
ok(!drawing.getNonce());
});
}); });
</script> </script>
</head> </head>