Fixed Layers in svgcanvas. Moved Layer class. New HistoryRecordingservice.

Canvas was referencing drawing.all_layers and drawing.current_layer.
Both variables now represent Layer instead of group element and should
be considered private.
Moved Layer class to layer.js
New HistoryRecordingService added to help with moving Layer code out of
Canvas. Started using it in Canvas.mergLayer
master
Flint O'Brien 2016-05-01 22:58:41 -04:00
parent ed16b0a8d1
commit 899853c963
8 changed files with 528 additions and 267 deletions

View File

@ -20,8 +20,6 @@ if (!svgedit.draw) {
}
// alias
var NS = svgedit.NS;
var LAYER_CLASS = svgedit.LAYER_CLASS;
var LAYER_CLASS_REGEX = svgedit.LAYER_CLASS_REGEX;
var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(',');
@ -32,147 +30,6 @@ var RandomizeModes = {
};
var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE;
/**
* Add class 'layer' to the element
*
* Parameters:
* @param {SVGGElement} elem - The SVG element to update
*/
function addLayerClass(elem) {
var classes = elem.getAttribute('class');
if (classes === null || classes === undefined || classes.length === 0) {
elem.setAttribute('class', LAYER_CLASS);
} else if (! LAYER_CLASS_REGEX.test(classes)) {
elem.setAttribute('class', classes + ' ' + LAYER_CLASS);
}
}
function createLayer(name, svgElem) {
if (!svgElem) {
return undefined;
}
var svgdoc = svgElem.ownerDocument;
var new_layer = svgdoc.createElementNS(NS.SVG, "g");
var layer_title = svgdoc.createElementNS(NS.SVG, "title");
layer_title.textContent = name;
new_layer.appendChild(layer_title);
svgElem.appendChild(new_layer);
return new_layer;
}
/**
* This class encapsulates the concept of a layer in the drawing. It can be constructed with
* an existing group element or, with three parameters, will create a new layer group element.
* @param {string} name - Layer name
* @param {SVGGElement} group - SVG group element that constitutes the layer or null if a group should be created and added to the DOM..
* @param {SVGGElement} svgElem - The SVG DOM element. If defined, use this to add
* a new layer to the document.
*/
var Layer = svgedit.draw.Layer = function(name, group, svgElem) {
this.name_ = name;
this.group_ = group || createLayer(name, svgElem);
addLayerClass(this.group_);
svgedit.utilities.walkTree(this.group_, function(e){e.setAttribute("style", "pointer-events:inherit");});
this.group_.setAttribute("style", svgElem ? "pointer-events:all" : "pointer-events:none");
};
/**
* Get the layer's name.
* @returns {string} The layer name
*/
Layer.prototype.getName = function() {
return this.name_;
};
/**
* Get the group element for this layer.
* @returns {SVGGElement} The layer SVG group
*/
Layer.prototype.getGroup = function() {
return this.group_;
};
/**
* Active this layer so it takes pointer events.
*/
Layer.prototype.activate = function() {
this.group_.setAttribute("style", "pointer-events:all");
};
/**
* Deactive this layer so it does NOT take pointer events.
*/
Layer.prototype.deactivate = function() {
this.group_.setAttribute("style", "pointer-events:none");
};
/**
* Set this layer visible or hidden based on 'visible' parameter.
* @param {boolean} visible - If true, make visible; otherwise, hide it.
*/
Layer.prototype.setVisible = function(visible) {
var expected = visible === undefined || visible ? "inline" : "none";
var oldDisplay = this.group_.getAttribute("display");
if (oldDisplay !== expected) {
this.group_.setAttribute("display", expected);
}
};
/**
* Is this layer visible?
* @returns {boolean} True if visible.
*/
Layer.prototype.isVisible = function() {
return this.group_.getAttribute('display') !== 'none';
};
/**
* Get layer opacity.
* @returns {number} Opacity value.
*/
Layer.prototype.getOpacity = function() {
var opacity = this.group_.getAttribute('opacity');
if (opacity === null || opacity === undefined) {
return 1;
}
return parseFloat(opacity);
};
/**
* Sets the opacity of this layer. If opacity is not a value between 0.0 and 1.0,
* nothing happens.
* @param {number} opacity - A float value in the range 0.0-1.0
*/
Layer.prototype.setOpacity = function(opacity) {
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
this.group_.setAttribute('opacity', opacity);
}
};
/**
* Append children to this layer.
* @param {SVGGElement} children - The children to append to this layer.
*/
Layer.prototype.appendChildren = function(children) {
for (var i = 0; i < children.length; ++i) {
this.group_.appendChild(children[i]);
}
};
/**
* Remove this layer's group from the DOM. No more functions on group can be called after this.
* @param {SVGGElement} children - The children to append to this layer.
* @returns {SVGGElement} The layer SVG group that was just removed.
*/
Layer.prototype.removeGroup = function() {
var parent = this.group_.parentNode;
var group = parent.removeChild(this.group_);
this.group_ = undefined;
return group;
};
@ -235,13 +92,17 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
* The z-ordered array of Layer objects. Each layer has a name
* and group element.
* The first layer is the one at the bottom of the rendering.
* @type {Layer[]}
* @type {Array.<Layer>}
*/
this.all_layers = [];
/**
* Map of all_layers by name.
* @type {Object.<string,Layer>}
*
* Note: Layers are ordered, but referenced externally by name; so, we need both container
* types depending on which function is called (i.e. all_layers and layer_map).
*
* @type {Object.<string, Layer>}
*/
this.layer_map = {};
@ -418,6 +279,15 @@ svgedit.draw.Drawing.prototype.getCurrentLayer = function() {
return this.current_layer ? this.current_layer.getGroup() : null;
};
/**
* Get a layer by name.
* @returns {SVGGElement} The SVGGElement representing the named layer or null.
*/
svgedit.draw.Drawing.prototype.getLayerByName = function(name) {
var layer = this.layer_map[name];
return layer ? layer.getGroup() : null;
};
/**
* Returns the name of the currently selected layer. If an error occurs, an empty string
* is returned.
@ -427,6 +297,107 @@ svgedit.draw.Drawing.prototype.getCurrentLayerName = function () {
return this.current_layer ? this.current_layer.getName() : '';
};
/**
* Set the current layer's name.
* @param {string} name - The new name.
* @returns {Object} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null.
*/
svgedit.draw.Drawing.prototype.setCurrentLayerName = function (name) {
return this.current_layer ? this.current_layer.setName(name) : null;
};
/**
* Set the current layer's position.
* @param {number} newpos - The zero-based index of the new position of the layer. Range should be 0 to layers-1
* @returns {Object} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null.
*/
svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) {
var layer_count = this.getNumLayers();
if (!this.current_layer || newpos < 0 || newpos >= layer_count) {
return null;
}
var oldpos;
for (oldpos = 0; oldpos < layer_count; ++oldpos) {
if (this.all_layers[oldpos] == this.current_layer) {break;}
}
// some unknown error condition (current_layer not in all_layers)
if (oldpos == layer_count) { return null; }
if (oldpos != newpos) {
// if our new position is below us, we need to insert before the node after newpos
var refGroup = null;
var current_group = this.current_layer.getGroup();
var oldNextSibling = current_group.nextSibling;
if (newpos > oldpos ) {
if (newpos < layer_count-1) {
refGroup = this.all_layers[newpos+1].getGroup();
}
}
// if our new position is above us, we need to insert before the node at newpos
else {
refGroup = this.all_layers[newpos].getGroup();
}
this.svgElem_.insertBefore(current_group, refGroup);
this.identifyLayers();
this.setCurrentLayer(this.getLayerName(newpos));
return {
currentGroup: current_group,
oldNextSibling: oldNextSibling
};
}
return null;
};
svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
var current_group = this.current_layer.getGroup();
var prevGroup = $(current_group).prev()[0];
if (!prevGroup) {return null;}
hrService.startBatchCommand('Merge Layer');
var layerNextSibling = current_group.nextSibling;
hrService.removeElement(current_group, layerNextSibling, this.svgElem_);
while (current_group.firstChild) {
var child = current_group.firstChild;
if (child.localName == 'title') {
hrService.removeElement(child, child.nextSibling, current_group);
current_group.removeChild(child);
continue;
}
var oldNextSibling = child.nextSibling;
prevGroup.appendChild(child);
hrService.moveElement(child, oldNextSibling, current_group);
}
// Remove current layer's group
this.current_layer.removeGroup();
// Remove the current layer and set the previous layer as the new current layer
var index = this.all_layers.indexOf(this.current_layer);
if (index > 0) {
var name = this.current_layer.getName();
this.current_layer = this.all_layers[index-1]
this.all_layers.splice(index, 1);
delete this.layer_map[name];
}
hrService.endBatchCommand();
};
svgedit.draw.Drawing.prototype.mergeAllLayers = function (hrService) {
// Set the current layer to the last layer.
this.current_layer = this.all_layers[this.all_layers.length-1];
hrService.startBatchCommand('Merge all Layers');
while (this.all_layers.length > 1) {
this.mergeLayer(hrService);
}
hrService.endBatchCommand();
};
/**
* Sets the current layer. If the name is not a valid layer name, then this
* function returns false. Otherwise it returns true. This is not an
@ -479,7 +450,7 @@ function findLayerNameInGroup(group) {
/**
* Given a set of names, return a new unique name.
* @param {string[]} existingLayerNames - Existing layer names.
* @param {Array.<string>} existingLayerNames - Existing layer names.
* @returns {string} - The new name.
*/
function getNewLayerName(existingLayerNames) {
@ -510,9 +481,9 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
var name = findLayerNameInGroup(child);
if (name) {
layernames.push(name);
layer = new Layer(name, child);
layer = new svgedit.draw.Layer(name, child);
this.all_layers.push(layer);
this.layer_map[ name] = layer;
this.layer_map[name] = layer;
} else {
// if group did not have a name, it is an orphan
orphans.push(child);
@ -526,10 +497,10 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
// If orphans or no layers found, create a new layer and add all the orphans to it
if (orphans.length > 0 || !childgroups) {
layer = new Layer(getNewLayerName(layernames), null, this.svgElem_);
layer = new svgedit.draw.Layer(getNewLayerName(layernames), null, this.svgElem_);
layer.appendChildren(orphans);
this.all_layers.push(layer);
this.layer_map[ name] = layer;
this.layer_map[name] = layer;
} else {
layer.activate();
}
@ -551,9 +522,9 @@ svgedit.draw.Drawing.prototype.createLayer = function(name) {
if (name === undefined || name === null || name === '' || this.layer_map[name]) {
name = getNewLayerName(Object.keys(this.layer_map));
}
var layer = new Layer(name, null, this.svgElem_);
var layer = new svgedit.draw.Layer(name, null, this.svgElem_);
this.all_layers.push(layer);
this.layer_map[ name] = layer;
this.layer_map[name] = layer;
this.current_layer = layer;
return layer.getGroup();
};

173
editor/historyrecording.js Normal file
View File

@ -0,0 +1,173 @@
/*globals svgedit*/
/*jslint vars: true, eqeq: true */
/**
* Package: svgedit.history
*
* Licensed under the MIT License
*
* Copyright(c) 2010 Alexis Deveria
* Copyright(c) 2010 Jeff Schiller
* Copyright(c) 2016 Flint O'Brien
*/
// Dependencies:
// 1) history.js
(function() {
'use strict';
if (!svgedit.history) {
svgedit.history = {};
}
var history = svgedit.history;
/**
* History recording service.
*
* A <strong>single</strong> service object that can be passed around to provide history
* recording. There is a simple start/end interface for batch commands.
* Easy to mock for unit tests. Built on top of history classes in history.js.
*
* HistoryRecordingService.NO_HISTORY is a singleton that can be passed in to functions
* that record history. This helps when the caller requires that no history be recorded.
*
* Usage:
* The following will record history: insert, batch, insert.
* ```
* hrService = new svgedit.history.HistoryRecordingService(this.undoMgr);
* hrService.insertElement(elem, text); // add simple command to history.
* hrService.startBatchCommand('create two elements');
* hrService.changeElement(elem, attrs, text); // add to batchCommand
* hrService.changeElement(elem, attrs2, text); // add to batchCommand
* hrService.endBatchCommand(); // add batch command with two change commands to history.
* hrService.insertElement(elem, text); // add simple command to history.
* ```
*
* Note that all functions return this, so commands can be chained, like so:
*
* ```
* hrService
* .startBatchCommand('create two elements')
* .insertElement(elem, text)
* .changeElement(elem, attrs, text)
* .endBatchCommand();
* ```
*
* @param {svgedit.history.UndoManager} undoManager - The undo manager.
* A value of null is valid for cases where no history recording is required.
* See singleton: HistoryRecordingService.NO_HISTORY
*/
var HistoryRecordingService = history.HistoryRecordingService = function(undoManager) {
this.undoManager = undoManager;
this.currentBatchCommand = null;
this.batchCommandStack = [];
};
/**
* @type {svgedit.history.HistoryRecordingService} NO_HISTORY - Singleton that can be passed
* in to functions that record history, but the caller requires that no history be recorded.
*/
HistoryRecordingService.NO_HISTORY = new HistoryRecordingService();
/**
* Start a batch command so multiple commands can recorded as a single history command.
* Requires a corresponding call to endBatchCommand. Start and end commands can be nested.
*
* @param {string} text - Optional string describing the batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.startBatchCommand = function(text) {
if (!this.undoManager) {return this;}
this.currentBatchCommand = new history.BatchCommand(text);
this.batchCommandStack.push(this.currentBatchCommand);
return this;
};
/**
* End a batch command and add it to the history or a parent batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.endBatchCommand = function() {
if (!this.undoManager) {return this;}
if (this.currentBatchCommand) {
var batchCommand = this.currentBatchCommand;
this.batchCommandStack.pop();
var length = this.batchCommandStack.length;
this.currentBatchCommand = length ? this.batchCommandStack[length-1] : null;
this._addCommand(batchCommand);
}
return this;
};
/**
* Add a MoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was moved
* @param {Element} oldNextSibling - The element's next sibling before it was moved
* @param {Element} oldParent - The element's parent before it was moved
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.moveElement = function(elem, oldNextSibling, oldParent, text) {
if (!this.undoManager) {return this;}
this._addCommand(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
};
/**
* Add an InsertElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was added
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.insertElement = function(elem, text) {
if (!this.undoManager) {return this;}
this._addCommand(new history.InsertElementCommand(elem, text));
return this;
};
/**
* Add a RemoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was removed
* @param {Element} oldNextSibling - The element's next sibling before it was removed
* @param {Element} oldParent - The element's parent before it was removed
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.removeElement = function(elem, oldNextSibling, oldParent, text) {
if (!this.undoManager) {return this;}
this._addCommand(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
};
/**
* Add a ChangeElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was changed
* @param {object} attrs - An object with the attributes to be changed and the values they had *before* the change
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.changeElement = function(elem, attrs, text) {
if (!this.undoManager) {return this;}
this._addCommand(new history.ChangeElementCommand(elem, attrs, text));
return this;
};
/**
* Private function to add a command to the history or current batch command.
* @param cmd
* @returns {svgedit.history.HistoryRecordingService}
* @private
*/
HistoryRecordingService.prototype._addCommand = function(cmd) {
if (!this.undoManager) {return this;}
if (this.currentBatchCommand) {
this.currentBatchCommand.addSubCommand(cmd);
} else {
this.undoManager.addCommandToHistory(cmd);
}
};
}());

200
editor/layer.js Normal file
View File

@ -0,0 +1,200 @@
/*globals svgedit*/
/*jslint vars: true, eqeq: true */
/**
* Package: svgedit.history
*
* Licensed under the MIT License
*
* Copyright(c) 2011 Jeff Schiller
* Copyright(c) 2016 Flint O'Brien
*/
// Dependencies:
// 1) svgedit.js
// 2) draw.js
(function() {
'use strict';
if (!svgedit.draw) {
svgedit.draw = {};
}
var NS = svgedit.NS;
/**
* This class encapsulates the concept of a layer in the drawing. It can be constructed with
* an existing group element or, with three parameters, will create a new layer group element.
* @param {string} name - Layer name
* @param {SVGGElement} group - SVG group element that constitutes the layer or null if a group should be created and added to the DOM..
* @param {SVGGElement} svgElem - The SVG DOM element. If defined, use this to add
* a new layer to the document.
*/
var Layer = svgedit.draw.Layer = function(name, group, svgElem) {
this.name_ = name;
this.group_ = group;
if (!group) {
// Create a group element with title and add it to the DOM.
var svgdoc = svgElem.ownerDocument;
this.group_ = svgdoc.createElementNS(NS.SVG, "g");
var layer_title = svgdoc.createElementNS(NS.SVG, "title");
layer_title.textContent = name;
this.group_.appendChild(layer_title);
svgElem.appendChild(this.group_);
}
addLayerClass(this.group_);
svgedit.utilities.walkTree(this.group_, function(e){e.setAttribute("style", "pointer-events:inherit");});
this.group_.setAttribute("style", svgElem ? "pointer-events:all" : "pointer-events:none");
};
/**
* @type {string} CLASS_NAME - class attribute assigned to all layer groups.
*/
Layer.CLASS_NAME = 'layer';
/**
* @type {RegExp} CLASS_REGEX - Used to test presence of class Layer.CLASS_NAME
*/
Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)');
/**
* Get the layer's name.
* @returns {string} The layer name
*/
Layer.prototype.getName = function() {
return this.name_;
};
/**
* Get the group element for this layer.
* @returns {SVGGElement} The layer SVG group
*/
Layer.prototype.getGroup = function() {
return this.group_;
};
/**
* Active this layer so it takes pointer events.
*/
Layer.prototype.activate = function() {
this.group_.setAttribute("style", "pointer-events:all");
};
/**
* Deactive this layer so it does NOT take pointer events.
*/
Layer.prototype.deactivate = function() {
this.group_.setAttribute("style", "pointer-events:none");
};
/**
* Set this layer visible or hidden based on 'visible' parameter.
* @param {boolean} visible - If true, make visible; otherwise, hide it.
*/
Layer.prototype.setVisible = function(visible) {
var expected = visible === undefined || visible ? "inline" : "none";
var oldDisplay = this.group_.getAttribute("display");
if (oldDisplay !== expected) {
this.group_.setAttribute("display", expected);
}
};
/**
* Is this layer visible?
* @returns {boolean} True if visible.
*/
Layer.prototype.isVisible = function() {
return this.group_.getAttribute('display') !== 'none';
};
/**
* Get layer opacity.
* @returns {number} Opacity value.
*/
Layer.prototype.getOpacity = function() {
var opacity = this.group_.getAttribute('opacity');
if (opacity === null || opacity === undefined) {
return 1;
}
return parseFloat(opacity);
};
/**
* Sets the opacity of this layer. If opacity is not a value between 0.0 and 1.0,
* nothing happens.
* @param {number} opacity - A float value in the range 0.0-1.0
*/
Layer.prototype.setOpacity = function(opacity) {
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
this.group_.setAttribute('opacity', opacity);
}
};
/**
* Append children to this layer.
* @param {SVGGElement} children - The children to append to this layer.
*/
Layer.prototype.appendChildren = function(children) {
for (var i = 0; i < children.length; ++i) {
this.group_.appendChild(children[i]);
}
};
Layer.prototype.getTitleElement = function() {
var len = this.group_.childNodes.length;
for (var i = 0; i < len; ++i) {
var child = this.group_.childNodes.item(i);
if (child && child.tagName === 'title') {
return child;
}
}
return null;
};
Layer.prototype.setName = function(name) {
var previousName = this.name_;
name = svgedit.utilities.toXml(name);
// now change the underlying title element contents
var title = this.getTitleElement();
if (title) {
while (title.firstChild) { title.removeChild(title.firstChild); }
title.textContent = name;
this.name_ = name;
return {title: title, previousName: previousName};
}
return null;
};
/**
* Remove this layer's group from the DOM. No more functions on group can be called after this.
* @param {SVGGElement} children - The children to append to this layer.
* @returns {SVGGElement} The layer SVG group that was just removed.
*/
Layer.prototype.removeGroup = function() {
var parent = this.group_.parentNode;
var group = parent.removeChild(this.group_);
this.group_ = undefined;
return group;
};
/**
* Add class Layer.CLASS_NAME to the element (usually class='layer').
*
* Parameters:
* @param {SVGGElement} elem - The SVG element to update
*/
function addLayerClass(elem) {
var classes = elem.getAttribute('class');
if (classes === null || classes === undefined || classes.length === 0) {
elem.setAttribute('class', Layer.CLASS_NAME);
} else if (! Layer.CLASS_REGEX.test(classes)) {
elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME);
}
}
}());

