From 2dfb852727f3924607a9f1c06f3e6083fab03a7e Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Thu, 18 Feb 2010 10:12:44 -0600 Subject: [PATCH] Fix connectors to work with foreignObject Alexis got this working on SVG-Edit trunk. --- .../editor/extensions/ext-connector.js | 85 +++++++------------ .../editor/extensions/ext-foreignobject.js | 1 - public/svg-edit/editor/svg-editor.html | 1 - public/svg-edit/editor/svgcanvas.js | 83 ++++++++++++------ public/svg-edit/test/test1.html | 9 +- 5 files changed, 95 insertions(+), 84 deletions(-) diff --git a/public/svg-edit/editor/extensions/ext-connector.js b/public/svg-edit/editor/extensions/ext-connector.js index a0e050e7..f64b6610 100644 --- a/public/svg-edit/editor/extensions/ext-connector.js +++ b/public/svg-edit/editor/extensions/ext-connector.js @@ -74,70 +74,44 @@ $(function() { } function findConnectors() { - // Check if selected elements have connections var elems = selElems; - var i = elems.length; var connectors = $(svgcontent).find(conn_sel); - if(!connectors.length) return; connections = []; - var sel = ':not(a,g,svg,'+conn_sel+')'; - var all_els = []; - // Get children from groups - - while(i--) { - var elem = elems[i]; - if(!elem) continue; - // Get all children that cannot contain children - var solid_elems = $(elem).find(sel); - // Include self if okay - if($(elem).filter(sel).length) { - solid_elems.push(elem); - } - $.merge(all_els, solid_elems); - } - - i = all_els.length; - - if(i > 1) { - // Multiselected, so unselect connector - svgCanvas.removeFromSelection($(conn_sel).toArray()); - } - - // Loop through selected elements - while(i--) { - var elem = all_els[i]; - if(!elem) continue; - - // Element was deleted, so delete connector - var was_deleted = !elem.parentNode; - - // Skip connector - if($(elem).data('c_start')) continue; - // Loop through connectors to see if one is connected to the element connectors.each(function() { var start = $(this).data("c_start"); var end = $(this).data("c_end"); - // Connector found for this element - if(start == elem.id || end == elem.id) { - - if(was_deleted) { - $(this).remove(); - return; + var parts = [getElem(start), getElem(end)]; + for(var i=0; i<2; i++) { + var c_elem = parts[i]; + var add_this = false; + // The connected element might be part of a selected group + $(c_elem).parents().each(function() { + if($.inArray(this, elems) !== -1) { + // Pretend this element is selected + add_this = true; } - var bb = svgCanvas.getStrokedBBox([elem]); + }); + + if(!c_elem || !c_elem.parentNode) { + $(this).remove(); + continue; + } + + if($.inArray(c_elem, elems) !== -1 || add_this) { + var bb = svgCanvas.getStrokedBBox([c_elem]); connections.push({ - elem: elem, + elem: c_elem, connector: this, - is_start: start == elem.id, + is_start: (i === 0), start_x: bb.x, start_y: bb.y }); } - }); } + }); } function updateConnectors() { @@ -300,7 +274,6 @@ $(function() { }, mouseDown: function(opts) { var e = opts.event; - start_x = opts.start_x, start_y = opts.start_y; var mode = svgCanvas.getMode(); @@ -316,7 +289,9 @@ $(function() { if($.inArray(svgcontent, parents) != -1) { // Connectable element - start_elem = mouse_target; + // If child of foreignObject, use parent + var fo = $(mouse_target).closest("foreignObject"); + start_elem = fo.length ? fo[0] : mouse_target; // Get center of source element var bb = svgCanvas.getStrokedBBox([start_elem]); @@ -422,10 +397,13 @@ $(function() { var zoom = svgCanvas.getZoom(); var e = opts.event, x = opts.mouse_x/zoom, - y = opts.mouse_y/zoom; + y = opts.mouse_y/zoom, + mouse_target = e.target; if(svgCanvas.getMode() == "connector") { - if(e.target.parentNode.parentNode != svgcontent) { + var fo = $(mouse_target).closest("foreignObject"); + if(fo.length) mouse_target = fo[0]; + if(mouse_target.parentNode.parentNode != svgcontent) { // Not a valid target element, so remove line $(cur_line).remove(); started = false; @@ -434,7 +412,7 @@ $(function() { element: null, started: started } - } else if(e.target == start_elem) { + } else if(mouse_target == start_elem) { // Start line through click started = true; return { @@ -444,7 +422,8 @@ $(function() { } } else { // Valid end element - end_elem = e.target; + end_elem = mouse_target; + var start_id = start_elem.id, end_id = end_elem.id; var conn_str = start_id + " " + end_id; var alt_str = end_id + " " + start_id; diff --git a/public/svg-edit/editor/extensions/ext-foreignobject.js b/public/svg-edit/editor/extensions/ext-foreignobject.js index d9692e2b..456d66fa 100644 --- a/public/svg-edit/editor/extensions/ext-foreignobject.js +++ b/public/svg-edit/editor/extensions/ext-foreignobject.js @@ -63,7 +63,6 @@ $(function() { var newDoc = Utils.text2xml(''+xmlString+''); // run it through our sanitizer to remove anything we do not support S.sanitizeSvg(newDoc.documentElement); - elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); S.call("changed", [elt]); svgCanvas.clearSelection(); diff --git a/public/svg-edit/editor/svg-editor.html b/public/svg-edit/editor/svg-editor.html index 123ef564..01b1b504 100644 --- a/public/svg-edit/editor/svg-editor.html +++ b/public/svg-edit/editor/svg-editor.html @@ -45,7 +45,6 @@ script type="text/javascript" src="locale/locale.min.js"> SVG-edit -
diff --git a/public/svg-edit/editor/svgcanvas.js b/public/svg-edit/editor/svgcanvas.js index 68510b4f..4e866be6 100644 --- a/public/svg-edit/editor/svgcanvas.js +++ b/public/svg-edit/editor/svgcanvas.js @@ -1385,6 +1385,11 @@ function BatchCommand(text) { } } + // Safari crashes on a without a xlink:href, so we just remove the node here + if (node.nodeName == "use" && !node.getAttributeNS(xlinkns,"href")) { + parent.removeChild(node); + return; + } // if the element has attributes pointing to a non-local reference, // need to remove the attribute $.each(["clip-path", "fill", "marker-end", "marker-mid", "marker-start", "mask", "stroke"],function(i,attr) { @@ -2647,6 +2652,7 @@ function BatchCommand(text) { }; var hasMatrixTransform = function(tlist) { + if(!tlist) return false; var num = tlist.numberOfItems; while (num--) { var xform = tlist.getItem(num); @@ -3083,11 +3089,13 @@ function BatchCommand(text) { start_x: start_x, start_y: start_y, selectedElements: selectedElements - }); + }, true); - if(ext_result) { - started = ext_result.started; + $.each(ext_result, function(i, r) { + if(r && r.started) { + started = true; } + }); }; // in this function we do not record any state changes yet (but we do update @@ -3604,13 +3612,15 @@ function BatchCommand(text) { event: evt, mouse_x: mouse_x, mouse_y: mouse_y - }); + }, true); - if(ext_result) { - keep = ext_result.keep; - element = ext_result.element; - started = ext_result.started; + $.each(ext_result, function(i, r) { + if(r) { + keep = r.keep || keep; + element = r.element; + started = r.started || started; } + }); if (!keep && element != null) { element.parentNode.removeChild(element); @@ -5618,28 +5628,33 @@ function BatchCommand(text) { var content = $(svgcontent); + var attrs = { + id: 'svgcontent', + overflow: 'visible' + }; + // determine proper size - var w, h; if (content.attr("viewBox")) { var vb = content.attr("viewBox").split(' '); - w = vb[2]; - h = vb[3]; + attrs.width = vb[2]; + attrs.height = vb[3]; } // handle content that doesn't have a viewBox else { - var dims = content.attr(["width", "height"]); - w = convertToNum('width', dims.width); - h = convertToNum('height', dims.height); - // svgcontent.setAttribute("viewBox", ["0", "0", w, h].join(" ")); + $.each(['width', 'height'], function(i, dim) { + // Set to 100 if not given + var val = content.attr(dim) || 100; + + if((val+'').substr(-1) === "%") { + // Use user units if percentage given + attrs[dim] = parseInt(val); + } else { + attrs[dim] = convertToNum(dim, val); + } + }); } - content.attr({ - id: 'svgcontent', - width: w, - height: h, - overflow: 'visible' - }); - + content.attr(attrs); batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); // update root to the correct size var changes = content.attr(["width", "height"]); @@ -6602,7 +6617,19 @@ function BatchCommand(text) { ret.y += parseFloat(selected.getAttribute('y')); } else { try { ret = selected.getBBox(); } - catch(e) { ret = null; } + catch(e) { + // Check if element is child of a foreignObject + var fo = $(selected).closest("foreignObject"); + if(fo.length) { + try { + ret = fo[0].getBBox(); + } catch(e) { + ret = null; + } + } else { + ret = null; + } + } } // get the bounding box from the DOM (which is in that element's coordinate system) @@ -7326,6 +7353,7 @@ function BatchCommand(text) { // re-creating the getCheckedBBox() function? shouldn't we make this a function // at the 'canvas' level var getCheckedBBox = function(elem) { + try { // TODO: Fix issue with rotated groups. Currently they work // fine in FF, but not in other browsers (same problem mentioned @@ -7399,7 +7427,10 @@ function BatchCommand(text) { } return bb; - } catch(e) { return null; } + } catch(e) { + console.log(elem, e); + return null; + } } var full_bb; @@ -7565,7 +7596,7 @@ function BatchCommand(text) { new_el.appendChild(copyElem(child)); break; case 3: // text node - new_el.appendChild(child.cloneNode(false)); + new_el.textContent = child.nodeValue; break; default: break; @@ -7723,7 +7754,7 @@ function BatchCommand(text) { // Function: getVersion // Returns a string which describes the revision number of SvgCanvas. this.getVersion = function() { - return "svgcanvas.js ($Rev: 1404 $)"; + return "svgcanvas.js ($Rev: 1409 $)"; }; this.setUiStrings = function(strs) { diff --git a/public/svg-edit/test/test1.html b/public/svg-edit/test/test1.html index c28be868..b29589d2 100644 --- a/public/svg-edit/test/test1.html +++ b/public/svg-edit/test/test1.html @@ -124,19 +124,22 @@ module("Import Module"); test("Test import use", function() { - expect(2); + expect(3); svgCanvas.setSvgString("" + "" + "" + "" + + "" + ""); var u = document.getElementById("the-use"), - fu = document.getElementById("foreign-use"); + fu = document.getElementById("foreign-use"), + nfu = document.getElementById("no-use"); equals((u && u.nodeName == "use"), true, "Did not import element"); - equals((fu && !fu.getAttributeNS(xlinkns,"href")), true, "Did not remove reference to foreign element in "); + equals(fu, null, "Removed element that had a foreign href"); + equals(nfu, null, "Removed element that had no href"); }); test("Test getUrlFromAttr", function() {