diff --git a/editor/draw.js b/editor/draw.js index 30b954f5..07eb8f6e 100644 --- a/editor/draw.js +++ b/editor/draw.js @@ -8,6 +8,8 @@ // Dependencies: // 1) jQuery +// 2) browser.js +// 3) svgutils.js (function() { if (!window.svgedit) { @@ -181,5 +183,69 @@ svgedit.draw.Drawing.prototype.hasLayer = function(name) { return false; }; +// Function: svgedit.draw.Drawing.identifyLayers +// Updates layer system +svgedit.draw.Drawing.prototype.identifyLayers = function() { + this.all_layers = []; + var numchildren = this.svgElem_.childNodes.length; + // loop through all children of SVG element + var orphans = [], layernames = []; + var current_layer = null; + var childgroups = false; + for (var i = 0; i < numchildren; ++i) { + var child = this.svgElem_.childNodes.item(i); + // for each g, find its layer name + if (child && child.nodeType == 1) { + if (child.tagName == "g") { + childgroups = true; + var name = $("title",child).text(); + + // Hack for Opera 10.60 + if(!name && svgedit.browser.isOpera() && child.querySelectorAll) { + name = $(child.querySelectorAll('title')).text(); + } + + // store layer and name in global variable + if (name) { + layernames.push(name); + this.all_layers.push( [name,child] ); + current_layer = child; + svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); + current_layer.setAttribute("style", "pointer-events:none"); + } + // if group did not have a name, it is an orphan + else { + orphans.push(child); + } + } + // if child has a bbox (i.e. not a or <defs> element), then it is an orphan + else if(svgedit.utilities.getBBox(child) && child.nodeName != 'defs') { // Opera returns a BBox for defs + var bb = svgedit.utilities.getBBox(child); + orphans.push(child); + } + } + } + + // create a new layer and add all the orphans to it + var svgdoc = this.svgElem_.ownerDocument; + if (orphans.length > 0 || !childgroups) { + var i = 1; + // TODO(codedread): What about internationalization of "Layer"? + while (layernames.indexOf(("Layer " + i)) >= 0) { i++; } + var newname = "Layer " + i; + current_layer = svgdoc.createElementNS(svg_ns, "g"); + var layer_title = svgdoc.createElementNS(svg_ns, "title"); + layer_title.textContent = newname; + current_layer.appendChild(layer_title); + for (var j = 0; j < orphans.length; ++j) { + current_layer.appendChild(orphans[j]); + } + this.svgElem_.appendChild(current_layer); + this.all_layers.push( [newname, current_layer] ); + } + svgedit.utilities.walkTree(current_layer, function(e){e.setAttribute("style","pointer-events:inherit");}); + current_layer.setAttribute("style","pointer-events:all"); +}; + })(); diff --git a/editor/svgcanvas.js b/editor/svgcanvas.js index e18ac81b..59d70eaf 100644 --- a/editor/svgcanvas.js +++ b/editor/svgcanvas.js @@ -6953,64 +6953,11 @@ this.importSvgString = function(xmlString) { // Function: identifyLayers // Updates layer system +// TODO(codedread): Remove this completely once current_context and current_layer are part of Drawing. var identifyLayers = canvas.identifyLayers = function() { - current_drawing.all_layers = []; leaveContext(); - var numchildren = svgcontent.childNodes.length; - // loop through all children of svgcontent - var orphans = [], layernames = []; - var childgroups = false; - for (var i = 0; i < numchildren; ++i) { - var child = svgcontent.childNodes.item(i); - // for each g, find its layer name - if (child && child.nodeType == 1) { - if (child.tagName == "g") { - childgroups = true; - var name = $("title",child).text(); - - // Hack for Opera 10.60 - if(!name && svgedit.browser.isOpera() && child.querySelectorAll) { - name = $(child.querySelectorAll('title')).text(); - } - - // store layer and name in global variable - if (name) { - layernames.push(name); - current_drawing.all_layers.push( [name,child] ); - current_layer = child; - svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); - current_layer.setAttribute("style", "pointer-events:none"); - } - // if group did not have a name, it is an orphan - else { - orphans.push(child); - } - } - // if child has a bbox (i.e. not a <title> or <defs> element), then it is an orphan - else if(getBBox(child) && child.nodeName != 'defs') { // Opera returns a BBox for defs - var bb = getBBox(child); - orphans.push(child); - } - } - } - - // create a new layer and add all the orphans to it - if (orphans.length > 0 || !childgroups) { - var i = 1; - while (layernames.indexOf(("Layer " + i)) >= 0) { i++; } - var newname = "Layer " + i; - current_layer = svgdoc.createElementNS(svgns, "g"); - var layer_title = svgdoc.createElementNS(svgns, "title"); - layer_title.textContent = newname; - current_layer.appendChild(layer_title); - for (var j = 0; j < orphans.length; ++j) { - current_layer.appendChild(orphans[j]); - } - current_layer = svgcontent.appendChild(current_layer); - current_drawing.all_layers.push( [newname, current_layer] ); - } - svgedit.utilities.walkTree(current_layer, function(e){e.setAttribute("style","pointer-events:inherit");}); - current_layer.setAttribute("style","pointer-events:all"); + current_drawing.identifyLayers(); + current_layer = current_drawing.all_layers[current_drawing.getNumLayers() - 1][1]; }; // Function: createLayer diff --git a/editor/svgutils.js b/editor/svgutils.js index 75ad60ae..434fc422 100644 --- a/editor/svgutils.js +++ b/editor/svgutils.js @@ -9,9 +9,8 @@ // Dependencies: // 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js -// 4) math.js +// 2) browser.js: only for getBBox() +// 3) svgtransformlist.js: only for getRotationAngle() (function() { diff --git a/test/draw_test.html b/test/draw_test.html index e8784405..84bc3a2b 100644 --- a/test/draw_test.html +++ b/test/draw_test.html @@ -2,7 +2,9 @@ <html> <head> <link rel='stylesheet' href='qunit/qunit.css' type='text/css'/> - <script src='../editor/jquery.js'></script> + <script type='text/javascript' src='../editor/jquery.js'></script> + <script type='text/javascript' src='../editor/browser.js'></script> + <script type='text/javascript' src='../editor/svgutils.js'></script> <script type='text/javascript' src='../editor/draw.js'></script> <script type='text/javascript' src='qunit/qunit.js'></script> <script type='text/javascript'> @@ -151,7 +153,7 @@ equals(doc.getNextId(), prefix+"3"); equals(doc.getId(), prefix+"3"); - while(svg_n.firstChild) {svg_n.removeChild(svg.firstChild);} + while(svg_n.firstChild) {svg_n.removeChild(svg_n.firstChild);} }); test('Test releaseId()', function() { @@ -187,6 +189,105 @@ ok(!doc.hasLayer('invalid-layer')); // TODO(codedread): More here once identifyLayers works. }); + + test('Test identifyLayers() with empty document', function() { + expect(9); + + var drawing = new svgedit.draw.Drawing(svg); + + // By default, an empty document gets an empty group created. + drawing.identifyLayers(); + + // Check that <svg> element now has one child node + ok(drawing.getSvgElem().hasChildNodes()); + equals(drawing.getSvgElem().childNodes.length, 1); + + // Check that all_layers is correctly set up. + equals(drawing.getNumLayers(), 1); + var empty_layer = drawing.all_layers[0][1]; + ok(empty_layer); + equals(empty_layer, drawing.getSvgElem().firstChild); + equals(empty_layer.tagName, 'g'); + ok(empty_layer.hasChildNodes()); + equals(empty_layer.childNodes.length, 1); + var firstChild = empty_layer.childNodes.item(0); + equals(firstChild.tagName, 'title'); + + while(svg.firstChild) {svg.removeChild(svg.firstChild);} + }); + + test('Test identifyLayers() with some layers', function() { + expect(5); + + var layer1 = document.createElementNS(SVGNS, 'g'); + var layer1_title = document.createElementNS(SVGNS, 'title'); + layer1_title.appendChild(document.createTextNode('Layer 1')); + layer1.appendChild(layer1_title); + + var layer2 = document.createElementNS(SVGNS, 'g'); + var layer2_title = document.createElementNS(SVGNS, 'title'); + layer2_title.appendChild(document.createTextNode('Layer 2')); + layer2.appendChild(layer2_title); + + var layer3 = document.createElementNS(SVGNS, 'g'); + var layer3_title = document.createElementNS(SVGNS, 'title'); + layer3_title.appendChild(document.createTextNode('Layer 3')); + layer3.appendChild(layer3_title); + + svg.appendChild(layer1); + svg.appendChild(layer2); + svg.appendChild(layer3); + equals(svg.childNodes.length, 3); + + var drawing = new svgedit.draw.Drawing(svg); + drawing.identifyLayers(); + + equals(drawing.getNumLayers(), 3); + equals(drawing.all_layers[0][1], svg.childNodes.item(0)); + equals(drawing.all_layers[1][1], svg.childNodes.item(1)); + equals(drawing.all_layers[2][1], svg.childNodes.item(2)); + + while(svg.firstChild) {svg.removeChild(svg.firstChild);} + }); + + test('Test identifyLayers() with some layers and orphans', function() { + expect(9); + + var layer1 = document.createElementNS(SVGNS, 'g'); + var layer1_title = document.createElementNS(SVGNS, 'title'); + layer1_title.appendChild(document.createTextNode('Layer 1')); + layer1.appendChild(layer1_title); + svg.appendChild(layer1); + + var layer2 = document.createElementNS(SVGNS, 'g'); + var layer2_title = document.createElementNS(SVGNS, 'title'); + layer2_title.appendChild(document.createTextNode('Layer 2')); + layer2.appendChild(layer2_title); + svg.appendChild(layer2); + + var orphan1 = document.createElementNS(SVGNS, 'rect'); + var orphan2 = document.createElementNS(SVGNS, 'rect'); + svg.appendChild(orphan1); + svg.appendChild(orphan2); + + equals(svg.childNodes.length, 4); + + var drawing = new svgedit.draw.Drawing(svg); + drawing.identifyLayers(); + + equals(drawing.getNumLayers(), 3); + equals(drawing.all_layers[0][1], svg.childNodes.item(0)); + equals(drawing.all_layers[1][1], svg.childNodes.item(1)); + equals(drawing.all_layers[2][1], svg.childNodes.item(2)); + var layer3 = drawing.all_layers[2][1]; + equals(layer3.tagName, 'g'); + equals(layer3.childNodes.length, 3); + equals(layer3.childNodes.item(1), orphan1); + equals(layer3.childNodes.item(2), orphan2); + + while(svg.firstChild) {svg.removeChild(svg.firstChild);} + }); + }); </script> </head>