Update layers panel on programatic call to createLayer.

Add class=“layer” to each layer element. This happens when calling
createLayer() or any call to identifyLayers(). This happens with new
drawings and when opening legacy drawings, so it’s fully backwards
compatible.
svg-editor.js elementChanged() looks for g.layer as an addition test
for calling populateLayers() which updates the layers panel.
Addition tests for class=“layer” added to draw_test.html.
Fixed Firefox exception in draw_test.html.
master
Flint O'Brien 2016-04-29 16:13:35 -04:00
parent 3ef423e30a
commit ebcf3d9c47
4 changed files with 77 additions and 21 deletions

View File

@ -20,6 +20,8 @@ if (!svgedit.draw) {
} }
// alias // alias
var NS = svgedit.NS; 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(','); var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(',');
@ -30,6 +32,21 @@ var RandomizeModes = {
}; };
var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE; 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);
}
}
/** /**
* This class encapsulates the concept of a layer in the drawing * This class encapsulates the concept of a layer in the drawing
* @param {String} name - Layer name * @param {String} name - Layer name
@ -386,6 +403,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
a_layer = child; a_layer = child;
svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");});
a_layer.setAttribute("style", "pointer-events:none"); a_layer.setAttribute("style", "pointer-events:none");
addLayerClass(a_layer)
} }
// if group did not have a name, it is an orphan // if group did not have a name, it is an orphan
else { else {
@ -407,15 +425,11 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
// TODO(codedread): What about internationalization of "Layer"? // TODO(codedread): What about internationalization of "Layer"?
while (layernames.indexOf(("Layer " + i)) >= 0) { i++; } while (layernames.indexOf(("Layer " + i)) >= 0) { i++; }
var newname = "Layer " + i; var newname = "Layer " + i;
a_layer = svgdoc.createElementNS(NS.SVG, "g"); a_layer = this._doCreateLayer(newname);
var layer_title = svgdoc.createElementNS(NS.SVG, "title");
layer_title.textContent = newname;
a_layer.appendChild(layer_title);
var j; var j;
for (j = 0; j < orphans.length; ++j) { for (j = 0; j < orphans.length; ++j) {
a_layer.appendChild(orphans[j]); a_layer.appendChild(orphans[j]);
} }
this.svgElem_.appendChild(a_layer);
this.all_layers.push([newname, a_layer] ); this.all_layers.push([newname, a_layer] );
} }
svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style", "pointer-events:inherit");}); svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style", "pointer-events:inherit");});
@ -423,6 +437,24 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
this.current_layer.setAttribute("style", "pointer-events:all"); this.current_layer.setAttribute("style", "pointer-events:all");
}; };
/**
* Private function that actually creates a new top-level layer in the drawing
* with the given name and sets the current layer to it.
* @param {string} name - The given name
* @returns {SVGGElement} The SVGGElement of the new layer, which is
* also the current layer of this drawing.
*/
svgedit.draw.Drawing.prototype._doCreateLayer = function(name) {
var svgdoc = this.svgElem_.ownerDocument;
var new_layer = svgdoc.createElementNS(NS.SVG, "g");
addLayerClass(new_layer);
var layer_title = svgdoc.createElementNS(NS.SVG, "title");
layer_title.textContent = name;
new_layer.appendChild(layer_title);
this.svgElem_.appendChild(new_layer);
return new_layer;
};
/** /**
* Creates a new top-level layer in the drawing with the given name and * Creates a new top-level layer in the drawing with the given name and
* sets the current layer to it. * sets the current layer to it.
@ -431,12 +463,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
* also the current layer of this drawing. * also the current layer of this drawing.
*/ */
svgedit.draw.Drawing.prototype.createLayer = function(name) { svgedit.draw.Drawing.prototype.createLayer = function(name) {
var svgdoc = this.svgElem_.ownerDocument; var new_layer = this._doCreateLayer(name);
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);
this.svgElem_.appendChild(new_layer);
this.identifyLayers(); this.identifyLayers();
return new_layer; return new_layer;
}; };

View File

