diff --git a/editor/contextmenu/jquery.contextMenu.js b/editor/contextmenu/jquery.contextMenu.js index 4883797b..b6187aa0 100755 --- a/editor/contextmenu/jquery.contextMenu.js +++ b/editor/contextmenu/jquery.contextMenu.js @@ -94,8 +94,8 @@ if(jQuery)( function() { }); // When items are selected - $('#' + o.menu).find('A').unbind('click'); - $('#' + o.menu).find('LI:not(.disabled) A').click( function() { + $('#' + o.menu).find('A').unbind('mouseup'); + $('#' + o.menu).find('LI:not(.disabled) A').mouseup( function() { $(document).unbind('click').unbind('keypress'); $(".contextMenu").hide(); // Callback diff --git a/editor/extensions/ext-connector.js b/editor/extensions/ext-connector.js index 2f1990a1..80a23065 100644 --- a/editor/extensions/ext-connector.js +++ b/editor/extensions/ext-connector.js @@ -256,8 +256,9 @@ svgEditor.addExtension("Connector", function(S) { svgCanvas.moveSelectedElements = function() { svgCanvas.removeFromSelection($(conn_sel).toArray()); - mse.apply(this, arguments); + var cmd = mse.apply(this, arguments); updateConnectors(); + return cmd; } se_ns = svgCanvas.getEditorNS(); diff --git a/editor/svg-editor.css b/editor/svg-editor.css index 4a18348d..9b65777b 100644 --- a/editor/svg-editor.css +++ b/editor/svg-editor.css @@ -1217,13 +1217,18 @@ span.zoom_tool { /* Generic context menu styles */ .contextMenu { position: absolute; - width: 120px; z-index: 99999; - border: solid 1px #CCC; - background: #EEE; - padding: 0px; + border: solid 1px rgba(0,0,0,.33); + background: rgba(255,255,255,.95); + padding: 5px 0; margin: 0px; display: none; + font: 14px/17px Lucida Sans, Helvetica, Verdana, sans-serif; + border-radius: 5px; + -moz-border-radius: 5px; + -moz-box-shadow: 2px 5px 10px rgba(0,0,0,.3); + -webkit-box-shadow: 2px 5px 10px rgba(0,0,0,.3); + box-shadow: 2px 5px 10px rgba(0,0,0,.3); } .contextMenu LI { @@ -1233,7 +1238,9 @@ span.zoom_tool { } .contextMenu A { - color: #333; + -moz-user-select: none; + -webkit-user-select: none; + color: #222; text-decoration: none; display: block; line-height: 20px; @@ -1241,17 +1248,17 @@ span.zoom_tool { background-position: 6px center; background-repeat: no-repeat; outline: none; - padding: 1px 5px; - padding-left: 28px; + padding: 0px 15px 1px 20px; } .contextMenu LI.hover A { - background-color: #FFC; + background-color: #2e5dea; + color: white; + cursor: default; } .contextMenu LI.disabled A { - color: #AAA; - cursor: default; + color: #999; } .contextMenu LI.hover.disabled A { @@ -1259,7 +1266,9 @@ span.zoom_tool { } .contextMenu LI.separator { - border-top: solid 1px #CCC; + border-top: solid 1px #E3E3E3; + padding-top: 5px; + margin-top: 5px; } /* diff --git a/editor/svg-editor.html b/editor/svg-editor.html index 35d0639c..e71dec5c 100644 --- a/editor/svg-editor.html +++ b/editor/svg-editor.html @@ -667,10 +667,11 @@ script type="text/javascript" src="locale/locale.min.js"> diff --git a/editor/svg-editor.js b/editor/svg-editor.js index dfc56488..929847e6 100644 --- a/editor/svg-editor.js +++ b/editor/svg-editor.js @@ -442,6 +442,7 @@ Utils = svgCanvas.Utils, default_img_url = curConfig.imgPath + "logo.png", workarea = $("#workarea"), + canv_menu = $("#cmenu_canvas"), show_save_warning = false, exportWindow = null, tool_scale = 1; @@ -1473,7 +1474,7 @@ else if (multiselected) { $('#multiselected_panel').show(); } else { - $('#cmenu_canvas li').disableContextMenu(); + $('#cmenu_canvas li').disableContextMenuItems('#delete,#cut,#copy'); } // update history buttons @@ -1497,7 +1498,7 @@ $('#selLayerNames').removeAttr('disabled').val(currentLayer); // Enable regular menu options - $('#cmenu_canvas').enableContextMenuItems('#delete'); + canv_menu.enableContextMenuItems('#delete,#cut,#copy'); } else { $('#selLayerNames').attr('disabled', 'disabled'); @@ -2201,6 +2202,18 @@ } }; + var cutSelected = function() { + if (selectedElement != null || multiselected) { + svgCanvas.cutSelectedElements(); + } + }; + + var copySelected = function() { + if (selectedElement != null || multiselected) { + svgCanvas.copySelectedElements(); + } + }; + var moveToTopSelected = function() { if (selectedElement != null) { svgCanvas.moveToTopSelectedElement(); @@ -3720,11 +3733,31 @@ case 'delete': deleteSelected(); break; + case 'cut': + cutSelected(); + break; + case 'copy': + copySelected(); + break; + case 'paste': + svgCanvas.pasteElements(); + break; + case 'paste_in_place': + svgCanvas.pasteElements('in_place'); + break; + } + + if(svgCanvas.clipBoard.length) { + canv_menu.enableContextMenuItems('#paste,#paste_in_place'); } }); + $('.contextMenu li').mousedown(function(ev) { + ev.preventDefault(); + }) + $('#cmenu_canvas li').disableContextMenu(); - $('#cmenu_canvas').enableContextMenuItems('#delete'); + canv_menu.enableContextMenuItems('#delete,#cut,#copy'); window.onbeforeunload = function() { // Suppress warning if page is empty diff --git a/editor/svgcanvas.js b/editor/svgcanvas.js index 14269fdb..d7d1dab3 100644 --- a/editor/svgcanvas.js +++ b/editor/svgcanvas.js @@ -1935,7 +1935,13 @@ var cur_shape = all_properties.shape, curBBoxes = [], // Object to contain all included extensions - extensions = {}; + extensions = {}, + + // Canvas point for the most recent right click + lastClickPoint = null; + +// Clipboard for cut, copy&pasted elements +canvas.clipBoard = []; // Should this return an array by default, so extension results aren't overwritten? var runExtensions = this.runExtensions = function(action, vars, returnArray) { @@ -4200,19 +4206,20 @@ var getMouseTarget = this.getMouseTarget = function(evt) { // and do nothing else var mouseDown = function(evt) { - console.log(evt.button); if(canvas.spaceKey) return; var right_click = evt.button === 2; - if(right_click) { - current_mode = "select"; - } root_sctm = svgcontent.getScreenCTM().inverse(); var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), mouse_x = pt.x * current_zoom, mouse_y = pt.y * current_zoom; evt.preventDefault(); + + if(right_click) { + current_mode = "select"; + lastClickPoint = pt; + } // This would seem to be unnecessary... // if($.inArray(current_mode, ['select', 'resize']) == -1) { @@ -10030,6 +10037,87 @@ this.deleteSelectedElements = function() { clearSelection(); }; +// Function: cutSelectedElements +// Removes all selected elements from the DOM and adds the change to the +// history stack. Remembers removed elements on the clipboard + +// TODO: Combine similar code with deleteSelectedElements +this.cutSelectedElements = function() { + var batchCmd = new BatchCommand("Cut Elements"); + var len = selectedElements.length; + var selectedCopy = []; //selectedElements is being deleted + for (var i = 0; i < len; ++i) { + var selected = selectedElements[i]; + if (selected == null) break; + + var parent = selected.parentNode; + var t = selected; + // this will unselect the element and remove the selectedOutline + selectorManager.releaseSelector(t); + var elem = parent.removeChild(t); + selectedCopy.push(selected) //for the copy + selectedElements[i] = null; + batchCmd.addSubCommand(new RemoveElementCommand(elem, parent)); + } + if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); + call("changed", selectedCopy); + clearSelection(); + + canvas.clipBoard = selectedCopy; +}; + +// Function: copySelectedElements +// Remembers the current selected elements on the clipboard +this.copySelectedElements = function() { + canvas.clipBoard = $.merge([], selectedElements); +}; + +this.pasteElements = function(type) { + var cb = canvas.clipBoard; + var len = cb.length; + if(!len) return; + + var pasted = []; + var batchCmd = new BatchCommand('Paste elements'); + + // Move elements to lastClickPoint + + while (len--) { + var elem = cb[len]; + if(!elem) continue; + var copy = copyElem(elem); + + // See if elem with elem ID is in the DOM already + if(!getElem(elem.id)) copy.id = elem.id; + + pasted.push(copy); + current_layer.appendChild(copy); + batchCmd.addSubCommand(new InsertElementCommand(copy)); + } + + clearSelection(true); + addToSelection(pasted); + + if(type !== 'in_place') { + var bbox = getStrokedBBox(pasted); + var cx = lastClickPoint.x - (bbox.x + bbox.width/2), + cy = lastClickPoint.y - (bbox.y + bbox.height/2), + dx = [], + dy = []; + + $.each(pasted, function(i, item) { + dx.push(cx); + dy.push(cy); + }); + + var cmd = canvas.moveSelectedElements(dx, dy, false); + batchCmd.addSubCommand(cmd); + } + + addCommandToHistory(batchCmd); + call("changed", pasted); +} + // Function: groupSelectedElements // Wraps all the selected elements in a group (g) element this.groupSelectedElements = function() {