Implemented a clipboard that works across tabs and windows.
parent
6f7aa650f8
commit
02c8721c2d
|
@ -160,6 +160,7 @@ svgEditor.addExtension("Connector", function(S) {
|
||||||
|
|
||||||
// Loop through connectors to see if one is connected to the element
|
// Loop through connectors to see if one is connected to the element
|
||||||
connectors.each(function() {
|
connectors.each(function() {
|
||||||
|
var connector = this;
|
||||||
var add_this;
|
var add_this;
|
||||||
function add () {
|
function add () {
|
||||||
if ($.inArray(this, elems) !== -1) {
|
if ($.inArray(this, elems) !== -1) {
|
||||||
|
@ -167,12 +168,24 @@ svgEditor.addExtension("Connector", function(S) {
|
||||||
add_this = true;
|
add_this = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var start = elData(this, "c_start");
|
|
||||||
var end = elData(this, "c_end");
|
|
||||||
|
|
||||||
var parts = [getElem(start), getElem(end)];
|
// Grab the ends
|
||||||
|
var parts = [];
|
||||||
|
['start', 'end'].forEach(function (pos, i) {
|
||||||
|
var part = elData(this, 'c_'+pos);
|
||||||
|
if(part == null) {
|
||||||
|
part = document.getElementById(
|
||||||
|
connector.attributes['se:connector'].value.split(' ')[i]
|
||||||
|
);
|
||||||
|
elData(connector, 'c_'+pos, part.id);
|
||||||
|
elData(connector, pos+'_bb', svgCanvas.getStrokedBBox([part]));
|
||||||
|
}
|
||||||
|
parts.push(part);
|
||||||
|
});
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
var c_elem = parts[i];
|
var c_elem = parts[i];
|
||||||
|
|
||||||
add_this = false;
|
add_this = false;
|
||||||
// The connected element might be part of a selected group
|
// The connected element might be part of a selected group
|
||||||
$(c_elem).parents().each(add);
|
$(c_elem).parents().each(add);
|
||||||
|
@ -261,7 +274,6 @@ svgEditor.addExtension("Connector", function(S) {
|
||||||
var mse = svgCanvas.moveSelectedElements;
|
var mse = svgCanvas.moveSelectedElements;
|
||||||
|
|
||||||
svgCanvas.moveSelectedElements = function() {
|
svgCanvas.moveSelectedElements = function() {
|
||||||
svgCanvas.removeFromSelection($(conn_sel).toArray());
|
|
||||||
var cmd = mse.apply(this, arguments);
|
var cmd = mse.apply(this, arguments);
|
||||||
updateConnectors();
|
updateConnectors();
|
||||||
return cmd;
|
return cmd;
|
||||||
|
@ -580,6 +592,18 @@ svgEditor.addExtension("Connector", function(S) {
|
||||||
updateConnectors();
|
updateConnectors();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
IDsUpdated: function(input) {
|
||||||
|
var remove = [];
|
||||||
|
input.elems.forEach(function(elem){
|
||||||
|
if('se:connector' in elem.attr) {
|
||||||
|
elem.attr['se:connector'] = elem.attr['se:connector'].split(' ')
|
||||||
|
.map(function(oldID){ return input.changes[oldID] }).join(' ');
|
||||||
|
if(!/. ./.test(elem.attr['se:connector']))
|
||||||
|
remove.push(elem.attr.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return {remove: remove};
|
||||||
|
},
|
||||||
toolButtonStateUpdate: function(opts) {
|
toolButtonStateUpdate: function(opts) {
|
||||||
if (opts.nostroke) {
|
if (opts.nostroke) {
|
||||||
if ($('#mode_connect').hasClass('tool_button_current')) {
|
if ($('#mode_connect').hasClass('tool_button_current')) {
|
||||||
|
|
|
@ -4818,9 +4818,6 @@ TODOS
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (svgCanvas.clipBoard.length) {
|
|
||||||
canv_menu.enableContextMenuItems('#paste,#paste_in_place');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4865,6 +4862,15 @@ TODOS
|
||||||
$('#cmenu_canvas li').disableContextMenu();
|
$('#cmenu_canvas li').disableContextMenu();
|
||||||
canv_menu.enableContextMenuItems('#delete,#cut,#copy');
|
canv_menu.enableContextMenuItems('#delete,#cut,#copy');
|
||||||
|
|
||||||
|
canv_menu[(localStorage.getItem('svgedit_clipboard') ? 'en' : 'dis') + 'ableContextMenuItems']
|
||||||
|
('#paste,#paste_in_place');
|
||||||
|
window.addEventListener('storage', function(e) {
|
||||||
|
if(e.key != 'svgedit_clipboard') return;
|
||||||
|
|
||||||
|
canv_menu[(localStorage.getItem('svgedit_clipboard') ? 'en' : 'dis') + 'ableContextMenuItems']
|
||||||
|
('#paste,#paste_in_place');
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener('beforeunload', function(e) {
|
window.addEventListener('beforeunload', function(e) {
|
||||||
// Suppress warning if page is empty
|
// Suppress warning if page is empty
|
||||||
if (undoMgr.getUndoStackSize() === 0) {
|
if (undoMgr.getUndoStackSize() === 0) {
|
||||||
|
|
|
@ -177,6 +177,30 @@ var cur_shape = all_properties.shape;
|
||||||
// default size of 1 until it needs to grow bigger
|
// default size of 1 until it needs to grow bigger
|
||||||
var selectedElements = [];
|
var selectedElements = [];
|
||||||
|
|
||||||
|
var getJsonFromSvgElement = this.getJsonFromSvgElement = function(data) {
|
||||||
|
// Text node
|
||||||
|
if(data.nodeType == 3) return data.nodeValue;
|
||||||
|
|
||||||
|
var retval = {
|
||||||
|
element: data.tagName,
|
||||||
|
//namespace: nsMap[data.namespaceURI],
|
||||||
|
attr: {},
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Itrate attributes
|
||||||
|
for(var i=0; i < data.attributes.length; i++) {
|
||||||
|
retval.attr[data.attributes[i].name] = data.attributes[i].value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iterate children
|
||||||
|
for(var i=0; i < data.childNodes.length; i++) {
|
||||||
|
retval.children.push(getJsonFromSvgElement(data.childNodes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
// Function: addSvgElementFromJson
|
// Function: addSvgElementFromJson
|
||||||
// Create a new SVG element based on the given object keys/values and add it to the current layer
|
// Create a new SVG element based on the given object keys/values and add it to the current layer
|
||||||
// The element will be ran through cleanupElement before being returned
|
// The element will be ran through cleanupElement before being returned
|
||||||
|
@ -504,9 +528,6 @@ var encodableImages = {},
|
||||||
// Map of deleted reference elements
|
// Map of deleted reference elements
|
||||||
removedElements = {};
|
removedElements = {};
|
||||||
|
|
||||||
// Clipboard for cut, copy&pasted elements
|
|
||||||
canvas.clipBoard = [];
|
|
||||||
|
|
||||||
// Should this return an array by default, so extension results aren't overwritten?
|
// Should this return an array by default, so extension results aren't overwritten?
|
||||||
var runExtensions = this.runExtensions = function(action, vars, returnArray) {
|
var runExtensions = this.runExtensions = function(action, vars, returnArray) {
|
||||||
var result = returnArray ? [] : false;
|
var result = returnArray ? [] : false;
|
||||||
|
@ -872,17 +893,13 @@ var root_sctm = null;
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// noCall - Optional boolean that when true does not call the "selected" handler
|
// noCall - Optional boolean that when true does not call the "selected" handler
|
||||||
var clearSelection = this.clearSelection = function(noCall) {
|
var clearSelection = this.clearSelection = function(noCall) {
|
||||||
if (selectedElements[0] != null) {
|
selectedElements.map(function(elem){
|
||||||
var i, elem,
|
if(elem == null) return;
|
||||||
len = selectedElements.length;
|
|
||||||
for (i = 0; i < len; ++i) {
|
|
||||||
elem = selectedElements[i];
|
|
||||||
if (elem == null) {break;}
|
|
||||||
selectorManager.releaseSelector(elem);
|
selectorManager.releaseSelector(elem);
|
||||||
selectedElements[i] = null;
|
});
|
||||||
}
|
selectedElements = [];
|
||||||
// selectedBBoxes[0] = null;
|
|
||||||
}
|
|
||||||
if (!noCall) {call('selected', selectedElements);}
|
if (!noCall) {call('selected', selectedElements);}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6310,6 +6327,7 @@ this.deleteSelectedElements = function() {
|
||||||
var batchCmd = new svgedit.history.BatchCommand('Delete Elements');
|
var batchCmd = new svgedit.history.BatchCommand('Delete Elements');
|
||||||
var len = selectedElements.length;
|
var len = selectedElements.length;
|
||||||
var selectedCopy = []; //selectedElements is being deleted
|
var selectedCopy = []; //selectedElements is being deleted
|
||||||
|
|
||||||
for (i = 0; i < len; ++i) {
|
for (i = 0; i < len; ++i) {
|
||||||
var selected = selectedElements[i];
|
var selected = selectedElements[i];
|
||||||
if (selected == null) {break;}
|
if (selected == null) {break;}
|
||||||
|
@ -6332,9 +6350,10 @@ this.deleteSelectedElements = function() {
|
||||||
var nextSibling = t.nextSibling;
|
var nextSibling = t.nextSibling;
|
||||||
var elem = parent.removeChild(t);
|
var elem = parent.removeChild(t);
|
||||||
selectedCopy.push(selected); //for the copy
|
selectedCopy.push(selected); //for the copy
|
||||||
selectedElements[i] = null;
|
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent));
|
batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent));
|
||||||
}
|
}
|
||||||
|
selectedElements = [];
|
||||||
|
|
||||||
if (!batchCmd.isEmpty()) {addCommandToHistory(batchCmd);}
|
if (!batchCmd.isEmpty()) {addCommandToHistory(batchCmd);}
|
||||||
call('changed', selectedCopy);
|
call('changed', selectedCopy);
|
||||||
clearSelection();
|
clearSelection();
|
||||||
|
@ -6343,65 +6362,60 @@ this.deleteSelectedElements = function() {
|
||||||
// Function: cutSelectedElements
|
// Function: cutSelectedElements
|
||||||
// Removes all selected elements from the DOM and adds the change to the
|
// Removes all selected elements from the DOM and adds the change to the
|
||||||
// history stack. Remembers removed elements on the clipboard
|
// history stack. Remembers removed elements on the clipboard
|
||||||
|
|
||||||
// TODO: Combine similar code with deleteSelectedElements
|
|
||||||
this.cutSelectedElements = function() {
|
this.cutSelectedElements = function() {
|
||||||
var i;
|
svgCanvas.copySelectedElements();
|
||||||
var batchCmd = new svgedit.history.BatchCommand('Cut Elements');
|
svgCanvas.deleteSelectedElements();
|
||||||
var len = selectedElements.length;
|
|
||||||
var selectedCopy = []; //selectedElements is being deleted
|
|
||||||
for (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);
|
|
||||||
|
|
||||||
// Remove the path if present.
|
|
||||||
svgedit.path.removePath_(t.id);
|
|
||||||
|
|
||||||
var nextSibling = t.nextSibling;
|
|
||||||
var elem = parent.removeChild(t);
|
|
||||||
selectedCopy.push(selected); //for the copy
|
|
||||||
selectedElements[i] = null;
|
|
||||||
batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent));
|
|
||||||
}
|
|
||||||
if (!batchCmd.isEmpty()) {addCommandToHistory(batchCmd);}
|
|
||||||
call('changed', selectedCopy);
|
|
||||||
clearSelection();
|
|
||||||
|
|
||||||
canvas.clipBoard = selectedCopy;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function: copySelectedElements
|
// Function: copySelectedElements
|
||||||
// Remembers the current selected elements on the clipboard
|
// Remembers the current selected elements on the clipboard
|
||||||
this.copySelectedElements = function() {
|
this.copySelectedElements = function() {
|
||||||
canvas.clipBoard = $.merge([], selectedElements);
|
localStorage.setItem('svgedit_clipboard', JSON.stringify(
|
||||||
|
selectedElements.map(function(x){ return getJsonFromSvgElement(x) })
|
||||||
|
));
|
||||||
|
|
||||||
|
$('#cmenu_canvas').enableContextMenuItems('#paste,#paste_in_place');
|
||||||
};
|
};
|
||||||
|
|
||||||
this.pasteElements = function(type, x, y) {
|
this.pasteElements = function(type, x, y) {
|
||||||
var cb = canvas.clipBoard;
|
var cb = JSON.parse(localStorage.getItem('svgedit_clipboard'));
|
||||||
var len = cb.length;
|
var len = cb.length;
|
||||||
if (!len) {return;}
|
if (!len) {return;}
|
||||||
|
|
||||||
var pasted = [];
|
var pasted = [];
|
||||||
var batchCmd = new svgedit.history.BatchCommand('Paste elements');
|
var batchCmd = new svgedit.history.BatchCommand('Paste elements');
|
||||||
var drawing = getCurrentDrawing();
|
var drawing = getCurrentDrawing();
|
||||||
|
var changedIDs = {};
|
||||||
|
|
||||||
|
// Recursively replace IDs and record the changes
|
||||||
|
function checkIDs(elem) {
|
||||||
|
if(elem.attr && elem.attr.id) {
|
||||||
|
changedIDs[elem.attr.id] = getNextId();
|
||||||
|
elem.attr.id = changedIDs[elem.attr.id];
|
||||||
|
}
|
||||||
|
if(elem.children) elem.children.forEach(checkIDs);
|
||||||
|
}
|
||||||
|
cb.forEach(checkIDs);
|
||||||
|
|
||||||
|
// Give extensions like the connector extension a chance to reflect new IDs and remove invalid elements
|
||||||
|
runExtensions('IDsUpdated', {elems: cb, changes: changedIDs}, true).forEach(function(extChanges){
|
||||||
|
if(!extChanges || !('remove' in extChanges)) return;
|
||||||
|
|
||||||
|
extChanges.remove.forEach(function(removeID){
|
||||||
|
cb = cb.filter(function(cbItem){
|
||||||
|
return cbItem.attr.id != removeID;
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// Move elements to lastClickPoint
|
// Move elements to lastClickPoint
|
||||||
while (len--) {
|
while (len--) {
|
||||||
var elem = cb[len];
|
var elem = cb[len];
|
||||||
if (!elem) {continue;}
|
if (!elem) {continue;}
|
||||||
var copy = drawing.copyElem(elem);
|
|
||||||
|
|
||||||
// See if elem with elem ID is in the DOM already
|
|
||||||
if (!svgedit.utilities.getElem(elem.id)) {copy.id = elem.id;}
|
|
||||||
|
|
||||||
|
var copy = addSvgElementFromJson(elem);
|
||||||
pasted.push(copy);
|
pasted.push(copy);
|
||||||
(current_group || drawing.getCurrentLayer()).appendChild(copy);
|
|
||||||
batchCmd.addSubCommand(new svgedit.history.InsertElementCommand(copy));
|
batchCmd.addSubCommand(new svgedit.history.InsertElementCommand(copy));
|
||||||
|
|
||||||
restoreRefElems(copy);
|
restoreRefElems(copy);
|
||||||
|
@ -6433,7 +6447,7 @@ this.pasteElements = function(type, x, y) {
|
||||||
});
|
});
|
||||||
|
|
||||||
var cmd = canvas.moveSelectedElements(dx, dy, false);
|
var cmd = canvas.moveSelectedElements(dx, dy, false);
|
||||||
batchCmd.addSubCommand(cmd);
|
if(cmd) batchCmd.addSubCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
addCommandToHistory(batchCmd);
|
addCommandToHistory(batchCmd);
|
||||||
|
|
|
@ -1191,8 +1191,9 @@ svgedit.utilities.copyElem = function(el, getNextId) {
|
||||||
var ref = $(el).data('symbol');
|
var ref = $(el).data('symbol');
|
||||||
$(new_el).data('ref', ref).data('symbol', ref);
|
$(new_el).data('ref', ref).data('symbol', ref);
|
||||||
} else if (new_el.tagName == 'image') {
|
} else if (new_el.tagName == 'image') {
|
||||||
preventClickDefault(new_el);
|
svgedit.utilities.preventClickDefault(new_el);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_el;
|
return new_el;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue