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 @@ | Undo Redo + Paste
| + Copy Delete Top Bottom @@ -65,6 +67,7 @@
| + Copy Delete
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); + } + + }; }