From 113e0af736670cc9b4b95bda6c2677194e0bd8f8 Mon Sep 17 00:00:00 2001 From: Jacques Distler Date: Fri, 13 Aug 2010 16:14:19 -0500 Subject: [PATCH] Update SVG-Edit Version 2.5.1 --- .../editor/extensions/ext-imagelib.js | 8 +- .../editor/extensions/imagelib/smiley.svg | 15 +- .../svg-edit/editor/images/svg_edit_icons.svg | 17 + .../editor/jgraduate/jquery.jgraduate.js | 27 +- .../svg-edit/editor/spinbtn/JQuerySpinBtn.js | 8 +- public/svg-edit/editor/svg-editor.css | 13 + public/svg-edit/editor/svg-editor.html | 32 +- public/svg-edit/editor/svg-editor.js | 554 ++++++++++++------ public/svg-edit/editor/svgcanvas.js | 378 ++++++++---- .../editor/svgicons/jquery.svgicons.js | 6 +- 10 files changed, 723 insertions(+), 335 deletions(-) diff --git a/public/svg-edit/editor/extensions/ext-imagelib.js b/public/svg-edit/editor/extensions/ext-imagelib.js index e2418687..563b2631 100644 --- a/public/svg-edit/editor/extensions/ext-imagelib.js +++ b/public/svg-edit/editor/extensions/ext-imagelib.js @@ -110,7 +110,7 @@ svgEditor.addExtension("imagelib", function() { }); var back = $('').appendTo(browser).click(function() { - frame.hide(); + frame.attr('src', 'about:blank').hide(); lib_opts.show(); header.text(all_libs); }).css({ @@ -122,7 +122,7 @@ svgEditor.addExtension("imagelib", function() { $.each(img_libs, function(i, opts) { $('
  • ').appendTo(lib_opts).text(opts.name).click(function() { frame.attr('src', opts.url).show(); - header.text(name); + header.text(opts.name); lib_opts.hide(); }).append('' + opts.description + ''); }); @@ -153,7 +153,7 @@ svgEditor.addExtension("imagelib", function() { width: 100%;\ height: 100%;\ background-color: rgba(0, 0, 0, .5);\ - z-index: 4;\ + z-index: 5;\ }\ \ #imgbrowse {\ @@ -183,6 +183,8 @@ svgEditor.addExtension("imagelib", function() { background: white;\ margin: 0;\ padding: 0;\ + }\ + #imgbrowse > ul {\ overflow: auto;\ }\ #imgbrowse li {\ diff --git a/public/svg-edit/editor/extensions/imagelib/smiley.svg b/public/svg-edit/editor/extensions/imagelib/smiley.svg index 36a7fef0..21a798d6 100644 --- a/public/svg-edit/editor/extensions/imagelib/smiley.svg +++ b/public/svg-edit/editor/extensions/imagelib/smiley.svg @@ -1,7 +1,12 @@ - - - Layer 1 - - + Cool smiley + + + + + + + + + \ No newline at end of file diff --git a/public/svg-edit/editor/images/svg_edit_icons.svg b/public/svg-edit/editor/images/svg_edit_icons.svg index 2255ba5e..26959c20 100644 --- a/public/svg-edit/editor/images/svg_edit_icons.svg +++ b/public/svg-edit/editor/images/svg_edit_icons.svg @@ -664,6 +664,23 @@ + + + + + + + + + + + + + + + + + diff --git a/public/svg-edit/editor/jgraduate/jquery.jgraduate.js b/public/svg-edit/editor/jgraduate/jquery.jgraduate.js index ab02a42b..21d1a3ad 100644 --- a/public/svg-edit/editor/jgraduate/jquery.jgraduate.js +++ b/public/svg-edit/editor/jgraduate/jquery.jgraduate.js @@ -56,21 +56,6 @@ if(!window.console) { this.dir = function(str) {}; }; } -$.cloneNode = function(el) { - if(!window.opera) return el.cloneNode(true); - // manually create a copy of the element - opera.postError(ns.svg, el.nodeName); - var new_el = document.createElementNS(ns.svg, el.nodeName); - $.each(el.attributes, function(i, attr) { - new_el.setAttributeNS(ns.svg, attr.nodeName, attr.nodeValue); - }); - $.each(el.childNodes, function(i, child) { - if(child.nodeType == 1) { - new_el.appendChild($.cloneNode(child)); - } - }); - return new_el; -} $.jGraduate = { Paint: @@ -92,10 +77,10 @@ $.jGraduate = { this.solidColor = options.copy.solidColor; break; case "linearGradient": - this.linearGradient = $.cloneNode(options.copy.linearGradient); + this.linearGradient = options.copy.linearGradient.cloneNode(true); break; case "radialGradient": - this.radialGradient = $.cloneNode(options.copy.radialGradient); + this.radialGradient = options.copy.radialGradient.cloneNode(true); break; } } @@ -104,14 +89,14 @@ $.jGraduate = { this.type = "linearGradient"; this.solidColor = null; this.radialGradient = null; - this.linearGradient = $.cloneNode(options.linearGradient); + this.linearGradient = options.linearGradient.cloneNode(true); } // create linear gradient paint else if (options.radialGradient) { this.type = "radialGradient"; this.solidColor = null; this.linearGradient = null; - this.radialGradient = $.cloneNode(options.radialGradient); + this.radialGradient = options.radialGradient.cloneNode(true); } // create solid color paint else if (options.solidColor) { @@ -328,7 +313,7 @@ jQuery.fn.jGraduate = // if we are sent a gradient, import it if ($this.paint.type == "linearGradient") { $this.paint.linearGradient.id = id+'_jgraduate_grad'; - $this.paint.linearGradient = svg.appendChild($.cloneNode($this.paint.linearGradient)); + $this.paint.linearGradient = svg.appendChild($this.paint.linearGradient.cloneNode(true)); } else { // we create a gradient var grad = svg.appendChild(document.createElementNS(ns.svg, 'linearGradient')); grad.id = id+'_jgraduate_grad'; @@ -650,7 +635,7 @@ jQuery.fn.jGraduate = // if we are sent a gradient, import it if ($this.paint.type == "radialGradient") { $this.paint.radialGradient.id = id+'_rg_jgraduate_grad'; - $this.paint.radialGradient = svg.appendChild($.cloneNode($this.paint.radialGradient)); + $this.paint.radialGradient = svg.appendChild($this.paint.radialGradient.cloneNode(true)); } else { // we create a gradient var grad = svg.appendChild(document.createElementNS(ns.svg, 'radialGradient')); grad.id = id+'_rg_jgraduate_grad'; diff --git a/public/svg-edit/editor/spinbtn/JQuerySpinBtn.js b/public/svg-edit/editor/spinbtn/JQuerySpinBtn.js index d6e83548..77f924ed 100644 --- a/public/svg-edit/editor/spinbtn/JQuerySpinBtn.js +++ b/public/svg-edit/editor/spinbtn/JQuerySpinBtn.js @@ -117,10 +117,12 @@ $.fn.SpinButton = function(cfg){ var x = e.pageX || e.x; var y = e.pageY || e.y; var el = e.target || e.srcElement; - var height = $(el).outerHeight()/2; + var scale = svgEditor.tool_scale || 1; + var height = $(el).height()/2; + var direction = - (x > coord(el,'offsetLeft') + el.offsetWidth - this.spinCfg._btn_width) - ? ((y < coord(el,'offsetTop') + height) ? 1 : -1) : 0; + (x > coord(el,'offsetLeft') + el.offsetWidth*scale - this.spinCfg._btn_width) + ? ((y < coord(el,'offsetTop') + height*scale) ? 1 : -1) : 0; if (direction !== this.spinCfg._direction) { // Style up/down buttons: diff --git a/public/svg-edit/editor/svg-editor.css b/public/svg-edit/editor/svg-editor.css index 7edc5543..a1107796 100644 --- a/public/svg-edit/editor/svg-editor.css +++ b/public/svg-edit/editor/svg-editor.css @@ -2,6 +2,13 @@ background: #D8D8D8; } +#svg_editor * { + transform-origin: 0 0; + -moz-transform-origin: 0 0; + -o-transform-origin: 0 0; + -webkit-transform-origin: 0 0; +} + #svg_editor { font-size: 8pt; font-family: Verdana, Helvetica, Arial; @@ -278,6 +285,7 @@ position: absolute; top: 4px; left: 4px; + z-index: 5; } @@ -466,6 +474,11 @@ height: 34px; } +#svg_editor div.toolset label span { +/* outline: 1px solid red;*/ + padding-top: 3px; + display: inline-block; +} #tools_top > div > * { float: left; diff --git a/public/svg-edit/editor/svg-editor.html b/public/svg-edit/editor/svg-editor.html index 62afe4ef..a96303a6 100644 --- a/public/svg-edit/editor/svg-editor.html +++ b/public/svg-edit/editor/svg-editor.html @@ -168,7 +168,7 @@ script type="text/javascript" src="locale/locale.min.js"> --> - @@ -227,11 +227,6 @@ script type="text/javascript" src="locale/locale.min.js"> -
    -
    -
    -
    -
    -
    + + +
    +
    + + + + +
    + +
    + +
    + +
    +
    +
    +
    @@ -507,7 +523,7 @@ script type="text/javascript" src="locale/locale.min.js">
    - +
    diff --git a/public/svg-edit/editor/svg-editor.js b/public/svg-edit/editor/svg-editor.js index e05146e7..4a6963fb 100644 --- a/public/svg-edit/editor/svg-editor.js +++ b/public/svg-edit/editor/svg-editor.js @@ -45,9 +45,11 @@ imgPath: 'images/', langPath: 'locale/', extPath: 'extensions/', + jGraduatePath: 'jgraduate/images/', extensions: ['ext-markers.js','ext-connector.js', 'ext-eyedropper.js', 'ext-imagelib.js', 'ext-itex.js'], initTool: 'select', - wireframe: false + wireframe: false, + colorPickerCSS: null }, uiStrings = Editor.uiStrings = { "invalidAttrValGiven":"Invalid value given", @@ -82,6 +84,8 @@ Editor.curConfig = curConfig; + Editor.tool_scale = 1; + // Store and retrieve preferences $.pref = function(key, val) { if(val) curPrefs[key] = val; @@ -147,6 +151,7 @@ Editor.setCustomHandlers = function(opts) { Editor.ready(function() { if(opts.open) { + $('#tool_open > input[type="file"]').remove(); $('#tool_open').show(); svgCanvas.open = opts.open; } @@ -207,7 +212,15 @@ var extFunc = function() { $.each(curConfig.extensions, function() { - $.getScript(curConfig.extPath + this); + var extname = this; + $.getScript(curConfig.extPath + extname, function(d) { + // Fails locally in Chrome 5 + if(!d) { + var s = document.createElement('script'); + s.src = curConfig.extPath + extname; + document.querySelector('head').appendChild(s); + } + }); }); } @@ -320,6 +333,7 @@ '#tool_reorient':'reorient', '#tool_group':'group', '#tool_ungroup':'ungroup', + '#tool_unlink_use':'unlink_use', '#tool_alignleft, #tool_posleft':'align_left', '#tool_aligncenter, #tool_poscenter':'align_center', @@ -377,18 +391,17 @@ $(this).parent().prepend(this); }); - // Use small icons by default if not all left tools are visible var tleft = $('#tools_left'); if (tleft.length != 0) { var min_height = tleft.offset().top + tleft.outerHeight(); } - var size = $.pref('iconsize'); - if(size && size != 'm') { - svgEditor.setIconSize(size); - } else if($(window).height() < min_height) { - // Make smaller - svgEditor.setIconSize('s'); - } +// var size = $.pref('iconsize'); +// if(size && size != 'm') { +// svgEditor.setIconSize(size); +// } else if($(window).height() < min_height) { +// // Make smaller +// svgEditor.setIconSize('s'); +// } // Look for any missing flyout icons from plugins $('.tools_flyout').each(function() { @@ -430,7 +443,8 @@ default_img_url = curConfig.imgPath + "logo.png", workarea = $("#workarea"), show_save_warning = false, - exportWindow = null; + exportWindow = null, + tool_scale = 1; // This sets up alternative dialog boxes. They mostly work the same way as // their UI counterparts, expect instead of returning the result, a callback @@ -521,7 +535,7 @@ // by default, we add the XML prolog back, systems integrating SVG-edit (wikis, CMSs) // can just provide their own custom save handler and might not want the XML prolog - svg = "\n" + svg; + svg = '\n' + svg; // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable @@ -566,15 +580,21 @@ var datauri = c.toDataURL('image/png'); exportWindow.location.href = datauri; - var note = uiStrings.saveFromBrowser.replace('%s', 'PNG'); - - // Check if there's issues - - if(issues.length) { - var pre = "\n \u2022 "; - note += ("\n\n" + uiStrings.noteTheseIssues + pre + issues.join(pre)); - } - exportWindow.alert(note); + var done = $.pref('export_notice_done'); + if(done !== "all") { + var note = uiStrings.saveFromBrowser.replace('%s', 'PNG'); + + // Check if there's issues + if(issues.length) { + var pre = "\n \u2022 "; + note += ("\n\n" + uiStrings.noteTheseIssues + pre + issues.join(pre)); + } + + // Note that this will also prevent the notice even though new issues may appear later. + // May want to find a way to deal with that without annoying the user + $.pref('export_notice_done', 'all'); + exportWindow.alert(note); + } }; // called when we've selected a different element @@ -618,8 +638,8 @@ } // Update selectedElement if element is no longer part of the image. // This occurs for the text elements in Firefox - else if(elem && selectedElement && selectedElement.parentNode == null - || elem && elem.tagName == "path" && !multiselected) { + else if(elem && selectedElement && selectedElement.parentNode == null) { +// || elem && elem.tagName == "path" && !multiselected) { // This was added in r1430, but not sure why selectedElement = elem; } } @@ -775,7 +795,7 @@ var shower = $('#' + this.id + '_show'); var pos = shower.offset(); var w = shower.outerWidth(); - $(this).css({left: pos.left + w, top: pos.top}); + $(this).css({left: (pos.left + w)*tool_scale, top: pos.top}); }); } @@ -789,13 +809,31 @@ shower[0].title = tooltips.join(' / '); }); } + + var resize_timer; var extAdded = function(window, ext) { var cb_called = false; + var resize_done = false; + var cb_ready = true; // Set to false to delay callback (e.g. wait for $.svgIcons) + + function prepResize() { + if(resize_timer) { + clearTimeout(resize_timer); + resize_timer = null; + } + if(!resize_done) { + resize_timer = setTimeout(function() { + resize_done = true; + setIconSize(curPrefs.iconsize); + }, 50); + } + } + var runCallback = function() { - if(ext.callback && !cb_called) { + if(ext.callback && !cb_called && cb_ready) { cb_called = true; ext.callback(); } @@ -1106,6 +1144,9 @@ $.each(btn_selects, function() { addAltDropDown(this.elem, this.list, this.callback, {seticon: true}); }); + + if (svgicons) + cb_ready = false; // Delay callback $.svgIcons(svgicons, { w:24, h:24, @@ -1116,8 +1157,9 @@ callback: function(icons) { // Non-ideal hack to make the icon match the current size if(curPrefs.iconsize && curPrefs.iconsize != 'm') { - setIconSize(curPrefs.iconsize, true); + prepResize(); } + cb_ready = true; // Ready for callback runCallback(); } @@ -1153,7 +1195,8 @@ // updates the toolbar (colors, opacity, etc) based on the selected element // This function also updates the opacity and id elements that are in the context panel var updateToolbar = function() { - if (selectedElement != null && $.inArray(selectedElement.tagName, ['image', 'text', 'foreignObject', 'g', 'a']) === -1) { + if (selectedElement != null && $.inArray(selectedElement.tagName, ['use', 'image', 'foreignObject', 'g', 'a']) === -1) { + // get opacity values var fillOpacity = parseFloat(selectedElement.getAttribute("fill-opacity")); if (isNaN(fillOpacity)) { @@ -1207,8 +1250,8 @@ strokeOpacity = "N/A"; } - $('#stroke_width').val(selectedElement.getAttribute("stroke-width")||1); - $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none"); + $('#stroke_width').val(selectedElement.getAttribute("stroke-width")||1).change(); + $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none").change(); var attr = selectedElement.getAttribute("stroke-linejoin") || 'miter'; @@ -1260,6 +1303,11 @@ } } + var setInputWidth = function(elem) { + var w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300); + $(elem).width(w); + } + // updates the context panel tools based on the selected element var updateContextPanel = function() { var elem = selectedElement; @@ -1276,7 +1324,7 @@ } var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false; $('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,\ - #ellipse_panel, #line_panel, #text_panel, #image_panel').hide(); + #ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel').hide(); if (elem != null) { var elname = elem.nodeName; @@ -1365,14 +1413,15 @@ circle: ['cx','cy','r'], ellipse: ['cx','cy','rx','ry'], line: ['x1','y1','x2','y2'], - text: [] + text: [], + 'use': [] }; var el_name = elem.tagName; - if($(elem).data('gsvg')) { - el_name = 'svg'; - } +// if($(elem).data('gsvg')) { +// $('#g_panel').show(); +// } if(panels[el_name]) { var cur_panel = panels[el_name]; @@ -1410,6 +1459,19 @@ var href = elem.getAttributeNS(xlinkNS, "href"); setImageURL(href); } // image + else if(el_name == 'g' || el_name == 'use') { + $('#container_panel').show(); + var title = svgCanvas.getTitle(); + var label = $('#g_title')[0]; + label.value = title; + setInputWidth(label); + var d = 'disabled'; + if(el_name == 'use') { + label.setAttribute(d, d); + } else { + label.removeAttribute(d); + } + } } } // if (elem != null) else if (multiselected) { @@ -1604,6 +1666,12 @@ $('#image_url').change(function(){ setImageURL(this.value); }); + + $('#g_title').change(function() { + svgCanvas.setGroupTitle(this.value); + setInputWidth(this); + + }); $('.attr_changer').change(function() { var attr = this.getAttribute("data-attr"); @@ -1828,8 +1896,9 @@ } }); }()); - - var addDropDown = function(elem, callback, dropUp) { + // Made public for UI customization. + // TODO: Group UI functions into a public svgEditor.ui interface. + Editor.addDropDown = function(elem, callback, dropUp) { var button = $(elem).find('button'); var list = $(elem).find('ul'); var on_button = false; @@ -1925,12 +1994,12 @@ } } - addDropDown('#font_family_dropdown', function() { + Editor.addDropDown('#font_family_dropdown', function() { var fam = $(this).text(); $('#font_family').val($(this).text()).change(); }); - addDropDown('#opacity_dropdown', function() { + Editor.addDropDown('#opacity_dropdown', function() { if($(this).find('div').length) return; var perc = parseInt($(this).text().split('%')[0]); changeOpacity(false, perc); @@ -1950,7 +2019,7 @@ } }); - addDropDown('#blur_dropdown', function() { + Editor.addDropDown('#blur_dropdown', function() { }); var slideStart = false; @@ -1973,7 +2042,7 @@ }); - addDropDown('#zoom_dropdown', function() { + Editor.addDropDown('#zoom_dropdown', function() { var item = $(this); var val = item.attr('data-val'); if(val) { @@ -2027,6 +2096,11 @@ workarea.mousedown(unfocus); }).blur(function() { workarea.unbind('mousedown', unfocus); + + // Go back to selecting text if in textedit mode + if(svgCanvas.getMode() == 'textedit') { + $('#text').focus(); + } }); }()); @@ -2134,7 +2208,7 @@ svgCanvas.moveToBottomSelectedElement(); } }; - + var convertToPath = function() { if (selectedElement != null) { svgCanvas.convertToPath(); @@ -2226,11 +2300,13 @@ var clickBold = function(){ svgCanvas.setBold( !svgCanvas.getBold() ); updateContextPanel(); + return false; }; var clickItalic = function(){ svgCanvas.setItalic( !svgCanvas.getItalic() ); updateContextPanel(); + return false; }; var clickSave = function(){ @@ -2289,7 +2365,7 @@ svgCanvas.groupSelectedElements(); } // ungroup - else if(selectedElement && selectedElement.tagName == 'g'){ + else if(selectedElement){ svgCanvas.ungroupSelectedElement(); } }; @@ -2487,161 +2563,260 @@ } var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { - var icon = (typeof icon_id == 'string') ? $.getSvgIcon(icon_id).clone() : icon_id.clone(); - $(elem).empty().append(icon); - if(forcedSize) { - var obj = {}; - obj[elem + ' .svg_icon'] = forcedSize; - $.resizeSvgIcons(obj); - } else { - var size = curPrefs.iconsize; - if(size && size !== 'm') { - var icon_sizes = { s:16, m:24, l:32, xl:48}, obj = {}; - obj[elem + ' .svg_icon'] = icon_sizes[size]; - $.resizeSvgIcons(obj); - } + var icon = (typeof icon_id == 'string') ? $.getSvgIcon(icon_id) : icon_id; + if(!icon) { + console.log('NOTE: Icon image missing: ' + icon_id); + return; } + icon = icon.clone(); + $(elem).empty().append(icon); +// if(forcedSize) { +// var obj = {}; +// obj[elem + ' .svg_icon'] = forcedSize; +// $.resizeSvgIcons(obj); +// } else { +// var size = curPrefs.iconsize; +// if(size && size !== 'm') { +// var icon_sizes = { s:16, m:24, l:32, xl:48}, obj = {}; +// obj[elem + ' .svg_icon'] = icon_sizes[size]; +// $.resizeSvgIcons(obj); +// } +// } } + var ua_prefix; + (ua_prefix = function() { + var regex = /^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/; + var someScript = document.getElementsByTagName('script')[0]; + for(var prop in someScript.style) { + if(regex.test(prop)) { + // test is faster than match, so it's better to perform + // that on the lot and match only when necessary + return prop.match(regex)[0]; + } + } + + // Nothing found so far? + if('WebkitOpacity' in someScript.style) return 'Webkit'; + if('KhtmlOpacity' in someScript.style) return 'Khtml'; + + return ''; + }()); + + var scaleElements = function(elems, scale) { + var prefix = '-' + ua_prefix.toLowerCase() + '-'; + + var sides = ['top', 'left', 'bottom', 'right']; + + elems.each(function() { +// console.log('go', scale); + + // Handled in CSS + // this.style[ua_prefix + 'Transform'] = 'scale(' + scale + ')'; + + var el = $(this); + + var w = el.outerWidth() * (scale - 1); + var h = el.outerHeight() * (scale - 1); + var margins = {}; + + for(var i = 0; i < 4; i++) { + var s = sides[i]; + + var cur = el.data('orig_margin-' + s); + if(cur == null) { + cur = parseInt(el.css('margin-' + s)); + // Cache the original margin + el.data('orig_margin-' + s, cur); + } + var val = cur * scale; + if(s === 'right') { + val += w; + } else if(s === 'bottom') { + val += h; + } + + el.css('margin-' + s, val); +// el.css('outline', '1px solid red'); + } + }); + } + var setIconSize = Editor.setIconSize = function(size, force) { if(size == curPrefs.size && !force) return; +// return; +// var elems = $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open'); + console.log('size', size); + + var sel_toscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,\ + #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\ + #g_panel > *, #tool_font_size > *, .tools_flyout'; + + var elems = $(sel_toscale); + + var scale = 1; + + if(typeof size == 'number') { + scale = size; + } else { + var icon_sizes = { s:.75, m:1, l:1.25, xl:1.5 }; + scale = icon_sizes[size]; + } + + Editor.tool_scale = tool_scale = scale; + + setFlyoutPositions(); + // $('.tools_flyout').each(function() { +// var pos = $(this).position(); +// console.log($(this), pos.left+(34 * scale)); +// $(this).css({'left': pos.left+(34 * scale), 'top': pos.top+(77 * scale)}); +// console.log('l', $(this).css('left')); +// }); + +// var scale = .75;//0.75; + + var hidden_ps = elems.parents(':hidden'); + hidden_ps.css('visibility', 'hidden').show(); + scaleElements(elems, scale); + hidden_ps.css('visibility', 'visible').hide(); +// console.timeEnd('elems'); +// return; + $.pref('iconsize', size); $('#iconsize').val(size); - var icon_sizes = { s:16, m:24, l:32, xl:48 }; - var size_num = icon_sizes[size]; + // Change icon size - $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open') - .find('> svg, > img').each(function() { - this.setAttribute('width',size_num); - this.setAttribute('height',size_num); - }); - - $.resizeSvgIcons({ - '.flyout_arrow_horiz > svg, .flyout_arrow_horiz > img': size_num / 5, - '#logo > svg, #logo > img': size_num * 1.3, - '#tools_bottom .icon_label > *': (size_num === 16 ? 18 : size_num * .75) - }); - if(size != 's') { - $.resizeSvgIcons({'#layerbuttons svg, #layerbuttons img': size_num * .6}); - } +// $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open') +// .find('> svg, > img').each(function() { +// this.setAttribute('width',size_num); +// this.setAttribute('height',size_num); +// }); +// +// $.resizeSvgIcons({ +// '.flyout_arrow_horiz > svg, .flyout_arrow_horiz > img': size_num / 5, +// '#logo > svg, #logo > img': size_num * 1.3, +// '#tools_bottom .icon_label > *': (size_num === 16 ? 18 : size_num * .75) +// }); +// if(size != 's') { +// $.resizeSvgIcons({'#layerbuttons svg, #layerbuttons img': size_num * .6}); +// } // Note that all rules will be prefixed with '#svg_editor' when parsed var cssResizeRules = { - ".tool_button,\ - .push_button,\ - .tool_button_current,\ - .push_button_pressed,\ - .disabled,\ - .icon_label,\ - .tools_flyout .tool_button": { - 'width': {s: '16px', l: '32px', xl: '48px'}, - 'height': {s: '16px', l: '32px', xl: '48px'}, - 'padding': {s: '1px', l: '2px', xl: '3px'} - }, - ".tool_sep": { - 'height': {s: '16px', l: '32px', xl: '48px'}, - 'margin': {s: '2px 2px', l: '2px 5px', xl: '2px 8px'} - }, - "#main_icon": { - 'width': {s: '31px', l: '53px', xl: '75px'}, - 'height': {s: '22px', l: '42px', xl: '64px'} - }, +// ".tool_button,\ +// .push_button,\ +// .tool_button_current,\ +// .push_button_pressed,\ +// .disabled,\ +// .icon_label,\ +// .tools_flyout .tool_button": { +// 'width': {s: '16px', l: '32px', xl: '48px'}, +// 'height': {s: '16px', l: '32px', xl: '48px'}, +// 'padding': {s: '1px', l: '2px', xl: '3px'} +// }, +// ".tool_sep": { +// 'height': {s: '16px', l: '32px', xl: '48px'}, +// 'margin': {s: '2px 2px', l: '2px 5px', xl: '2px 8px'} +// }, +// "#main_icon": { +// 'width': {s: '31px', l: '53px', xl: '75px'}, +// 'height': {s: '22px', l: '42px', xl: '64px'} +// }, "#tools_top": { - 'left': {s: '36px', l: '60px', xl: '80px'}, - 'height': {s: '50px', l: '88px', xl: '125px'} + 'left': 50, + 'height': 72 }, "#tools_left": { - 'width': {s: '22px', l: '30px', xl: '38px'}, - 'top': {s: '50px', l: '87px', xl: '125px'} + 'width': 31, + 'top': 74 }, "div#workarea": { - 'left': {s: '27px', l: '46px', xl: '65px'}, - 'top': {s: '50px', l: '88px', xl: '125px'}, - 'bottom': {s: '55px', l: '98px', xl: '145px'} + 'left': 38, + 'top': 74 }, - "#tools_bottom": { - 'left': {s: '27px', l: '46px', xl: '65px'}, - 'height': {s: '58px', l: '98px', xl: '145px'} - }, - "#color_tools": { - 'border-spacing': {s: '0 1px'}, - 'margin-top': {s: '-1px'} - }, - "#color_tools .icon_label": { - 'width': {l:'43px', xl: '60px'} - }, - ".color_tool": { - 'height': {s: '20px'} - }, - "#tool_opacity": { - 'top': {s: '1px'}, - 'height': {s: 'auto', l:'auto', xl:'auto'} - }, - "#tools_top input, #tools_bottom input": { - 'margin-top': {s: '2px', l: '4px', xl: '5px'}, - 'height': {s: 'auto', l: 'auto', xl: 'auto'}, - 'border': {s: '1px solid #555', l: 'auto', xl: 'auto'}, - 'font-size': {s: '.9em', l: '1.2em', xl: '1.4em'} - }, - "#zoom_panel": { - 'margin-top': {s: '3px', l: '4px', xl: '5px'} - }, - "#copyright, #tools_bottom .label": { - 'font-size': {l: '1.5em', xl: '2em'}, - 'line-height': {s: '15px'} - }, - "#tools_bottom_2": { - 'width': {l: '295px', xl: '355px'}, - 'top': {s: '4px'} - }, - "#tools_top > div, #tools_top": { - 'line-height': {s: '17px', l: '34px', xl: '50px'} - }, - ".dropdown button": { - 'height': {s: '18px', l: '34px', xl: '40px'}, - 'line-height': {s: '18px', l: '34px', xl: '40px'}, - 'margin-top': {s: '3px'} - }, - "#tools_top label, #tools_bottom label": { - 'font-size': {s: '1em', l: '1.5em', xl: '2em'}, - 'height': {s: '25px', l: '42px', xl: '64px'} - }, - "div.toolset": { - 'height': {s: '25px', l: '42px', xl: '64px'} - }, - "#tool_bold, #tool_italic": { - 'font-size': {s: '1.5em', l: '3em', xl: '4.5em'} - }, - "#sidepanels": { - 'top': {s: '50px', l: '88px', xl: '125px'}, - 'bottom': {s: '51px', l: '68px', xl: '65px'} - }, - '#layerbuttons': { - 'width': {l: '130px', xl: '175px'}, - 'height': {l: '24px', xl: '30px'} - }, - '#layerlist': { - 'width': {l: '128px', xl: '150px'} - }, - '.layer_button': { - 'width': {l: '19px', xl: '28px'}, - 'height': {l: '19px', xl: '28px'} - }, - "input.spin-button": { - 'background-image': {l: "url('images/spinbtn_updn_big.png')", xl: "url('images/spinbtn_updn_big.png')"}, - 'background-position': {l: '100% -5px', xl: '100% -2px'}, - 'padding-right': {l: '24px', xl: '24px' } - }, - "input.spin-button.up": { - 'background-position': {l: '100% -45px', xl: '100% -42px'} - }, - "input.spin-button.down": { - 'background-position': {l: '100% -85px', xl: '100% -82px'} - }, - "#position_opts": { - 'width': {all: (size_num*4) +'px'} - } +// "#tools_bottom": { +// 'left': {s: '27px', l: '46px', xl: '65px'}, +// 'height': {s: '58px', l: '98px', xl: '145px'} +// }, +// "#color_tools": { +// 'border-spacing': {s: '0 1px'}, +// 'margin-top': {s: '-1px'} +// }, +// "#color_tools .icon_label": { +// 'width': {l:'43px', xl: '60px'} +// }, +// ".color_tool": { +// 'height': {s: '20px'} +// }, +// "#tool_opacity": { +// 'top': {s: '1px'}, +// 'height': {s: 'auto', l:'auto', xl:'auto'} +// }, +// "#tools_top input, #tools_bottom input": { +// 'margin-top': {s: '2px', l: '4px', xl: '5px'}, +// 'height': {s: 'auto', l: 'auto', xl: 'auto'}, +// 'border': {s: '1px solid #555', l: 'auto', xl: 'auto'}, +// 'font-size': {s: '.9em', l: '1.2em', xl: '1.4em'} +// }, +// "#zoom_panel": { +// 'margin-top': {s: '3px', l: '4px', xl: '5px'} +// }, +// "#copyright, #tools_bottom .label": { +// 'font-size': {l: '1.5em', xl: '2em'}, +// 'line-height': {s: '15px'} +// }, +// "#tools_bottom_2": { +// 'width': {l: '295px', xl: '355px'}, +// 'top': {s: '4px'} +// }, +// "#tools_top > div, #tools_top": { +// 'line-height': {s: '17px', l: '34px', xl: '50px'} +// }, +// ".dropdown button": { +// 'height': {s: '18px', l: '34px', xl: '40px'}, +// 'line-height': {s: '18px', l: '34px', xl: '40px'}, +// 'margin-top': {s: '3px'} +// }, +// "#tools_top label, #tools_bottom label": { +// 'font-size': {s: '1em', l: '1.5em', xl: '2em'}, +// 'height': {s: '25px', l: '42px', xl: '64px'} +// }, +// "div.toolset": { +// 'height': {s: '25px', l: '42px', xl: '64px'} +// }, +// "#tool_bold, #tool_italic": { +// 'font-size': {s: '1.5em', l: '3em', xl: '4.5em'} +// }, +// "#sidepanels": { +// 'top': {s: '50px', l: '88px', xl: '125px'}, +// 'bottom': {s: '51px', l: '68px', xl: '65px'} +// }, +// '#layerbuttons': { +// 'width': {l: '130px', xl: '175px'}, +// 'height': {l: '24px', xl: '30px'} +// }, +// '#layerlist': { +// 'width': {l: '128px', xl: '150px'} +// }, +// '.layer_button': { +// 'width': {l: '19px', xl: '28px'}, +// 'height': {l: '19px', xl: '28px'} +// }, +// "input.spin-button": { +// 'background-image': {l: "url('images/spinbtn_updn_big.png')", xl: "url('images/spinbtn_updn_big.png')"}, +// 'background-position': {l: '100% -5px', xl: '100% -2px'}, +// 'padding-right': {l: '24px', xl: '24px' } +// }, +// "input.spin-button.up": { +// 'background-position': {l: '100% -45px', xl: '100% -42px'} +// }, +// "input.spin-button.down": { +// 'background-position': {l: '100% -85px', xl: '100% -82px'} +// }, +// "#position_opts": { +// 'width': {all: (size_num*4) +'px'} +// } }; var rule_elem = $('#tool_size_rules'); @@ -2657,12 +2832,21 @@ selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor'); style_str += selector + '{'; $.each(rules, function(prop, values) { - if(values[size] || values.all) { - style_str += (prop + ':' + (values[size] || values.all) + ';'); + if(typeof values === 'number') { + var val = (values * scale) + 'px'; + } else if(values[size] || values.all) { + var val = (values[size] || values.all); } + style_str += (prop + ':' + val + ';'); }); style_str += '}'; }); + //this.style[ua_prefix + 'Transform'] = 'scale(' + scale + ')'; + var prefix = '-' + ua_prefix.toLowerCase() + '-'; + style_str += (sel_toscale + '{' + prefix + 'transform: scale(' + scale + ');}' + + ' #svg_editor div.toolset .toolset {' + prefix + 'transform: scale(1); margin: 1px !important;}' // Hack for markers + + ' #svg_editor .ui-slider {' + prefix + 'transform: scale(' + (1/scale) + ');}' // Hack for sliders + ); rule_elem.text(style_str); } @@ -2778,12 +2962,12 @@ var pos = elem.position(); $("#color_picker") .draggable({cancel:'.jPicker_table,.jGraduate_lgPick,.jGraduate_rgPick'}) - .css({'left': pos.left, 'bottom': 50 - pos.top}) + .css(curConfig.colorPickerCSS || {'left': pos.left, 'bottom': 50 - pos.top}) .jGraduate( { paint: paint, window: { pickerTitle: title }, - images: { clientPath: "jgraduate/images/" } + images: { clientPath: curConfig.jGraduatePath } }, function(p) { paint = new $.jGraduate.Paint(p); @@ -3341,6 +3525,7 @@ {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey+'C', true]}, {sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey+'G', true]}, {sel:'#tool_ungroup', fn: clickGroup, evt: 'click'}, + {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, // these two lines are required to make Opera work properly with the flyout mechanism // {sel:'#tools_rect_show', fn: clickRect, evt: 'click'}, @@ -3650,7 +3835,7 @@ updateCanvas(true); // }); - // var revnums = "svg-editor.js ($Rev: 1638 $) "; + // var revnums = "svg-editor.js ($Rev: 1659 $) "; // revnums += svgCanvas.getVersion(); // $('#copyright')[0].setAttribute("title", revnums); @@ -3823,7 +4008,6 @@ })(); - // ?iconsize=s&bkgd_color=555 // svgEditor.setConfig({ diff --git a/public/svg-edit/editor/svgcanvas.js b/public/svg-edit/editor/svgcanvas.js index e20c5819..c32c6e4c 100644 --- a/public/svg-edit/editor/svgcanvas.js +++ b/public/svg-edit/editor/svgcanvas.js @@ -1253,9 +1253,11 @@ var SelectorManager; // The bbox for a group does not include stroke vals, so we // get the bbox based on its children. var stroked_bbox = getStrokedBBox(selected.childNodes); - $.each(bbox, function(key, val) { - bbox[key] = stroked_bbox[key]; - }); + if(stroked_bbox) { + $.each(bbox, function(key, val) { + bbox[key] = stroked_bbox[key]; + }); + } } // loop and transform our bounding box until we reach our first rotation @@ -1834,8 +1836,8 @@ var addSvgElementFromJson = this.addSvgElementFromJson = function(data) { (function() { // TODO: make this string optional and set by the client var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ "); - // Lead to invalid content with Instiki's Sanitizer - // svgcontent.appendChild(comment); + // Lead to invalid content with Instiki's Sanitizer + // svgcontent.appendChild(comment); // TODO For Issue 208: this is a start on a thumbnail // var svgthumb = svgdoc.createElementNS(svgns, "use"); @@ -2280,7 +2282,12 @@ var copyElem = function(el) { if($(el).data('gsvg')) { $(new_el).data('gsvg', new_el.firstChild); - } else if(new_el.tagName == 'image') { + } else if($(el).data('symbol')) { + var ref = $(el).data('symbol'); + $(new_el).data('ref', ref).data('symbol', ref); + } + + else if(new_el.tagName == 'image') { preventClickDefault(new_el); } return new_el; @@ -2885,10 +2892,10 @@ var remapElement = this.remapElement = function(selected,changes,m) { changes["height"] = scaleh(changes["height"]); break; case "use": - var pt1 = remap(changes["x"],changes["y"]); - changes["x"] = pt1.x; - changes["y"] = pt1.y; - break; +// var pt1 = remap(changes["x"],changes["y"]); +// changes["x"] = pt1.x; +// changes["y"] = pt1.y; +// break; case "g": case "text": // if it was a translate, then just update x,y @@ -2999,9 +3006,6 @@ var remapElement = this.remapElement = function(selected,changes,m) { changes.height = Math.abs(changes.height); assignAttributes(selected, changes, 1000, true); break; - case "use": - assignAttributes(selected, changes, 1000, true); - break; case "ellipse": changes.rx = Math.abs(changes.rx); changes.ry = Math.abs(changes.ry); @@ -3009,6 +3013,7 @@ var remapElement = this.remapElement = function(selected,changes,m) { if(changes.r) changes.r = Math.abs(changes.r); case "line": case "text": + case "use": assignAttributes(selected, changes, 1000, true); break; case "g": @@ -3168,8 +3173,6 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) { attrs = ["width", "height", "x", "y"]; break; case "use": - attrs = ["x", "y"]; - break; case "text": attrs = ["x", "y"]; break; @@ -3280,6 +3283,22 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) { if (!childTlist) continue; var m = transformListToTransform(childTlist).matrix; + + // Convert a matrix to a scale if applicable +// if(hasMatrixTransform(childTlist) && childTlist.numberOfItems == 1) { +// if(m.b==0 && m.c==0 && m.e==0 && m.f==0) { +// childTlist.removeItem(0); +// var translateOrigin = svgroot.createSVGTransform(), +// scale = svgroot.createSVGTransform(), +// translateBack = svgroot.createSVGTransform(); +// translateOrigin.setTranslate(0, 0); +// scale.setScale(m.a, m.d); +// translateBack.setTranslate(0, 0); +// childTlist.appendItem(translateBack); +// childTlist.appendItem(scale); +// childTlist.appendItem(translateOrigin); +// } +// } var angle = getRotationAngle(child); var old_start_transform = start_transform; @@ -3445,6 +3464,8 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) { start_transform = child.getAttribute("transform"); var childTlist = getTransformList(child); + if (!childTlist) continue; + var em = matrixMultiply(m, transformListToTransform(childTlist).matrix); var e2m = svgroot.createSVGTransform(); e2m.setMatrix(em); @@ -3595,8 +3616,11 @@ var recalculateDimensions = this.recalculateDimensions = function(selected) { // if we had [M][T][S][T] we want to extract the matrix equivalent of // [T][S][T] and push it down to the element if (N >= 3 && tlist.getItem(N-2).type == 3 && - tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2 && - selected.nodeName != "use") + tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2) + + // Removed this so a with a given [T][S][T] would convert to a matrix. + // Is that bad? + // && selected.nodeName != "use" { operation = 3; // scale m = transformListToTransform(tlist,N-3,N-1).matrix; @@ -4522,12 +4546,13 @@ var getMouseTarget = this.getMouseTarget = function(evt) { // to be a translate var xform = svgroot.createSVGTransform(); var tlist = getTransformList(selected); + // Note that if Webkit and there's no ID for this + // element, the dummy transform may have gotten lost. + // This results in unexpected behaviour + xform.setTranslate(dx,dy); if(tlist.numberOfItems) { tlist.replaceItem(xform, 0); - // TODO: Webkit returns null here, find out why -// console.log(selected.getAttribute("transform")) - } else { tlist.appendItem(xform); } @@ -5077,7 +5102,10 @@ var getMouseTarget = this.getMouseTarget = function(evt) { to: cur_shape.opacity, dur: ani_dur }).appendTo(element); - c_ani[0].beginElement(); + try { + // Fails in FF4 on foreignObject + c_ani[0].beginElement(); + } catch(e){} } else { ani_dur = 0; } @@ -5174,6 +5202,7 @@ var textActions = canvas.textActions = function() { function setCursor(index) { var empty = (textinput.value === ""); + $(textinput).focus(); if(!arguments.length) { if(empty) { @@ -5430,6 +5459,8 @@ var textActions = canvas.textActions = function() { allow_dbl = false; current_mode = "textedit"; selectorManager.requestSelector(curtext).showGrips(false); + // Make selector group accept clicks + var sel = selectorManager.requestSelector(curtext).selectorRect; textActions.init(); $(curtext).css('cursor', 'text'); @@ -5480,7 +5511,7 @@ var textActions = canvas.textActions = function() { }, setInputElem: function(elem) { textinput = elem; - $(textinput).blur(hideCursor); +// $(textinput).blur(hideCursor); }, clear: function() { current_text = null; @@ -5562,7 +5593,9 @@ var pathActions = this.pathActions = function() { 8: ['x','y','x1','y1'], 10: ['x','y','r1','r2','angle','largeArcFlag','sweepFlag'], 12: ['x'], - 14: ['y'] + 14: ['y'], + 16: ['x','y','x2','y2'], + 18: ['x','y'] }; function retPath() { @@ -7823,6 +7856,94 @@ var uniquifyElems = this.uniquifyElems = function(g) { obj_num++; } +// Function: convertToGroup +// Converts selected/given or child SVG element to a group +var convertToGroup = this.convertToGroup = function(elem) { + if(!elem) { + elem = selectedElements[0]; + } + var $elem = $(elem); + + var batchCmd = new BatchCommand(); + + var ts; + + if($elem.data('gsvg')) { + // Use the gsvg as the new group + var svg = elem.firstChild; + var pt = $(svg).attr(['x', 'y']); + + $(elem.firstChild.firstChild).unwrap(); + $(elem).removeData('gsvg'); + + var tlist = getTransformList(elem); + var xform = svgroot.createSVGTransform(); + xform.setTranslate(pt.x, pt.y); + tlist.appendItem(xform); + recalculateDimensions(elem); + call("selected", [elem]); + } else if($elem.data('symbol')) { + elem = $elem.data('symbol'); + + ts = $elem.attr('transform'); + var pos = $elem.attr(['x','y']); + + // Not ideal, but works + ts += "translate(" + pos.x + "," + pos.y + ")"; + + var prev = $elem.prev(); + + // Remove element + batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].parentNode)); + $elem.remove(); + + // See if other elements reference this symbol + var has_more = $(svgcontent).find('use:data(symbol)').length; + + var g = svgdoc.createElementNS(svgns, "g"); + var childs = elem.childNodes; + + for(var i = 0; i < childs.length; i++) { + g.appendChild(childs[i].cloneNode(true)); + } + +// while (elem.hasChildNodes()) +// g.appendChild(elem.firstChild.cloneNode(true)); + if (ts) + g.setAttribute("transform", ts); + + var parent = elem.parentNode; + + uniquifyElems(g); + + // now give the g itself a new id + g.id = getNextId(); + + prev.after(g); + + if(parent) { + if(!has_more) { + // remove symbol/svg element + parent.removeChild(elem); + batchCmd.addSubCommand(new RemoveElementCommand(elem, parent)); + } + batchCmd.addSubCommand(new InsertElementCommand(g)); + } + + // recalculate dimensions on the top-level children so that unnecessary transforms + // are removed + walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); + + clearSelection(); + addToSelection([g]); + + addCommandToHistory(batchCmd); + + } else { + console.log('Unexpected element to ungroup:', elem); + } +} + // // Function: setSvgString // This function sets the current drawing as the input SVG XML. @@ -7879,11 +8000,14 @@ this.setSvgString = function(xmlString) { // Wrap child SVGs in group elements $(svgcontent).find('svg').each(function() { + // Skip if it's in a + if($(this).closest('defs').length) return; + uniquifyElems(this); // Check if it already has a gsvg group var pa = this.parentNode; - if(pa.children.length === 1 && pa.nodeName === 'g') { + if(pa.childNodes.length === 1 && pa.nodeName === 'g') { $(pa).data('gsvg', this); pa.id = pa.id || getNextId(); } else { @@ -7891,6 +8015,16 @@ this.setSvgString = function(xmlString) { } }); + // Set ref element for elements + $(svgcontent).find('use').each(function() { + var id = this.getAttributeNS(xlinkns,"href").substr(1); + var ref_elem = getElem(id); + $(this).data('ref', ref_elem); + if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') { + $(this).data('symbol', ref_elem); + } + }); + // convert gradients with userSpaceOnUse to objectBoundingBox $(svgcontent).find('linearGradient, radialGradient').each(function() { var grad = this; @@ -8013,12 +8147,11 @@ this.setSvgString = function(xmlString) { }; // Function: importSvgString -// This function imports the input SVG XML into the current layer in the drawing +// This function imports the input SVG XML as a in the , then adds a +// to the current layer. // // Parameters: // xmlString - The SVG as XML text. -// toElements - Boolean indicating whether or not to convert the SVG to a group -// with children // // Returns: // This function returns false if the import was unsuccessful, true otherwise. @@ -8029,8 +8162,7 @@ this.setSvgString = function(xmlString) { // arbitrary transform lists, but makes some assumptions about how the transform list // was obtained // * import should happen in top-left of current zoomed viewport -// * create a new layer for the imported SVG -this.importSvgString = function(xmlString, toElements) { +this.importSvgString = function(xmlString) { try { // convert string into XML document var newDoc = Utils.text2xml(xmlString); @@ -8040,11 +8172,11 @@ this.importSvgString = function(xmlString, toElements) { var batchCmd = new BatchCommand("Change Source"); // import new svg document into our document - var importedNode = svgdoc.importNode(newDoc.documentElement, true); + var svg = svgdoc.importNode(newDoc.documentElement, true); - var innerw = convertToNum('width', importedNode.getAttribute("width")), - innerh = convertToNum('height', importedNode.getAttribute("height")), - innervb = importedNode.getAttribute("viewBox"), + var innerw = convertToNum('width', svg.getAttribute("width")), + innerh = convertToNum('height', svg.getAttribute("height")), + innervb = svg.getAttribute("viewBox"), // if no explicit viewbox, create one out of the width and height vb = innervb ? innervb.split(" ") : [0,0,innerw,innerh]; for (var j = 0; j < 4; ++j) @@ -8064,79 +8196,40 @@ this.importSvgString = function(xmlString, toElements) { // Hack to make recalculateDimensions understand how to scale ts = "translate(0) " + ts + " translate(0)"; - - if(!toElements) { - var elem = $(importedNode).appendTo(current_layer)[0]; - groupSvgElem(elem); - clearSelection(); - - var g = elem.parentNode; - - g.setAttribute("transform", ts); - recalculateDimensions(g); - - addToSelection([g]); - - return; - } + + // Uncomment this once Firefox has fixed their symbol bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 +// var symbol = svgdoc.createElementNS(svgns, "symbol"); +// while (svg.firstChild) { +// symbol.appendChild(svg.firstChild); +// } +// var attrs = svg.attributes; +// for(var i=0; i < attrs.length; i++) { +// var attr = attrs[i]; +// symbol.setAttribute(attr.nodeName, attr.nodeValue); +// } + var symbol = svg; + symbol.id = getNextId(); + + var use_el = svgdoc.createElementNS(svgns, "use"); + use_el.id = getNextId(); + use_el.setAttributeNS(xlinkns, "xlink:href", "#" + symbol.id); + findDefs().appendChild(symbol); + current_layer.appendChild(use_el); + clearSelection(); + + use_el.setAttribute("transform", ts); + recalculateDimensions(use_el); + $(use_el).data('symbol', symbol); + addToSelection([use_el]); + return true; + // TODO: Find way to add this in a recalculateDimensions-parsable way // if (vb[0] != 0 || vb[1] != 0) // ts = "translate(" + (-vb[0]) + "," + (-vb[1]) + ") " + ts; - // add all children of the imported to the we create - var g = svgdoc.createElementNS(svgns, "g"); - while (importedNode.hasChildNodes()) - g.appendChild(importedNode.firstChild); - if (ts) - g.setAttribute("transform", ts); - - uniquifyElems(g); - // now give the g itself a new id - g.id = getNextId(); - - current_layer.appendChild(g); - - // change image href vals if possible -// $(svgcontent).find('image').each(function() { -// var image = this; -// preventClickDefault(image); -// var val = this.getAttributeNS(xlinkns, "href"); -// if(val.indexOf('data:') === 0) { -// // Check if an SVG-edit data URI -// var m = val.match(/svgedit_url=(.*?);/); -// if(m) { -// var url = decodeURIComponent(m[1]); -// $(new Image()).load(function() { -// image.setAttributeNS(xlinkns,'xlink:href',url); -// }).attr('src',url); -// } -// } -// // Add to encodableImages if it loads -// canvas.embedImage(val); -// }); - - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - - batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); - - // reset zoom - TODO: why? -// current_zoom = 1; - - // identify layers -// identifyLayers(); - - // reset transform lists - svgTransformLists = {}; - clearSelection(); - - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); } catch(e) { console.log(e); return false; @@ -8614,7 +8707,7 @@ this.getZoom = function(){return current_zoom;}; // Function: getVersion // Returns a string which describes the revision number of SvgCanvas. this.getVersion = function() { - return "svgcanvas.js ($Rev: 1636 $)"; + return "svgcanvas.js ($Rev: 1653 $)"; }; // Function: setUiStrings @@ -8636,9 +8729,12 @@ this.setConfig = function(opts) { } // Function: getDocumentTitle -// Returns the current document title or an empty string if not found -this.getDocumentTitle = function() { - var childs = svgcontent.childNodes; +// Returns the current group/SVG's title contents +this.getTitle = function(elem) { + elem = elem || selectedElements[0]; + if(!elem) return; + elem = $(elem).data('gsvg') || $(elem).data('symbol') || elem; + var childs = elem.childNodes; for (var i=0; i + if(!chtlist) continue; + if (glist.numberOfItems) { // TODO: if the group's transform is just a rotate, we can always transfer the // rotate() down to the children (collapsing consecutive rotates and factoring diff --git a/public/svg-edit/editor/svgicons/jquery.svgicons.js b/public/svg-edit/editor/svgicons/jquery.svgicons.js index 2db257ea..85d19dff 100644 --- a/public/svg-edit/editor/svgicons/jquery.svgicons.js +++ b/public/svg-edit/editor/svgicons/jquery.svgicons.js @@ -172,7 +172,9 @@ $(function() { $(function() { getIcons('ajax'); }); - } + } else { + $(useFallback); + } } } }); @@ -252,7 +254,7 @@ $(function() { } if(isOpera) { setTimeout(function() { - icon.attr('style','visibility:visible;'); + icon.removeAttr('style'); },1); } }