diff --git a/editor/svg-editor.html b/editor/svg-editor.html
index 84ae5dd4..83687046 100644
--- a/editor/svg-editor.html
+++ b/editor/svg-editor.html
@@ -40,11 +40,13 @@
+

+
![Move to Bottom [Shift+Down] Bottom](images/move_bottom.png)
@@ -65,6 +67,7 @@
diff --git a/editor/svg-editor.js b/editor/svg-editor.js
index 47f1150b..5c4c3a6d 100644
--- a/editor/svg-editor.js
+++ b/editor/svg-editor.js
@@ -370,7 +370,7 @@ function svg_edit_setup() {
var moveSelected = function(dx,dy) {
if (selectedElement != null || multiselected) {
- svgCanvas.moveSelectedElement(dx,dy);
+ svgCanvas.moveSelectedElements(dx,dy);
}
};
@@ -410,6 +410,13 @@ function svg_edit_setup() {
svgCanvas.redo();
};
+ var clickCopy = function(){
+ svgCanvas.copySelectedElements();
+ };
+ var clickPaste = function(){
+ svgCanvas.pasteElements();
+ };
+
var showSourceEditor = function(){
if (editingsource) return;
editingsource = true;
@@ -465,6 +472,9 @@ function svg_edit_setup() {
$('#tool_move_bottom').click(moveToBottomSelected);
$('#tool_undo').click(clickUndo);
$('#tool_redo').click(clickRedo);
+ $('#tool_paste').click(clickPaste);
+ $('#tool_copy').click(clickCopy);
+ $('#tool_copy_multi').click(clickCopy);
// these two lines are required to make Opera work properly with the flyout mechanism
$('#tools_rect_show').click(clickSquare);
$('#tools_ellipse_show').click(clickCircle);
@@ -494,6 +504,15 @@ function svg_edit_setup() {
$('#tool_redo').mousedown(function(){ if (!$('#tool_redo').hasClass('tool_button_disabled')) $('#tool_redo').addClass('tool_button_current');});
$('#tool_redo').mouseup(function(){$('#tool_redo').removeClass('tool_button_current');});
$('#tool_redo').mouseout(function(){$('#tool_redo').removeClass('tool_button_current');});
+ $('#tool_paste').mousedown(function(){$('#tool_paste').addClass('tool_button_current');});
+ $('#tool_paste').mouseup(function(){$('#tool_paste').removeClass('tool_button_current');});
+ $('#tool_paste').mouseout(function(){$('#tool_paste').removeClass('tool_button_current');});
+ $('#tool_copy').mousedown(function(){$('#tool_copy').addClass('tool_button_current');});
+ $('#tool_copy').mouseup(function(){$('#tool_copy').removeClass('tool_button_current');});
+ $('#tool_copy').mouseout(function(){$('#tool_copy').removeClass('tool_button_current');});
+ $('#tool_copy_multi').mousedown(function(){$('#tool_copy').addClass('tool_button_current');});
+ $('#tool_copy_multi').mouseup(function(){$('#tool_copy').removeClass('tool_button_current');});
+ $('#tool_copy_multi').mouseout(function(){$('#tool_copy').removeClass('tool_button_current');});
$('#tool_move_top').mousedown(function(){$('#tool_move_top').addClass('tool_button_current');});
$('#tool_move_top').mouseup(function(){$('#tool_move_top').removeClass('tool_button_current');});
$('#tool_move_top').mouseout(function(){$('#tool_move_top').removeClass('tool_button_current');});
@@ -524,6 +543,8 @@ function svg_edit_setup() {
$(document).bind('keydown', {combi:'shift+z', disableInInput: true}, clickRedo);
$(document).bind('keydown', {combi:'y', disableInInput: true}, clickRedo);
$(document).bind('keydown', {combi:'u', disableInInput: true}, function(evt){showSourceEditor();evt.preventDefault();});
+ $(document).bind('keydown', {combi:'c', disableInInput: true}, clickCopy);
+ $(document).bind('keydown', {combi:'v', disableInInput: true}, clickPaste);
$(document).bind('keydown', {combi:'esc', disableInInput: false}, hideSourceEditor);
var colorPicker = function(elem) {
diff --git a/editor/svgcanvas.js b/editor/svgcanvas.js
index 42f1538a..010d7104 100644
--- a/editor/svgcanvas.js
+++ b/editor/svgcanvas.js
@@ -429,12 +429,12 @@ function SvgCanvas(c)
var selectedBBoxes = new Array(1);
// this object manages selectors for us
var selectorManager = new SelectorManager();
- // this object holds the one-and-only selector (for now)
- var theSelector = null;
var rubberBox = null;
var events = {};
var undoStackPointer = 0;
var undoStack = [];
+ // this holds all the currently copied elements
+ var copiedElements = new Array(1);
// This method sends back an array or a NodeList full of elements that
// intersect the multi-select rubber-band-box.
@@ -486,7 +486,6 @@ function SvgCanvas(c)
}
undoStack.push(cmd);
undoStackPointer = undoStack.length;
- console.log(undoStack);
};
// private functions
@@ -1238,8 +1237,9 @@ function SvgCanvas(c)
selectorManager.requestSelector(selected).showGrips(selected.tagName != "text");
}
recalculateAllSelectedDimensions();
- var i = selectedElements.length;
- while(i--) {
+ var len = selectedElements.length;
+ for(var i = 0; i < len; ++i) {
+ if (selectedElements[i] == null) break;
selectorManager.requestSelector(selectedElements[i]).resize(selectedBBoxes[i]);
}
}
@@ -1677,7 +1677,9 @@ function SvgCanvas(c)
}
};
- this.moveSelectedElement = function(dx,dy) {
+ this.moveSelectedElements = function(dx,dy,undoable) {
+ // if undoable is not sent, default to true
+ var undoable = undoable&&true;
var batchCmd = new BatchCommand("position");
var i = selectedElements.length;
while (i--) {
@@ -1694,7 +1696,8 @@ function SvgCanvas(c)
}
}
if (!batchCmd.isEmpty()) {
- addCommandToHistory(batchCmd);
+ if (undoable)
+ addCommandToHistory(batchCmd);
call("changed", selectedElements);
}
};
@@ -1734,6 +1737,38 @@ function SvgCanvas(c)
call("changed", cmd.elements());
}
};
+
+ // this creates deep DOM copies (clones) of all selected elements
+ this.copySelectedElements = function() {
+ copiedElements = [];
+ var len = selectedElements.length;
+ for (var i = 0; i < len; ++i) {
+ if (selectedElements[i] == null) break;
+ copiedElements.push(selectedElements[i].cloneNode(true));
+ }
+ };
+
+ this.pasteElements = function() {
+ var batchCmd = new BatchCommand("Paste Elements");
+ this.clearSelection();
+ var len = copiedElements.length;
+ for (var i = 0; i < len; ++i) {
+ var elem = copiedElements[i];
+ elem.id = getNextId();
+ svgroot.appendChild(elem);
+ batchCmd.addSubCommand(new InsertElementCommand(elem));
+ }
+
+ if (!batchCmd.isEmpty()) {
+ this.addToSelection(copiedElements);
+ this.moveSelectedElements(20,20,false);
+ addCommandToHistory(batchCmd);
+ // re-copy the elements so we can paste again
+ this.copySelectedElements();
+ call("selected", selectedElements);
+ }
+
+ };
}