@ -1835,6 +1835,15 @@ TODOS
}); });
}; };
/**
* Test whether an element is a layer or not.
* @param {SVGGElement} elem - The SVGGElement to test.
* @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'))
}
// called when any element has changed // called when any element has changed
var elementChanged = function(win, elems) { var elementChanged = function(win, elems) {
var i, var i,
@ -1846,11 +1855,14 @@ TODOS
for (i = 0; i < elems.length; ++i) { for (i = 0; i < elems.length; ++i) {
var elem = elems[i]; var elem = elems[i];
// if the element changed was the svg, then it could be a resolution change var isSvgElem = (elem && elem.tagName === 'svg');
if (elem && elem.tagName === 'svg') { if (isSvgElem || isLayer(elem)) {
populateLayers(); populateLayers();
// if the element changed was the svg, then it could be a resolution change
if (isSvgElem) {
updateCanvas(); updateCanvas();
} }
}
// Update selectedElement if element is no longer part of the image. // Update selectedElement if element is no longer part of the image.
// This occurs for the text elements in Firefox // This occurs for the text elements in Firefox
else if (elem && selectedElement && selectedElement.parentNode == null) { else if (elem && selectedElement && selectedElement.parentNode == null) {

View File

@ -15,8 +15,10 @@ svgedit = {
XLINK: 'http://www.w3.org/1999/xlink', XLINK: 'http://www.w3.org/1999/xlink',
XML: 'http://www.w3.org/XML/1998/namespace', 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 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 // return the svgedit.NS with key values switched and lowercase
svgedit.getReverseNS = function() {'use strict'; svgedit.getReverseNS = function() {'use strict';

View File

@ -19,12 +19,16 @@
} }
}; };
var NS = svgedit.NS; var NS = svgedit.NS;
var LAYER_CLASS = svgedit.LAYER_CLASS;
var NONCE = 'foo'; var NONCE = 'foo';
var LAYER1 = 'Layer 1'; var LAYER1 = 'Layer 1';
var LAYER2 = 'Layer 2'; var LAYER2 = 'Layer 2';
var LAYER3 = 'Layer 3'; var LAYER3 = 'Layer 3';
var svg = document.createElementNS(NS.SVG, 'svg'); var svg = document.createElementNS(NS.SVG, 'svg');
var sandbox = document.getElementById('sandbox');
// Firefox throws exception in getBBox() when svg is not attached to DOM.
sandbox.appendChild(svg);
// Set up <svg> with nonce. // Set up <svg> with nonce.
var svg_n = document.createElementNS(NS.SVG, 'svg'); var svg_n = document.createElementNS(NS.SVG, 'svg');
@ -244,7 +248,7 @@
}); });
test('Test identifyLayers() with empty document', function() { test('Test identifyLayers() with empty document', function() {
expect(9); expect(10);
var drawing = new svgedit.draw.Drawing(svg); var drawing = new svgedit.draw.Drawing(svg);
// By default, an empty document gets an empty group created. // By default, an empty document gets an empty group created.
@ -260,6 +264,7 @@
ok(empty_layer); ok(empty_layer);
equals(empty_layer, drawing.getSvgElem().firstChild); equals(empty_layer, drawing.getSvgElem().firstChild);
equals(empty_layer.tagName, 'g'); equals(empty_layer.tagName, 'g');
equals(empty_layer.getAttribute('class'), LAYER_CLASS);
ok(empty_layer.hasChildNodes()); ok(empty_layer.hasChildNodes());
equals(empty_layer.childNodes.length, 1); equals(empty_layer.childNodes.length, 1);
var firstChild = empty_layer.childNodes.item(0); var firstChild = empty_layer.childNodes.item(0);
@ -269,7 +274,7 @@
}); });
test('Test identifyLayers() with some layers', function() { test('Test identifyLayers() with some layers', function() {
expect(5); expect(8);
var drawing = new svgedit.draw.Drawing(svg); var drawing = new svgedit.draw.Drawing(svg);
setupSvgWith3Layers(svg); setupSvgWith3Layers(svg);
@ -283,11 +288,15 @@
equals(drawing.all_layers[1][1], svg.childNodes.item(1)); equals(drawing.all_layers[1][1], svg.childNodes.item(1));
equals(drawing.all_layers[2][1], svg.childNodes.item(2)); equals(drawing.all_layers[2][1], svg.childNodes.item(2));
equals(drawing.all_layers[0][1].getAttribute('class'), LAYER_CLASS);
equals(drawing.all_layers[1][1].getAttribute('class'), LAYER_CLASS);
equals(drawing.all_layers[2][1].getAttribute('class'), LAYER_CLASS);
cleanupSvg(svg); cleanupSvg(svg);
}); });
test('Test identifyLayers() with some layers and orphans', function() { test('Test identifyLayers() with some layers and orphans', function() {
expect(10); expect(14);
setupSvgWith3Layers(svg); setupSvgWith3Layers(svg);
@ -307,6 +316,11 @@
equals(drawing.all_layers[2][1], svg.childNodes.item(2)); equals(drawing.all_layers[2][1], svg.childNodes.item(2));
equals(drawing.all_layers[3][1], svg.childNodes.item(3)); equals(drawing.all_layers[3][1], svg.childNodes.item(3));
equals(drawing.all_layers[0][1].getAttribute('class'), LAYER_CLASS);
equals(drawing.all_layers[1][1].getAttribute('class'), LAYER_CLASS);
equals(drawing.all_layers[2][1].getAttribute('class'), LAYER_CLASS);
equals(drawing.all_layers[3][1].getAttribute('class'), LAYER_CLASS);
var layer4 = drawing.all_layers[3][1]; var layer4 = drawing.all_layers[3][1];
equals(layer4.tagName, 'g'); equals(layer4.tagName, 'g');
equals(layer4.childNodes.length, 3); equals(layer4.childNodes.length, 3);
@ -367,7 +381,7 @@
}); });
test('Test createLayer()', function() { test('Test createLayer()', function() {
expect(6); expect(7);
var drawing = new svgedit.draw.Drawing(svg); var drawing = new svgedit.draw.Drawing(svg);
setupSvgWith3Layers(svg); setupSvgWith3Layers(svg);
@ -380,6 +394,7 @@
var layer_g = drawing.createLayer(NEW_LAYER_NAME); var layer_g = drawing.createLayer(NEW_LAYER_NAME);
equals(4, drawing.getNumLayers()); equals(4, drawing.getNumLayers());
equals(layer_g, drawing.getCurrentLayer()); equals(layer_g, drawing.getCurrentLayer());
equals(layer_g.getAttribute('class'), LAYER_CLASS);
equals(NEW_LAYER_NAME, drawing.getCurrentLayerName()); equals(NEW_LAYER_NAME, drawing.getCurrentLayerName());
equals(NEW_LAYER_NAME, drawing.getLayerName(3)); equals(NEW_LAYER_NAME, drawing.getLayerName(3));
@ -530,6 +545,6 @@
<h2 id='qunit-banner'></h2> <h2 id='qunit-banner'></h2>
<h2 id='qunit-userAgent'></h2> <h2 id='qunit-userAgent'></h2>
<ol id='qunit-tests'></ol> <ol id='qunit-tests'></ol>
<div id='anchor' style='visibility:hidden'></div> <div id='sandbox' style='visibility:hidden'></div>
</body> </body>
</html> </html>