View File

@ -39,10 +39,12 @@
<script src="svgutils.js"></script>
<script src="sanitize.js"></script>
<script src="history.js"></script>
<script src="historyrecording.js"></script>
<script src="coords.js"></script>
<script src="recalculate.js"></script>
<script src="select.js"></script>
<script src="draw.js"></script>
<script src="layer.js"></script>
<script src="path.js"></script>
<script src="svgcanvas.js"></script>
<script src="svg-editor.js"></script>

View File

@ -1841,7 +1841,7 @@ TODOS
* @returns {boolean} True if the element is a layer
*/
function isLayer(elem) {
return elem && elem.tagName === 'g' && svgedit.LAYER_CLASS_REGEX.test(elem.getAttribute('class'))
return elem && elem.tagName === 'g' && svgedit.draw.Layer.CLASS_REGEX.test(elem.getAttribute('class'))
}
// called when any element has changed

View File

@ -5055,39 +5055,17 @@ this.setCurrentLayer = function(name) {
// Returns:
// true if the rename succeeded, false otherwise.
this.renameCurrentLayer = function(newname) {
var i;
var drawing = getCurrentDrawing();
if (drawing.current_layer) {
var oldLayer = drawing.current_layer;
// setCurrentLayer will return false if the name doesn't already exist
// this means we are free to rename our oldLayer
if (!canvas.setCurrentLayer(newname)) {
var layer = drawing.getCurrentLayer();
if (layer) {
var result = drawing.setCurrentLayerName( newname);
if (result) {
var batchCmd = new svgedit.history.BatchCommand('Rename Layer');
// find the index of the layer
for (i = 0; i < drawing.getNumLayers(); ++i) {
if (drawing.all_layers[i][1] == oldLayer) {break;}
}
var oldname = drawing.getLayerName(i);
drawing.all_layers[i][0] = svgedit.utilities.toXml(newname);
// now change the underlying title element contents
var len = oldLayer.childNodes.length;
for (i = 0; i < len; ++i) {
var child = oldLayer.childNodes.item(i);
// found the <title> element, now append all the
if (child && child.tagName == 'title') {
// wipe out old name
while (child.firstChild) { child.removeChild(child.firstChild); }
child.textContent = newname;
batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(child, {'#text':oldname}));
addCommandToHistory(batchCmd);
call('changed', [oldLayer]);
return true;
}
}
batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(result.title, {'#text':result.previousName}));
addCommandToHistory(batchCmd);
call('changed', [layer]);
return true;
}
drawing.current_layer = oldLayer;
}
return false;
};
@ -5105,36 +5083,11 @@ this.renameCurrentLayer = function(newname) {
// true if the current layer position was changed, false otherwise.
this.setCurrentLayerPosition = function(newpos) {
var oldpos, drawing = getCurrentDrawing();
if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) {
for (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)
if (oldpos == drawing.getNumLayers()) { return false; }
if (oldpos != newpos) {
// if our new position is below us, we need to insert before the node after newpos
var refLayer = null;
var oldNextSibling = drawing.current_layer.nextSibling;
if (newpos > oldpos ) {
if (newpos < drawing.getNumLayers()-1) {
refLayer = drawing.all_layers[newpos+1][1];
}
}
// if our new position is above us, we need to insert before the node at newpos
else {
refLayer = drawing.all_layers[newpos][1];
}
svgcontent.insertBefore(drawing.current_layer, refLayer);
addCommandToHistory(new svgedit.history.MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent));
identifyLayers();
canvas.setCurrentLayer(drawing.getLayerName(newpos));
return true;
}
var result = drawing.setCurrentLayerPosition(newpos);
if (result) {
addCommandToHistory(new svgedit.history.MoveElementCommand(result.currentGroup, result.oldNextSibling, svgcontent));
return true;
}
return false;
};
@ -5179,14 +5132,8 @@ this.setLayerVisibility = function(layername, bVisible) {
this.moveSelectedToLayer = function(layername) {
// find the layer
var i;
var layer = null;
var drawing = getCurrentDrawing();
for (i = 0; i < drawing.getNumLayers(); ++i) {
if (drawing.getLayerName(i) == layername) {
layer = drawing.all_layers[i][1];
break;
}
}
var layer = drawing.getLayerByName(layername);
if (!layer) {return false;}
var batchCmd = new svgedit.history.BatchCommand('Move Elements to Layer');
@ -5209,57 +5156,25 @@ this.moveSelectedToLayer = function(layername) {
return true;
};
this.mergeLayer = function(skipHistory) {
var batchCmd = new svgedit.history.BatchCommand('Merge Layer');
var drawing = getCurrentDrawing();
var prev = $(drawing.current_layer).prev()[0];
if (!prev) {return;}
var childs = drawing.current_layer.childNodes;
var len = childs.length;
var layerNextSibling = drawing.current_layer.nextSibling;
batchCmd.addSubCommand(new svgedit.history.RemoveElementCommand(drawing.current_layer, layerNextSibling, svgcontent));
while (drawing.current_layer.firstChild) {
var ch = drawing.current_layer.firstChild;
if (ch.localName == 'title') {
var chNextSibling = ch.nextSibling;
batchCmd.addSubCommand(new svgedit.history.RemoveElementCommand(ch, chNextSibling, drawing.current_layer));
drawing.current_layer.removeChild(ch);
continue;
}
var oldNextSibling = ch.nextSibling;
prev.appendChild(ch);
batchCmd.addSubCommand(new svgedit.history.MoveElementCommand(ch, oldNextSibling, drawing.current_layer));
this.mergeLayer = function(hrService) {
if (!hrService) {
hrService = new svgedit.history.HistoryRecordingService(this.undoMgr);
}
// Remove current layer
svgcontent.removeChild(drawing.current_layer);
if (!skipHistory) {
clearSelection();
identifyLayers();
call('changed', [svgcontent]);
addCommandToHistory(batchCmd);
}
drawing.current_layer = prev;
return batchCmd;
getCurrentDrawing().mergeLayer(hrService);
clearSelection();
leaveContext();
call('changed', [svgcontent]);
};
this.mergeAllLayers = function() {
var batchCmd = new svgedit.history.BatchCommand('Merge all Layers');
var drawing = getCurrentDrawing();
drawing.current_layer = drawing.all_layers[drawing.getNumLayers()-1][1];
while ($(svgcontent).children('g').length > 1) {
batchCmd.addSubCommand(canvas.mergeLayer(true));
this.mergeAllLayers = function(hrService) {
if (!hrService) {
hrService = new svgedit.history.HistoryRecordingService(this.undoMgr);
}
getCurrentDrawing().mergeAllLayers(hrService);
clearSelection();
identifyLayers();
leaveContext();
call('changed', [svgcontent]);
addCommandToHistory(batchCmd);
};
// Function: leaveContext

View File

@ -15,10 +15,8 @@ svgedit = {
XLINK: 'http://www.w3.org/1999/xlink',
XML: 'http://www.w3.org/XML/1998/namespace',
XMLNS: 'http://www.w3.org/2000/xmlns/' // see http://www.w3.org/TR/REC-xml-names/#xmlReserved
},
LAYER_CLASS: 'layer'
}
};
svgedit.LAYER_CLASS_REGEX = new RegExp('(\\s|^)' + svgedit.LAYER_CLASS + '(\\s|$)');
// return the svgedit.NS with key values switched and lowercase
svgedit.getReverseNS = function() {'use strict';

View File

@ -6,9 +6,11 @@
<link rel='stylesheet' href='qunit/qunit.css' type='text/css'/>
<script src='../editor/jquery.js'></script>
<script src='../editor/svgedit.js'></script>
<script src='../editor/pathseg.js'></script>
<script src='../editor/browser.js'></script>
<script src='../editor/svgutils.js'></script>
<script src='../editor/draw.js'></script>
<script src='../editor/layer.js'></script>
<script src='qunit/qunit.js'></script>
<script>
$(function() {
@ -19,7 +21,7 @@
}
};
var NS = svgedit.NS;
var LAYER_CLASS = svgedit.LAYER_CLASS;
var LAYER_CLASS = svgedit.draw.Layer.CLASS_NAME;
var NONCE = 'foo';
var LAYER1 = 'Layer 1';
var LAYER2 = 'Layer 2';