diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2166a3c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +build/firefox/* +build/opera/* +build/svg-edit-2.6/* +build/svg-edit-2.6-src/* +build/svg-edit-2.6-src.tar.gz +build/svg-edit-2.6.wgt +build/svg-edit-2.6.xpi +build/svg-edit-2.6.zip \ No newline at end of file diff --git a/Makefile b/Makefile index d1ca4b3..7dc42f5 100644 --- a/Makefile +++ b/Makefile @@ -85,12 +85,6 @@ $(COMPILED_JS): compile: $(COMPILED_JS) $(COMPILED_CSS) release: build/$(PACKAGE) - cd build ; $(ZIP) $(PACKAGE).zip -r $(PACKAGE) ; cd .. - tar -z -c -f build/$(PACKAGE)-src.tar.gz \ - --exclude='\.svn' \ - --exclude='\.git' \ - --exclude='build/*' \ - . deploy: cp -R build/svg-edit-2.6 ../Method.ac/public diff --git a/build/firefox/chrome.manifest b/build/firefox/chrome.manifest deleted file mode 100644 index 3e98b2d..0000000 --- a/build/firefox/chrome.manifest +++ /dev/null @@ -1,2 +0,0 @@ -content svg-edit content/ -overlay chrome://browser/content/browser.xul chrome://svg-edit/content/svg-edit-overlay.xul diff --git a/build/firefox/content/editor/browser-not-supported.html b/build/firefox/content/editor/browser-not-supported.html deleted file mode 100644 index 3010fcf..0000000 --- a/build/firefox/content/editor/browser-not-supported.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - -Browser does not support SVG | SVG-edit - - - -
-SVG-edit logo
-

Sorry, but your browser does not support SVG. Below is a list of alternate browsers and versions that support SVG and SVG-edit (from caniuse.com).

-

Try the latest version of Firefox, Google Chrome, Safari, Opera or Internet Explorer.

-

If you are unable to install one of these and must use an old version of Internet Explorer, you can install the Google Chrome Frame plugin.

- - - -
- - - diff --git a/build/firefox/content/editor/browser.js b/build/firefox/content/editor/browser.js deleted file mode 100644 index edfba7b..0000000 --- a/build/firefox/content/editor/browser.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Package: svgedit.browser - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Alexis Deveria - */ - -// Dependencies: -// 1) jQuery (for $.alert()) - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.browser) { - svgedit.browser = {}; -} -var supportsSvg_ = (function() { - return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect; -})(); -svgedit.browser.supportsSvg = function() { return supportsSvg_; } -if(!svgedit.browser.supportsSvg()) { - window.location = "browser-not-supported.html"; -} -else{ - -var svgns = 'http://www.w3.org/2000/svg'; -var userAgent = navigator.userAgent; -var svg = document.createElementNS(svgns, 'svg'); - -// Note: Browser sniffing should only be used if no other detection method is possible -var isOpera_ = !!window.opera; -var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0; -var isGecko_ = userAgent.indexOf('Gecko/') >= 0; -var isIE_ = userAgent.indexOf('MSIE') >= 0; -var isChrome_ = userAgent.indexOf('Chrome/') >= 0; -var isWindows_ = userAgent.indexOf('Windows') >= 0; -var isMac_ = userAgent.indexOf('Macintosh') >= 0; -var isTouch_ = 'ontouchstart' in window; - -var supportsSelectors_ = (function() { - return !!svg.querySelector; -})(); - -var supportsXpath_ = (function() { - return !!document.evaluate; -})(); - -// segList functions (for FF1.5 and 2.0) -var supportsPathReplaceItem_ = (function() { - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.replaceItem(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -var supportsPathInsertItemBefore_ = (function() { - var path = document.createElementNS(svgns,'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.insertItemBefore(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -// text character positioning (for IE9) -var supportsGoodTextCharPos_ = (function() { - var retValue = false; - var svgroot = document.createElementNS(svgns, 'svg'); - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgroot); - svgcontent.setAttribute('x', 5); - svgroot.appendChild(svgcontent); - var text = document.createElementNS(svgns,'text'); - text.textContent = 'a'; - svgcontent.appendChild(text); - var pos = text.getStartPositionOfChar(0).x; - document.documentElement.removeChild(svgroot); - return (pos === 0); -})(); - -var supportsPathBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 C0,0 10,10 10,0'); - svgcontent.appendChild(path); - var bbox = path.getBBox(); - document.documentElement.removeChild(svgcontent); - return (bbox.height > 4 && bbox.height < 5); -})(); - -// Support for correct bbox sizing on groups with horizontal/vertical lines -var supportsHVLineContainerBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,0'); - var path2 = document.createElementNS(svgns, 'path'); - path2.setAttribute('d','M5,0 15,0'); - var g = document.createElementNS(svgns, 'g'); - g.appendChild(path); - g.appendChild(path2); - svgcontent.appendChild(g); - var bbox = g.getBBox(); - document.documentElement.removeChild(svgcontent); - // Webkit gives 0, FF gives 10, Opera (correctly) gives 15 - return (bbox.width == 15); -})(); - -var supportsEditableText_ = (function() { - // TODO: Find better way to check support for this - return isOpera_; -})(); - -var supportsGoodDecimals_ = (function() { - // Correct decimals on clone attributes (Opera < 10.5/win/non-en) - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('x',.1); - var crect = rect.cloneNode(false); - var retValue = (crect.getAttribute('x').indexOf(',') == -1); - if(!retValue) { - $.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\ - Please upgrade to the latest version in which the problems have been fixed."); - } - return retValue; -})(); - -var supportsNonScalingStroke_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('style','vector-effect:non-scaling-stroke'); - return rect.style.vectorEffect === 'non-scaling-stroke'; -})(); - -var supportsNativeSVGTransformLists_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - var rxform = rect.transform.baseVal; - - var t1 = svg.createSVGTransform(); - rxform.appendItem(t1); - return rxform.getItem(0) == t1; -})(); - -// Public API - -svgedit.browser.isOpera = function() { return isOpera_; } -svgedit.browser.isWebkit = function() { return isWebkit_; } -svgedit.browser.isGecko = function() { return isGecko_; } -svgedit.browser.isIE = function() { return isIE_; } -svgedit.browser.isChrome = function() { return isChrome_; } -svgedit.browser.isWindows = function() { return isWindows_; } -svgedit.browser.isMac = function() { return isMac_; } -svgedit.browser.isTouch = function() { return isTouch_; } - -svgedit.browser.supportsSelectors = function() { return supportsSelectors_; } -svgedit.browser.supportsXpath = function() { return supportsXpath_; } - -svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; } -svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; } -svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; } -svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; } -svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; } -svgedit.browser.supportsEditableText = function() { return supportsEditableText_; } -svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; } -svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; } -svgedit.browser.supportsNativeTransformLists = function() { return supportsNativeSVGTransformLists_; } - -} - -})(); diff --git a/build/firefox/content/editor/canvg/canvg.js b/build/firefox/content/editor/canvg/canvg.js deleted file mode 100644 index 7b24a38..0000000 --- a/build/firefox/content/editor/canvg/canvg.js +++ /dev/null @@ -1,2620 +0,0 @@ -/* - * canvg.js - Javascript SVG parser and renderer on Canvas - * MIT Licensed - * Gabe Lerner (gabelerner@gmail.com) - * http://code.google.com/p/canvg/ - * - * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ - */ -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(!Array.prototype.indexOf){ - Array.prototype.indexOf = function(obj){ - for(var i=0; i ignore mouse events - // ignoreAnimation: true => ignore animations - // ignoreDimensions: true => does not try to resize canvas - // ignoreClear: true => does not clear canvas - // offsetX: int => draws at a x offset - // offsetY: int => draws at a y offset - // scaleWidth: int => scales horizontally to width - // scaleHeight: int => scales vertically to height - // renderCallback: function => will call the function after the first render is completed - // forceRedraw: function => will call the function on every frame, if it returns true, will redraw - this.canvg = function (target, s, opts) { - // no parameters - if (target == null && s == null && opts == null) { - var svgTags = document.getElementsByTagName('svg'); - for (var i=0; i]*>/, ''); - var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); - xmlDoc.async = 'false'; - xmlDoc.loadXML(xml); - return xmlDoc; - } - } - - svg.Property = function(name, value) { - this.name = name; - this.value = value; - - this.hasValue = function() { - return (this.value != null && this.value !== ''); - } - - // return the numerical value of the property - this.numValue = function() { - if (!this.hasValue()) return 0; - - var n = parseFloat(this.value); - if ((this.value + '').match(/%$/)) { - n = n / 100.0; - } - return n; - } - - this.valueOrDefault = function(def) { - if (this.hasValue()) return this.value; - return def; - } - - this.numValueOrDefault = function(def) { - if (this.hasValue()) return this.numValue(); - return def; - } - - /* EXTENSIONS */ - var that = this; - - // color extensions - this.Color = { - // augment the current color value with the opacity - addOpacity: function(opacity) { - var newValue = that.value; - if (opacity != null && opacity != '') { - var color = new RGBColor(that.value); - if (color.ok) { - newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')'; - } - } - return new svg.Property(that.name, newValue); - } - } - - // definition extensions - this.Definition = { - // get the definition from the definitions table - getDefinition: function() { - var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2'); - return svg.Definitions[name]; - }, - - isUrl: function() { - return that.value.indexOf('url(') == 0 - }, - - getFillStyle: function(e) { - var def = this.getDefinition(); - - // gradient - if (def != null && def.createGradient) { - return def.createGradient(svg.ctx, e); - } - - // pattern - if (def != null && def.createPattern) { - return def.createPattern(svg.ctx, e); - } - - return null; - } - } - - // length extensions - this.Length = { - DPI: function(viewPort) { - return 96.0; // TODO: compute? - }, - - EM: function(viewPort) { - var em = 12; - - var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); - if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort); - - return em; - }, - - // get the length as pixels - toPixels: function(viewPort) { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/em$/)) return that.numValue() * this.EM(viewPort); - if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0; - if (s.match(/px$/)) return that.numValue(); - if (s.match(/pt$/)) return that.numValue() * 1.25; - if (s.match(/pc$/)) return that.numValue() * 15; - if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54; - if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4; - if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort); - if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort); - return that.numValue(); - } - } - - // time extensions - this.Time = { - // get the time as milliseconds - toMilliseconds: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/s$/)) return that.numValue() * 1000; - if (s.match(/ms$/)) return that.numValue(); - return that.numValue(); - } - } - - // angle extensions - this.Angle = { - // get the angle as radians - toRadians: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0); - if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0); - if (s.match(/rad$/)) return that.numValue(); - return that.numValue() * (Math.PI / 180.0); - } - } - } - - // fonts - svg.Font = new (function() { - this.Styles = ['normal','italic','oblique','inherit']; - this.Variants = ['normal','small-caps','inherit']; - this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit']; - - this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { - var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); - return { - fontFamily: fontFamily || f.fontFamily, - fontSize: fontSize || f.fontSize, - fontStyle: fontStyle || f.fontStyle, - fontWeight: fontWeight || f.fontWeight, - fontVariant: fontVariant || f.fontVariant, - toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } - } - } - - var that = this; - this.Parse = function(s) { - var f = {}; - var d = svg.trim(svg.compressSpaces(s || '')).split(' '); - var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } - var ff = ''; - for (var i=0; i this.x2) this.x2 = x; - } - - if (y != null) { - if (isNaN(this.y1) || isNaN(this.y2)) { - this.y1 = y; - this.y2 = y; - } - if (y < this.y1) this.y1 = y; - if (y > this.y2) this.y2 = y; - } - } - this.addX = function(x) { this.addPoint(x, null); } - this.addY = function(y) { this.addPoint(null, y); } - - this.addBoundingBox = function(bb) { - this.addPoint(bb.x1, bb.y1); - this.addPoint(bb.x2, bb.y2); - } - - this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { - var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) - var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) - this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); - } - - this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { - // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; - this.addPoint(p0[0], p0[1]); - this.addPoint(p3[0], p3[1]); - - for (i=0; i<=1; i++) { - var f = function(t) { - return Math.pow(1-t, 3) * p0[i] - + 3 * Math.pow(1-t, 2) * t * p1[i] - + 3 * (1-t) * Math.pow(t, 2) * p2[i] - + Math.pow(t, 3) * p3[i]; - } - - var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; - var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; - var c = 3 * p1[i] - 3 * p0[i]; - - if (a == 0) { - if (b == 0) continue; - var t = -c / b; - if (0 < t && t < 1) { - if (i == 0) this.addX(f(t)); - if (i == 1) this.addY(f(t)); - } - continue; - } - - var b2ac = Math.pow(b, 2) - 4 * c * a; - if (b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); - if (0 < t1 && t1 < 1) { - if (i == 0) this.addX(f(t1)); - if (i == 1) this.addY(f(t1)); - } - var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); - if (0 < t2 && t2 < 1) { - if (i == 0) this.addX(f(t2)); - if (i == 1) this.addY(f(t2)); - } - } - } - - this.isPointInBox = function(x, y) { - return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); - } - - this.addPoint(x1, y1); - this.addPoint(x2, y2); - } - - // transforms - svg.Transform = function(v) { - var that = this; - this.Type = {} - - // translate - this.Type.translate = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.translate(this.p.x || 0.0, this.p.y || 0.0); - } - this.applyToPoint = function(p) { - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - } - } - - // rotate - this.Type.rotate = function(s) { - var a = svg.ToNumberArray(s); - this.angle = new svg.Property('angle', a[0]); - this.cx = a[1] || 0; - this.cy = a[2] || 0; - this.apply = function(ctx) { - ctx.translate(this.cx, this.cy); - ctx.rotate(this.angle.Angle.toRadians()); - ctx.translate(-this.cx, -this.cy); - } - this.applyToPoint = function(p) { - var a = this.angle.Angle.toRadians(); - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); - p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); - } - } - - this.Type.scale = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); - } - this.applyToPoint = function(p) { - p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); - } - } - - this.Type.matrix = function(s) { - this.m = svg.ToNumberArray(s); - this.apply = function(ctx) { - ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); - } - this.applyToPoint = function(p) { - p.applyTransform(this.m); - } - } - - this.Type.SkewBase = function(s) { - this.base = that.Type.matrix; - this.base(s); - this.angle = new svg.Property('angle', s); - } - this.Type.SkewBase.prototype = new this.Type.matrix; - - this.Type.skewX = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0]; - } - this.Type.skewX.prototype = new this.Type.SkewBase; - - this.Type.skewY = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0]; - } - this.Type.skewY.prototype = new this.Type.SkewBase; - - this.transforms = []; - - this.apply = function(ctx) { - for (var i=0; i= this.tokens.length - 1; - } - - this.isCommandOrEnd = function() { - if (this.isEnd()) return true; - return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; - } - - this.isRelativeCommand = function() { - return this.command == this.command.toLowerCase(); - } - - this.getToken = function() { - this.i = this.i + 1; - return this.tokens[this.i]; - } - - this.getScalar = function() { - return parseFloat(this.getToken()); - } - - this.nextCommand = function() { - this.previousCommand = this.command; - this.command = this.getToken(); - } - - this.getPoint = function() { - var p = new svg.Point(this.getScalar(), this.getScalar()); - return this.makeAbsolute(p); - } - - this.getAsControlPoint = function() { - var p = this.getPoint(); - this.control = p; - return p; - } - - this.getAsCurrentPoint = function() { - var p = this.getPoint(); - this.current = p; - return p; - } - - this.getReflectedControlPoint = function() { - if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') { - return this.current; - } - - // reflect point - var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); - return p; - } - - this.makeAbsolute = function(p) { - if (this.isRelativeCommand()) { - p.x = this.current.x + p.x; - p.y = this.current.y + p.y; - } - return p; - } - - this.addMarker = function(p, from, priorTo) { - // if the last angle isn't filled in because we didn't have this point yet ... - if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) { - this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo); - } - this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); - } - - this.addMarkerAngle = function(p, a) { - this.points.push(p); - this.angles.push(a); - } - - this.getMarkerPoints = function() { return this.points; } - this.getMarkerAngles = function() { - for (var i=0; i 1) { - rx *= Math.sqrt(l); - ry *= Math.sqrt(l); - } - // cx', cy' - var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( - ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / - (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) - ); - if (isNaN(s)) s = 0; - var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); - // cx, cy - var centp = new svg.Point( - (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, - (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y - ); - // vector magnitude - var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } - // ratio between two vectors - var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } - // angle between two vectors - var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } - // initial angle - var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); - // angle delta - var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; - var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; - var ad = a(u, v); - if (r(u,v) <= -1) ad = Math.PI; - if (r(u,v) >= 1) ad = 0; - - if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI; - if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI; - - // for markers - var halfWay = new svg.Point( - centp.x - rx * Math.cos((a1 + ad) / 2), - centp.y - ry * Math.sin((a1 + ad) / 2) - ); - pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - - bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better - if (ctx != null) { - var r = rx > ry ? rx : ry; - var sx = rx > ry ? 1 : rx / ry; - var sy = rx > ry ? ry / rx : 1; - - ctx.translate(centp.x, centp.y); - ctx.rotate(xAxisRotation); - ctx.scale(sx, sy); - ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); - ctx.scale(1/sx, 1/sy); - ctx.rotate(-xAxisRotation); - ctx.translate(-centp.x, -centp.y); - } - } - break; - case 'Z': - if (ctx != null) ctx.closePath(); - pp.current = pp.start; - } - } - - return bb; - } - - this.getMarkers = function() { - var points = this.PathParser.getMarkerPoints(); - var angles = this.PathParser.getMarkerAngles(); - - var markers = []; - for (var i=0; i this.maxDuration) { - // loop for indefinitely repeating animations - if (this.attribute('repeatCount').value == 'indefinite') { - this.duration = 0.0 - } - else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { - this.removed = true; - this.getProperty().value = this.initialValue; - return true; - } - else { - return false; // no updates made - } - } - this.duration = this.duration + delta; - - // if we're past the begin time - var updated = false; - if (this.begin < this.duration) { - var newValue = this.calcValue(); // tween - - if (this.attribute('type').hasValue()) { - // for transform, etc. - var type = this.attribute('type').value; - newValue = type + '(' + newValue + ')'; - } - - this.getProperty().value = newValue; - updated = true; - } - - return updated; - } - - // fraction of duration we've covered - this.progress = function() { - return ((this.duration - this.begin) / (this.maxDuration - this.begin)); - } - } - svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; - - // animate element - svg.Element.animate = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = this.attribute('from').numValue(); - var to = this.attribute('to').numValue(); - - // tween value linearly - return from + (to - from) * this.progress(); - }; - } - svg.Element.animate.prototype = new svg.Element.AnimateBase; - - // animate color element - svg.Element.animateColor = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = new RGBColor(this.attribute('from').value); - var to = new RGBColor(this.attribute('to').value); - - if (from.ok && to.ok) { - // tween color linearly - var r = from.r + (to.r - from.r) * this.progress(); - var g = from.g + (to.g - from.g) * this.progress(); - var b = from.b + (to.b - from.b) * this.progress(); - return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; - } - return this.attribute('from').value; - }; - } - svg.Element.animateColor.prototype = new svg.Element.AnimateBase; - - // animate transform element - svg.Element.animateTransform = function(node) { - this.base = svg.Element.animate; - this.base(node); - } - svg.Element.animateTransform.prototype = new svg.Element.animate; - - // font element - svg.Element.font = function(node) { - this.base = svg.Element.ElementBase; - this.base(node); - - this.horizAdvX = this.attribute('horiz-adv-x').numValue(); - - this.isRTL = false; - this.isArabic = false; - this.fontFace = null; - this.missingGlyph = null; - this.glyphs = []; - for (var i=0; i0 && text[i-1]!=' ' && i0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial'; - if (typeof(font.glyphs[c]) != 'undefined') { - glyph = font.glyphs[c][arabicForm]; - if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c]; - } - } - else { - glyph = font.glyphs[c]; - } - if (glyph == null) glyph = font.missingGlyph; - return glyph; - } - - this.renderChildren = function(ctx) { - var customFont = this.parent.style('font-family').Definition.getDefinition(); - if (customFont != null) { - var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); - var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle); - var text = this.getText(); - if (customFont.isRTL) text = text.split("").reverse().join(""); - - var dx = svg.ToNumberArray(this.parent.attribute('dx').value); - for (var i=0; i 0 ? node.childNodes[0].nodeValue : // element - node.text; - this.getText = function() { - return this.text; - } - } - svg.Element.tspan.prototype = new svg.Element.TextElementBase; - - // tref - svg.Element.tref = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.getText = function() { - var element = this.attribute('xlink:href').Definition.getDefinition(); - if (element != null) return element.children[0].getText(); - } - } - svg.Element.tref.prototype = new svg.Element.TextElementBase; - - // a element - svg.Element.a = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.hasText = true; - for (var i=0; i 1 ? node.childNodes[1].nodeValue : ''); - css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments - css = svg.compressSpaces(css); // replace whitespace - var cssDefs = css.split('}'); - for (var i=0; i 0) { - var urlStart = srcs[s].indexOf('url'); - var urlEnd = srcs[s].indexOf(')', urlStart); - var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6); - var doc = svg.parseXml(svg.ajax(url)); - var fonts = doc.getElementsByTagName('font'); - for (var f=0; f - * @link http://www.phpied.com/rgb-color-parser-in-javascript/ - * @license Use it if you like it - */ -function RGBColor(color_string) -{ - this.ok = false; - - // strip any leading # - if (color_string.charAt(0) == '#') { // remove # if any - color_string = color_string.substr(1,6); - } - - color_string = color_string.replace(/ /g,''); - color_string = color_string.toLowerCase(); - - // before getting into regexps, try simple matches - // and overwrite the input - var simple_colors = { - aliceblue: 'f0f8ff', - antiquewhite: 'faebd7', - aqua: '00ffff', - aquamarine: '7fffd4', - azure: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '000000', - blanchedalmond: 'ffebcd', - blue: '0000ff', - blueviolet: '8a2be2', - brown: 'a52a2a', - burlywood: 'deb887', - cadetblue: '5f9ea0', - chartreuse: '7fff00', - chocolate: 'd2691e', - coral: 'ff7f50', - cornflowerblue: '6495ed', - cornsilk: 'fff8dc', - crimson: 'dc143c', - cyan: '00ffff', - darkblue: '00008b', - darkcyan: '008b8b', - darkgoldenrod: 'b8860b', - darkgray: 'a9a9a9', - darkgreen: '006400', - darkkhaki: 'bdb76b', - darkmagenta: '8b008b', - darkolivegreen: '556b2f', - darkorange: 'ff8c00', - darkorchid: '9932cc', - darkred: '8b0000', - darksalmon: 'e9967a', - darkseagreen: '8fbc8f', - darkslateblue: '483d8b', - darkslategray: '2f4f4f', - darkturquoise: '00ced1', - darkviolet: '9400d3', - deeppink: 'ff1493', - deepskyblue: '00bfff', - dimgray: '696969', - dodgerblue: '1e90ff', - feldspar: 'd19275', - firebrick: 'b22222', - floralwhite: 'fffaf0', - forestgreen: '228b22', - fuchsia: 'ff00ff', - gainsboro: 'dcdcdc', - ghostwhite: 'f8f8ff', - gold: 'ffd700', - goldenrod: 'daa520', - gray: '808080', - green: '008000', - greenyellow: 'adff2f', - honeydew: 'f0fff0', - hotpink: 'ff69b4', - indianred : 'cd5c5c', - indigo : '4b0082', - ivory: 'fffff0', - khaki: 'f0e68c', - lavender: 'e6e6fa', - lavenderblush: 'fff0f5', - lawngreen: '7cfc00', - lemonchiffon: 'fffacd', - lightblue: 'add8e6', - lightcoral: 'f08080', - lightcyan: 'e0ffff', - lightgoldenrodyellow: 'fafad2', - lightgrey: 'd3d3d3', - lightgreen: '90ee90', - lightpink: 'ffb6c1', - lightsalmon: 'ffa07a', - lightseagreen: '20b2aa', - lightskyblue: '87cefa', - lightslateblue: '8470ff', - lightslategray: '778899', - lightsteelblue: 'b0c4de', - lightyellow: 'ffffe0', - lime: '00ff00', - limegreen: '32cd32', - linen: 'faf0e6', - magenta: 'ff00ff', - maroon: '800000', - mediumaquamarine: '66cdaa', - mediumblue: '0000cd', - mediumorchid: 'ba55d3', - mediumpurple: '9370d8', - mediumseagreen: '3cb371', - mediumslateblue: '7b68ee', - mediumspringgreen: '00fa9a', - mediumturquoise: '48d1cc', - mediumvioletred: 'c71585', - midnightblue: '191970', - mintcream: 'f5fffa', - mistyrose: 'ffe4e1', - moccasin: 'ffe4b5', - navajowhite: 'ffdead', - navy: '000080', - oldlace: 'fdf5e6', - olive: '808000', - olivedrab: '6b8e23', - orange: 'ffa500', - orangered: 'ff4500', - orchid: 'da70d6', - palegoldenrod: 'eee8aa', - palegreen: '98fb98', - paleturquoise: 'afeeee', - palevioletred: 'd87093', - papayawhip: 'ffefd5', - peachpuff: 'ffdab9', - peru: 'cd853f', - pink: 'ffc0cb', - plum: 'dda0dd', - powderblue: 'b0e0e6', - purple: '800080', - red: 'ff0000', - rosybrown: 'bc8f8f', - royalblue: '4169e1', - saddlebrown: '8b4513', - salmon: 'fa8072', - sandybrown: 'f4a460', - seagreen: '2e8b57', - seashell: 'fff5ee', - sienna: 'a0522d', - silver: 'c0c0c0', - skyblue: '87ceeb', - slateblue: '6a5acd', - slategray: '708090', - snow: 'fffafa', - springgreen: '00ff7f', - steelblue: '4682b4', - tan: 'd2b48c', - teal: '008080', - thistle: 'd8bfd8', - tomato: 'ff6347', - turquoise: '40e0d0', - violet: 'ee82ee', - violetred: 'd02090', - wheat: 'f5deb3', - white: 'ffffff', - whitesmoke: 'f5f5f5', - yellow: 'ffff00', - yellowgreen: '9acd32' - }; - for (var key in simple_colors) { - if (color_string == key) { - color_string = simple_colors[key]; - } - } - // emd of simple type-in colors - - // array of color definition objects - var color_defs = [ - { - re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, - example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], - process: function (bits){ - return [ - parseInt(bits[1]), - parseInt(bits[2]), - parseInt(bits[3]) - ]; - } - }, - { - re: /^(\w{2})(\w{2})(\w{2})$/, - example: ['#00ff00', '336699'], - process: function (bits){ - return [ - parseInt(bits[1], 16), - parseInt(bits[2], 16), - parseInt(bits[3], 16) - ]; - } - }, - { - re: /^(\w{1})(\w{1})(\w{1})$/, - example: ['#fb0', 'f0f'], - process: function (bits){ - return [ - parseInt(bits[1] + bits[1], 16), - parseInt(bits[2] + bits[2], 16), - parseInt(bits[3] + bits[3], 16) - ]; - } - } - ]; - - // search through the definitions to find a match - for (var i = 0; i < color_defs.length; i++) { - var re = color_defs[i].re; - var processor = color_defs[i].process; - var bits = re.exec(color_string); - if (bits) { - channels = processor(bits); - this.r = channels[0]; - this.g = channels[1]; - this.b = channels[2]; - this.ok = true; - } - - } - - // validate/cleanup values - this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); - this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); - this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); - - // some getters - this.toRGB = function () { - return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; - } - this.toHex = function () { - var r = this.r.toString(16); - var g = this.g.toString(16); - var b = this.b.toString(16); - if (r.length == 1) r = '0' + r; - if (g.length == 1) g = '0' + g; - if (b.length == 1) b = '0' + b; - return '#' + r + g + b; - } - - // help - this.getHelpXML = function () { - - var examples = new Array(); - // add regexps - for (var i = 0; i < color_defs.length; i++) { - var example = color_defs[i].example; - for (var j = 0; j < example.length; j++) { - examples[examples.length] = example[j]; - } - } - // add type-in colors - for (var sc in simple_colors) { - examples[examples.length] = sc; - } - - var xml = document.createElement('ul'); - xml.setAttribute('id', 'rgbcolor-examples'); - for (var i = 0; i < examples.length; i++) { - try { - var list_item = document.createElement('li'); - var list_color = new RGBColor(examples[i]); - var example_div = document.createElement('div'); - example_div.style.cssText = - 'margin: 3px; ' - + 'border: 1px solid black; ' - + 'background:' + list_color.toHex() + '; ' - + 'color:' + list_color.toHex() - ; - example_div.appendChild(document.createTextNode('test')); - var list_item_value = document.createTextNode( - ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() - ); - list_item.appendChild(example_div); - list_item.appendChild(list_item_value); - xml.appendChild(list_item); - - } catch(e){} - } - return xml; - - } - -} diff --git a/build/firefox/content/editor/contextmenu.js b/build/firefox/content/editor/contextmenu.js deleted file mode 100644 index afa4318..0000000 --- a/build/firefox/content/editor/contextmenu.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Package: svgedit.contextmenu - * - * Licensed under the Apache License, Version 2 - * - * Author: Adam Bender - */ -// Dependencies: -// 1) jQuery (for dom injection of context menus)\ - -var svgedit = svgedit || {}; -(function() { - var self = this; - if (!svgedit.contextmenu) { - svgedit.contextmenu = {}; - } - self.contextMenuExtensions = {} - var addContextMenuItem = function(menuItem) { - // menuItem: {id, label, shortcut, action} - if (!menuItemIsValid(menuItem)) { - console - .error("Menu items must be defined and have at least properties: id, label, action, where action must be a function"); - return; - } - if (menuItem.id in self.contextMenuExtensions) { - console.error('Cannot add extension "' + menuItem.id - + '", an extension by that name already exists"'); - return; - } - // Register menuItem action, see below for deferred menu dom injection - console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}"); - self.contextMenuExtensions[menuItem.id] = menuItem; - //TODO: Need to consider how to handle custom enable/disable behavior - } - var hasCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey] && true; - } - var getCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey].action; - } - var injectExtendedContextMenuItemIntoDom = function(menuItem) { - if (Object.keys(self.contextMenuExtensions).length == 0) { - // all menuItems appear at the bottom of the menu in their own container. - // if this is the first extension menu we need to add the separator. - $("#cmenu_canvas").append("
  • "); - } - var shortcut = menuItem.shortcut || ""; - $("#cmenu_canvas").append("
  • " - + menuItem.label + "" - + shortcut + "
  • "); - } - - var menuItemIsValid = function(menuItem) { - return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function'; - } - - // Defer injection to wait out initial menu processing. This probably goes away once all context - // menu behavior is brought here. - svgEditor.ready(function() { - for (menuItem in contextMenuExtensions) { - injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]); - } - }); - svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {}} - svgedit.contextmenu.add = addContextMenuItem; - svgedit.contextmenu.hasCustomHandler = hasCustomHandler; - svgedit.contextmenu.getCustomHandler = getCustomHandler; -})(); diff --git a/build/firefox/content/editor/contextmenu/jquery.contextMenu.js b/build/firefox/content/editor/contextmenu/jquery.contextMenu.js deleted file mode 100755 index 009d6cd..0000000 --- a/build/firefox/content/editor/contextmenu/jquery.contextMenu.js +++ /dev/null @@ -1,203 +0,0 @@ -// jQuery Context Menu Plugin -// -// Version 1.01 -// -// Cory S.N. LaViska -// A Beautiful Site (http://abeautifulsite.net/) -// Modified by Alexis Deveria -// -// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/ -// -// Terms of Use -// -// This plugin is dual-licensed under the GNU General Public License -// and the MIT License and is copyright A Beautiful Site, LLC. -// -if(jQuery)( function() { - var win = $(window); - var doc = $(document); - - $.extend($.fn, { - - contextMenu: function(o, callback) { - // Defaults - if( o.menu == undefined ) return false; - if( o.inSpeed == undefined ) o.inSpeed = 150; - if( o.outSpeed == undefined ) o.outSpeed = 75; - // 0 needs to be -1 for expected results (no fade) - if( o.inSpeed == 0 ) o.inSpeed = -1; - if( o.outSpeed == 0 ) o.outSpeed = -1; - // Loop each context menu - $(this).each( function() { - var el = $(this); - var offset = $(el).offset(); - - var menu = $('#' + o.menu); - - // Add contextMenu class - menu.addClass('contextMenu'); - // Simulate a true right click - $(this).bind( "mousedown", function(e) { - var evt = e; - $(this).mouseup( function(e) { - var srcElement = $(this); - srcElement.unbind('mouseup'); - $(".contextMenu").hide(); - if( evt.button === 2 || o.allowLeft || (evt.ctrlKey && svgedit.browser.isMac()) ) { - e.stopPropagation(); - - // Get this context menu - - if( el.hasClass('disabled') ) return false; - - // Detect mouse position - var d = {}, x = e.pageX, y = e.pageY; - - var x_off = win.width() - menu.width(), - y_off = win.height() - menu.height(); - - if(x > x_off - 15) x = x_off-15; - if(y > y_off - 30) y = y_off-30; // 30 is needed to prevent scrollbars in FF - - // Show the menu - doc.unbind('click'); - menu.css({ top: y, left: x }).fadeIn(o.inSpeed); - // Hover events - menu.find('A').mouseover( function() { - menu.find('LI.hover').removeClass('hover'); - $(this).parent().addClass('hover'); - }).mouseout( function() { - menu.find('LI.hover').removeClass('hover'); - }); - - // Keyboard - doc.keypress( function(e) { - switch( e.keyCode ) { - case 38: // up - if( !menu.find('LI.hover').length ) { - menu.find('LI:last').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:last').addClass('hover'); - } - break; - case 40: // down - if( menu.find('LI.hover').length == 0 ) { - menu.find('LI:first').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:first').addClass('hover'); - } - break; - case 13: // enter - menu.find('LI.hover A').trigger('click'); - break; - case 27: // esc - doc.trigger('click'); - break - } - }); - - // When items are selected - menu.find('A').unbind('mouseup'); - menu.find('LI:not(.disabled) A').mouseup( function() { - doc.unbind('click').unbind('keypress'); - $(".contextMenu").hide(); - // Callback - if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); - return false; - }); - - // Hide bindings - setTimeout( function() { // Delay for Mozilla - doc.click( function() { - doc.unbind('click').unbind('keypress'); - menu.fadeOut(o.outSpeed); - return false; - }); - }, 0); - } - }); - }); - - // Disable text selection - if( $.browser.mozilla ) { - $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); - } else if( $.browser.msie ) { - $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); - } else { - $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); - } - // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) - $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); - - }); - return $(this); - }, - - // Disable context menu items on the fly - disableContextMenuItems: function(o) { - if( o == undefined ) { - // Disable all - $(this).find('LI').addClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Enable context menu items on the fly - enableContextMenuItems: function(o) { - if( o == undefined ) { - // Enable all - $(this).find('LI.disabled').removeClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Disable context menu(s) - disableContextMenu: function() { - $(this).each( function() { - $(this).addClass('disabled'); - }); - return( $(this) ); - }, - - // Enable context menu(s) - enableContextMenu: function() { - $(this).each( function() { - $(this).removeClass('disabled'); - }); - return( $(this) ); - }, - - // Destroy context menu(s) - destroyContextMenu: function() { - // Destroy specified context menus - $(this).each( function() { - // Disable action - $(this).unbind('mousedown').unbind('mouseup'); - }); - return( $(this) ); - } - - }); -})(jQuery); \ No newline at end of file diff --git a/build/firefox/content/editor/draginput.js b/build/firefox/content/editor/draginput.js deleted file mode 100644 index 0c172b1..0000000 --- a/build/firefox/content/editor/draginput.js +++ /dev/null @@ -1,47 +0,0 @@ -;(function($) { - - var methods = { - - init : function(options) { - - return this.each(function() { - - var settings = { - }; - - if(options) { - $.extend(settings, options); - } - - var plugin = this; - var $plugin = $(this); - - $plugin.settings = settings; - - this.privateMethod = function() { - } - - $plugin.data("example", {}); - - // Plug-in code here... - }); - - }, - - publicFunction : function() { - } - }; - - $.fn.example = function(method) { - if(methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } - else if(typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } - else { - $.error("Method " + method + " does not exist on jQuery.example"); - } - }; - -})(jQuery); \ No newline at end of file diff --git a/build/firefox/content/editor/draw.js b/build/firefox/content/editor/draw.js deleted file mode 100644 index 8db3138..0000000 --- a/build/firefox/content/editor/draw.js +++ /dev/null @@ -1,528 +0,0 @@ -/** - * Package: svgedit.draw - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2011 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgutils.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.draw) { - svgedit.draw = {}; -} - -var svg_ns = "http://www.w3.org/2000/svg"; -var se_ns = "http://svg-edit.googlecode.com"; -var xmlns_ns = "http://www.w3.org/2000/xmlns/"; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); - -var RandomizeModes = { - LET_DOCUMENT_DECIDE: 0, - ALWAYS_RANDOMIZE: 1, - NEVER_RANDOMIZE: 2 -}; -var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE; - -/** - * This class encapsulates the concept of a layer in the drawing - * @param name {String} Layer name - * @param child {SVGGElement} Layer SVG group. - */ -svgedit.draw.Layer = function(name, group) { - this.name_ = name; - this.group_ = group; -}; - -svgedit.draw.Layer.prototype.getName = function() { - return this.name_; -}; - -svgedit.draw.Layer.prototype.getGroup = function() { - return this.group_; -}; - - -// Called to ensure that drawings will or will not have randomized ids. -// The current_drawing will have its nonce set if it doesn't already. -// -// Params: -// enableRandomization - flag indicating if documents should have randomized ids -svgedit.draw.randomizeIds = function(enableRandomization, current_drawing) { - randomize_ids = enableRandomization == false ? - RandomizeModes.NEVER_RANDOMIZE : - RandomizeModes.ALWAYS_RANDOMIZE; - - if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !current_drawing.getNonce()) { - current_drawing.setNonce(Math.floor(Math.random() * 100001)); - } else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && current_drawing.getNonce()) { - current_drawing.clearNonce(); - } -}; - -/** - * This class encapsulates the concept of a SVG-edit drawing - * - * @param svgElem {SVGSVGElement} The SVG DOM Element that this JS object - * encapsulates. If the svgElem has a se:nonce attribute on it, then - * IDs will use the nonce as they are generated. - * @param opt_idPrefix {String} The ID prefix to use. Defaults to "svg_" - * if not specified. - */ -svgedit.draw.Drawing = function(svgElem, opt_idPrefix) { - if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI || - svgElem.tagName != 'svg' || svgElem.namespaceURI != svg_ns) { - throw "Error: svgedit.draw.Drawing instance initialized without a element"; - } - - /** - * The SVG DOM Element that represents this drawing. - * @type {SVGSVGElement} - */ - this.svgElem_ = svgElem; - - /** - * The latest object number used in this drawing. - * @type {number} - */ - this.obj_num = 0; - - /** - * The prefix to prepend to each element id in the drawing. - * @type {String} - */ - this.idPrefix = opt_idPrefix || "svg_"; - - /** - * An array of released element ids to immediately reuse. - * @type {Array.} - */ - this.releasedNums = []; - - /** - * The z-ordered array of tuples containing layer names and elements. - * The first layer is the one at the bottom of the rendering. - * TODO: Turn this into an Array. - * @type {Array.>} - */ - this.all_layers = []; - - /** - * The current layer being used. - * TODO: Make this a {Layer}. - * @type {SVGGElement} - */ - this.current_layer = null; - - /** - * The nonce to use to uniquely identify elements across drawings. - * @type {!String} - */ - this.nonce_ = ""; - var n = this.svgElem_.getAttributeNS(se_ns, 'nonce'); - // If already set in the DOM, use the nonce throughout the document - // else, if randomizeIds(true) has been called, create and set the nonce. - if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) { - this.nonce_ = n; - } else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) { - this.setNonce(Math.floor(Math.random() * 100001)); - } -}; - -svgedit.draw.Drawing.prototype.getElem_ = function(id) { - if(this.svgElem_.querySelector) { - // querySelector lookup - return this.svgElem_.querySelector('#'+id); - } else { - // jQuery lookup: twice as slow as xpath in FF - return $(this.svgElem_).find('[id=' + id + ']')[0]; - } -}; - -svgedit.draw.Drawing.prototype.getSvgElem = function() { - return this.svgElem_; -}; - -svgedit.draw.Drawing.prototype.getNonce = function() { - return this.nonce_; -}; - -svgedit.draw.Drawing.prototype.setNonce = function(n) { - this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns); - this.svgElem_.setAttributeNS(se_ns, 'se:nonce', n); - this.nonce_ = n; -}; - -svgedit.draw.Drawing.prototype.clearNonce = function() { - // We deliberately leave any se:nonce attributes alone, - // we just don't use it to randomize ids. - this.nonce_ = ""; -}; - -/** - * Returns the latest object id as a string. - * @return {String} The latest object Id. - */ -svgedit.draw.Drawing.prototype.getId = function() { - return this.nonce_ ? - this.idPrefix + this.nonce_ +'_' + this.obj_num : - this.idPrefix + this.obj_num; -}; - -/** - * Returns the next object Id as a string. - * @return {String} The next object Id to use. - */ -svgedit.draw.Drawing.prototype.getNextId = function() { - var oldObjNum = this.obj_num; - var restoreOldObjNum = false; - - // If there are any released numbers in the release stack, - // use the last one instead of the next obj_num. - // We need to temporarily use obj_num as that is what getId() depends on. - if (this.releasedNums.length > 0) { - this.obj_num = this.releasedNums.pop(); - restoreOldObjNum = true; - } else { - // If we are not using a released id, then increment the obj_num. - this.obj_num++; - } - - // Ensure the ID does not exist. - var id = this.getId(); - while (this.getElem_(id)) { - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - restoreOldObjNum = false; - } - this.obj_num++; - id = this.getId(); - } - // Restore the old object number if required. - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - } - return id; -}; - -// Function: svgedit.draw.Drawing.releaseId -// Releases the object Id, letting it be used as the next id in getNextId(). -// This method DOES NOT remove any elements from the DOM, it is expected -// that client code will do this. -// -// Parameters: -// id - The id to release. -// -// Returns: -// True if the id was valid to be released, false otherwise. -svgedit.draw.Drawing.prototype.releaseId = function(id) { - // confirm if this is a valid id for this Document, else return false - var front = this.idPrefix + (this.nonce_ ? this.nonce_ +'_' : ''); - if (typeof id != typeof '' || id.indexOf(front) != 0) { - return false; - } - // extract the obj_num of this id - var num = parseInt(id.substr(front.length)); - - // if we didn't get a positive number or we already released this number - // then return false. - if (typeof num != typeof 1 || num <= 0 || this.releasedNums.indexOf(num) != -1) { - return false; - } - - // push the released number into the released queue - this.releasedNums.push(num); - - return true; -}; - -// Function: svgedit.draw.Drawing.getNumLayers -// Returns the number of layers in the current drawing. -// -// Returns: -// The number of layers in the current drawing. -svgedit.draw.Drawing.prototype.getNumLayers = function() { - return this.all_layers.length; -}; - -// Function: svgedit.draw.Drawing.hasLayer -// Check if layer with given name already exists -svgedit.draw.Drawing.prototype.hasLayer = function(name) { - for(var i = 0; i < this.getNumLayers(); i++) { - if(this.all_layers[i][0] == name) return true; - } - return false; -}; - - -// Function: svgedit.draw.Drawing.getLayerName -// Returns the name of the ith layer. If the index is out of range, an empty string is returned. -// -// Parameters: -// i - the zero-based index of the layer you are querying. -// -// Returns: -// The name of the ith layer -svgedit.draw.Drawing.prototype.getLayerName = function(i) { - if (i >= 0 && i < this.getNumLayers()) { - return this.all_layers[i][0]; - } - return ""; -}; - -// Function: svgedit.draw.Drawing.getCurrentLayer -// Returns: -// The SVGGElement representing the current layer. -svgedit.draw.Drawing.prototype.getCurrentLayer = function() { - return this.current_layer; -}; - -// Function: getCurrentLayerName -// Returns the name of the currently selected layer. If an error occurs, an empty string -// is returned. -// -// Returns: -// The name of the currently active layer. -svgedit.draw.Drawing.prototype.getCurrentLayerName = function() { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.all_layers[i][1] == this.current_layer) { - return this.getLayerName(i); - } - } - return ""; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (name == this.getLayerName(i)) { - if (this.current_layer != this.all_layers[i][1]) { - this.current_layer.setAttribute("style", "pointer-events:none"); - this.current_layer = this.all_layers[i][1]; - this.current_layer.setAttribute("style", "pointer-events:all"); - } - return true; - } - } - return false; -}; - - -// Function: svgedit.draw.Drawing.deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -// Returns: -// The SVGGElement of the layer removed or null. -svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() { - if (this.current_layer && this.getNumLayers() > 1) { - // actually delete from the DOM and return it - var parent = this.current_layer.parentNode; - var nextSibling = this.current_layer.nextSibling; - var oldLayerGroup = parent.removeChild(this.current_layer); - this.identifyLayers(); - return oldLayerGroup; - } - return null; -}; - -// Function: svgedit.draw.Drawing.identifyLayers -// Updates layer system and sets the current layer to the -// top-most layer (last child of this drawing). -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 a_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] ); - a_layer = child; - svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); - a_layer.setAttribute("style", "pointer-events:none"); - } - // if group did not have a name, it is an orphan - else { - orphans.push(child); - } - } - // if child has is "visible" (i.e. not a or element), then it is an orphan - else if(~visElems_arr.indexOf(child.nodeName)) { - 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; - a_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = newname; - a_layer.appendChild(layer_title); - for (var j = 0; j < orphans.length; ++j) { - a_layer.appendChild(orphans[j]); - } - this.svgElem_.appendChild(a_layer); - this.all_layers.push( [newname, a_layer] ); - } - svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style","pointer-events:inherit");}); - this.current_layer = a_layer; - this.current_layer.setAttribute("style","pointer-events:all"); -}; - -// Function: svgedit.draw.Drawing.createLayer -// Creates a new top-level layer in the drawing with the given name and -// sets the current layer to it. -// -// Parameters: -// name - The given name -// -// Returns: -// The SVGGElement of the new layer, which is also the current layer -// of this drawing. -svgedit.draw.Drawing.prototype.createLayer = function(name) { - var svgdoc = this.svgElem_.ownerDocument; - var new_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - this.svgElem_.appendChild(new_layer); - this.identifyLayers(); - return new_layer; -}; - -// Function: svgedit.draw.Drawing.getLayerVisibility -// Returns whether the layer is visible. If the layer name is not valid, then this function -// returns false. -// -// Parameters: -// layername - the name of the layer which you want to query. -// -// Returns: -// The visibility state of the layer, or false if the layer name was invalid. -svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) { - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return false; - return (layer.getAttribute('display') != 'none'); -}; - -// Function: svgedit.draw.Drawing.setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// The SVGGElement representing the layer if the layername was valid, otherwise null. -svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) { - if (typeof bVisible != typeof true) { - return null; - } - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return null; - - var oldDisplay = layer.getAttribute("display"); - if (!oldDisplay) oldDisplay = "inline"; - layer.setAttribute("display", bVisible ? "inline" : "none"); - return layer; -}; - - -// Function: svgedit.draw.Drawing.getLayerOpacity -// Returns the opacity of the given layer. If the input name is not a layer, null is returned. -// -// Parameters: -// layername - name of the layer on which to get the opacity -// -// Returns: -// The opacity value of the given layer. This will be a value between 0.0 and 1.0, or null -// if layername is not a valid layer -svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - var opacity = g.getAttribute('opacity'); - if (!opacity) { - opacity = '1.0'; - } - return parseFloat(opacity); - } - } - return null; -}; - -// Function: svgedit.draw.Drawing.setLayerOpacity -// Sets the opacity of the given layer. If the input name is not a layer, nothing happens. -// If opacity is not a value between 0.0 and 1.0, then nothing happens. -// -// Parameters: -// layername - name of the layer on which to set the opacity -// opacity - a float value in the range 0.0-1.0 -svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) { - if (typeof opacity != typeof 1.0 || opacity < 0.0 || opacity > 1.0) { - return; - } - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - g.setAttribute("opacity", opacity); - break; - } - } -}; - -})(); diff --git a/build/firefox/content/editor/embedapi.html b/build/firefox/content/editor/embedapi.html deleted file mode 100644 index 3db0364..0000000 --- a/build/firefox/content/editor/embedapi.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - -
    - - - - diff --git a/build/firefox/content/editor/extensions/closepath_icons.svg b/build/firefox/content/editor/extensions/closepath_icons.svg deleted file mode 100644 index 7294f5e..0000000 --- a/build/firefox/content/editor/extensions/closepath_icons.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - - Layer 1 - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/firefox/content/editor/extensions/ext-arrows.js b/build/firefox/content/editor/extensions/ext-arrows.js deleted file mode 100644 index 4bb5cd2..0000000 --- a/build/firefox/content/editor/extensions/ext-arrows.js +++ /dev/null @@ -1,298 +0,0 @@ -/* - * ext-arrows.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - - -svgEditor.addExtension("Arrows", function(S) { - var svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomize_ids = S.randomize_ids, - selElems; - - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); - - var lang_list = { - "en":[ - {"id": "arrow_none", "textContent": "No arrow" } - ], - "fr":[ - {"id": "arrow_none", "textContent": "Sans flèche" } - ] - }; - - var prefix = 'se_arrow_'; - if (randomize_ids) { - var arrowprefix = prefix + nonce + '_'; - } else { - var arrowprefix = prefix; - } - - var pathdata = { - fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, - bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} - } - - function setArrowNonce(window, n) { - randomize_ids = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function unsetArrowNonce(window) { - randomize_ids = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if(!str) return null; - var m = str.match(/\(\#(.*)\)/); - if(!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } - - function showPanel(on) { - $('#arrow_panel').toggle(on); - - if(on) { - var el = selElems[0]; - var end = el.getAttribute("marker-end"); - var start = el.getAttribute("marker-start"); - var mid = el.getAttribute("marker-mid"); - var val; - - if(end && start) { - val = "both"; - } else if(end) { - val = "end"; - } else if(start) { - val = "start"; - } else if(mid) { - val = "mid"; - if(mid.indexOf("bk") != -1) { - val = "mid_bk"; - } - } - - if(!start && !mid && !end) { - val = "none"; - } - - $("#arrow_list").val(val); - } - } - - function resetMarker() { - var el = selElems[0]; - el.removeAttribute("marker-start"); - el.removeAttribute("marker-mid"); - el.removeAttribute("marker-end"); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var marker = S.getElem(id); - - var data = pathdata[dir]; - - if(type == "mid") { - data.refx = 5; - } - - if(!marker) { - marker = addElem({ - "element": "marker", - "attr": { - "viewBox": "0 0 10 10", - "id": id, - "refY": 5, - "markerUnits": "strokeWidth", - "markerWidth": 5, - "markerHeight": 5, - "orient": "auto", - "style": "pointer-events:none" // Currently needed for Opera - } - }); - var arrow = addElem({ - "element": "path", - "attr": { - "d": data.d, - "fill": "#000000" - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - var type = this.value; - resetMarker(); - - if(type == "none") { - return; - } - - // Set marker on element - var dir = "fw"; - if(type == "mid_bk") { - type = "mid"; - dir = "bk"; - } else if(type == "both") { - addMarker("bk", type); - svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); - type = "end"; - dir = "fw"; - } else if (type == "start") { - dir = "bk"; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); - S.call("changed", selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - - var mtypes = ['start','mid','end']; - var defs = S.findDefs(); - - $.each(mtypes, function(i, type) { - var marker = getLinked(elem, 'marker-'+type); - if(!marker) return; - - var cur_color = $(marker).children().attr('fill'); - var cur_d = $(marker).children().attr('d'); - var new_marker = null; - if(cur_color === color) return; - - var all_markers = $(defs).find('marker'); - // Different color, check if already made - all_markers.each(function() { - var attrs = $(this).children().attr(['fill', 'd']); - if(attrs.fill === color && attrs.d === cur_d) { - // Found another marker with this color and this path - new_marker = this; - } - }); - - if(!new_marker) { - // Create a new marker with this color - var last_id = marker.id; - var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; - - new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); - - $(new_marker).children().attr('fill', color); - } - - $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function() { - var elem = this; - $.each(mtypes, function(j, mtype) { - if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { - return remove = false; - } - }); - if(!remove) return false; - }); - - // Not found, so can safely remove - if(remove) { - $(marker).remove(); - } - - }); - - } - - return { - name: "Arrows", - context_tools: [{ - type: "select", - panel: "arrow_panel", - title: "Select arrow type", - id: "arrow_list", - options: { - none: "No arrow", - end: "---->", - start: "<----", - both: "<--->", - mid: "-->--", - mid_bk: "--<--" - }, - defval: "none", - events: { - change: setArrow - } - }], - callback: function() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function(lang) { - return { - data: lang_list[lang] - }; - }, - selectedChanged: function(opts) { - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - var marker_elems = ['line','path','polyline','polygon']; - - while(i--) { - var elem = selElems[i]; - if(elem && $.inArray(elem.tagName, marker_elems) != -1) { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function(opts) { - var elem = opts.elems[0]; - if(elem && ( - elem.getAttribute("marker-start") || - elem.getAttribute("marker-mid") || - elem.getAttribute("marker-end") - )) { - // var start = elem.getAttribute("marker-start"); - // var mid = elem.getAttribute("marker-mid"); - // var end = elem.getAttribute("marker-end"); - // Has marker, so see if it should match color - colorChanged(elem); - } - - } - }; -}); diff --git a/build/firefox/content/editor/extensions/ext-closepath.js b/build/firefox/content/editor/extensions/ext-closepath.js deleted file mode 100644 index bf8e72c..0000000 --- a/build/firefox/content/editor/extensions/ext-closepath.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ext-closepath.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * - */ - -// This extension adds a simple button to the contextual panel for paths -// The button toggles whether the path is open or closed -svgEditor.addExtension("ClosePath", function(S) { - var selElems, - updateButton = function(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) updateButton(path); - } - }, - - toggleClosed = function() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if(seglist.getItem(last).pathSegType == 1) { - seglist.removeItem(last); - } - else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; - - return { - name: "ClosePath", - svgicons: "extensions/closepath_icons.svg", - buttons: [{ - id: "tool_openpath", - type: "context", - panel: "closepath_panel", - title: "Open path", - events: { - 'click': function() { - toggleClosed(); - } - } - }, - { - id: "tool_closepath", - type: "context", - panel: "closepath_panel", - title: "Close path", - events: { - 'click': function() { - toggleClosed(); - } - } - }], - callback: function() { - $('#closepath_panel').hide(); - }, - selectedChanged: function(opts) { - selElems = opts.elems; - var i = selElems.length; - - while(i--) { - var elem = selElems[i]; - if(elem && elem.tagName == 'path') { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; -}); diff --git a/build/firefox/content/editor/extensions/ext-connector.js b/build/firefox/content/editor/extensions/ext-connector.js deleted file mode 100644 index 3498c7f..0000000 --- a/build/firefox/content/editor/extensions/ext-connector.js +++ /dev/null @@ -1,587 +0,0 @@ -/* - * ext-connector.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - -svgEditor.addExtension("Connector", function(S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = svgEditor.curConfig, - started = false, - start_x, - start_y, - cur_line, - start_elem, - end_elem, - connections = [], - conn_sel = ".se_connector", - se_ns, -// connect_str = "-SE_CONNECT-", - selElems = []; - - elData = $.data; - - var lang_list = { - "en":[ - {"id": "mode_connect", "title": "Connect two objects" } - ], - "fr":[ - {"id": "mode_connect", "title": "Connecter deux objets"} - ] - }; - - function getOffset(side, line) { - var give_offset = !!line.getAttribute('marker-' + side); -// var give_offset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return give_offset ? size : 0; - } - - function showPanel(on) { - var conn_rules = $('#connector_rules'); - if(!conn_rules.length) { - conn_rules = $(' -
    - -
    - - -
    -
    -

    Layers

    -
    -
    -
    -
    -
    -
    -
    -
    - - - - - - -
    Layer 1
    - Move elements to: - -
    -
    L a y e r s
    -
    - - - - - -
    - -
    - -
    -

    Canvas

    - - -
    - -
    - -
    -

    Rectangle

    -
    - - -
    - -
    - -
    -

    Path

    -
    - -
    -

    Image

    -
    - - -
    -
    - - -
    -
    - -
    -
    - - -
    -
    - -
    -
    - -
    -

    Ellipse

    -
    - - -
    -
    - - -
    -
    - -
    -

    Line

    -
    - - -
    -
    - - -
    -
    - -
    -

    Text

    - -
    - - - - -
    - -
    -
    B
    -
    i
    -
    - - - - - -
    - - -
    - - - - -
    - -
    - -
    - -
    -

    Group

    -
    - - -
    - -
    - -
    -

    Path

    -
    - -
    - - - - -
    -
    -
    -
    -
    - - -
    - - - - - - - - -

    Stroke

    -
    - -
    - - - - - - -

    Align

    -
    - -
    -
    -

    Position

    - - -
    -
    - - -
    -

    Multiple Elements

    - - - - - - -
    -

    Align

    - -
    - -
    - -
    - -
    -
    - -
    - - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    - -
    -
    -
    -
    -
    - -
    - -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    - - -
    - -
    - -
    - -
    - -
    -
    -
    -
    - - - - - -
    - - - -
    -
    -
    -
    -

    Copy the contents of this box into a text editor, then save the file with a .svg extension.

    - -
    -
    - -
    -
    - - -
    -
    -
    - - -
    -
    -
    - -
    - Canvas Dimensions - - - - - - -
    -
    - - -
    -
    -
    - -
    -
    -
    - -
    - Editor Preferences - - - - - - - - - - - - - - - - - -
    -
    - - -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    - - - - - - - - - diff --git a/build/firefox/content/editor/svg-editor.js b/build/firefox/content/editor/svg-editor.js deleted file mode 100644 index bd7bbe6..0000000 --- a/build/firefox/content/editor/svg-editor.js +++ /dev/null @@ -1,4893 +0,0 @@ -/* - * svg-editor.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Narendra Sisodiya - * - */ - -// Dependencies: -// 1) units.js -// 2) browser.js -// 3) svgcanvas.js - -(function() { - - document.addEventListener("touchstart", touchHandler, true); - document.addEventListener("touchmove", touchHandler, true); - document.addEventListener("touchend", touchHandler, true); - document.addEventListener("touchcancel", touchHandler, true); - if(!window.svgEditor) window.svgEditor = function($) { - var svgCanvas; - var Editor = {}; - var is_ready = false; - - var defaultPrefs = { - lang:'en', - iconsize:'m', - bkgd_color:'FFF', - bkgd_url:'', - img_save:'embed' - }, - curPrefs = {}, - - // Note: Difference between Prefs and Config is that Prefs can be - // changed in the UI and are stored in the browser, config can not - - curConfig = { - canvas_expansion: 1.2, - dimensions: [640,480], - initFill: { - color: 'fff', // solid red - opacity: 1 - }, - initStroke: { - width: 1.5, - color: '000', // solid black - opacity: 1 - }, - initOpacity: 1, - imgPath: 'images/', - langPath: 'locale/', - extPath: 'extensions/', - jGraduatePath: 'jgraduate/images/', - extensions: ['ext-markers.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-grid.js'], - initTool: 'select', - wireframe: false, - colorPickerCSS: false, - gridSnapping: false, - gridColor: "#000", - baseUnit: 'px', - snappingStep: 10, - showRulers: true, - show_outside_canvas: false, - no_save_warning: true - }, - uiStrings = Editor.uiStrings = { - common: { - "ok":"OK", - "cancel":"Cancel", - "key_up":"Up", - "key_down":"Down", - "key_backspace":"Backspace", - "key_del":"Del" - - }, - // This is needed if the locale is English, since the locale strings are not read in that instance. - layers: { - "layer":"Layer" - }, - notification: { - "invalidAttrValGiven":"Invalid value given", - "noContentToFitTo":"No content to fit to", - "dupeLayerName":"There is already a layer named that!", - "enterUniqueLayerName":"Please enter a unique layer name", - "enterNewLayerName":"Please enter the new layer name", - "layerHasThatName":"Layer already has that name", - "QmoveElemsToLayer":"Move selected elements to layer \"%s\"?", - "QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!", - "QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!", - "QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?", - "QignoreSourceChanges":"Ignore changes made to SVG source?", - "featNotSupported":"Feature not supported", - "enterNewImgURL":"Enter the new image URL", - "defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.", - "loadingImage":"Loading image, please wait...", - "saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.", - "noteTheseIssues": "Also note the following issues: ", - "unsavedChanges": "There are unsaved changes.", - "enterNewLinkURL": "Enter the new hyperlink URL", - "errorLoadingSVG": "Error: Unable to load SVG data", - "URLloadFail": "Unable to load from URL", - "retrieving": 'Retrieving "%s" ...' - } - }; - - var curPrefs = {}; //$.extend({}, defaultPrefs); - - var customHandlers = {}; - - Editor.curConfig = curConfig; - - Editor.tool_scale = 1; - -// window.ontouchmove = function(e) { -// e.stopPropagation(); -// }; -// -// $(document).bind("touchmove", function(evt) { -// if (evt.target.tagName.toLowerCase() !== "path" && evt.target.tagName.toLowerCase() !== "a") { -// return evt.preventDefault(); -// } -// }); - - // Store and retrieve preferences - $.pref = function(key, val) { - if(val) curPrefs[key] = val; - key = 'svg-edit-'+key; - var host = location.hostname, - onweb = host && host.indexOf('.') >= 0, - store = (val != undefined), - storage = false; - // Some FF versions throw security errors here - try { - if(window.localStorage) { // && onweb removed so Webkit works locally - storage = localStorage; - } - } catch(e) {} - try { - if(window.globalStorage && onweb) { - storage = globalStorage[host]; - } - } catch(e) {} - - if(storage) { - if(store) storage.setItem(key, val); - else if (storage.getItem(key)) return storage.getItem(key) + ''; // Convert to string for FF (.value fails in Webkit) - } else if(window.widget) { - if(store) widget.setPreferenceForKey(val, key); - else return widget.preferenceForKey(key); - } else { - if(store) { - var d = new Date(); - d.setTime(d.getTime() + 31536000000); - val = encodeURIComponent(val); - document.cookie = key+'='+val+'; expires='+d.toUTCString(); - } else { - var result = document.cookie.match(new RegExp(key + "=([^;]+)")); - return result?decodeURIComponent(result[1]):''; - } - } - } - - Editor.setConfig = function(opts) { - $.each(opts, function(key, val) { - // Only allow prefs defined in defaultPrefs - if(key in defaultPrefs) { - $.pref(key, val); - } - }); - $.extend(true, curConfig, opts); - if(opts.extensions) { - curConfig.extensions = opts.extensions; - } - - } - - // Extension mechanisms must call setCustomHandlers with two functions: opts.open and opts.save - // opts.open's responsibilities are: - // - invoke a file chooser dialog in 'open' mode - // - let user pick a SVG file - // - calls setCanvas.setSvgString() with the string contents of that file - // opts.save's responsibilities are: - // - accept the string contents of the current document - // - invoke a file chooser dialog in 'save' mode - // - save the file to location chosen by the user - Editor.setCustomHandlers = function(opts) { - Editor.ready(function() { - if(opts.open) { - $('#tool_open > input[type="file"]').remove(); - $('#tool_open').show(); - svgCanvas.open = opts.open; - } - if(opts.save) { - Editor.show_save_warning = false; - svgCanvas.bind("saved", opts.save); - } - if(opts.pngsave) { - svgCanvas.bind("exported", opts.pngsave); - } - customHandlers = opts; - }); - } - - Editor.randomizeIds = function() { - svgCanvas.randomizeIds(arguments) - } - - Editor.init = function() { - // For external openers - (function() { - // let the opener know SVG Edit is ready - var w = window.opener; - if (w) { - try { - var svgEditorReadyEvent = w.document.createEvent("Event"); - svgEditorReadyEvent.initEvent("svgEditorReady", true, true); - w.document.documentElement.dispatchEvent(svgEditorReadyEvent); - } - catch(e) {} - } - })(); - - (function() { - // Load config/data from URL if given - var urldata = $.deparam.querystring(true); - if(!$.isEmptyObject(urldata)) { - if(urldata.dimensions) { - urldata.dimensions = urldata.dimensions.split(','); - } - - if(urldata.extensions) { - urldata.extensions = urldata.extensions.split(','); - } - - if(urldata.bkgd_color) { - urldata.bkgd_color = '#' + urldata.bkgd_color; - } - - svgEditor.setConfig(urldata); - - var src = urldata.source; - var qstr = $.param.querystring(); - - if(!src) { // urldata.source may have been null if it ended with '=' - if(qstr.indexOf('source=data:') >= 0) { - src = qstr.match(/source=(data:[^&]*)/)[1]; - } - } - - if(src) { - if(src.indexOf("data:") === 0) { - // plusses get replaced by spaces, so re-insert - src = src.replace(/ /g, "+"); - Editor.loadFromDataURI(src); - } else { - Editor.loadFromString(src); - } - } else if(qstr.indexOf('paramurl=') !== -1) { - // Get paramater URL (use full length of remaining location.href) - svgEditor.loadFromURL(qstr.substr(9)); - } else if(urldata.url) { - svgEditor.loadFromURL(urldata.url); - } - } - })(); - - var extFunc = function() { - $.each(curConfig.extensions, function() { - 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); - } - }); - }); - - var good_langs = []; - - $('#lang_select option').each(function() { - good_langs.push(this.value); - }); - - // var lang = ('lang' in curPrefs) ? curPrefs.lang : null; - Editor.putLocale(null, good_langs); - } - - // Load extensions - // Bit of a hack to run extensions in local Opera/IE9 - if(document.location.protocol === 'file:') { - setTimeout(extFunc, 100); - } else { - extFunc(); - } - $.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { - w:24, h:24, - id_match: false, - no_img: !svgedit.browser.isWebkit(), // Opera & Firefox 4 gives odd behavior w/images - fallback_path: curConfig.imgPath, - fallback:{ - 'new_image':'clear.png', - 'save':'save.png', - 'open':'open.png', - 'source':'source.png', - 'docprops':'document-properties.png', - 'wireframe':'wireframe.png', - - 'undo':'undo.png', - 'redo':'redo.png', - - 'select':'select.png', - 'select_node':'select_node.png', - 'pencil':'fhpath.png', - 'pen':'line.png', - 'square':'square.png', - 'rect':'rect.png', - 'fh_rect':'freehand-square.png', - 'circle':'circle.png', - 'ellipse':'ellipse.png', - 'fh_ellipse':'freehand-circle.png', - 'path':'path.png', - 'text':'text.png', - 'image':'image.png', - 'zoom':'zoom.png', - - 'clone':'clone.png', - 'node_clone':'node_clone.png', - 'delete':'delete.png', - 'node_delete':'node_delete.png', - //'group':'shape_group.png', - //'ungroup':'shape_ungroup.png', - 'move_top':'move_top.png', - 'move_bottom':'move_bottom.png', - 'to_path':'to_path.png', - 'link_controls':'link_controls.png', - 'reorient':'reorient.png', - - 'align_left':'align-left.png', - 'align_center':'align-center', - 'align_right':'align-right', - 'align_top':'align-top', - 'align_middle':'align-middle', - 'align_bottom':'align-bottom', - - 'go_up':'go-up.png', - 'go_down':'go-down.png', - - 'ok':'save.png', - 'cancel':'cancel.png', - - 'arrow_right':'flyouth.png', - 'arrow_down':'dropdown.gif' - }, - placement: { - '#tool_docprops > div':'docprops', - - '#tool_select':'select', - '#tool_fhpath':'pencil', - '#tool_line':'pen', - '#tool_rect,#tools_rect_show':'rect', - '#tool_square':'square', - '#tool_fhrect':'fh_rect', - '#tool_ellipse,#tools_ellipse_show':'ellipse', - '#tool_circle':'circle', - '#tool_fhellipse':'fh_ellipse', - '#tool_path':'path', - '#tool_text,#layer_rename':'text', - '#tool_image':'image', - '#tool_zoom':'zoom', - - '#tool_node_clone':'node_clone', - '#tool_node_delete':'node_delete', - '#tool_add_subpath':'add_subpath', - '#tool_openclose_path':'open_path', - '#tool_node_link':'link_controls', - //'#tool_group':'group', - //'#tool_ungroup':'ungroup', - //'#tool_unlink_use':'unlink_use', - - '#tool_alignleft, #tool_posleft':'align_left', - '#tool_aligncenter, #tool_poscenter':'align_center', - '#tool_alignright, #tool_posright':'align_right', - '#tool_aligntop, #tool_postop':'align_top', - '#tool_alignmiddle, #tool_posmiddle':'align_middle', - '#tool_alignbottom, #tool_posbottom':'align_bottom', - '#cur_position':'align', - - '#linecap_butt,#cur_linecap':'linecap_butt', - '#linecap_round':'linecap_round', - '#linecap_square':'linecap_square', - - '#linejoin_miter,#cur_linejoin':'linejoin_miter', - '#linejoin_round':'linejoin_round', - '#linejoin_bevel':'linejoin_bevel', - - '#url_notice':'warning', - - '#layer_up':'go_up', - '#layer_down':'go_down', - '#layer_moreopts':'context_menu', - '#layerlist td.layervis':'eye', - - '#tool_source_save,#tool_docprops_save,#tool_prefs_save':'ok', - '#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel':'cancel', - - '#rwidthLabel, #iwidthLabel':'width', - '#rheightLabel, #iheightLabel':'height', - //'#cornerRadiusLabel span':'c_radius', - '#angleLabel':'angle', - '#linkLabel,#tool_make_link,#tool_make_link_multi':'globe_link', - '#zoomLabel':'zoom', - //'#tool_fill label': 'fill', - //'#tool_stroke .icon_label': 'stroke', - //'#group_opacityLabel': 'opacity', - '#blurLabel': 'blur', - //'#font_sizeLabel': 'fontsize', - - '.flyout_arrow_horiz':'arrow_right', - //'.dropdown button, #main_button .dropdown':'arrow_down', - '#palette .palette_item:first, #fill_bg, #stroke_bg':'no_color' - }, - resize: { - '#logo .svg_icon': 32, - '.flyout_arrow_horiz .svg_icon': 5, - '.layer_button .svg_icon, #layerlist td.layervis .svg_icon': 14, - //'.dropdown button .svg_icon': 7, - '#main_button .dropdown .svg_icon': 9, - '#fill_bg .svg_icon, #stroke_bg .svg_icon': 24, - '.palette_item:first .svg_icon': 16, - '.toolbar_button button .svg_icon':16, - '.stroke_tool div div .svg_icon': 20, - '#tools_bottom label .svg_icon': 18, - '#zoom_dropdown .svg_icon': 7 - }, - callback: function(icons) { - $('.toolbar_button button > svg, .toolbar_button button > img').each(function() { - $(this).parent().prepend(this); - }); - - var tleft = $('#tools_left'); - if (tleft.length != 0) { - var min_height = tleft.offset().top + tleft.outerHeight(); - } - - // Look for any missing flyout icons from plugins - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var sel = shower.attr('data-curopt'); - // Check if there's an icon here - if(!shower.children('svg, img').length) { - var clone = $(sel).children().clone(); - if(clone.length) { - clone[0].removeAttribute('style'); //Needed for Opera - shower.append(clone); - } - } - }); - - svgEditor.runCallbacks(); - - setTimeout(function() { - $('.flyout_arrow_horiz:empty').each(function() { - $(this).append($.getSvgIcon('arrow_right').width(5).height(5)); - }); - }, 1); - } - }); - - Editor.canvas = svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), curConfig); - Editor.show_save_warning = false; - var palette = ["#000000", "#3f3f3f", "#7f7f7f", "#bfbfbf", "#ffffff", - "#ff0000", "#ff7f00", "#ffff00", "#7fff00", - "#00ff00", "#00ff7f", "#00ffff", "#007fff", - "#0000ff", "#7f00ff", "#ff00ff", "#ff007f", - "#7f0000", "#7f3f00", "#7f7f00", "#3f7f00", - "#007f00", "#007f3f", "#007f7f", "#003f7f", - "#00007f", "#3f007f", "#7f007f", "#7f003f", - "#ffaaaa", "#ffd4aa", "#ffffaa", "#d4ffaa", - "#aaffaa", "#aaffd4", "#aaffff", "#aad4ff", - "#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4" - ], - isMac = (navigator.platform.indexOf("Mac") >= 0), - isWebkit = (navigator.userAgent.indexOf("AppleWebKit") >= 0), - modKey = (isMac ? "meta+" : "ctrl+"), // ⌘ - path = svgCanvas.pathActions, - undoMgr = svgCanvas.undoMgr, - Utils = svgedit.utilities, - default_img_url = curConfig.imgPath + "placeholder.svg", - workarea = $("#workarea"), - canv_menu = $("#cmenu_canvas"), - layer_menu = $("#cmenu_layers"), - exportWindow = null, - tool_scale = 1, - zoomInIcon = 'crosshair', - zoomOutIcon = 'crosshair', - ui_context = 'toolbars', - orig_source = '', - paintBox = {fill: null, stroke:null}; - - // This sets up alternative dialog boxes. They mostly work the same way as - // their UI counterparts, expect instead of returning the result, a callback - // needs to be included that returns the result as its first parameter. - // In the future we may want to add additional types of dialog boxes, since - // they should be easy to handle this way. - (function() { - $('#dialog_container').draggable({cancel:'#dialog_content, #dialog_buttons *', containment: 'window'}); - var box = $('#dialog_box'), btn_holder = $('#dialog_buttons'); - - var dbox = function(type, msg, callback, defText) { - $('#dialog_content').html('

    '+msg.replace(/\n/g,'

    ')+'

    ') - .toggleClass('prompt',(type=='prompt')); - btn_holder.empty(); - - var ok = $('').appendTo(btn_holder); - - if(type != 'alert') { - $('') - .appendTo(btn_holder) - .click(function() { box.hide();callback(false)}); - } - - if(type == 'prompt') { - var input = $('').prependTo(btn_holder); - input.val(defText || ''); - input.bind('keydown', 'return', function() {ok.click();}); - } - - if(type == 'process') { - ok.hide(); - } - - box.show(); - - ok.click(function() { - box.hide(); - var resp = (type == 'prompt')?input.val():true; - if(callback) callback(resp); - }).focus(); - - if(type == 'prompt') input.focus(); - } - - $.alert = function(msg, cb) { dbox('alert', msg, cb);}; - $.confirm = function(msg, cb) { dbox('confirm', msg, cb);}; - $.process_cancel = function(msg, cb) { dbox('process', msg, cb);}; - $.prompt = function(msg, txt, cb) { dbox('prompt', msg, cb, txt);}; - }()); - - var setSelectMode = function() { - var curr = $('.tool_button_current'); - if(curr.length && curr[0].id !== 'tool_select') { - curr.removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}'); - } - svgCanvas.setMode('select'); - }; - - var togglePathEditMode = function(editmode, elems) { - $('#path_node_panel').toggle(editmode); - $('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); - if(editmode) { - // Change select icon - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - setIcon('#tool_select', 'select_node'); - multiselected = false; - if(elems.length) { - selectedElement = elems[0]; - } - } else { - setIcon('#tool_select', 'select'); - } - } - - // used to make the flyouts stay on the screen longer the very first time - var flyoutspeed = 1250; - var textBeingEntered = false; - var selectedElement = null; - var multiselected = false; - var editingsource = false; - var docprops = false; - var preferences = false; - var cur_context = ''; - var orig_title = $('title:first').text(); - - var saveHandler = function(window,svg) { - Editor.show_save_warning = false; - - // 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; - - // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable - - var ua = navigator.userAgent; - - // Chrome 5 (and 6?) don't allow saving, show source instead ( http://code.google.com/p/chromium/issues/detail?id=46735 ) - // IE9 doesn't allow standalone Data URLs ( https://connect.microsoft.com/IE/feedback/details/542600/data-uri-images-fail-when-loaded-by-themselves ) - if((~ua.indexOf('Chrome') && $.browser.version >= 533) || ~ua.indexOf('MSIE')) { - showSourceEditor(0,true); - return; - } - var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg)); - - // Alert will only appear the first time saved OR the first time the bug is encountered - var done = $.pref('save_notice_done'); - if(done !== "all") { - - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'SVG'); - - // Check if FF and has - if(ua.indexOf('Gecko/') !== -1) { - if(svg.indexOf('', {id: 'export_canvas'}).hide().appendTo('body'); - } - var c = $('#export_canvas')[0]; - - c.width = svgCanvas.contentW; - c.height = svgCanvas.contentH; - canvg(c, data.svg, {renderCallback: function() { - var datauri = c.toDataURL('image/png'); - exportWindow.location.href = datauri; - var done = $.pref('export_notice_done'); - if(done !== "all") { - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'PNG'); - - // Check if there's issues - if(issues.length) { - var pre = "\n \u2022 "; - note += ("\n\n" + uiStrings.notification.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 - var selectedChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") setSelectMode(); - var is_node = (mode == "pathedit"); - // if elems[1] is present, then we have more than one element - selectedElement = (elems.length == 1 || elems[1] == null ? elems[0] : null); - multiselected = (elems.length >= 2 && elems[1] != null); - if (selectedElement != null) { - // unless we're already in always set the mode of the editor to select because - // upon creation of a text element the editor is switched into - // select mode and this event fires - we need our UI to be in sync - - if (!is_node) { - updateToolbar(); - } - - } // if (elem != null) - // Deal with pathedit mode - togglePathEditMode(is_node, elems); - updateContextPanel(); - svgCanvas.runExtensions("selectedChanged", { - elems: elems, - selectedElement: selectedElement, - multiselected: multiselected - }); - }; - - // Call when part of element is in process of changing, generally - // on mousemove actions like rotate, move, etc. - var elementTransition = function(window,elems) { - var mode = svgCanvas.getMode(); - var elem = elems[0]; - - if(!elem) return; - - multiselected = (elems.length >= 2 && elems[1] != null); - // Only updating fields for single elements for now - if(!multiselected) { - switch ( mode ) { - case "rotate": - var ang = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(ang)); - $('#tool_reorient').toggleClass('disabled', ang == 0); - break; - - // TODO: Update values that change on move/resize, etc -// case "select": -// case "resize": -// break; - } - } - svgCanvas.runExtensions("elementTransition", { - elems: elems - }); - }; - - // called when any element has changed - var elementChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") { - setSelectMode(); - } - - for (var i = 0; i < elems.length; ++i) { - var elem = elems[i]; - - // if the element changed was the svg, then it could be a resolution change - if (elem && elem.tagName === "svg") { - populateLayers(); - updateCanvas(); - } - // 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) { // This was added in r1430, but not sure why - selectedElement = elem; - } - } - - Editor.show_save_warning = true; - - // we update the contextual panel with potentially new - // positional/sizing information (we DON'T want to update the - // toolbar here as that creates an infinite loop) - // also this updates the history buttons - - // we tell it to skip focusing the text control if the - // text element was previously in focus - updateContextPanel(); - - // In the event a gradient was flipped: - if(selectedElement && mode === "select") { - paintBox.fill.update(); - paintBox.stroke.update(); - } - - svgCanvas.runExtensions("elementChanged", { - elems: elems - }); - }; - - var zoomChanged = function(window, bbox, autoCenter) { - var scrbar = 15, - res = svgCanvas.getResolution(), - w_area = workarea, - canvas_pos = $('#svgcanvas').position(); - var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); - if(!z_info) return; - var zoomlevel = z_info.zoom, - bb = z_info.bbox; - - if(zoomlevel < .001) { - changeZoom({value: .1}); - return; - } - -// $('#zoom').val(Math.round(zoomlevel*100)); - $('#zoom').val(zoomlevel*100); - - if(autoCenter) { - updateCanvas(); - } else { - updateCanvas(false, {x: bb.x * zoomlevel + (bb.width * zoomlevel)/2, y: bb.y * zoomlevel + (bb.height * zoomlevel)/2}); - } - - if(svgCanvas.getMode() == 'zoom' && bb.width) { - // Go to select if a zoom box was drawn - setSelectMode(); - } - - zoomDone(); - } - - $('#cur_context_panel').delegate('a', 'click', function() { - var link = $(this); - if(link.attr('data-root')) { - svgCanvas.leaveContext(); - } else { - svgCanvas.setContext(link.text()); - } - return false; - }); - - var contextChanged = function(win, context) { - - var link_str = ''; - if(context) { - var str = ''; - link_str = '' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + ''; - - $(context).parentsUntil('#svgcontent > g').andSelf().each(function() { - if(this.id) { - str += ' > ' + this.id; - if(this !== context) { - link_str += ' > ' + this.id + ''; - } else { - link_str += ' > ' + this.id; - } - } - }); - - cur_context = str; - } else { - cur_context = null; - } - $('#cur_context_panel').toggle(!!context).html(link_str); - - - updateTitle(); - } - - // Makes sure the current selected paint is available to work with - var prepPaints = function() { - paintBox.fill.prep(); - paintBox.stroke.prep(); - } - - var flyout_funcs = {}; - - var setupFlyouts = function(holders) { - $.each(holders, function(hold_sel, btn_opts) { - var buttons = $(hold_sel).children(); - var show_sel = hold_sel + '_show'; - var shower = $(show_sel); - var def = false; - buttons.addClass('tool_button') - .unbind('click mousedown mouseup') // may not be necessary - .each(function(i) { - // Get this buttons options - var opts = btn_opts[i]; - - // Remember the function that goes with this ID - flyout_funcs[opts.sel] = opts.fn; - - if(opts.isDefault) def = i; - - // Clicking the icon in flyout should set this set's icon - var func = function(event) { - var options = opts; - //find the currently selected tool if comes from keystroke - if (event.type === "keydown") { - var flyoutIsSelected = $(options.parent + "_show").hasClass('tool_button_current'); - var currentOperation = $(options.parent + "_show").attr("data-curopt"); - $.each(holders[opts.parent], function(i, tool){ - if (tool.sel == currentOperation) { - if(!event.shiftKey || !flyoutIsSelected) { - options = tool; - } - else { - options = holders[opts.parent][i+1] || holders[opts.parent][0]; - } - } - }); - } - if($(this).hasClass('disabled')) return false; - if (toolButtonClick(show_sel)) { - options.fn(); - } - if(options.icon) { - var icon = $.getSvgIcon(options.icon, true); - } else { - var icon = $(options.sel).children().eq(0).clone(); - } - - icon[0].setAttribute('width',shower.width()); - icon[0].setAttribute('height',shower.height()); - shower.children(':not(.flyout_arrow_horiz)').remove(); - shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode - } - - $(this).mouseup(func); - - if(opts.key) { - $(document).bind('keydown', opts.key[0] + " shift+" + opts.key[0], func); - } - }); - - if(def) { - shower.attr('data-curopt', btn_opts[def].sel); - } else if(!shower.attr('data-curopt')) { - // Set first as default - shower.attr('data-curopt', btn_opts[0].sel); - } - - var timer; - - var pos = $(show_sel).position(); - $(hold_sel).css({'left': pos.left+34, 'top': pos.top+77}); - - // Clicking the "show" icon should set the current mode - shower.mousedown(function(evt) { - if ($('#tools_shapelib').is(":visible")) toolButtonClick(show_sel, false); - if(shower.hasClass('disabled')) return false; - var holder = $(hold_sel); - var l = pos.left+34; - var w = holder.width()*-1; - var time = holder.data('shown_popop')?200:0; - timer = setTimeout(function() { - // Show corresponding menu - if(!shower.data('isLibrary')) { - holder.css('left', w).show().animate({ - left: l - },150); - } else { - holder.css('left', l).show(); - } - holder.data('shown_popop',true); - },time); - evt.preventDefault(); - }).mouseup(function(evt) { - clearTimeout(timer); - var opt = $(this).attr('data-curopt'); - // Is library and popped up, so do nothing - if(shower.data('isLibrary') && $(show_sel.replace('_show','')).is(':visible')) { - toolButtonClick(show_sel, true); - return; - } - if (toolButtonClick(show_sel) && (opt in flyout_funcs)) { - flyout_funcs[opt](); - } - }); - - // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();}); - }); - - setFlyoutTitles(); - } - - var makeFlyoutHolder = function(id, child) { - var div = $('
    ',{ - 'class': 'tools_flyout', - id: id - }).appendTo('#svg_editor').append(child); - - return div; - } - - var setFlyoutPositions = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var pos = shower.offset(); - var w = shower.outerWidth(); - $(this).css({left: (pos.left + w)*tool_scale, top: pos.top}); - }); - } - - var setFlyoutTitles = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - if(shower.data('isLibrary')) return; - - var tooltips = []; - $(this).children().each(function() { - tooltips.push(this.title); - }); - 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 && cb_ready) { - cb_called = true; - ext.callback(); - } - } - - var btn_selects = []; - - if(ext.context_tools) { - $.each(ext.context_tools, function(i, tool) { - // Add select tool - var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):""; - - var panel = $('#' + tool.panel); - - // create the panel if it doesn't exist - if(!panel.length) - panel = $('
    ', {id: tool.panel}).appendTo("#tools_top"); - - // TODO: Allow support for other types, or adding to existing tool - switch (tool.type) { - case 'tool_button': - var html = '
    ' + tool.id + '
    '; - var div = $(html).appendTo(panel); - if (tool.events) { - $.each(tool.events, function(evt, func) { - $(div).bind(evt, func); - }); - } - break; - case 'select': - var html = '' - + '"; - // Creates the tool, hides & adds it, returns the select element - var sel = $(html).appendTo(panel).find('select'); - - $.each(tool.events, function(evt, func) { - $(sel).bind(evt, func); - }); - break; - case 'button-select': - var html = ''; - - var list = $('
      ').appendTo('#option_lists'); - - if(tool.colnum) { - list.addClass('optcols' + tool.colnum); - } - - // Creates the tool, hides & adds it, returns the select element - var dropdown = $(html).appendTo(panel).children(); - - btn_selects.push({ - elem: ('#' + tool.id), - list: ('#' + tool.id + '_opts'), - title: tool.title, - callback: tool.events.change, - cur: ('#cur_' + tool.id) - }); - - break; - case 'input': - var html = '' - + '' - + tool.label + ':' - + '' - - // Creates the tool, hides & adds it, returns the select element - - // Add to given tool.panel - var inp = $(html).appendTo(panel).find('input'); - - if(tool.spindata) { - inp.SpinButton(tool.spindata); - } - - if(tool.events) { - $.each(tool.events, function(evt, func) { - inp.bind(evt, func); - }); - } - break; - - default: - break; - } - }); - } - - if(ext.buttons) { - var fallback_obj = {}, - placement_obj = {}, - svgicons = ext.svgicons; - var holders = {}; - - - // Add buttons given by extension - $.each(ext.buttons, function(i, btn) { - var icon; - var id = btn.id; - var num = i; - - // Give button a unique ID - while($('#'+id).length) { - id = btn.id + '_' + (++num); - } - - if(!svgicons) { - icon = (btn.type == "menu") ? "" : $(''); - } else { - fallback_obj[id] = btn.icon; - var svgicon = btn.svgicon?btn.svgicon:btn.id; - if(btn.type == 'app_menu') { - placement_obj['#' + id + ' > div'] = svgicon; - } else { - placement_obj['#' + id] = svgicon; - } - } - - var cls, parent; - - - - // Set button up according to its type - switch ( btn.type ) { - case 'mode_flyout': - case 'mode': - cls = 'tool_button'; - if(btn.cls) { - cls += " " + btn.cls; - } - parent = "#tools_left"; - break; - case 'context': - cls = 'tool_button'; - parent = "#" + btn.panel; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
      ', {id: btn.panel}).appendTo("#tools_top"); - break; - case 'menu': - cls = 'menu_item tool_button'; - parent = "#" + (btn.after || btn.panel); - break; - case 'app_menu': - cls = ''; - parent = btn.parent || '#main_menu ul'; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
      ', {id: btn.panel}).appendTo("#tools_top"); - break; - } - - var button = $((btn.list || btn.type == 'app_menu')?'
    • ':'
      ') - .attr("id", id) - .attr("title", btn.title) - .addClass(cls); - if(!btn.includeWith && !btn.list) { - if("position" in btn) { - $(parent).children().eq(btn.position).before(button); - } else { - if (btn.type != "menu" || !btn.after) button.appendTo(parent); - else $(parent).after(button); - } - - if(btn.type =='mode_flyout') { - // Add to flyout menu / make flyout menu - // var opts = btn.includeWith; - // // opts.button, default, position - var ref_btn = $(button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
      ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - flyout_holder.data('isLibrary', true); - show_btn.data('isLibrary', true); - } - - - - // var ref_data = Actions.getButtonData(opts.button); - - placement_obj['#' + tls_id + '_show'] = btn.id; - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, -// key: btn.key, - isDefault: true - }, ref_data]; - - } else if(btn.type == 'app_menu' || btn.type == 'menu') { - button.append(btn.title); - } - - } else if(btn.list) { - // Add button to list - button.addClass('push_button'); - $('#' + btn.list + '_opts').append(button); - if(btn.isDefault) { - $('#cur_' + btn.list).append(button.children().clone()); - var svgicon = btn.svgicon?btn.svgicon:btn.id; - placement_obj['#cur_' + btn.list] = svgicon; - } - } else if(btn.includeWith) { - // Add to flyout menu / make flyout menu - var opts = btn.includeWith; - // opts.button, default, position - var ref_btn = $(opts.button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
      ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - } - - var ref_data = Actions.getButtonData(opts.button); - - if(opts.isDefault) { - placement_obj['#' + tls_id + '_show'] = btn.id; - } - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, - key: btn.key, - isDefault: btn.includeWith?btn.includeWith.isDefault:0 - }, ref_data]; - - // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} - - var pos = ("position" in opts)?opts.position:'last'; - var len = flyout_holder.children().length; - - // Add at given position or end - if(!isNaN(pos) && pos >= 0 && pos < len) { - flyout_holder.children().eq(pos).before(button); - } else { - flyout_holder.append(button); - cur_h.reverse(); - } - } - - if(!svgicons) { - button.append(icon); - } - - if(!btn.list) { - // Add given events to button - $.each(btn.events, function(name, func) { - if(name == "click") { - if(btn.type == 'mode') { - if(btn.includeWith) { - button.bind(name, func); - } else { - button.bind(name, function() { - if(toolButtonClick(button)) { - func(); - } - }); - } - if(btn.key) { - $(document).bind('keydown', btn.key, func); - if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']'); - } - } else { - button.bind(name, func); - } - } else { - button.bind(name, func); - } - }); - } - setupFlyouts(holders); - }); - - $.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, - id_match: false, - no_img: (!isWebkit), - fallback: fallback_obj, - placement: placement_obj, - callback: function(icons) { - // Non-ideal hack to make the icon match the current size - if(curPrefs.iconsize && curPrefs.iconsize != 'm') { - prepResize(); - } - cb_ready = true; // Ready for callback - runCallback(); - } - - }); - } - - runCallback(); - }; - - var getPaint = function(color, opac, type) { - // update the editor's fill paint - var opts = null; - if (color.indexOf("url(#") === 0) { - var refElem = svgCanvas.getRefElem(color); - if(refElem) { - refElem = refElem.cloneNode(true); - } else { - refElem = $("#" + type + "_color defs *")[0]; - } - - opts = { alpha: opac }; - opts[refElem.tagName] = refElem; - } - else if (color.indexOf("#") === 0) { - opts = { - alpha: opac, - solidColor: color.substr(1) - }; - } - else { - opts = { - alpha: opac, - solidColor: 'none' - }; - } - return new $.jGraduate.Paint(opts); - }; - - // set the canvas properties at init - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#docprops_button').on("click", function(){showDocProperties()}); - - // 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) { - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - break; - case 'g': - case 'a': - // Look for common styles - - var gWidth = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var swidth = childs[i].getAttribute("stroke-width"); - - if(i === 0) { - gWidth = swidth; - } else if(gWidth !== swidth) { - gWidth = null; - } - } - - $('#stroke_width').val(gWidth === null ? "" : gWidth); - - paintBox.fill.update(true); - paintBox.stroke.update(true); - - - break; - default: - paintBox.fill.update(true); - paintBox.stroke.update(true); - - $('#stroke_width').val(selectedElement.getAttribute("stroke-width") || 1); - $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none"); - - var attr = selectedElement.getAttribute("stroke-linejoin") || 'miter'; - - if ($('#linejoin_' + attr).length != 0) - setStrokeOpt($('#linejoin_' + attr)[0]); - - attr = selectedElement.getAttribute("stroke-linecap") || 'butt'; - - if ($('#linecap_' + attr).length != 0) - setStrokeOpt($('#linecap_' + attr)[0]); - } - - } - - // All elements including image and group have opacity - if(selectedElement != null) { - var opac_perc = ((selectedElement.getAttribute("opacity")||1.0)*100); - $('#group_opacity').val(opac_perc); - $('#opac_slider').slider('option', 'value', opac_perc); - $('#elem_id').val(selectedElement.id); - } - - updateToolButtonState(); - }; - - var setImageURL = Editor.setImageURL = function(url) { - if(!url) url = default_img_url; - - svgCanvas.setImageURL(url); - $('#image_url').val(url); - - if(url.indexOf('data:') === 0) { - // data URI found - $('#image_url').hide(); - $('#change_image_url').show(); - } else { - // regular URL - - svgCanvas.embedImage(url, function(datauri) { - if(!datauri) { - // Couldn't embed, so show warning - $('#url_notice').show(); - } else { - $('#url_notice').hide(); - } - default_img_url = url; - }); - $('#image_url').show(); - $('#change_image_url').hide(); - } - } - - 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; - // If element has just been deleted, consider it null - if(elem != null && !elem.parentNode) elem = null; - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var currentMode = svgCanvas.getMode(); - var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; - - var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false; - var menu_items = $('#cmenu_canvas li'); - $('#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\ - #ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel').hide(); - $('.menu_item', '#edit_menu').addClass('disabled'); - $('.menu_item', '#object_menu').addClass('disabled'); - if (!elem && !multiselected) $("#canvas_panel").show(); - if (elem != null) { - var elname = elem.nodeName; - var angle = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(angle)); - - var blurval = svgCanvas.getBlur(elem); - $('#blur').val(blurval); - $('#blur_slider').slider('option', 'value', blurval); - - if(svgCanvas.addedNew) { - if(elname === 'image') { - // Prompt for URL if not a data URL - if(svgCanvas.getHref(elem).indexOf('data:') !== 0) { - promptImgURL(); - } - } /*else if(elname == 'text') { - // TODO: Do something here for new text - }*/ - } - - if(!is_node && currentMode != 'pathedit') { - $('#selected_panel').show(); - $('.action_selected').removeClass('disabled'); - // Elements in this array already have coord fields - if(['line', 'circle', 'ellipse'].indexOf(elname) >= 0) { - $('#xy_panel').hide(); - } else { - var x,y; - - // Get BBox vals for g, polyline and path - if(['g', 'polyline', 'path'].indexOf(elname) >= 0) { - var bb = svgCanvas.getStrokedBBox([elem]); - if(bb) { - x = bb.x; - y = bb.y; - } - } else { - x = elem.getAttribute('x'); - y = elem.getAttribute('y'); - } - - if(unit) { - x = svgedit.units.convertUnit(x); - y = svgedit.units.convertUnit(y); - } - - $('#selected_x').val(x || 0); - $('#selected_y').val(y || 0); - $('#xy_panel').show(); - } - - // Elements in this array cannot be converted to a path - var no_path = ['image', 'text', 'path', 'g', 'use'].indexOf(elname) == -1; - if (no_path) $('.action_path_convert_selected').removeClass('disabled'); - if (elname === "path") $('.action_path_selected').removeClass('disabled'); - } else { - var point = path.getNodePoint(); - $('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); - $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); - - // Show open/close button based on selected point - setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); - - if(point) { - var seg_type = $('#seg_type'); - if(unit) { - point.x = svgedit.units.convertUnit(point.x); - point.y = svgedit.units.convertUnit(point.y); - } - $('#path_node_x').val(point.x); - $('#path_node_y').val(point.y); - if(point.type) { - seg_type.val(point.type).removeAttr('disabled'); - } else { - seg_type.val(4).attr('disabled','disabled'); - } - } - return; - } - - // update contextual tools here - var panels = { - g: [], - a: [], - rect: ['rx','width','height'], - image: ['width','height'], - circle: ['cx','cy','r'], - ellipse: ['cx','cy','rx','ry'], - line: ['x1','y1','x2','y2'], - text: [], - 'use': [] - }; - - var el_name = elem.tagName; - - if($(elem).data('gsvg')) { - $('#g_panel').show(); - } - - if (el_name == "path") { - $('#path_panel').show(); - } - -// var link_href = null; -// if (el_name === 'a') { -// link_href = svgCanvas.getHref(elem); -// $('#g_panel').show(); -// } -// -// if(elem.parentNode.tagName === 'a') { -// if(!$(elem).siblings().length) { -// $('#a_panel').show(); -// link_href = svgCanvas.getHref(elem.parentNode); -// } -// } -// -// // Hide/show the make_link buttons -// $('#tool_make_link, #tool_make_link').toggle(!link_href); -// -// if(link_href) { -// $('#link_url').val(link_href); -// } - - if(panels[el_name]) { - var cur_panel = panels[el_name]; - $('#' + el_name + '_panel').show(); - - $.each(cur_panel, function(i, item) { - var attrVal = elem.getAttribute(item); - if(curConfig.baseUnit !== 'px' && elem[item]) { - var bv = elem[item].baseVal.value; - attrVal = svgedit.units.convertUnit(bv); - } - - $('#' + el_name + '_' + item).val(attrVal || 0); - }); - if(el_name == 'text') { - $('#text_panel').css("display", "inline"); - if (svgCanvas.getItalic()) { - $('#tool_italic').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_italic').removeClass('push_button_pressed').addClass('tool_button'); - } - if (svgCanvas.getBold()) { - $('#tool_bold').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_bold').removeClass('push_button_pressed').addClass('tool_button'); - } - $('#font_family').val(elem.getAttribute("font-family")); - $('#font_size').val(elem.getAttribute("font-size")); - $('#text').val(elem.textContent); - if (svgCanvas.addedNew) { - // Timeout needed for IE9 - setTimeout(function() { - $('#text').focus().select(); - },100); - } - } // text - else if(el_name == 'image') { - setImageURL(svgCanvas.getHref(elem)); - } // image - else if(el_name === 'g' || el_name === 'use') { - $('#container_panel').show(); - $('.action_group_selected').removeClass('disabled'); - 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); - } - } - } - menu_items[(el_name === 'g' ? 'en':'dis') + 'ableContextMenuItems']('#ungroup'); - menu_items[((el_name === 'g' || !multiselected) ? 'dis':'en') + 'ableContextMenuItems']('#group'); - } // if (elem != null) - else if (multiselected) { - $('#multiselected_panel').show(); - $('.action_multi_selected').removeClass('disabled'); - menu_items - .enableContextMenuItems('#group') - .disableContextMenuItems('#ungroup'); - } else { - menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); - } - - // update history buttons - if (undoMgr.getUndoStackSize() > 0) { - $('#tool_undo').removeClass( 'disabled'); - } - else { - $('#tool_undo').addClass( 'disabled'); - } - if (undoMgr.getRedoStackSize() > 0) { - $('#tool_redo').removeClass( 'disabled'); - } - else { - $('#tool_redo').addClass( 'disabled'); - } - - svgCanvas.addedNew = false; - - if ( (elem && !is_node) || multiselected) { - // update the selected elements' layer - $('#selLayerNames').removeAttr('disabled').val(currentLayerName); - - // Enable regular menu options - canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); - } - else { - $('#selLayerNames').attr('disabled', 'disabled'); - } - }; - - $('#text').focus( function(){ textBeingEntered = true; } ); - $('#text').blur( function(){ textBeingEntered = false; } ); - - // bind the selected event to our function that handles updates to the UI - svgCanvas.bind("selected", selectedChanged); - svgCanvas.bind("transition", elementTransition); - svgCanvas.bind("changed", elementChanged); - svgCanvas.bind("saved", saveHandler); - svgCanvas.bind("exported", exportHandler); - svgCanvas.bind("zoomed", zoomChanged); - svgCanvas.bind("contextset", contextChanged); - svgCanvas.bind("extension_added", extAdded); - svgCanvas.textActions.setInputElem($("#text")[0]); - - var str = '
      ' - $.each(palette, function(i,item){ - str += '
      '; - }); - $('#palette').append(str); - - // Set up editor background functionality - // TODO add checkerboard as "pattern" - var color_blocks = ['#FFF','#888','#000']; // ,'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP%2F%2F%2F9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG%2Bgq4jM3IFLJgpswNly%2FXkcBpIiVaInlLJr9FZWAQA7)']; - var str = ''; - $.each(color_blocks, function() { - str += '
      '; - }); - $('#bg_blocks').append(str); - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - blocks.each(function() { - var blk = $(this); - blk.click(function() { - blocks.removeClass(cur_bg); - $(this).addClass(cur_bg); - }); - }); - - if($.pref('bkgd_color')) { - setBackground($.pref('bkgd_color'), $.pref('bkgd_url')); - } else if($.pref('bkgd_url')) { - // No color set, only URL - setBackground(defaultPrefs.bkgd_color, $.pref('bkgd_url')); - } - - if($.pref('img_save')) { - curPrefs.img_save = $.pref('img_save'); - $('#image_save_opts input').val([curPrefs.img_save]); - } - - var changeRectRadius = function(ctl) { - svgCanvas.setRectRadius(ctl.value); - } - - var changeFontSize = function(ctl) { - svgCanvas.setFontSize(ctl.value); - } - - var changeStrokeWidth = function(ctl) { - var val = ctl.value; - if(val == 0 && selectedElement && ['line', 'polyline'].indexOf(selectedElement.nodeName) >= 0) { - val = ctl.value = 1; - } - svgCanvas.setStrokeWidth(val); - } - - var changeRotationAngle = function(ctl) { - svgCanvas.setRotationAngle(ctl.value); - $('#tool_reorient').toggleClass('disabled', ctl.value == 0); - } - var changeZoom = function(ctl) { - var zoomlevel = ctl.value / 100; - if(zoomlevel < .001) { - ctl.value = .1; - return; - } - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - - zoomChanged(window, { - width: 0, - height: 0, - // center pt of scroll position - x: (w_area[0].scrollLeft + w_area.width()/2)/zoom, - y: (w_area[0].scrollTop + w_area.height()/2)/zoom, - zoom: zoomlevel - }, true); - } - - var changeOpacity = function(ctl, val) { - if(val == null) val = ctl.value; - $('#group_opacity').val(val); - if(!ctl || !ctl.handle) { - $('#opac_slider').slider('option', 'value', val); - } - svgCanvas.setOpacity(val/100); - } - - var changeBlur = function(ctl, val, noUndo) { - if(val == null) val = ctl.value; - $('#blur').val(val); - var complete = false; - if(!ctl || !ctl.handle) { - $('#blur_slider').slider('option', 'value', val); - complete = true; - } - if(noUndo) { - svgCanvas.setBlurNoUndo(val); - } else { - svgCanvas.setBlur(val, complete); - } - } - - var operaRepaint = function() { - // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change - if(!window.opera) return; - $('

      ').hide().appendTo('body').remove(); - } - - $('#stroke_style').change(function(){ - svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val()); - operaRepaint(); - }); - - $('#stroke_linejoin').change(function(){ - svgCanvas.setStrokeAttr('stroke-linejoin', $(this).val()); - operaRepaint(); - }); - - - // Lose focus for select elements when changed (Allows keyboard shortcuts to work better) - $('select').change(function(){$(this).blur();}); - - // fired when user wants to move elements to another layer - var promptMoveLayerOnce = false; - $('#selLayerNames').change(function(){ - var destLayer = this.options[this.selectedIndex].value; - var confirm_str = uiStrings.notification.QmoveElemsToLayer.replace('%s',destLayer); - var moveToLayer = function(ok) { - if(!ok) return; - promptMoveLayerOnce = true; - svgCanvas.moveSelectedToLayer(destLayer); - svgCanvas.clearSelection(); - populateLayers(); - } - if (destLayer) { - if(promptMoveLayerOnce) { - moveToLayer(true); - } else { - $.confirm(confirm_str, moveToLayer); - } - } - }); - - $('#font_family').change(function() { - svgCanvas.setFontFamily(this.value); - }); - - $('#seg_type').change(function() { - svgCanvas.setSegType($(this).val()); - }); - - $('#text').keyup(function(){ - svgCanvas.setTextContent(this.value); - }); - - $('#image_url').change(function(){ - setImageURL(this.value); - }); - - $('#link_url').change(function() { - if(this.value.length) { - svgCanvas.setLinkURL(this.value); - } else { - svgCanvas.removeHyperlink(); - } - }); - - $('#g_title').change(function() { - svgCanvas.setGroupTitle(this.value); - }); - - $('.attr_changer').change(function() { - var attr = this.getAttribute("data-attr"); - var val = this.value; - var valid = svgedit.units.isValidUnit(attr, val, selectedElement); - if(!valid) { - $.alert(uiStrings.notification.invalidAttrValGiven); - this.value = selectedElement.getAttribute(attr); - return false; - } - else{ - this.blur() - } - - if (attr !== "id") { - if (isNaN(val)) { - val = svgCanvas.convertToNum(attr, val); - } else if(curConfig.baseUnit !== 'px') { - // Convert unitless value to one with given unit - - var unitData = svgedit.units.getTypeMap(); - - if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") { - val *= unitData[curConfig.baseUnit]; - } - } - } - - // if the user is changing the id, then de-select the element first - // change the ID, then re-select it with the new ID - if (attr === "id") { - var elem = selectedElement; - svgCanvas.clearSelection(); - elem.id = val; - svgCanvas.addToSelection([elem],true); - } - else { - svgCanvas.changeSelectedAttribute(attr, val); - } - this.blur(); - }); - - // Prevent selection of elements when shift-clicking - $('#palette').mouseover(function() { - var inp = $(''); - $(this).append(inp); - inp.focus().remove(); - }); - - $('.palette_item').mousedown(function(evt){ - var isStroke = $('#tool_stroke').hasClass('active'); - var picker = isStroke ? "stroke" : "fill"; - var color = $(this).attr('data-rgb'); - var paint = null; - - // Webkit-based browsers returned 'initial' here for no stroke - console.log(color); - if (color === 'transparent' || color === 'initial' || color === '#none') { - color = 'none'; - paint = new $.jGraduate.Paint(); - } - else { - paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)}); - } - - paintBox[picker].setPaint(paint); - - if (isStroke) { - svgCanvas.setColor('stroke', color); - if (color != 'none' && svgCanvas.getStrokeOpacity() != 1) { - svgCanvas.setPaintOpacity('stroke', 1.0); - } - } else { - svgCanvas.setColor('fill', color); - if (color != 'none' && svgCanvas.getFillOpacity() != 1) { - svgCanvas.setPaintOpacity('fill', 1.0); - } - } - updateToolButtonState(); - }).bind('contextmenu', function(e) {e.preventDefault()}); - - $("#toggle_stroke_tools").toggle(function() { - $(".stroke_tool").css('display','table-cell'); - $(this).addClass('expanded'); - resetScrollPos(); - }, function() { - $(".stroke_tool").css('display','none'); - $(this).removeClass('expanded'); - resetScrollPos(); - }); - - // This is a common function used when a tool has been clicked (chosen) - // It does several common things: - // - removes the tool_button_current class from whatever tool currently has it - // - hides any flyouts - // - adds the tool_button_current class to the button passed in - var toolButtonClick = function(button, noHiding) { - if ($(button).hasClass('disabled')) return false; - if($(button).parent().hasClass('tools_flyout')) return true; - var fadeFlyouts = fadeFlyouts || 'normal'; - if(!noHiding) { - $('.tools_flyout').fadeOut(fadeFlyouts); - } - $('#styleoverrides').text(''); - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $(button).addClass('tool_button_current').removeClass('tool_button'); - return true; - }; - - (function() { - var last_x = null, last_y = null, w_area = workarea[0], - panning = false, keypan = false; - - $('#svgcanvas').bind('mousemove mouseup', function(evt) { - if(panning === false) return; - - w_area.scrollLeft -= (evt.clientX - last_x); - w_area.scrollTop -= (evt.clientY - last_y); - - last_x = evt.clientX; - last_y = evt.clientY; - - if(evt.type === 'mouseup') panning = false; - return false; - }).mousedown(function(evt) { - if(evt.button === 1 || keypan === true) { - panning = true; - last_x = evt.clientX; - last_y = evt.clientY; - return false; - } - }); - - $(window).mouseup(function() { - panning = false; - }); - - $(document).bind('keydown', 'space', function(evt) { - svgCanvas.spaceKey = keypan = true; - evt.preventDefault(); - }).bind('keyup', 'space', function(evt) { - evt.preventDefault(); - svgCanvas.spaceKey = keypan = false; - }).bind('keydown', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.addClass('out'); - } - }).bind('keyup', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.removeClass('out'); - } - }) - }()); - - - function setStrokeOpt(opt, changeElem) { - var id = opt.id; - var bits = id.split('_'); - var pre = bits[0]; - var val = bits[1]; - - if(changeElem) { - svgCanvas.setStrokeAttr('stroke-' + pre, val); - } - operaRepaint(); - setIcon('#cur_' + pre , id, 20); - $(opt).addClass('current').siblings().removeClass('current'); - } - - //menu handling - var menus = $('.menu'); - var blinker = function(e) { - e.target.style.background = "#fff"; - setTimeout(function(){e.target.style.background = "#ddd";}, 50); - setTimeout(function(){e.target.style.background = "#fff";}, 150); - setTimeout(function(){e.target.style.background = "#ddd";}, 200); - setTimeout(function(){e.target.style.background = "";}, 200); - setTimeout(function(){$('#menu_bar').removeClass('active')}, 220); - return false; - } - var closer = function(e){ - if (!$(e.target).hasClass("menu_title") && $('#menu_bar').hasClass("active")) { - if(!$(e.target).hasClass("disabled") && $(e.target).hasClass("menu_item")) { - blinker(e); - return; - } - $('#menu_bar').removeClass('active') - $('.tools_flyout').hide(); - $('input').blur(); - } - } - $('.menu_item').live('click', function(e){blinker(e)}); - $("svg, body").on('click', function(e){closer(e)}); - $('.menu_title').on('click', function() {$("#menu_bar").toggleClass('active');}); - $('.menu_title').on('mouseover', function() { - menus.removeClass('open'); - $(this).parent().addClass('open'); - }); - - // Made public for UI customization. - // TODO: Group UI functions into a public svgEditor.ui interface. - Editor.addDropDown = function(elem, callback, dropUp) { - if ($(elem).length == 0) return; // Quit if called on non-existant element - var button = $(elem).find('button'); - - var list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list'); - - if(!dropUp) { - // Move list to place where it can overflow container - $('#option_lists').append(list); - } - - var on_button = false; - if(dropUp) { - $(elem).addClass('dropup'); - } - - list.find('li').bind('mouseup', callback); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - } - on_button = false; - }); - - button.bind('mousedown',function() { - if (!button.hasClass('down')) { - button.addClass('down'); - - if(!dropUp) { - var pos = $(elem).offset(); - // position slider - list.css({ - top: pos.top, - left: pos.left - 110 - }); - } - list.show(); - - on_button = true; - } else { - button.removeClass('down'); - list.hide(); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - } - - // TODO: Combine this with addDropDown or find other way to optimize - var addAltDropDown = function(elem, list, callback, opts) { - var button = $(elem); - var list = $(list); - var on_button = false; - var dropUp = opts.dropUp; - if(dropUp) { - $(elem).addClass('dropup'); - } - list.find('li').bind('mouseup', function() { - if(opts.seticon) { - setIcon('#cur_' + button[0].id , $(this).children()); - $(this).addClass('current').siblings().removeClass('current'); - } - callback.apply(this, arguments); - - }); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - list.css({top:0, left:0}); - } - on_button = false; - }); - - var height = list.height(); - $(elem).bind('mousedown',function() { - var off = $(elem).offset(); - if(dropUp) { - off.top -= list.height(); - off.left += 8; - } else { - off.top += $(elem).height(); - } - $(list).offset(off); - - if (!button.hasClass('down')) { - button.addClass('down'); - list.show(); - on_button = true; - return false; - } else { - button.removeClass('down'); - // CSS position must be reset for Webkit - list.hide(); - list.css({top:0, left:0}); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - - if(opts.multiclick) { - list.mousedown(function() { - on_button = true; - }); - } - } - - Editor.addDropDown('#font_family_dropdown', function() { - var fam = $(this).text(); - $('#font_family').val($(this).text()).change(); - }); - - Editor.addDropDown('#opacity_dropdown', function() { - if($(this).find('div').length) return; - var perc = parseInt($(this).text().split('%')[0]); - changeOpacity(false, perc); - }, false); - - // For slider usage, see: http://jqueryui.com/demos/slider/ - $("#opac_slider").slider({ - start: function() { - $('#opacity_dropdown li:not(.special)').hide(); - }, - stop: function() { - $('#opacity_dropdown li').show(); - $(window).mouseup(); - }, - slide: function(evt, ui){ - changeOpacity(ui); - } - }); - - Editor.addDropDown('#blur_dropdown', $.noop); - - var slideStart = false; - - $("#blur_slider").slider({ - max: 10, - step: .1, - stop: function(evt, ui) { - slideStart = false; - changeBlur(ui); - $('#blur_dropdown li').show(); - $(window).mouseup(); - }, - start: function() { - slideStart = true; - }, - slide: function(evt, ui){ - changeBlur(ui, null, slideStart); - } - }); - - - Editor.addDropDown('#zoom_dropdown', function() { - var item = $(this); - var val = item.attr('data-val'); - if(val) { - zoomChanged(window, val); - } else { - changeZoom({value:parseInt(item.text())}); - } - }, true); - - addAltDropDown('#stroke_linecap', '#linecap_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - addAltDropDown('#stroke_linejoin', '#linejoin_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - $('div', '#position_opts').each(function(){ - this.addEventListener("mouseup", function(){ - var letter = this.id.replace('tool_pos','').charAt(0); - svgCanvas.alignSelectedElements(letter, 'page'); - }) - }); - - /* - - When a flyout icon is selected - (if flyout) { - - Change the icon - - Make pressing the button run its stuff - } - - Run its stuff - - When its shortcut key is pressed - - If not current in list, do as above - , else: - - Just run its stuff - - */ - - // Unfocus text input when workarea is mousedowned. - (function() { - var inp; - var unfocus = function() { - $(inp).blur(); - } - - $('#svg_editor').find('button, select, input:not(#text)').focus(function() { - inp = this; - ui_context = 'toolbars'; - workarea.mousedown(unfocus); - }).blur(function() { - ui_context = 'canvas'; - workarea.unbind('mousedown', unfocus); - // Go back to selecting text if in textedit mode - if(svgCanvas.getMode() == 'textedit') { - $('#text').focus(); - } - }); - - }()); - - var clickSelect = function() { - if (toolButtonClick('#tool_select')) { - svgCanvas.setMode('select'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}'); - } - }; - - var clickFHPath = function() { - if (toolButtonClick('#tool_fhpath')) { - svgCanvas.setMode('fhpath'); - } - }; - - var clickLine = function() { - if (toolButtonClick('#tool_line')) { - svgCanvas.setMode('line'); - } - }; - - var clickSquare = function(){ - if (toolButtonClick('#tool_square')) { - svgCanvas.setMode('square'); - } - }; - - var clickRect = function(){ - if (toolButtonClick('#tool_rect')) { - svgCanvas.setMode('rect'); - } - }; - - var clickFHRect = function(){ - if (toolButtonClick('#tool_fhrect')) { - svgCanvas.setMode('fhrect'); - } - }; - - var clickCircle = function(){ - if (toolButtonClick('#tool_circle')) { - svgCanvas.setMode('circle'); - } - }; - - var clickEllipse = function(){ - if (toolButtonClick('#tool_ellipse')) { - svgCanvas.setMode('ellipse'); - } - }; - - var clickFHEllipse = function(){ - if (toolButtonClick('#tool_fhellipse')) { - svgCanvas.setMode('fhellipse'); - } - }; - - var clickImage = function(){ - if (toolButtonClick('#tool_image')) { - svgCanvas.setMode('image'); - } - }; - - var clickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - svgCanvas.setMode('zoom'); - } - }; - - var dblclickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - zoomImage(); - setSelectMode(); - } - }; - - var clickText = function(){ - if (toolButtonClick('#tool_text')) { - svgCanvas.setMode('text'); - } - }; - - var clickPath = function(){ - if (toolButtonClick('#tool_path')) { - svgCanvas.setMode('path'); - } - }; - - // Delete is a contextual tool that only appears in the ribbon if - // an element has been selected - var deleteSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.deleteSelectedElements(); - } - }; - - var cutSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.cutSelectedElements(); - } - }; - - var copySelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.copySelectedElements(); - } - }; - - var pasteInCenter = function() { - var zoom = svgCanvas.getZoom(); - - var x = (workarea[0].scrollLeft + workarea.width()/2)/zoom - svgCanvas.contentW; - var y = (workarea[0].scrollTop + workarea.height()/2)/zoom - svgCanvas.contentH; - svgCanvas.pasteElements('point', x, y); - } - - var moveToTopSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToTopSelectedElement(); - } - }; - - var moveToBottomSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToBottomSelectedElement(); - } - }; - - var moveUpSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Up"); - } - }; - - var moveDownSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Down"); - } - }; - - var moveUpDownSelected = function(dir) { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected(dir); - } - }; - - var convertToPath = function() { - if (selectedElement != null) { - svgCanvas.convertToPath(); - } - } - - var reorientPath = function() { - if (selectedElement != null) { - path.reorient(); - } - } - - var makeHyperlink = function() { - if (selectedElement != null || multiselected) { - $.prompt(uiStrings.notification.enterNewLinkURL, "http://", function(url) { - if(url) svgCanvas.makeHyperlink(url); - }); - } - } - - var moveSelected = function(dx,dy) { - if (selectedElement != null || multiselected) { - if(curConfig.gridSnapping) { - // Use grid snap value regardless of zoom level - var multi = svgCanvas.getZoom() * curConfig.snappingStep; - dx *= multi; - dy *= multi; - } - svgCanvas.moveSelectedElements(dx,dy); - } - }; - - var linkControlPoints = function() { - var linked = !$('#tool_node_link').hasClass('push_button_pressed'); - if (linked) - $('#tool_node_link').addClass('push_button_pressed').removeClass('tool_button'); - else - $('#tool_node_link').removeClass('push_button_pressed').addClass('tool_button'); - - path.linkControlPoints(linked); - } - - var clonePathNode = function() { - if (path.getNodePoint()) { - path.clonePathNode(); - } - }; - - var deletePathNode = function() { - if (path.getNodePoint()) { - path.deletePathNode(); - } - }; - - var addSubPath = function() { - var button = $('#tool_add_subpath'); - var sp = !button.hasClass('push_button_pressed'); - if (sp) { - button.addClass('push_button_pressed').removeClass('tool_button'); - } else { - button.removeClass('push_button_pressed').addClass('tool_button'); - } - - path.addSubPath(sp); - - }; - - var opencloseSubPath = function() { - path.opencloseSubPath(); - } - - var selectNext = function() { - svgCanvas.cycleElement(1); - }; - - var selectPrev = function() { - svgCanvas.cycleElement(0); - }; - - var rotateSelected = function(cw,step) { - if (selectedElement == null || multiselected) return; - if(!cw) step *= -1; - var new_angle = $('#angle').val()*1 + step; - svgCanvas.setRotationAngle(new_angle); - updateContextPanel(); - }; - - var clickClear = function(){ - var dims = curConfig.dimensions; - $.confirm(uiStrings.notification.QwantToClear, function(ok) { - if(!ok) return; - setSelectMode(); - svgCanvas.clear(); - svgCanvas.setResolution(dims[0], dims[1]); - updateCanvas(true); - zoomImage(); - populateLayers(); - updateContextPanel(); - prepPaints(); - svgCanvas.runExtensions('onNewDocument'); - }); - }; - - var clickBold = function(){ - svgCanvas.setBold( !svgCanvas.getBold() ); - updateContextPanel(); - return false; - }; - - var clickItalic = function(){ - svgCanvas.setItalic( !svgCanvas.getItalic() ); - updateContextPanel(); - return false; - }; - - var clickSave = function(){ - // In the future, more options can be provided here - var saveOpts = { - 'images': curPrefs.img_save, - 'round_digits': 6 - } - svgCanvas.save(saveOpts); - }; - - var clickExport = function() { - // Open placeholder window (prevents popup) - if(!customHandlers.pngsave) { - var str = uiStrings.notification.loadingImage; - exportWindow = window.open("data:text/html;charset=utf-8," + str + "<\/title><h1>" + str + "<\/h1>"); - } - - if(window.canvg) { - svgCanvas.rasterExport(); - } else { - $.getScript('canvg/rgbcolor.js', function() { - $.getScript('canvg/canvg.js', function() { - svgCanvas.rasterExport(); - }); - }); - } - } - - // by default, svgCanvas.open() is a no-op. - // it is up to an extension mechanism (opera widget, etc) - // to call setCustomHandlers() which will make it do something - var clickOpen = function(){ - svgCanvas.open(); - }; - var clickImport = function(){ - }; - - var flash = function($menu){ - var menu_title = $menu.prev(); - menu_title.css("background", "#09f"); - setTimeout(function(){menu_title.css("background", "")}, 200); - } - - var clickUndo = function(){ - if (undoMgr.getUndoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.undo(); - populateLayers(); - } - }; - - var clickRedo = function(){ - if (undoMgr.getRedoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.redo(); - populateLayers(); - } - }; - - var clickGroup = function(){ - // group - if (multiselected) { - svgCanvas.groupSelectedElements(); - } - // ungroup - else if(selectedElement){ - svgCanvas.ungroupSelectedElement(); - } - }; - - var clickClone = function(){ - if (window.event.type === "keydown") flash($('#edit_menu')); - svgCanvas.cloneSelectedElements(20,20); - }; - - var clickAlign = function() { - var letter = this.id.replace('tool_align','').charAt(0); - svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val()); - }; - - var clickSwitch = function() { - var stroke_rect = document.querySelector('#tool_stroke rect'); - var fill_rect = document.querySelector('#tool_fill rect'); - var fill_color = fill_rect.getAttribute("fill"); - var stroke_color = stroke_rect.getAttribute("fill"); - var stroke_opacity = parseFloat(stroke_rect.getAttribute("stroke-opacity")); - if (isNaN(stroke_opacity)) {stroke_opacity = 100;} - var fill_opacity = parseFloat(fill_rect.getAttribute("fill-opacity")); - if (isNaN(fill_opacity)) {fill_opacity = 100;} - var stroke = getPaint(stroke_color, stroke_opacity, "stroke"); - var fill = getPaint(fill_color, fill_opacity, "fill"); - paintBox.fill.setPaint(stroke, true); - paintBox.stroke.setPaint(fill, true); - - }; - - var zoomImage = function(multiplier) { - var res = svgCanvas.getResolution(); - multiplier = multiplier?res.zoom * multiplier:1; - // setResolution(res.w * multiplier, res.h * multiplier, true); - $('#zoom').val(multiplier * 100); - svgCanvas.setZoom(multiplier); - zoomDone(); - updateCanvas(true); - }; - - var zoomDone = function() { - // updateBgImage(); - updateWireFrame(); - //updateCanvas(); // necessary? - } - - var clickWireframe = function() { - var wf = !$('#tool_wireframe').hasClass('push_button_pressed'); - if (wf) - $('#tool_wireframe').addClass('push_button_pressed'); - else - $('#tool_wireframe').removeClass('push_button_pressed'); - workarea.toggleClass('wireframe'); - - if(supportsNonSS) return; - var wf_rules = $('#wireframe_rules'); - if(!wf_rules.length) { - wf_rules = $('<style id="wireframe_rules"><\/style>').appendTo('head'); - } else { - wf_rules.empty(); - } - - updateWireFrame(); - } - - var clickRulers = function() { - var rulers = !$('#tool_rulers').hasClass('push_button_pressed'); - if (rulers) { - $('#tool_rulers').addClass('push_button_pressed'); - $('#show_rulers').attr("checked", true); - curConfig.showRulers = true; - } - else { - $('#tool_rulers').removeClass('push_button_pressed'); - $('#show_rulers').attr("checked", false); - curConfig.showRulers = false; - } - $('#rulers').toggle(!!curConfig.showRulers) - } - - var updateWireFrame = function() { - // Test support - if(supportsNonSS) return; - - var rule = "#workarea.wireframe #svgcontent * { stroke-width: " + 1/svgCanvas.getZoom() + "px; }"; - $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ""); - } - - var showSourceEditor = function(e, forSaving){ - if (editingsource) return; - editingsource = true; - - $('#save_output_btns').toggle(!!forSaving); - $('#tool_source_back').toggle(!forSaving); - - var str = orig_source = svgCanvas.getSvgString(); - $('#svg_source_textarea').val(str); - $('#svg_source_editor').fadeIn(); - properlySourceSizeTextArea(); - $('#svg_source_textarea').focus(); - }; - - var showDocProperties = function(){ - if (docprops) return; - docprops = true; - - // This selects the correct radio button by using the array notation - $('#image_save_opts input').val([curPrefs.img_save]); - - // update resolution option with actual resolution - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#canvas_title').val(svgCanvas.getDocumentTitle()); - - $('#svg_docprops').show(); - }; - - var showPreferences = function(){ - if (preferences) return; - preferences = true; - - // Update background color with current one - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - var canvas_bg = $.pref('bkgd_color'); - var url = $.pref('bkgd_url'); - // if(url) url = url[1]; - blocks.each(function() { - var blk = $(this); - var is_bg = blk.css('background-color') == canvas_bg; - blk.toggleClass(cur_bg, is_bg); - if(is_bg) $('#canvas_bg_url').removeClass(cur_bg); - }); - if(!canvas_bg) blocks.eq(0).addClass(cur_bg); - if(url) { - $('#canvas_bg_url').val(url); - } - $('grid_snapping_step').attr('value', curConfig.snappingStep); - if (curConfig.gridSnapping == true) { - $('#grid_snapping_on').attr('checked', 'checked'); - } else { - $('#grid_snapping_on').removeAttr('checked'); - } - - $('#svg_prefs').show(); - }; - - var properlySourceSizeTextArea = function(){ - // TODO: remove magic numbers here and get values from CSS - var height = $('#svg_source_container').height() - 50; - $('#svg_source_textarea').css('height', height); - }; - - var saveSourceEditor = function(){ - if (!editingsource) return; - - var saveChanges = function() { - svgCanvas.clearSelection(); - hideSourceEditor(); - zoomImage(); - populateLayers(); - updateTitle(); - prepPaints(); - } - - if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { - $.confirm(uiStrings.notification.QerrorsRevertToSource, function(ok) { - if(!ok) return false; - saveChanges(); - }); - } else { - saveChanges(); - } - setSelectMode(); - }; - - var updateTitle = function(title) { - title = title || svgCanvas.getDocumentTitle(); - var new_title = orig_title + (title?': ' + title:''); - - // Remove title update with current context info, isn't really necessary -// if(cur_context) { -// new_title = new_title + cur_context; -// } - $('title:first').text(new_title); - } - - var saveDocProperties = function(){ - - // update resolution - var width = $('#canvas_width'), w = width.val(); - var height = $('#canvas_height'), h = height.val(); - - if(w != "fit" && !svgedit.units.isValidUnit('width', w)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - width.parent().addClass('error'); - return false; - } - - width.parent().removeClass('error'); - - if(h != "fit" && !svgedit.units.isValidUnit('height', h)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - height.parent().addClass('error'); - return false; - } - - height.parent().removeClass('error'); - - if(!svgCanvas.setResolution(w, h)) { - $.alert(uiStrings.notification.noContentToFitTo); - return false; - } - - // set image save option - curPrefs.img_save = $('#image_save_opts :checked').val(); - $.pref('img_save',curPrefs.img_save); - updateCanvas(); - hideDocProperties(); - }; - - var savePreferences = function() { - // set background - var color = $('#bg_blocks div.cur_background').css('background-color') || '#FFF'; - setBackground(color, $('#canvas_bg_url').val()); - - // set language - var lang = $('#lang_select').val(); - if(lang != curPrefs.lang) { - Editor.putLocale(lang); - } - - // set icon size - setIconSize($('#iconsize').val()); - - // set grid setting - curConfig.gridSnapping = $('#grid_snapping_on')[0].checked; - curConfig.snappingStep = $('#grid_snapping_step').val(); - curConfig.showRulers = $('#show_rulers')[0].checked; - - $('#rulers').toggle(curConfig.showRulers); - if(curConfig.showRulers) updateRulers(); - curConfig.baseUnit = $('#base_unit').val(); - - svgCanvas.setConfig(curConfig); - - updateCanvas(); - hidePreferences(); - } - - function setBackground(color, url) { -// if(color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return; - $.pref('bkgd_color', color); - $.pref('bkgd_url', url); - - // This should be done in svgcanvas.js for the borderRect fill - svgCanvas.setBackground(color, url); - } - - var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { - var icon = (typeof icon_id === 'string') ? $.getSvgIcon(icon_id, true) : icon_id.clone(); - if(!icon) { - console.log('NOTE: Icon image missing: ' + icon_id); - return; - } - - $(elem).empty().append(icon); - } - - 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); - - - // 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}); -// } - - // 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'} -// }, - "#tools_top": { - 'left': 50, - 'height': 72 - }, - "#tools_left": { - 'width': 31, - 'top': 74 - }, - "div#workarea": { - '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'} -// } - }; - - var rule_elem = $('#tool_size_rules'); - if(!rule_elem.length) { - rule_elem = $('<style id="tool_size_rules"><\/style>').appendTo('head'); - } else { - rule_elem.empty(); - } - - if(size != 'm') { - var style_str = ''; - $.each(cssResizeRules, function(selector, rules) { - selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor'); - style_str += selector + '{'; - $.each(rules, function(prop, values) { - 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); - } - - setFlyoutPositions(); - } - - var cancelOverlays = function() { - $('#dialog_box').hide(); - if (!editingsource && !docprops && !preferences) { - if(cur_context) { - svgCanvas.leaveContext(); - } - return; - }; - - if (editingsource) { - if (orig_source !== $('#svg_source_textarea').val()) { - $.confirm(uiStrings.notification.QignoreSourceChanges, function(ok) { - if(ok) hideSourceEditor(); - }); - } else { - hideSourceEditor(); - } - } - else if (docprops) { - hideDocProperties(); - } else if (preferences) { - hidePreferences(); - } - resetScrollPos(); - }; - - var hideSourceEditor = function(){ - $('#svg_source_editor').hide(); - editingsource = false; - $('#svg_source_textarea').blur(); - }; - - var hideDocProperties = function(){ - $('#svg_docprops').hide(); - $('#canvas_width,#canvas_height').removeAttr('disabled'); - $('#resolution')[0].selectedIndex = 0; - $('#image_save_opts input').val([curPrefs.img_save]); - docprops = false; - }; - - var hidePreferences = function(){ - $('#svg_prefs').hide(); - preferences = false; - }; - - var win_wh = {width:$(window).width(), height:$(window).height()}; - - var resetScrollPos = $.noop, curScrollPos; - - // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9) - if(svgedit.browser.isIE()) { - (function() { - resetScrollPos = function() { - if(workarea[0].scrollLeft === 0 - && workarea[0].scrollTop === 0) { - workarea[0].scrollLeft = curScrollPos.left; - workarea[0].scrollTop = curScrollPos.top; - } - } - - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - - $(window).resize(resetScrollPos); - svgEditor.ready(function() { - // TODO: Find better way to detect when to do this to minimize - // flickering effect - setTimeout(function() { - resetScrollPos(); - }, 500); - }); - - workarea.scroll(function() { - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - }); - }()); - } - - $(window).resize(function(evt) { - if (editingsource) { - properlySourceSizeTextArea(); - } - - $.each(win_wh, function(type, val) { - var curval = $(window)[type](); - workarea[0]['scroll' + (type==='width'?'Left':'Top')] -= (curval - val)/2; - win_wh[type] = curval; - }); - }); - - (function() { - workarea.scroll(function() { - // TODO: jQuery's scrollLeft/Top() wouldn't require a null check - if ($('#ruler_x').length != 0) { - $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; - } - if ($('#ruler_y').length != 0) { - $('#ruler_y')[0].scrollTop = workarea[0].scrollTop; - } - }); - - }()); - - $('#url_notice').click(function() { - $.alert(this.title); - }); - - $('#change_image_url').click(promptImgURL); - - function promptImgURL() { - var curhref = svgCanvas.getHref(selectedElement); - curhref = curhref.indexOf("data:") === 0?"":curhref; - $.prompt(uiStrings.notification.enterNewImgURL, curhref, function(url) { - if(url) setImageURL(url); - }); - } - - // added these event handlers for all the push buttons so they - // behave more like buttons being pressed-in and not images - (function() { - var toolnames = ['clear','open','save','source','delete','delete_multi','paste','clone','clone_multi','move_top','move_bottom']; - var all_tools = ''; - var cur_class = 'tool_button_current'; - - $.each(toolnames, function(i,item) { - all_tools += '#tool_' + item + (i==toolnames.length-1?',':''); - }); - - $(all_tools).mousedown(function() { - $(this).addClass(cur_class); - }).bind('mousedown mouseout', function() { - $(this).removeClass(cur_class); - }); - - $('#tool_undo, #tool_redo').mousedown(function(){ - if (!$(this).hasClass('disabled')) $(this).addClass(cur_class); - }).bind('mousedown mouseout',function(){ - $(this).removeClass(cur_class);} - ); - }()); - - // switch modifier key in tooltips if mac - // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta - // in Opera and Chrome - if (isMac && !window.opera) { - var shortcutButtons = ["tool_clear", "tool_save", "tool_source", "tool_undo", "tool_redo", "tool_clone"]; - var i = shortcutButtons.length; - while (i--) { - var button = document.getElementById(shortcutButtons[i]); - if (button != null) { - var title = button.title; - var index = title.indexOf("Ctrl+"); - button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join(''); - } - } - } - - // TODO: go back to the color boxes having white background-color and then setting - // background-image to none.png (otherwise partially transparent gradients look weird) - var colorPicker = function(elem) { - var picker = elem.attr('id') == 'stroke_color' ? 'stroke' : 'fill'; -// var opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); - var paint = paintBox[picker].paint; - var title = (picker == 'stroke' ? 'Pick a Stroke Paint and Opacity' : 'Pick a Fill Paint and Opacity'); - var was_none = false; - var pos = elem.position(); - $("#color_picker") - .draggable({cancel:'.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window'}) - .css(curConfig.colorPickerCSS || {'left': pos.left, 'bottom': 50 - pos.top}) - .jGraduate( - { - paint: paint, - window: { pickerTitle: title }, - images: { clientPath: curConfig.jGraduatePath }, - newstop: 'inverse' - }, - function(p) { - paint = new $.jGraduate.Paint(p); - - paintBox[picker].setPaint(paint); - svgCanvas.setPaint(picker, paint); - - $('#color_picker').hide(); - }, - function(p) { - $('#color_picker').hide(); - }); - }; - - var updateToolButtonState = function() { - var bNoFill = (svgCanvas.getColor('fill') == 'none'); - var bNoStroke = (svgCanvas.getColor('stroke') == 'none'); - var buttonsNeedingStroke = [ '#tool_fhpath', '#tool_line' ]; - var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; - if (bNoStroke) { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - $(button).removeClass('disabled'); - } - } - - if (bNoStroke && bNoFill) { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - $(button).removeClass('disabled'); - } - } - - svgCanvas.runExtensions("toolButtonStateUpdate", { - nofill: bNoFill, - nostroke: bNoStroke - }); - - // Disable flyouts if all inside are disabled - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var has_enabled = false; - $(this).children().each(function() { - if(!$(this).hasClass('disabled')) { - has_enabled = true; - } - }); - shower.toggleClass('disabled', !has_enabled); - }); - - operaRepaint(); - }; - - - - var PaintBox = function(container, type) { - var cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke']; - - // set up gradients to be used for the buttons - var svgdocbox = new DOMParser().parseFromString( - '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\ - fill="#' + cur.color + '" opacity="' + cur.opacity + '"/>\ - <defs><linearGradient id="gradbox_"/></defs></svg>', 'text/xml'); - var docElem = svgdocbox.documentElement; - - docElem = $(container)[0].appendChild(document.importNode(docElem, true)); - - docElem.setAttribute('width',24.5); - - this.rect = docElem.firstChild; - this.defs = docElem.getElementsByTagName('defs')[0]; - this.grad = this.defs.firstChild; - this.paint = new $.jGraduate.Paint({solidColor: cur.color}); - this.type = type; - - this.setPaint = function(paint, apply) { - this.paint = paint; - - var fillAttr = "none"; - var ptype = paint.type; - var opac = paint.alpha / 100; - - switch ( ptype ) { - case 'solidColor': - fillAttr = "#" + paint[ptype]; - break; - case 'linearGradient': - case 'radialGradient': - this.defs.removeChild(this.grad); - this.grad = this.defs.appendChild(paint[ptype]); - var id = this.grad.id = 'gradbox_' + this.type; - fillAttr = "url(#" + id + ')'; - } - - this.rect.setAttribute('fill', fillAttr); - this.rect.setAttribute('opacity', opac); - - if(apply) { - svgCanvas.setColor(this.type, fillAttr, true); - svgCanvas.setPaintOpacity(this.type, opac, true); - } - } - - this.update = function(apply) { - if(!selectedElement) return; - var type = this.type; - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - // These elements don't have fill or stroke, so don't change - // the current value - return; - case 'g': - case 'a': - var gPaint = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var elem = childs[i]; - var p = elem.getAttribute(type); - if(i === 0) { - gPaint = p; - } else if(gPaint !== p) { - gPaint = null; - break; - } - } - if(gPaint === null) { - // No common color, don't update anything - var paintColor = null; - return; - } - var paintColor = gPaint; - - var paintOpacity = 1; - break; - default: - var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity")); - if (isNaN(paintOpacity)) { - paintOpacity = 1.0; - } - - var defColor = type === "fill" ? "black" : "none"; - var paintColor = selectedElement.getAttribute(type) || defColor; - } - - if(apply) { - svgCanvas.setColor(type, paintColor, true); - svgCanvas.setPaintOpacity(type, paintOpacity, true); - } - - paintOpacity *= 100; - - var paint = getPaint(paintColor, paintOpacity, type); - // update the rect inside #fill_color/#stroke_color - this.setPaint(paint); - } - - this.prep = function() { - var ptype = this.paint.type; - - switch ( ptype ) { - case 'linearGradient': - case 'radialGradient': - var paint = new $.jGraduate.Paint({copy: this.paint}); - svgCanvas.setPaint(type, paint); - } - } - }; - - paintBox.fill = new PaintBox('#fill_color', 'fill'); - paintBox.stroke = new PaintBox('#stroke_color', 'stroke'); - - $('#stroke_width').val(curConfig.initStroke.width); - $('#group_opacity').val(curConfig.initOpacity * 100); - - // Use this SVG elem to test vectorEffect support - var test_el = paintBox.fill.rect.cloneNode(false); - test_el.setAttribute('style','vector-effect:non-scaling-stroke'); - var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke'); - test_el.removeAttribute('style'); - var svgdocbox = paintBox.fill.rect.ownerDocument; - // Use this to test support for blur element. Seems to work to test support in Webkit - var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur'); - if(typeof blur_test.stdDeviationX === "undefined") { - $('#tool_blur').hide(); - } - $(blur_test).remove(); - - - - // Test for embedImage support (use timeout to not interfere with page load) - setTimeout(function() { - svgCanvas.embedImage('images/placeholder.svg', function(datauri) { - if(!datauri) { - // Disable option - $('#image_save_opts [value=embed]').attr('disabled','disabled'); - $('#image_save_opts input').val(['ref']); - curPrefs.img_save = 'ref'; - $('#image_opt_embed').css('color','#666').attr('title',uiStrings.notification.featNotSupported); - } - }); - },1000); - - $('#tool_fill').click(function(){ - if ($('#tool_fill').hasClass('active')) { - colorPicker($('#fill_color')); - updateToolButtonState(); - } - else { - $('#tool_fill').addClass('active'); - $("#tool_stroke").removeClass('active'); - } - }); - - $('#tool_stroke').click(function(){ - - if ($('#tool_stroke').hasClass('active')) { - colorPicker($('#stroke_color')); - updateToolButtonState(); - } - else { - $('#tool_stroke').addClass('active'); - console.log($('#tool_stroke')); - $("#tool_fill").removeClass('active'); - } - }); - - $('#group_opacityLabel').click(function() { - $('#opacity_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#zoomLabel').click(function() { - $('#zoom_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#tool_move_top').mousedown(function(evt){ - $('#tools_stacking').show(); - evt.preventDefault(); - }); - - $('.layer_button').mousedown(function() { - $(this).addClass('layer_buttonpressed'); - }).mouseout(function() { - $(this).removeClass('layer_buttonpressed'); - }).mouseup(function() { - $(this).removeClass('layer_buttonpressed'); - }); - - $('.push_button').mousedown(function() { - if (!$(this).hasClass('disabled')) { - $(this).addClass('push_button_pressed').removeClass('push_button'); - } - }).mouseout(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }).mouseup(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }); - - $('#layer_new').click(function() { - var i = svgCanvas.getCurrentDrawing().getNumLayers(); - do { - var uniqName = uiStrings.layers.layer + " " + ++i; - } while(svgCanvas.getCurrentDrawing().hasLayer(uniqName)); - - $.prompt(uiStrings.notification.enterUniqueLayerName,uniqName, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.createLayer(newName); - updateContextPanel(); - populateLayers(); - }); - }); - - function deleteLayer() { - if (svgCanvas.deleteCurrentLayer()) { - updateContextPanel(); - populateLayers(); - // This matches what SvgCanvas does - // TODO: make this behavior less brittle (svg-editor should get which - // layer is selected from the canvas and then select that one in the UI) - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:first').addClass("layersel"); - } - } - - function cloneLayer() { - var name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy'; - - $.prompt(uiStrings.notification.enterUniqueLayerName, name, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.cloneLayer(newName); - updateContextPanel(); - populateLayers(); - }); - } - - function mergeLayer() { - if($('#layerlist tr.layersel').index() == svgCanvas.getCurrentDrawing().getNumLayers()-1) return; - svgCanvas.mergeLayer(); - updateContextPanel(); - populateLayers(); - } - - function moveLayer(pos) { - var curIndex = $('#layerlist tr.layersel').index(); - var total = svgCanvas.getCurrentDrawing().getNumLayers(); - if(curIndex > 0 || curIndex < total-1) { - curIndex += pos; - svgCanvas.setCurrentLayerPosition(total-curIndex-1); - populateLayers(); - } - } - - $('#layer_delete').click(deleteLayer); - - $('#layer_up').click(function() { - moveLayer(-1); - }); - - $('#layer_down').click(function() { - moveLayer(1); - }); - - $('#layer_rename').click(function() { - var curIndex = $('#layerlist tr.layersel').prevAll().length; - var oldName = $('#layerlist tr.layersel td.layername').text(); - $.prompt(uiStrings.notification.enterNewLayerName,"", function(newName) { - if (!newName) return; - if (oldName == newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.layerHasThatName); - return; - } - - svgCanvas.renameCurrentLayer(newName); - populateLayers(); - }); - }); - - var SIDEPANEL_MAXWIDTH = 300; - var SIDEPANEL_OPENWIDTH = 150; - var sidedrag = -1, sidedragging = false, allowmove = false; - - var resizePanel = function(evt) { - if (!allowmove) return; - if (sidedrag == -1) return; - sidedragging = true; - var deltax = sidedrag - evt.pageX; - - var sidepanels = $('#sidepanels'); - var sidewidth = parseInt(sidepanels.css('width')); - if (sidewidth+deltax > SIDEPANEL_MAXWIDTH) { - deltax = SIDEPANEL_MAXWIDTH - sidewidth; - sidewidth = SIDEPANEL_MAXWIDTH; - } - else if (sidewidth+deltax < 2) { - deltax = 2 - sidewidth; - sidewidth = 2; - } - - if (deltax == 0) return; - sidedrag -= deltax; - - var layerpanel = $('#layerpanel'); - workarea.css('right', parseInt(workarea.css('right'))+deltax); - sidepanels.css('width', parseInt(sidepanels.css('width'))+deltax); - layerpanel.css('width', parseInt(layerpanel.css('width'))+deltax); - var ruler_x = $('#ruler_x'); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - } - - $('#sidepanel_handle') - .mousedown(function(evt) { - sidedrag = evt.pageX; - $(window).mousemove(resizePanel); - allowmove = false; - // Silly hack for Chrome, which always runs mousemove right after mousedown - setTimeout(function() { - allowmove = true; - }, 20); - }) - .mouseup(function(evt) { - if (!sidedragging) toggleSidePanel(); - sidedrag = -1; - sidedragging = false; - }); - - $(window).mouseup(function() { - sidedrag = -1; - sidedragging = false; - $('#svg_editor').unbind('mousemove', resizePanel); - }); - - // if width is non-zero, then fully close it, otherwise fully open it - // the optional close argument forces the side panel closed - var toggleSidePanel = function(close){ - var w = parseInt($('#sidepanels').css('width')); - var deltax = (w > 2 || close ? 2 : SIDEPANEL_OPENWIDTH) - w; - var sidepanels = $('#sidepanels'); - var layerpanel = $('#layerpanel'); - var ruler_x = $('#ruler_x'); - workarea.css('right', parseInt(workarea.css('right')) + deltax); - sidepanels.css('width', parseInt(sidepanels.css('width')) + deltax); - layerpanel.css('width', parseInt(layerpanel.css('width')) + deltax); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - }; - - // this function highlights the layer passed in (by fading out the other layers) - // if no layer is passed in, this function restores the other layers - var toggleHighlightLayer = function(layerNameToHighlight) { - var curNames = new Array(svgCanvas.getCurrentDrawing().getNumLayers()); - for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getCurrentDrawing().getLayerName(i); } - - if (layerNameToHighlight) { - for (var i = 0; i < curNames.length; ++i) { - if (curNames[i] != layerNameToHighlight) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 0.5); - } - } - } - else { - for (var i = 0; i < curNames.length; ++i) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 1.0); - } - } - }; - - var populateLayers = function(){ - var layerlist = $('#layerlist tbody'); - var selLayerNames = $('#selLayerNames'); - layerlist.empty(); - selLayerNames.empty(); - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var layer = svgCanvas.getCurrentDrawing().getNumLayers(); - var icon = $.getSvgIcon('eye'); - // we get the layers in the reverse z-order (the layer rendered on top is listed first) - while (layer--) { - var name = svgCanvas.getCurrentDrawing().getLayerName(layer); - // contenteditable=\"true\" - var appendstr = "<tr class=\"layer"; - if (name == currentLayerName) { - appendstr += " layersel" - } - appendstr += "\">"; - - if (svgCanvas.getCurrentDrawing().getLayerVisibility(name)) { - appendstr += "<td class=\"layervis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - else { - appendstr += "<td class=\"layervis layerinvis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - layerlist.append(appendstr); - selLayerNames.append("<option value=\"" + name + "\">" + name + "</option>"); - } - if(icon !== undefined) { - var copy = icon.clone(); - $('td.layervis',layerlist).append(icon.clone()); - $.resizeSvgIcons({'td.layervis .svg_icon':14}); - } - // handle selection of layer - $('#layerlist td.layername') - .mouseup(function(evt){ - $('#layerlist tr.layer').removeClass("layersel"); - var row = $(this.parentNode); - row.addClass("layersel"); - svgCanvas.setCurrentLayer(this.textContent); - evt.preventDefault(); - }) - .mouseover(function(evt){ - $(this).css({"font-style": "italic", "color":"blue"}); - toggleHighlightLayer(this.textContent); - }) - .mouseout(function(evt){ - $(this).css({"font-style": "normal", "color":"black"}); - toggleHighlightLayer(); - }); - $('#layerlist td.layervis').click(function(evt){ - var row = $(this.parentNode).prevAll().length; - var name = $('#layerlist tr.layer:eq(' + row + ') td.layername').text(); - var vis = $(this).hasClass('layerinvis'); - svgCanvas.setLayerVisibility(name, vis); - if (vis) { - $(this).removeClass('layerinvis'); - } - else { - $(this).addClass('layerinvis'); - } - }); - - // if there were too few rows, let's add a few to make it not so lonely - var num = 5 - $('#layerlist tr.layer').size(); - while (num-- > 0) { - // FIXME: there must a better way to do this - layerlist.append("<tr><td style=\"color:white\">_</td><td/></tr>"); - } - }; - populateLayers(); - - // function changeResolution(x,y) { - // var zoom = svgCanvas.getResolution().zoom; - // setResolution(x * zoom, y * zoom); - // } - - var centerCanvas = function() { - // this centers the canvas vertically in the workarea (horizontal handled in CSS) - workarea.css('line-height', workarea.height() + 'px'); - }; - - $(window).bind('load resize', centerCanvas); - - function stepFontSize(elem, step) { - var orig_val = elem.value-0; - var sug_val = orig_val + step; - var increasing = sug_val >= orig_val; - if(step === 0) return orig_val; - - if(orig_val >= 24) { - if(increasing) { - return Math.round(orig_val * 1.1); - } else { - return Math.round(orig_val / 1.1); - } - } else if(orig_val <= 1) { - if(increasing) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } else { - return sug_val; - } - } - - function stepZoom(elem, step) { - var orig_val = elem.value-0; - if(orig_val === 0) return 100; - var sug_val = orig_val + step; - if(step === 0) return orig_val; - - if(orig_val >= 100) { - return sug_val; - } else { - if(sug_val >= orig_val) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } - } - - // function setResolution(w, h, center) { - // updateCanvas(); - // // w-=0; h-=0; - // // $('#svgcanvas').css( { 'width': w, 'height': h } ); - // // $('#canvas_width').val(w); - // // $('#canvas_height').val(h); - // // - // // if(center) { - // // var w_area = workarea; - // // var scroll_y = h/2 - w_area.height()/2; - // // var scroll_x = w/2 - w_area.width()/2; - // // w_area[0].scrollTop = scroll_y; - // // w_area[0].scrollLeft = scroll_x; - // // } - // } - - $('#resolution').change(function(){ - var wh = $('#canvas_width,#canvas_height'); - if(!this.selectedIndex) { - if($('#canvas_width').val() == 'fit') { - wh.removeAttr("disabled").val(100); - } - } else if(this.value == 'content') { - wh.val('fit').attr("disabled","disabled"); - } else { - var dims = this.value.split('x'); - $('#canvas_width').val(dims[0]); - $('#canvas_height').val(dims[1]); - wh.removeAttr("disabled"); - } - }); - - //Prevent browser from erroneously repopulating fields - $('input,select').attr("autocomplete","off"); - - // Associate all button actions as well as non-button keyboard shortcuts - var Actions = function() { - // sel:'selector', fn:function, evt:'event', key:[key, preventDefault, NoDisableInInput] - var tool_buttons = [ - {sel:'#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]}, - {sel:'#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]}, - {sel:'#tool_line', fn: clickLine, evt: 'click', key: ['L', true]}, - {sel:'#tool_rect', fn: clickRect, evt: 'click', key: ['R', true], icon: 'rect'}, - {sel:'#tool_ellipse', fn: clickEllipse, evt: 'mouseup', key: ['C', true], icon: 'ellipse'}, - //{sel:'#tool_circle', fn: clickCircle, evt: 'mouseup', icon: 'circle'}, - //{sel:'#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup', parent: '#tools_ellipse', icon: 'fh_ellipse'}, - {sel:'#tool_path', fn: clickPath, evt: 'click', key: ['P', true]}, - {sel:'#tool_text', fn: clickText, evt: 'click', key: ['T', true]}, - {sel:'#tool_image', fn: clickImage, evt: 'mouseup'}, - {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]}, - {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey + 'N', true]}, - {sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey + 'S', true]}, - {sel:'#tool_export', fn: clickExport, evt: 'mouseup'}, - {sel:'#tool_open', fn: clickOpen, evt: 'mouseup'}, - {sel:'#tool_import', fn: clickImport, evt: 'mouseup'}, - {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: [modKey + 'U', true]}, - {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click'}, - {sel:'#tool_rulers', fn: clickRulers, evt: 'click'}, - {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, - {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'}, - {sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'}, - {sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup'}, - {sel:'#tool_prefs_save', fn: savePreferences, evt: 'click'}, - {sel:'#tool_prefs_option', fn: function() {showPreferences();return false}, evt: 'mouseup'}, - {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]}, - {sel:'#tool_reorient', fn: reorientPath, evt: 'click'}, - {sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'}, - {sel:'#tool_node_clone', fn: clonePathNode, evt: 'click'}, - {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'}, - {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'}, - {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'}, - {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: modKey + 'shift+up'}, - {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: modKey + 'shift+down'}, - {sel:'#tool_move_up', fn: moveUpSelected, evt:'click', key: [modKey+'up', true]}, - {sel:'#tool_move_down', fn: moveDownSelected, evt:'click', key: [modKey+'down', true]}, - {sel:'#tool_topath', fn: convertToPath, evt: 'click'}, - {sel:'#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'}, - {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: [modKey + 'Z', true]}, - {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]}, - {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey + 'D', true]}, - {sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey + 'G', true]}, - {sel:'#tool_ungroup', fn: clickGroup, evt: 'click', key: modKey + 'shift+G'}, - {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, - {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, - {sel:'#tool_switch', fn: clickSwitch, evt: 'click', key: ['X', true]}, - // these two lines are required to make Opera work properly with the flyout mechanism - // {sel:'#tools_rect_show', fn: clickRect, evt: 'click'}, - // {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'}, - {sel:'#tool_bold', fn: clickBold, evt: 'mousedown', key: [modKey + 'B', true]}, - {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown', key: [modKey + 'I', true]}, - //{sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']}, - {sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'}, - - // Shortcuts not associated with buttons - - {key: 'ctrl+left', fn: function(){rotateSelected(0,1)}}, - {key: 'ctrl+right', fn: function(){rotateSelected(1,1)}}, - {key: 'ctrl+shift+left', fn: function(){rotateSelected(0,5)}}, - {key: 'ctrl+shift+right', fn: function(){rotateSelected(1,5)}}, - {key: 'shift+O', fn: selectPrev}, - {key: 'shift+P', fn: selectNext}, - {key: [modKey+'+', true], fn: function(){zoomImage(2);}}, - {key: [modKey+'-', true], fn: function(){zoomImage(.5);}}, - {key: ['up', true], fn: function(){moveSelected(0,-1);}}, - {key: ['down', true], fn: function(){moveSelected(0,1);}}, - {key: ['left', true], fn: function(){moveSelected(-1,0);}}, - {key: ['right', true], fn: function(){moveSelected(1,0);}}, - {key: 'shift+up', fn: function(){moveSelected(0,-10)}}, - {key: 'shift+down', fn: function(){moveSelected(0,10)}}, - {key: 'shift+left', fn: function(){moveSelected(-10,0)}}, - {key: 'shift+right', fn: function(){moveSelected(10,0)}}, - {key: ['alt+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-1)}}, - {key: ['alt+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,1)}}, - {key: ['alt+left', true], fn: function(){svgCanvas.cloneSelectedElements(-1,0)}}, - {key: ['alt+right', true], fn: function(){svgCanvas.cloneSelectedElements(1,0)}}, - {key: ['alt+shift+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-10)}}, - {key: ['alt+shift+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,10)}}, - {key: ['alt+shift+left', true], fn: function(){svgCanvas.cloneSelectedElements(-10,0)}}, - {key: ['alt+shift+right', true], fn: function(){svgCanvas.cloneSelectedElements(10,0)}}, - {key: modKey + 'A', fn: function(){svgCanvas.selectAllInCurrentLayer();}}, - - // Standard shortcuts - {key: modKey + 'z', fn: clickUndo}, - {key: modKey + 'shift+z', fn: clickRedo}, - {key: modKey + 'y', fn: clickRedo}, - - {key: modKey+'x', fn: cutSelected}, - {key: modKey+'c', fn: copySelected}, - {key: modKey+'v', fn: pasteInCenter} - - - ]; - - // Tooltips not directly associated with a single function - var key_assocs = { - '4/Shift+4': '#tools_rect_show', - '5/Shift+5': '#tools_ellipse_show' - }; - - return { - setAll: function() { - var flyouts = {}; - - $.each(tool_buttons, function(i, opts) { - // Bind function to button - if(opts.sel) { - var btn = $(opts.sel); - if (btn.length == 0) return true; // Skip if markup does not exist - if(opts.evt) { - if (svgedit.browser.isTouch() && opts.evt === "click") opts.evt = "mousedown" - btn[opts.evt](opts.fn); - } - - // Add to parent flyout menu, if able to be displayed - if(opts.parent && $(opts.parent + '_show').length != 0) { - var f_h = $(opts.parent); - if(!f_h.length) { - f_h = makeFlyoutHolder(opts.parent.substr(1)); - } - - f_h.append(btn); - - if(!$.isArray(flyouts[opts.parent])) { - flyouts[opts.parent] = []; - } - flyouts[opts.parent].push(opts); - } - } - - - // Bind function to shortcut key - if(opts.key) { - // Set shortcut based on options - var keyval, shortcut = '', disInInp = true, fn = opts.fn, pd = false; - if($.isArray(opts.key)) { - keyval = opts.key[0]; - if(opts.key.length > 1) pd = opts.key[1]; - if(opts.key.length > 2) disInInp = opts.key[2]; - } else { - keyval = opts.key; - } - keyval += ''; - if (svgedit.browser.isMac && keyval.indexOf("+") != -1) { - var modifier_key = keyval.split("+")[0]; - if (modifier_key == "ctrl") keyval.replace("ctrl", "cmd") - } - - $.each(keyval.split('/'), function(i, key) { - $(document).bind('keydown', key, function(e) { - fn(); - if(pd) { - e.preventDefault(); - } - // Prevent default on ALL keys? - return false; - }); - }); - - // Put shortcut in title - if(opts.sel && !opts.hidekey && btn.attr('title')) { - var new_title = btn.attr('title').split('[')[0] + ' (' + keyval + ')'; - key_assocs[keyval] = opts.sel; - // Disregard for menu items - if(!btn.parents('#main_menu').length) { - btn.attr('title', new_title); - } - } - } - }); - - // Setup flyouts - setupFlyouts(flyouts); - - - // Misc additional actions - - // Make "return" keypress trigger the change event - $('.attr_changer, #image_url').bind('keydown', 'return', - function(evt) {$(this).change();evt.preventDefault();} - ); - - $(window).bind('keydown', 'tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectNext(); - } - }).bind('keydown', 'shift+tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectPrev(); - } - }); - - $('#tool_zoom').dblclick(dblclickZoom); - }, - setTitles: function() { - $.each(key_assocs, function(keyval, sel) { - var menu = ($(sel).parents('#main_menu').length); - - $(sel).each(function() { - if(menu) { - var t = $(this).text().split(' [')[0]; - } else { - var t = this.title.split(' [')[0]; - } - var key_str = ''; - // Shift+Up - $.each(keyval.split('/'), function(i, key) { - var mod_bits = key.split('+'), mod = ''; - if(mod_bits.length > 1) { - mod = mod_bits[0] + '+'; - key = mod_bits[1]; - } - key_str += (i?'/':'') + mod + (uiStrings['key_'+key] || key); - }); - if(menu) { - this.lastChild.textContent = t +' ['+key_str+']'; - } else { - this.title = t +' ['+key_str+']'; - } - }); - }); - }, - getButtonData: function(sel) { - var b; - $.each(tool_buttons, function(i, btn) { - if(btn.sel === sel) b = btn; - }); - return b; - } - }; - }(); - - Actions.setAll(); - - // Select given tool - Editor.ready(function() { - var tool, - itool = curConfig.initTool, - container = $("#tools_left, #svg_editor .tools_flyout"), - pre_tool = container.find("#tool_" + itool), - reg_tool = container.find("#" + itool); - if(pre_tool.length) { - tool = pre_tool; - } else if(reg_tool.length){ - tool = reg_tool; - } else { - tool = $("#tool_select"); - } - tool.click().mouseup(); - - if(curConfig.wireframe) { - $('#tool_wireframe').click(); - } - - if(curConfig.showlayers) { - toggleSidePanel(); - } - - $('#rulers').toggle(!!curConfig.showRulers); - - if (curConfig.showRulers) { - $('#show_rulers')[0].checked = true; - } - - if(curConfig.gridSnapping) { - $('#grid_snapping_on')[0].checked = true; - } - - if(curConfig.baseUnit) { - $('#base_unit').val(curConfig.baseUnit); - } - - if(curConfig.snappingStep) { - $('#grid_snapping_step').val(curConfig.snappingStep); - } - }); - - $('#rect_rx').SpinButton({ min: 0, max: 1000, step: 1, callback: changeRectRadius }); - $('#stroke_width').SpinButton({ min: 0, max: 99, step: 1, smallStep: 0.1, callback: changeStrokeWidth }); - $('#angle').SpinButton({ min: -180, max: 180, step: 5, callback: changeRotationAngle }); - $('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize }); - $('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity }); - $('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur }); - $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom }) - // Set default zoom - .val(svgCanvas.getZoom() * 100); - - $("#workarea").contextMenu({ - menu: 'cmenu_canvas', - inSpeed: 0 - }, - function(action, el, pos) { - switch ( action ) { - case 'delete': - deleteSelected(); - break; - case 'cut': - cutSelected(); - break; - case 'copy': - copySelected(); - break; - case 'paste': - svgCanvas.pasteElements(); - break; - case 'paste_in_place': - svgCanvas.pasteElements('in_place'); - break; - case 'group': - svgCanvas.groupSelectedElements(); - break; - case 'ungroup': - svgCanvas.ungroupSelectedElement(); - break; - case 'move_front': - moveToTopSelected(); - break; - case 'move_up': - moveUpDownSelected('Up'); - break; - case 'move_down': - moveUpDownSelected('Down'); - break; - case 'move_back': - moveToBottomSelected(); - break; - default: - if(svgedit.contextmenu && svgedit.contextmenu.hasCustomHandler(action)){ - svgedit.contextmenu.getCustomHandler(action).call(); - } - break; - } - - if(svgCanvas.clipBoard.length) { - canv_menu.enableContextMenuItems('#paste,#paste_in_place'); - } - }); - - var lmenu_func = function(action, el, pos) { - switch ( action ) { - case 'dupe': - cloneLayer(); - break; - case 'delete': - deleteLayer(); - break; - case 'merge_down': - mergeLayer(); - break; - case 'merge_all': - svgCanvas.mergeAllLayers(); - updateContextPanel(); - populateLayers(); - break; - } - } - - $("#layerlist").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0 - }, - lmenu_func - ); - - $("#layer_moreopts").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0, - allowLeft: true - }, - lmenu_func - ); - - $('.contextMenu li').mousedown(function(ev) { - ev.preventDefault(); - }) - - $('#cmenu_canvas li').disableContextMenu(); - canv_menu.enableContextMenuItems('#delete,#cut,#copy'); - - window.onbeforeunload = function() { - // Suppress warning if page is empty - if(undoMgr.getUndoStackSize() === 0) { - Editor.show_save_warning = false; - } - - // show_save_warning is set to "false" when the page is saved. - if(!curConfig.no_save_warning && Editor.show_save_warning) { - // Browser already asks question about closing the page - return uiStrings.notification.unsavedChanges; - } - }; - - Editor.openPrep = function(func) { - $('#main_menu').hide(); - if(undoMgr.getUndoStackSize() === 0) { - func(true); - } else { - $.confirm(uiStrings.notification.QwantToOpen, func); - } - } - - // use HTML5 File API: http://www.w3.org/TR/FileAPI/ - // if browser has HTML5 File API support, then we will show the open menu item - // and provide a file input to click. When that change event fires, it will - // get the text contents of the file and send it to the canvas - if (window.FileReader) { - var inp = $('<input type="file">').change(function() { - var f = this; - Editor.openPrep(function(ok) { - if(!ok) return; - svgCanvas.clear(); - if(f.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - loadSvgString(e.target.result); - updateCanvas(); - }; - reader.readAsText(f.files[0]); - } - }); - }); - $("#tool_open").show().prepend(inp); - var inp2 = $('<input type="file">').change(function() { - $('#main_menu').hide(); - if(this.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - svgCanvas.importSvgString(e.target.result, true); - updateCanvas(); - }; - reader.readAsText(this.files[0]); - } - }); - $("#tool_import").show().prepend(inp2); - } - - var updateCanvas = Editor.updateCanvas = function(center, new_ctr) { - - var w = workarea.width(), h = workarea.height(); - var w_orig = w, h_orig = h; - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - var cnvs = $("#svgcanvas"); - - var old_ctr = { - x: w_area[0].scrollLeft + w_orig/2, - y: w_area[0].scrollTop + h_orig/2 - }; - - var multi = curConfig.canvas_expansion; - w = Math.max(w_orig, svgCanvas.contentW * zoom * multi); - h = Math.max(h_orig, svgCanvas.contentH * zoom * multi); - - if(w == w_orig && h == h_orig) { - workarea.css('overflow','hidden'); - } else { - workarea.css('overflow','scroll'); - } - - var old_can_y = cnvs.height()/2; - var old_can_x = cnvs.width()/2; - cnvs.width(w).height(h); - var new_can_y = h/2; - var new_can_x = w/2; - var offset = svgCanvas.updateCanvas(w, h); - - var ratio = new_can_x / old_can_x; - - var scroll_x = w/2 - w_orig/2; - var scroll_y = h/2 - h_orig/2; - - if(!new_ctr) { - - var old_dist_x = old_ctr.x - old_can_x; - var new_x = new_can_x + old_dist_x * ratio; - - var old_dist_y = old_ctr.y - old_can_y; - var new_y = new_can_y + old_dist_y * ratio; - - new_ctr = { - x: new_x, - y: new_y - }; - - } else { - new_ctr.x += offset.x, - new_ctr.y += offset.y; - } - - if(center) { - // Go to top-left for larger documents - if(svgCanvas.contentW > w_area.width()) { - // Top-left - workarea[0].scrollLeft = offset.x - 10; - workarea[0].scrollTop = offset.y - 10; - } else { - // Center - w_area[0].scrollLeft = scroll_x; - w_area[0].scrollTop = scroll_y; - } - } else { - w_area[0].scrollLeft = new_ctr.x - w_orig/2; - w_area[0].scrollTop = new_ctr.y - h_orig/2; - } - if(curConfig.showRulers) { - updateRulers(cnvs, zoom); - workarea.scroll(); - } - } - - // Make [1,2,5] array - var r_intervals = []; - for(var i = .1; i < 1E5; i *= 10) { - r_intervals.push(1 * i); - r_intervals.push(2 * i); - r_intervals.push(5 * i); - } - - function updateRulers(scanvas, zoom) { - var ruler_x_cursor = document.getElementById("ruler_x_cursor"); - var ruler_y_cursor = document.getElementById("ruler_y_cursor"); - var workarea = document.getElementById("workarea"); - var title_show = document.getElementById("title_show"); - var offset_x = 66; - var offset_y = 48; - $("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers", function(e){ - e.stopPropagation(); - ruler_x_cursor.style.left = (e.pageX-offset_x+workarea.scrollLeft) + "px"; - ruler_y_cursor.style.top = (e.pageY-offset_y+workarea.scrollTop) + "px"; - var title = e.target.getAttribute("title"); - if (typeof title != 'undefined' && title) title_show.innerHTML(title); - }) - if(!zoom) zoom = svgCanvas.getZoom(); - if(!scanvas) scanvas = $("#svgcanvas"); - - var limit = 30000; - - var c_elem = svgCanvas.getContentElem(); - - var units = svgedit.units.getTypeMap(); - var unit = units[curConfig.baseUnit]; // 1 = 1px - - for(var d = 0; d < 2; d++) { - var is_x = (d === 0); - var dim = is_x ? 'x' : 'y'; - var lentype = is_x?'width':'height'; - var content_d = c_elem.getAttribute(dim)-0; - - var $hcanv_orig = $('#ruler_' + dim + ' canvas:first'); - - // Bit of a hack to fully clear the canvas in Safari & IE9 - $hcanv = $hcanv_orig.clone(); - $hcanv_orig.replaceWith($hcanv); - - var hcanv = $hcanv[0]; - - // Set the canvas size to the width of the container - var ruler_len = scanvas[lentype]()*2; - var total_len = ruler_len; - hcanv.parentNode.style[lentype] = total_len + 'px'; - - var canv_count = 1; - var ctx_num = 0; - var ctx_arr; - var ctx = hcanv.getContext("2d"); - - ctx.fillStyle = "rgb(200,0,0)"; - ctx.fillRect(0,0,hcanv.width,hcanv.height); - - // Remove any existing canvasses - $hcanv.siblings().remove(); - - // Create multiple canvases when necessary (due to browser limits) - if(ruler_len >= limit) { - var num = parseInt(ruler_len / limit) + 1; - ctx_arr = Array(num); - ctx_arr[0] = ctx; - for(var i = 1; i < num; i++) { - hcanv[lentype] = limit; - var copy = hcanv.cloneNode(true); - hcanv.parentNode.appendChild(copy); - ctx_arr[i] = copy.getContext('2d'); - } - - copy[lentype] = ruler_len % limit; - - // set copy width to last - ruler_len = limit; - } - - hcanv[lentype] = ruler_len; - - var u_multi = unit * zoom; - - // Calculate the main number interval - var raw_m = 50 / u_multi; - var multi = 1; - for(var i = 0; i < r_intervals.length; i++) { - var num = r_intervals[i]; - multi = num; - if(raw_m <= num) { - break; - } - } - - var big_int = multi * u_multi; - ctx.font = "normal 9px 'Lucida Grande', sans-serif"; - ctx.fillStyle = "#777"; - - var ruler_d = ((content_d / u_multi) % multi) * u_multi; - var label_pos = ruler_d - big_int; - for (; ruler_d < total_len; ruler_d += big_int) { - label_pos += big_int; - var real_d = ruler_d - content_d; - - var cur_d = Math.round(ruler_d) + .5; - if(is_x) { - ctx.moveTo(cur_d, 15); - ctx.lineTo(cur_d, 0); - } else { - ctx.moveTo(15, cur_d); - ctx.lineTo(0, cur_d); - } - - var num = (label_pos - content_d) / u_multi; - var label; - if(multi >= 1) { - label = Math.round(num); - } else { - var decs = (multi+'').split('.')[1].length; - label = num.toFixed(decs)-0; - } - - // Do anything special for negative numbers? -// var is_neg = label < 0; -// real_d2 = Math.abs(real_d2); - - // Change 1000s to Ks - if(label !== 0 && label !== 1000 && label % 1000 === 0) { - label = (label / 1000) + 'K'; - } - - if(is_x) { - ctx.fillText(label, ruler_d+2, 8); - ctx.fillStyle = "#777"; - } else { - var str = (label+'').split(''); - for(var i = 0; i < str.length; i++) { - ctx.fillText(str[i], 1, (ruler_d+9) + i*9); - ctx.fillStyle = "#777"; - } - } - - var part = big_int / 10; - for(var i = 1; i < 10; i++) { - var sub_d = Math.round(ruler_d + part * i) + .5; - if(ctx_arr && sub_d > ruler_len) { - ctx_num++; - ctx.stroke(); - if(ctx_num >= ctx_arr.length) { - i = 10; - ruler_d = total_len; - continue; - } - ctx = ctx_arr[ctx_num]; - ruler_d -= limit; - sub_d = Math.round(ruler_d + part * i) + .5; - } - - var line_num = (i % 2)?12:10; - if(is_x) { - ctx.moveTo(sub_d, 15); - ctx.lineTo(sub_d, line_num); - } else { - ctx.moveTo(15, sub_d); - ctx.lineTo(line_num ,sub_d); - } - } - } - - // console.log('ctx', ctx); - ctx.strokeStyle = "#666"; - ctx.stroke(); - } - } - -// $(function() { - updateCanvas(true); -// }); - - // var revnums = "svg-editor.js ($Rev: 2083 $) "; - // revnums += svgCanvas.getVersion(); - // $('#copyright')[0].setAttribute("title", revnums); - - // Callback handler for embedapi.js - try{ - var json_encode = function(obj){ - //simple partial JSON encoder implementation - if(window.JSON && JSON.stringify) return JSON.stringify(obj); - var enc = arguments.callee; //for purposes of recursion - if(typeof obj == "boolean" || typeof obj == "number"){ - return obj+'' //should work... - }else if(typeof obj == "string"){ - //a large portion of this is stolen from Douglas Crockford's json2.js - return '"'+ - obj.replace( - /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g - , function (a) { - return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) - +'"'; //note that this isn't quite as purtyful as the usualness - }else if(obj.length){ //simple hackish test for arrayish-ness - for(var i = 0; i < obj.length; i++){ - obj[i] = enc(obj[i]); //encode every sub-thingy on top - } - return "["+obj.join(",")+"]"; - }else{ - var pairs = []; //pairs will be stored here - for(var k in obj){ //loop through thingys - pairs.push(enc(k)+":"+enc(obj[k])); //key: value - } - return "{"+pairs.join(",")+"}" //wrap in the braces - } - } - window.addEventListener("message", function(e){ - var cbid = parseInt(e.data.substr(0, e.data.indexOf(";"))); - try{ - e.source.postMessage("SVGe"+cbid+";"+json_encode(eval(e.data)), "*"); - }catch(err){ - e.source.postMessage("SVGe"+cbid+";error:"+err.message, "*"); - } - }, false) - }catch(err){ - window.embed_error = err; - } - - - - // For Compatibility with older extensions - $(function() { - window.svgCanvas = svgCanvas; - svgCanvas.ready = svgEditor.ready; - }); - - - Editor.setLang = function(lang, allStrings) { - $.pref('lang', lang); - $('#lang_select').val(lang); - if(allStrings) { - - var notif = allStrings.notification; - - - - // $.extend will only replace the given strings - var oldLayerName = $('#layerlist tr.layersel td.layername').text(); - var rename_layer = (oldLayerName == uiStrings.common.layer + ' 1'); - - $.extend(uiStrings, allStrings); - svgCanvas.setUiStrings(allStrings); - Actions.setTitles(); - - if(rename_layer) { - svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1'); - populateLayers(); - } - - svgCanvas.runExtensions("langChanged", lang); - - // Update flyout tooltips - setFlyoutTitles(); - - // Copy title for certain tool elements - var elems = { - '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', - '#fill_color': '#tool_fill label, #tool_fill .color_block', - '#linejoin_miter': '#cur_linejoin', - '#linecap_butt': '#cur_linecap' - } - - $.each(elems, function(source, dest) { - $(dest).attr('title', $(source)[0].title); - }); - - // Copy alignment titles - $('#multiselected_panel div[id^=tool_align]').each(function() { - $('#tool_pos' + this.id.substr(10))[0].title = this.title; - }); - - } - }; - }; - - var callbacks = []; - - function loadSvgString(str, callback) { - var success = svgCanvas.setSvgString(str) !== false; - callback = callback || $.noop; - if(success) { - callback(true); - } else { - $.alert(uiStrings.notification.errorLoadingSVG, function() { - callback(false); - }); - } - } - - Editor.ready = function(cb) { - if(!is_ready) { - callbacks.push(cb); - } else { - cb(); - } - }; - - Editor.runCallbacks = function() { - $.each(callbacks, function() { - this(); - }); - is_ready = true; - }; - - Editor.loadFromString = function(str) { - Editor.ready(function() { - loadSvgString(str); - }); - }; - - Editor.disableUI = function(featList) { -// $(function() { -// $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove(); -// $('#tools_top').css('left', 5); -// }); - }; - - Editor.loadFromURL = function(url, opts) { - if(!opts) opts = {}; - - var cache = opts.cache; - var cb = opts.callback; - - Editor.ready(function() { - $.ajax({ - 'url': url, - 'dataType': 'text', - cache: !!cache, - success: function(str) { - loadSvgString(str, cb); - }, - error: function(xhr, stat, err) { - if(xhr.status != 404 && xhr.responseText) { - loadSvgString(xhr.responseText, cb); - } else { - $.alert(uiStrings.notification.URLloadFail + ": \n"+err+'', cb); - } - } - }); - }); - }; - - Editor.loadFromDataURI = function(str) { - Editor.ready(function() { - var pre = 'data:image/svg+xml;base64,'; - var src = str.substring(pre.length); - loadSvgString(svgedit.utilities.decode64(src)); - }); - }; - - Editor.addExtension = function() { - var args = arguments; - - // Note that we don't want this on Editor.ready since some extensions - // may want to run before then (like server_opensave). - $(function() { - if(svgCanvas) svgCanvas.addExtension.apply(this, args); - }); - }; - - return Editor; - }(jQuery); - - // Run init once DOM is loaded - $(svgEditor.init); - -})(); - -// ?iconsize=s&bkgd_color=555 - -// svgEditor.setConfig({ -// // imgPath: 'foo', -// dimensions: [800, 600], -// canvas_expansion: 5, -// initStroke: { -// color: '0000FF', -// width: 3.5, -// opacity: .5 -// }, -// initFill: { -// color: '550000', -// opacity: .75 -// }, -// extensions: ['ext-helloworld.js'] -// }) diff --git a/build/firefox/content/editor/svg-editor.manifest b/build/firefox/content/editor/svg-editor.manifest deleted file mode 100644 index b156374..0000000 --- a/build/firefox/content/editor/svg-editor.manifest +++ /dev/null @@ -1,121 +0,0 @@ -CACHE MANIFEST -svg-editor.html -images/logo.png -jgraduate/css/jPicker-1.0.9.css -jgraduate/css/jGraduate-0.2.0.css -svg-editor.css -spinbtn/JQuerySpinBtn.css -jquery.js -js-hotkeys/jquery.hotkeys.min.js -jquery-ui/jquery-ui-1.7.2.custom.min.js -jgraduate/jpicker-1.0.9.min.js -jgraduate/jquery.jgraduate.js -spinbtn/JQuerySpinBtn.js -svgcanvas.js -svg-editor.js -images/align-bottom.png -images/align-center.png -images/align-left.png -images/align-middle.png -images/align-right.png -images/align-top.png -images/bold.png -images/cancel.png -images/circle.png -images/clear.png -images/clone.png -images/copy.png -images/cut.png -images/delete.png -images/document-properties.png -images/dropdown.gif -images/ellipse.png -images/eye.png -images/flyouth.png -images/flyup.gif -images/freehand-circle.png -images/freehand-square.png -images/go-down.png -images/go-up.png -images/image.png -images/italic.png -images/line.png -images/logo.png -images/logo.svg -images/move_bottom.png -images/move_top.png -images/none.png -images/open.png -images/paste.png -images/path.png -images/polygon.png -images/rect.png -images/redo.png -images/save.png -images/select.png -images/sep.png -images/shape_group.png -images/shape_ungroup.png -images/source.png -images/square.png -images/text.png -images/undo.png -images/view-refresh.png -images/wave.png -images/zoom.png -locale/locale.js -locale/lang.af.js -locale/lang.ar.js -locale/lang.az.js -locale/lang.be.js -locale/lang.bg.js -locale/lang.ca.js -locale/lang.cs.js -locale/lang.cy.js -locale/lang.da.js -locale/lang.de.js -locale/lang.el.js -locale/lang.en.js -locale/lang.es.js -locale/lang.et.js -locale/lang.fa.js -locale/lang.fi.js -locale/lang.fr.js -locale/lang.ga.js -locale/lang.gl.js -locale/lang.hi.js -locale/lang.hr.js -locale/lang.hu.js -locale/lang.hy.js -locale/lang.id.js -locale/lang.is.js -locale/lang.it.js -locale/lang.iw.js -locale/lang.ja.js -locale/lang.ko.js -locale/lang.lt.js -locale/lang.lv.js -locale/lang.mk.js -locale/lang.ms.js -locale/lang.mt.js -locale/lang.nl.js -locale/lang.no.js -locale/lang.pl.js -locale/lang.pt-PT.js -locale/lang.ro.js -locale/lang.ru.js -locale/lang.sk.js -locale/lang.sl.js -locale/lang.sq.js -locale/lang.sr.js -locale/lang.sv.js -locale/lang.sw.js -locale/lang.th.js -locale/lang.tl.js -locale/lang.tr.js -locale/lang.uk.js -locale/lang.vi.js -locale/lang.yi.js -locale/lang.zh-CN.js -locale/lang.zh-TW.js -locale/lang.zh.js diff --git a/build/firefox/content/editor/svgcanvas.js b/build/firefox/content/editor/svgcanvas.js deleted file mode 100644 index ab1305a..0000000 --- a/build/firefox/content/editor/svgcanvas.js +++ /dev/null @@ -1,8819 +0,0 @@ -/* - * svgcanvas.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js -// 4) math.js -// 5) units.js -// 6) svgutils.js -// 7) sanitize.js -// 8) history.js -// 9) select.js -// 10) draw.js -// 11) path.js - -/*jslint browser: true*/ - -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(window.opera) { - window.console.log = function(str) { opera.postError(str); }; - window.console.dir = function(str) {}; -} - -(function() { - - // This fixes $(...).attr() to work as expected with SVG elements. - // Does not currently use *AttributeNS() since we rarely need that. - - // See http://api.jquery.com/attr/ for basic documentation of .attr() - - // Additional functionality: - // - When getting attributes, a string that's a number is return as type number. - // - If an array is supplied as first parameter, multiple values are returned - // as an object with values for each given attributes - - var proxied = jQuery.fn.attr, svgns = "http://www.w3.org/2000/svg"; - jQuery.fn.attr = function(key, value) { - var len = this.length; - if(!len) return proxied.apply(this, arguments); - for(var i=0; i<len; i++) { - var elem = this[i]; - // set/get SVG attribute - if(elem.namespaceURI === svgns) { - // Setting attribute - if(value !== undefined) { - elem.setAttribute(key, value); - } else if($.isArray(key)) { - // Getting attributes from array - var j = key.length, obj = {}; - - while(j--) { - var aname = key[j]; - var attr = elem.getAttribute(aname); - // This returns a number when appropriate - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - obj[aname] = attr; - } - return obj; - - } else if(typeof key === "object") { - // Setting attributes form object - for(var v in key) { - elem.setAttribute(v, key[v]); - } - // Getting attribute - } else { - var attr = elem.getAttribute(key); - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - - return attr; - } - } else { - return proxied.apply(this, arguments); - } - } - return this; - }; - -}()); - -// Class: SvgCanvas -// The main SvgCanvas class that manages all SVG-related functions -// -// Parameters: -// container - The container HTML element that should hold the SVG root element -// config - An object that contains configuration data -$.SvgCanvas = function(container, config) -{ -// Namespace constants -var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - xmlns = "http://www.w3.org/XML/1998/namespace", - xmlnsns = "http://www.w3.org/2000/xmlns/", // see http://www.w3.org/TR/REC-xml-names/#xmlReserved - se_ns = "http://svg-edit.googlecode.com", - htmlns = "http://www.w3.org/1999/xhtml", - mathns = "http://www.w3.org/1998/Math/MathML"; - -// Default configuration options -var curConfig = { - show_outside_canvas: true, - selectNew: true, - dimensions: [640, 480] -}; - -// Update config with new one if given -if(config) { - $.extend(curConfig, config); -} - -// Array with width/height of canvas -var dimensions = curConfig.dimensions; - -var canvas = this; - -// "document" element associated with the container (same as window.document using default svg-editor.js) -// NOTE: This is not actually a SVG document, but a HTML document. -var svgdoc = container.ownerDocument; - -// This is a container for the document being edited, not the document itself. -var svgroot = svgdoc.importNode(svgedit.utilities.text2xml( - '<svg id="svgroot" xmlns="' + svgns + '" xlinkns="' + xlinkns + '" ' + - 'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' + - '<defs>' + - '<filter id="canvashadow" filterUnits="objectBoundingBox">' + - '<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>'+ - '<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>'+ - '<feMerge>'+ - '<feMergeNode in="offsetBlur"/>'+ - '<feMergeNode in="SourceGraphic"/>'+ - '</feMerge>'+ - '</filter>'+ - '</defs>'+ - '</svg>').documentElement, true); -container.appendChild(svgroot); - -// The actual element that represents the final output SVG element -var svgcontent = svgdoc.createElementNS(svgns, "svg"); - -// This function resets the svgcontent element while keeping it in the DOM. -var clearSvgContentElement = canvas.clearSvgContentElement = function() { - while (svgcontent.firstChild) { svgcontent.removeChild(svgcontent.firstChild); } - - // TODO: Clear out all other attributes first? - $(svgcontent).attr({ - id: 'svgcontent', - width: dimensions[0], - height: dimensions[1], - x: dimensions[0], - y: dimensions[1], - overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden', - xmlns: svgns, - "xmlns:se": se_ns, - "xmlns:xlink": xlinkns - }).appendTo(svgroot); - - // TODO: make this string optional and set by the client - var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ "); - svgcontent.appendChild(comment); -}; -clearSvgContentElement(); - -// Prefix string for element IDs -var idprefix = "svg_"; - -// Function: setIdPrefix -// Changes the ID prefix to the given value -// -// Parameters: -// p - String with the new prefix -canvas.setIdPrefix = function(p) { - idprefix = p; -}; - -// Current svgedit.draw.Drawing object -// @type {svgedit.draw.Drawing} -canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - -// Function: getCurrentDrawing -// Returns the current Drawing. -// @return {svgedit.draw.Drawing} -var getCurrentDrawing = canvas.getCurrentDrawing = function() { - return canvas.current_drawing_; -}; - -// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc) -var current_zoom = 1; - -// pointer to current group (for in-group editing) -var current_group = null; - -// Object containing data for the currently selected styles -var all_properties = { - shape: { - fill: (curConfig.initFill.color == 'none' ? '' : '#') + curConfig.initFill.color, - fill_paint: null, - fill_opacity: curConfig.initFill.opacity, - stroke: "#" + curConfig.initStroke.color, - stroke_paint: null, - stroke_opacity: curConfig.initStroke.opacity, - stroke_width: curConfig.initStroke.width, - stroke_dasharray: 'none', - stroke_linejoin: 'miter', - stroke_linecap: 'butt', - opacity: curConfig.initOpacity - } -}; - -all_properties.text = $.extend(true, {}, all_properties.shape); -$.extend(all_properties.text, { - fill: "#000000", - stroke_width: 0, - font_size: 24, - font_family: 'Junction' -}); - -// Current shape style properties -var cur_shape = all_properties.shape; - -// Array with all the currently selected elements -// default size of 1 until it needs to grow bigger -var selectedElements = new Array(1); - -// Function: addSvgElementFromJson -// Create a new SVG element based on the given object keys/values and add it to the current layer -// The element will be ran through cleanupElement before being returned -// -// Parameters: -// data - Object with the following keys/values: -// * element - tag name of the SVG element to create -// * attr - Object with attributes key-values to assign to the new element -// * curStyles - Boolean indicating that current style attributes should be applied first -// -// Returns: The new element -var addSvgElementFromJson = this.addSvgElementFromJson = function(data) { - var shape = svgedit.utilities.getElem(data.attr.id); - // if shape is a path but we need to create a rect/ellipse, then remove the path - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (shape && data.element != shape.tagName) { - current_layer.removeChild(shape); - shape = null; - } - if (!shape) { - shape = svgdoc.createElementNS(svgns, data.element); - if (current_layer) { - (current_group || current_layer).appendChild(shape); - } - } - if(data.curStyles) { - svgedit.utilities.assignAttributes(shape, { - "fill": cur_shape.fill, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - }, 100); - } - svgedit.utilities.assignAttributes(shape, data.attr, 100); - svgedit.utilities.cleanupElement(shape); - return shape; -}; - - -// import svgtransformlist.js -var getTransformList = canvas.getTransformList = svgedit.transformlist.getTransformList; - -// import from math.js. -var transformPoint = svgedit.math.transformPoint; -var matrixMultiply = canvas.matrixMultiply = svgedit.math.matrixMultiply; -var hasMatrixTransform = canvas.hasMatrixTransform = svgedit.math.hasMatrixTransform; -var transformListToTransform = canvas.transformListToTransform = svgedit.math.transformListToTransform; -var snapToAngle = svgedit.math.snapToAngle; -var getMatrix = svgedit.math.getMatrix; - -// initialize from units.js -// send in an object implementing the ElementContainer interface (see units.js) -svgedit.units.init({ - getBaseUnit: function() { return curConfig.baseUnit; }, - getElement: svgedit.utilities.getElem, - getHeight: function() { return svgcontent.getAttribute("height")/current_zoom; }, - getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; }, - getRoundDigits: function() { return save_options.round_digits; } -}); -// import from units.js -var convertToNum = canvas.convertToNum = svgedit.units.convertToNum; - -// import from svgutils.js -svgedit.utilities.init({ - getDOMDocument: function() { return svgdoc; }, - getDOMContainer: function() { return container; }, - getSVGRoot: function() { return svgroot; }, - // TODO: replace this mostly with a way to get the current drawing. - getSelectedElements: function() { return selectedElements; }, - getSVGContent: function() { return svgcontent; } -}); -var getUrlFromAttr = canvas.getUrlFromAttr = svgedit.utilities.getUrlFromAttr; -var getHref = canvas.getHref = svgedit.utilities.getHref; -var setHref = canvas.setHref = svgedit.utilities.setHref; -var getPathBBox = svgedit.utilities.getPathBBox; -var getBBox = canvas.getBBox = svgedit.utilities.getBBox; -var getRotationAngle = canvas.getRotationAngle = svgedit.utilities.getRotationAngle; -var getElem = canvas.getElem = svgedit.utilities.getElem; -var assignAttributes = canvas.assignAttributes = svgedit.utilities.assignAttributes; -var cleanupElement = this.cleanupElement = svgedit.utilities.cleanupElement; - -// import from sanitize.js -var nsMap = svgedit.sanitize.getNSMap(); -var sanitizeSvg = canvas.sanitizeSvg = svgedit.sanitize.sanitizeSvg; - -// import from history.js -var MoveElementCommand = svgedit.history.MoveElementCommand; -var InsertElementCommand = svgedit.history.InsertElementCommand; -var RemoveElementCommand = svgedit.history.RemoveElementCommand; -var ChangeElementCommand = svgedit.history.ChangeElementCommand; -var BatchCommand = svgedit.history.BatchCommand; -// Implement the svgedit.history.HistoryEventHandler interface. -canvas.undoMgr = new svgedit.history.UndoManager({ - handleHistoryEvent: function(eventType, cmd) { - var EventTypes = svgedit.history.HistoryEventTypes; - // TODO: handle setBlurOffsets. - if (eventType == EventTypes.BEFORE_UNAPPLY || eventType == EventTypes.BEFORE_APPLY) { - canvas.clearSelection(); - } else if (eventType == EventTypes.AFTER_APPLY || eventType == EventTypes.AFTER_UNAPPLY) { - var elems = cmd.elements(); - canvas.pathActions.clear(); - call("changed", elems); - - var cmdType = cmd.type(); - var isApply = (eventType == EventTypes.AFTER_APPLY); - if (cmdType == MoveElementCommand.type()) { - var parent = isApply ? cmd.newParent : cmd.oldParent; - if (parent == svgcontent) { - canvas.identifyLayers(); - } - } else if (cmdType == InsertElementCommand.type() || - cmdType == RemoveElementCommand.type()) { - if (cmd.parent == svgcontent) { - canvas.identifyLayers(); - } - if (cmdType == InsertElementCommand.type()) { - if (isApply) restoreRefElems(cmd.elem); - } else { - if (!isApply) restoreRefElems(cmd.elem); - } - - if(cmd.elem.tagName === 'use') { - setUseData(cmd.elem); - } - } else if (cmdType == ChangeElementCommand.type()) { - // if we are changing layer names, re-identify all layers - if (cmd.elem.tagName == "title" && cmd.elem.parentNode.parentNode == svgcontent) { - canvas.identifyLayers(); - } - var values = isApply ? cmd.newValues : cmd.oldValues; - // If stdDeviation was changed, update the blur. - if (values["stdDeviation"]) { - canvas.setBlurOffsets(cmd.elem.parentNode, values["stdDeviation"]); - } - - // Remove & Re-add hack for Webkit (issue 775) - if(cmd.elem.tagName === 'use' && svgedit.browser.isWebkit()) { - var elem = cmd.elem; - if(!elem.getAttribute('x') && !elem.getAttribute('y')) { - var parent = elem.parentNode; - var sib = elem.nextSibling; - parent.removeChild(elem); - parent.insertBefore(elem, sib); - } - } - } - } - } -}); -var addCommandToHistory = function(cmd) { - canvas.undoMgr.addCommandToHistory(cmd); -}; - -// import from select.js -svgedit.select.init(curConfig, { - createSVGElement: function(jsonMap) { return canvas.addSvgElementFromJson(jsonMap); }, - svgRoot: function() { return svgroot; }, - svgContent: function() { return svgcontent; }, - currentZoom: function() { return current_zoom; }, - // TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js. - getStrokedBBox: function(elems) { return canvas.getStrokedBBox([elems]); } -}); -// this object manages selectors for us -var selectorManager = this.selectorManager = svgedit.select.getSelectorManager(); - -// Import from path.js -svgedit.path.init({ - getCurrentZoom: function() { return current_zoom; }, - getSVGRoot: function() { return svgroot; } -}); - -// Function: snapToGrid -// round value to for snapping -// NOTE: This function did not move to svgutils.js since it depends on curConfig. -svgedit.utilities.snapToGrid = function(value){ - var stepSize = curConfig.snappingStep; - var unit = curConfig.baseUnit; - if(unit !== "px") { - stepSize *= svgedit.units.getTypeMap()[unit]; - } - value = Math.round(value/stepSize)*stepSize; - return value; -}; -var snapToGrid = svgedit.utilities.snapToGrid; - -// Interface strings, usually for title elements -var uiStrings = { - "exportNoBlur": "Blurred elements will appear as un-blurred", - "exportNoforeignObject": "foreignObject elements will not appear", - "exportNoDashArray": "Strokes will appear filled", - "exportNoText": "Text may not appear as expected" -}; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var ref_attrs = ["clip-path", "fill", "filter", "marker-end", "marker-mid", "marker-start", "mask", "stroke"]; - -var elData = $.data; - -// Animation element to change the opacity of any newly created element -var opac_ani = false; //document.createElementNS(svgns, 'animate'); -//$(opac_ani).attr({ -// attributeName: 'opacity', -// begin: 'indefinite', -// dur: 0, -// fill: 'freeze' -//}).appendTo(svgroot); - -var restoreRefElems = function(elem) { - // Look for missing reference elements, restore any found - var attrs = $(elem).attr(ref_attrs); - for(var o in attrs) { - var val = attrs[o]; - if (val && val.indexOf('url(') === 0) { - var id = getUrlFromAttr(val).substr(1); - var ref = getElem(id); - if(!ref) { - findDefs().appendChild(removedElements[id]); - delete removedElements[id]; - } - } - } - - var childs = elem.getElementsByTagName('*'); - - if(childs.length) { - for(var i = 0, l = childs.length; i < l; i++) { - restoreRefElems(childs[i]); - } - } -}; - -(function() { - // TODO For Issue 208: this is a start on a thumbnail - // var svgthumb = svgdoc.createElementNS(svgns, "use"); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // svgedit.utilities.setHref(svgthumb, '#svgcontent'); - // svgroot.appendChild(svgthumb); - -})(); - -// Object to contain image data for raster images that were found encodable -var encodableImages = {}, - - // String with image URL of last loadable image - last_good_img_url = curConfig.imgPath + 'logo.png', - - // Array with current disabled elements (for in-group editing) - disabled_elems = [], - - // Object with save options - save_options = {round_digits: 5}, - - // Boolean indicating whether or not a draw action has been started - started = false, - - // String with an element's initial transform attribute value - start_transform = null, - - // String indicating the current editor mode - current_mode = "select", - - // String with the current direction in which an element is being resized - current_resize_mode = "none", - - // Object with IDs for imported files, to see if one was already added - import_ids = {}; - -// Current text style properties -var cur_text = all_properties.text, - - // Current general properties - cur_properties = cur_shape, - - // Array with selected elements' Bounding box object -// selectedBBoxes = new Array(1), - - // The DOM element that was just selected - justSelected = null, - - // DOM element for selection rectangle drawn by the user - rubberBox = null, - - // Array of current BBoxes (still needed?) - curBBoxes = [], - - // Object to contain all included extensions - extensions = {}, - - // Canvas point for the most recent right click - lastClickPoint = null, - - // Map of deleted reference elements - removedElements = {} - -// Clipboard for cut, copy&pasted elements -canvas.clipBoard = []; - -// Should this return an array by default, so extension results aren't overwritten? -var runExtensions = this.runExtensions = function(action, vars, returnArray) { - var result = false; - if(returnArray) result = []; - $.each(extensions, function(name, opts) { - if(action in opts) { - if(returnArray) { - result.push(opts[action](vars)) - } else { - result = opts[action](vars); - } - } - }); - return result; -} - -// Function: addExtension -// Add an extension to the editor -// -// Parameters: -// name - String with the ID of the extension -// ext_func - Function supplied by the extension with its data -this.addExtension = function(name, ext_func) { - if(!(name in extensions)) { - // Provide private vars/funcs here. Is there a better way to do this? - - if($.isFunction(ext_func)) { - var ext = ext_func($.extend(canvas.getPrivateMethods(), { - svgroot: svgroot, - svgcontent: svgcontent, - nonce: getCurrentDrawing().getNonce(), - selectorManager: selectorManager - })); - } else { - var ext = ext_func; - } - extensions[name] = ext; - call("extension_added", ext); - } else { - console.log('Cannot add extension "' + name + '", an extension by that name already exists"'); - } -}; - -// This method rounds the incoming value to the nearest value based on the current_zoom -var round = this.round = function(val) { - return parseInt(val*current_zoom)/current_zoom; -}; - -// This method sends back an array or a NodeList full of elements that -// intersect the multi-select rubber-band-box on the current_layer only. -// -// Since the only browser that supports the SVG DOM getIntersectionList is Opera, -// we need to provide an implementation here. We brute-force it for now. -// -// Reference: -// Firefox does not implement getIntersectionList(), see https://bugzilla.mozilla.org/show_bug.cgi?id=501421 -// Webkit does not implement getIntersectionList(), see https://bugs.webkit.org/show_bug.cgi?id=11274 -var getIntersectionList = this.getIntersectionList = function(rect) { - if (rubberBox == null) { return null; } - - var parent = current_group || getCurrentDrawing().getCurrentLayer(); - - if(!curBBoxes.length) { - // Cache all bboxes - curBBoxes = getVisibleElementsAndBBoxes(parent); - } - - var resultList = null; - try { - resultList = parent.getIntersectionList(rect, null); - } catch(e) { } - - if (resultList == null || typeof(resultList.item) != "function") { - resultList = []; - - if(!rect) { - var rubberBBox = rubberBox.getBBox(); - var bb = {}; - - for(var o in rubberBBox) { - bb[o] = rubberBBox[o] / current_zoom; - } - rubberBBox = bb; - - } else { - var rubberBBox = rect; - } - var i = curBBoxes.length; - while (i--) { - if(!rubberBBox.width || !rubberBBox.width) continue; - if (svgedit.math.rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); - } - } - } - // addToSelection expects an array, but it's ok to pass a NodeList - // because using square-bracket notation is allowed: - // http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html - return resultList; -}; - -// TODO(codedread): Migrate this into svgutils.js -// Function: getStrokedBBox -// Get the bounding box for one or more stroked and/or transformed elements -// -// Parameters: -// elems - Array with DOM elements to check -// -// Returns: -// A single bounding box object -getStrokedBBox = this.getStrokedBBox = function(elems) { - if(!elems) elems = getVisibleElements(); - if(!elems.length) return false; - // Make sure the expected BBox is returned if the element is a group - 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 - // in Issue 339 comment #2). - - var bb = svgedit.utilities.getBBox(elem); - - var angle = svgedit.utilities.getRotationAngle(elem); - if ((angle && angle % 90) || - svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(elem))) { - // Accurate way to get BBox of rotated element in Firefox: - // Put element in group and get its BBox - - var good_bb = false; - - // Get the BBox from the raw path for these elements - var elemNames = ['ellipse','path','line','polyline','polygon']; - if(elemNames.indexOf(elem.tagName) >= 0) { - bb = good_bb = canvas.convertToPath(elem, true); - } else if(elem.tagName == 'rect') { - // Look for radius - var rx = elem.getAttribute('rx'); - var ry = elem.getAttribute('ry'); - if(rx || ry) { - bb = good_bb = canvas.convertToPath(elem, true); - } - } - - if(!good_bb) { - // Must use clone else FF freaks out - var clone = elem.cloneNode(true); - var g = document.createElementNS(svgns, "g"); - var parent = elem.parentNode; - parent.appendChild(g); - g.appendChild(clone); - bb = svgedit.utilities.bboxToObj(g.getBBox()); - parent.removeChild(g); - } - - - // Old method: Works by giving the rotated BBox, - // this is (unfortunately) what Opera and Safari do - // natively when getting the BBox of the parent group -// var angle = angle * Math.PI / 180.0; -// var rminx = Number.MAX_VALUE, rminy = Number.MAX_VALUE, -// rmaxx = Number.MIN_VALUE, rmaxy = Number.MIN_VALUE; -// var cx = round(bb.x + bb.width/2), -// cy = round(bb.y + bb.height/2); -// var pts = [ [bb.x - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y + bb.height - cy], -// [bb.x - cx, bb.y + bb.height - cy] ]; -// var j = 4; -// while (j--) { -// var x = pts[j][0], -// y = pts[j][1], -// r = Math.sqrt( x*x + y*y ); -// var theta = Math.atan2(y,x) + angle; -// x = round(r * Math.cos(theta) + cx); -// y = round(r * Math.sin(theta) + cy); -// -// // now set the bbox for the shape after it's been rotated -// if (x < rminx) rminx = x; -// if (y < rminy) rminy = y; -// if (x > rmaxx) rmaxx = x; -// if (y > rmaxy) rmaxy = y; -// } -// -// bb.x = rminx; -// bb.y = rminy; -// bb.width = rmaxx - rminx; -// bb.height = rmaxy - rminy; - } - return bb; - } catch(e) { - console.log(elem, e); - return null; - } - }; - - var full_bb; - $.each(elems, function() { - if(full_bb) return; - if(!this.parentNode) return; - full_bb = getCheckedBBox(this); - }); - - // This shouldn't ever happen... - if(full_bb == null) return null; - - // full_bb doesn't include the stoke, so this does no good! -// if(elems.length == 1) return full_bb; - - var max_x = full_bb.x + full_bb.width; - var max_y = full_bb.y + full_bb.height; - var min_x = full_bb.x; - var min_y = full_bb.y; - - // FIXME: same re-creation problem with this function as getCheckedBBox() above - var getOffset = function(elem) { - var sw = elem.getAttribute("stroke-width"); - var offset = 0; - if (elem.getAttribute("stroke") != "none" && !isNaN(sw)) { - offset += sw/2; - } - return offset; - } - var bboxes = []; - $.each(elems, function(i, elem) { - var cur_bb = getCheckedBBox(elem); - if(cur_bb) { - var offset = getOffset(elem); - min_x = Math.min(min_x, cur_bb.x - offset); - min_y = Math.min(min_y, cur_bb.y - offset); - bboxes.push(cur_bb); - } - }); - - full_bb.x = min_x; - full_bb.y = min_y; - - $.each(elems, function(i, elem) { - var cur_bb = bboxes[i]; - // ensure that elem is really an element node - if (cur_bb && elem.nodeType == 1) { - var offset = getOffset(elem); - max_x = Math.max(max_x, cur_bb.x + cur_bb.width + offset); - max_y = Math.max(max_y, cur_bb.y + cur_bb.height + offset); - } - }); - - full_bb.width = max_x - min_x; - full_bb.height = max_y - min_y; - return full_bb; -} - -// Function: getVisibleElements -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with all "visible" elements. -var getVisibleElements = this.getVisibleElements = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push(elem); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: getVisibleElementsAndBBoxes -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with objects that include: -// * elem - The element -// * bbox - The element's BBox as retrieved from getStrokedBBox -var getVisibleElementsAndBBoxes = this.getVisibleElementsAndBBoxes = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push({'elem':elem, 'bbox':getStrokedBBox([elem])}); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: groupSvgElem -// Wrap an SVG element into a group element, mark the group as 'gsvg' -// -// Parameters: -// elem - SVG element to wrap -var groupSvgElem = this.groupSvgElem = function(elem) { - var g = document.createElementNS(svgns, "g"); - elem.parentNode.replaceChild(g, elem); - $(g).append(elem).data('gsvg', elem)[0].id = getNextId(); -} - -// Function: copyElem -// Create a clone of an element, updating its ID and its children's IDs when needed -// -// Parameters: -// el - DOM element to clone -// -// Returns: The cloned element -var copyElem = function(el) { - var new_el = document.createElementNS(el.namespaceURI, el.nodeName); - // set the copied element's new id - new_el.removeAttribute("id"); - // manually create a copy of the element - $.each(el.attributes, function(i, attr) { - if (attr.localName != '-moz-math-font-style') { - new_el.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.nodeValue); - } - }); - - // Opera's "d" value needs to be reset for Opera/Win/non-EN - // Also needed for webkit (else does not keep curved segments on clone) - if(svgedit.browser.isWebkit() && el.nodeName == 'path') { - var fixed_d = pathActions.convertPath(el); - new_el.setAttribute('d', fixed_d); - } - - // now create copies of all children - $.each(el.childNodes, function(i, child) { - switch(child.nodeType) { - case 1: // element node - new_el.appendChild(copyElem(child)); - break; - case 3: // text node - new_el.textContent = child.nodeValue; - break; - default: - break; - } - }); - - if($(el).data('gsvg')) { - $(new_el).data('gsvg', new_el.firstChild); - } 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); - } - new_el.id = getNextId(); - console.log(new_el); - return new_el; -}; - -// Set scope for these functions -var getId, getNextId, call; - -(function(c) { - - // Object to contain editor event names and callback functions - var events = {}; - - getId = c.getId = function() { return getCurrentDrawing().getId(); }; - getNextId = c.getNextId = function() { return getCurrentDrawing().getNextId(); }; - - // Function: call - // Run the callback function associated with the given event - // - // Parameters: - // event - String with the event name - // arg - Argument to pass through to the callback function - call = c.call = function(event, arg) { - if (events[event]) { - return events[event](this, arg); - } - }; - - // Function: bind - // Attaches a callback function to an event - // - // Parameters: - // event - String indicating the name of the event - // f - The callback function to bind to the event - // - // Return: - // The previous event - c.bind = function(event, f) { - var old = events[event]; - events[event] = f; - return old; - }; - -}(canvas)); - -// Function: canvas.prepareSvg -// Runs the SVG Document through the sanitizer and then updates its paths. -// -// Parameters: -// newDoc - The SVG DOM document -this.prepareSvg = function(newDoc) { - this.sanitizeSvg(newDoc.documentElement); - - // convert paths into absolute commands - var paths = newDoc.getElementsByTagNameNS(svgns, "path"); - for (var i = 0, len = paths.length; i < len; ++i) { - var path = paths[i]; - path.setAttribute('d', pathActions.convertPath(path)); - pathActions.fixEnd(path); - } -}; - -// Function getRefElem -// Get the reference element associated with the given attribute value -// -// Parameters: -// attrVal - The attribute value as a string -var getRefElem = this.getRefElem = function(attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); -} - -// Function: ffClone -// Hack for Firefox bugs where text element features aren't updated or get -// messed up. See issue 136 and issue 137. -// This function clones the element and re-selects it -// TODO: Test for this bug on load and add it to "support" object instead of -// browser sniffing -// -// Parameters: -// elem - The (text) DOM element to clone -var ffClone = function(elem) { - if(!svgedit.browser.isGecko()) return elem; - var clone = elem.cloneNode(true) - elem.parentNode.insertBefore(clone, elem); - elem.parentNode.removeChild(elem); - selectorManager.releaseSelector(elem); - selectedElements[0] = clone; - selectorManager.requestSelector(clone).showGrips(true); - return clone; -} - - -// this.each is deprecated, if any extension used this it can be recreated by doing this: -// $(canvas.getRootElem()).children().each(...) - -// this.each = function(cb) { -// $(svgroot).children().each(cb); -// }; - - -// Function: setRotationAngle -// Removes any old rotations if present, prepends a new rotation at the -// transformed center -// -// Parameters: -// val - The new rotation angle in degrees -// preventUndo - Boolean indicating whether the action should be undoable or not -this.setRotationAngle = function(val, preventUndo) { - // ensure val is the proper type - val = parseFloat(val); - var elem = selectedElements[0]; - var oldTransform = elem.getAttribute("transform"); - var bbox = svgedit.utilities.getBBox(elem); - var cx = bbox.x+bbox.width/2, cy = bbox.y+bbox.height/2; - var tlist = getTransformList(elem); - - // only remove the real rotational transform if present (i.e. at index=0) - if (tlist.numberOfItems > 0) { - var xform = tlist.getItem(0); - if (xform.type == 4) { - tlist.removeItem(0); - } - } - // find R_nc and insert it - if (val != 0) { - var center = transformPoint(cx,cy,transformListToTransform(tlist).matrix); - var R_nc = svgroot.createSVGTransform(); - R_nc.setRotate(val, center.x, center.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(R_nc, 0); - } else { - tlist.appendItem(R_nc); - } - } - else if (tlist.numberOfItems == 0) { - elem.removeAttribute("transform"); - } - - if (!preventUndo) { - // we need to undo it, then redo it so it can be undo-able! :) - // TODO: figure out how to make changes to transform list undo-able cross-browser? - var newTransform = elem.getAttribute("transform"); - elem.setAttribute("transform", oldTransform); - changeSelectedAttribute("transform",newTransform,selectedElements); - call("changed", selectedElements); - } - var pointGripContainer = getElem("pathpointgrip_container"); -// if(elem.nodeName == "path" && pointGripContainer) { -// pathActions.setPointContainerTransform(elem.getAttribute("transform")); -// } - var selector = selectorManager.requestSelector(selectedElements[0]); - selector.resize(); - selector.updateGripCursors(val); -}; - -// Function: recalculateAllSelectedDimensions -// Runs recalculateDimensions on the selected elements, -// adding the changes to a single batch command -var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function() { - var text = (current_resize_mode == "none" ? "position" : "size"); - var batchCmd = new BatchCommand(text); - - var i = selectedElements.length; - while(i--) { - var elem = selectedElements[i]; -// if(getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) continue; - var cmd = recalculateDimensions(elem); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - } - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - call("changed", selectedElements); - } -}; - -// this is how we map paths to our preferred relative segment types -var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', - 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; - -// Debug tool to easily see the current matrix in the browser's console -var logMatrix = function(m) { - console.log([m.a,m.b,m.c,m.d,m.e,m.f]); -}; - -// Function: remapElement -// Applies coordinate changes to an element based on the given matrix -// -// Parameters: -// selected - DOM element to be changed -// changes - Object with changes to be remapped -// m - Matrix object to use for remapping coordinates -var remapElement = this.remapElement = function(selected,changes,m) { - - var remap = function(x,y) { return transformPoint(x,y,m); }, - scalew = function(w) { return m.a*w; }, - scaleh = function(h) { return m.d*h; }, - doSnapping = curConfig.gridSnapping && selected.parentNode.parentNode.localName === "svg", - finishUp = function() { - if(doSnapping) for(var o in changes) changes[o] = snapToGrid(changes[o]); - assignAttributes(selected, changes, 1000, true); - } - box = svgedit.utilities.getBBox(selected); - - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = selected.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - if(m.a < 0 || m.d < 0) { - var grad = getRefElem(attrVal); - var newgrad = grad.cloneNode(true); - - if(m.a < 0) { - //flip x - var x1 = newgrad.getAttribute('x1'); - var x2 = newgrad.getAttribute('x2'); - newgrad.setAttribute('x1', -(x1 - 1)); - newgrad.setAttribute('x2', -(x2 - 1)); - } - - if(m.d < 0) { - //flip y - var y1 = newgrad.getAttribute('y1'); - var y2 = newgrad.getAttribute('y2'); - newgrad.setAttribute('y1', -(y1 - 1)); - newgrad.setAttribute('y2', -(y2 - 1)); - } - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - selected.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - - // Not really working :( -// if(selected.tagName === 'path') { -// reorientGrads(selected, m); -// } - } - } - - - var elName = selected.tagName; - if(elName === "g" || elName === "text" || elName === "use") { - // if it was a translate, then just update x,y - if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && - (m.e != 0 || m.f != 0) ) - { - // [T][M] = [M][T'] - // therefore [T'] = [M_inv][T][M] - var existing = transformListToTransform(selected).matrix, - t_new = matrixMultiply(existing.inverse(), m, existing); - changes.x = parseFloat(changes.x) + t_new.e; - changes.y = parseFloat(changes.y) + t_new.f; - } - else { - // we just absorb all matrices into the element and don't do any remapping - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } - } - - // now we have a set of changes and an applied reduced transform list - // we apply the changes directly to the DOM - switch (elName) - { - case "foreignObject": - case "rect": - case "image": - - // Allow images to be inverted (give them matrix when flipped) - if(elName === 'image' && (m.a < 0 || m.d < 0)) { - // Convert to matrix - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } else { - var pt1 = remap(changes.x,changes.y); - - changes.width = scalew(changes.width); - changes.height = scaleh(changes.height); - - changes.x = pt1.x + Math.min(0,changes.width); - changes.y = pt1.y + Math.min(0,changes.height); - changes.width = Math.abs(changes.width); - changes.height = Math.abs(changes.height); - } - finishUp(); - break; - case "ellipse": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - changes.rx = scalew(changes.rx); - changes.ry = scaleh(changes.ry); - - changes.rx = Math.abs(changes.rx); - changes.ry = Math.abs(changes.ry); - finishUp(); - break; - case "circle": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - // take the minimum of the new selected box's dimensions for the new circle radius - var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m); - var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y; - changes.r = Math.min(w/2, h/2); - - if(changes.r) changes.r = Math.abs(changes.r); - finishUp(); - break; - case "line": - var pt1 = remap(changes.x1,changes.y1), - pt2 = remap(changes.x2,changes.y2); - changes.x1 = pt1.x; - changes.y1 = pt1.y; - changes.x2 = pt2.x; - changes.y2 = pt2.y; - - case "text": - var tspan = selected.querySelectorAll('tspan'); - var i = tspan.length - while(i--) { - var selX = convertToNum("x", selected.getAttribute('x')); - var tx = convertToNum("x", tspan[i].getAttribute('x')); - var selY = convertToNum("y", selected.getAttribute('y')); - var ty = convertToNum("y", tspan[i].getAttribute('y')); - var offset = new Object(); - if (!isNaN(selX) && !isNaN(tx) && selX!=0 && tx!=0 && changes.x) - offset.x = changes.x - (selX - tx); - if (!isNaN(selY) && !isNaN(ty) && selY!=0 && ty!=0 && changes.y) - offset.y = changes.y - (selY - ty); - if (offset.x || offset.y) - assignAttributes(tspan[i], offset, 1000, true); - } - finishUp(); - break; - case "use": - finishUp(); - break; - case "g": - var gsvg = $(selected).data('gsvg'); - if(gsvg) { - assignAttributes(gsvg, changes, 1000, true); - } - break; - case "polyline": - case "polygon": - var len = changes.points.length; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pt = remap(pt.x,pt.y); - changes.points[i].x = pt.x; - changes.points[i].y = pt.y; - } - - var len = changes.points.length; - var pstr = ""; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pstr += pt.x + "," + pt.y + " "; - } - selected.setAttribute("points", pstr); - break; - case "path": - - var segList = selected.pathSegList; - var len = segList.numberOfItems; - changes.d = new Array(len); - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - changes.d[i] = { - type: seg.pathSegType, - x: seg.x, - y: seg.y, - x1: seg.x1, - y1: seg.y1, - x2: seg.x2, - y2: seg.y2, - r1: seg.r1, - r2: seg.r2, - angle: seg.angle, - largeArcFlag: seg.largeArcFlag, - sweepFlag: seg.sweepFlag - }; - } - - var len = changes.d.length, - firstseg = changes.d[0], - currentpt = remap(firstseg.x,firstseg.y); - changes.d[0].x = currentpt.x; - changes.d[0].y = currentpt.y; - for (var i = 1; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 - // if relative, we want to scalew, scaleh - if (type % 2 == 0) { // absolute - var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands - thisy = (seg.y != undefined) ? seg.y : currentpt.y, // for H commands - pt = remap(thisx,thisy), - pt1 = remap(seg.x1,seg.y1), - pt2 = remap(seg.x2,seg.y2); - seg.x = pt.x; - seg.y = pt.y; - seg.x1 = pt1.x; - seg.y1 = pt1.y; - seg.x2 = pt2.x; - seg.y2 = pt2.y; - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - else { // relative - seg.x = scalew(seg.x); - seg.y = scaleh(seg.y); - seg.x1 = scalew(seg.x1); - seg.y1 = scaleh(seg.y1); - seg.x2 = scalew(seg.x2); - seg.y2 = scaleh(seg.y2); - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - } // for each segment - - var dstr = ""; - var len = changes.d.length; - for (var i = 0; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - dstr += pathMap[type]; - switch(type) { - case 13: // relative horizontal line (h) - case 12: // absolute horizontal line (H) - dstr += seg.x + " "; - break; - case 15: // relative vertical line (v) - case 14: // absolute vertical line (V) - dstr += seg.y + " "; - break; - case 3: // relative move (m) - case 5: // relative line (l) - case 19: // relative smooth quad (t) - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - dstr += seg.x + "," + seg.y + " "; - break; - case 7: // relative cubic (c) - case 6: // absolute cubic (C) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x2 + "," + seg.y2 + " " + - seg.x + "," + seg.y + " "; - break; - case 9: // relative quad (q) - case 8: // absolute quad (Q) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x + "," + seg.y + " "; - break; - case 11: // relative elliptical arc (a) - case 10: // absolute elliptical arc (A) - dstr += seg.r1 + "," + seg.r2 + " " + seg.angle + " " + (+seg.largeArcFlag) + - " " + (+seg.sweepFlag) + " " + seg.x + "," + seg.y + " "; - break; - case 17: // relative smooth cubic (s) - case 16: // absolute smooth cubic (S) - dstr += seg.x2 + "," + seg.y2 + " " + seg.x + "," + seg.y + " "; - break; - } - } - - selected.setAttribute("d", dstr); - break; - } -}; - -// Function: updateClipPath -// Updates a <clipPath>s values based on the given translation of an element -// -// Parameters: -// attr - The clip-path attribute value with the clipPath's ID -// tx - The translation's x value -// ty - The translation's y value -var updateClipPath = function(attr, tx, ty) { - var path = getRefElem(attr).firstChild; - - var cp_xform = getTransformList(path); - - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx, ty); - - cp_xform.appendItem(newxlate); - - // Update clipPath's dimensions - recalculateDimensions(path); -} - -// Function: recalculateDimensions -// Decides the course of action based on the element's transform list -// -// Parameters: -// selected - The DOM element to recalculate -// -// Returns: -// Undo command object with the resulting change -var recalculateDimensions = this.recalculateDimensions = function(selected) { - if (selected == null) return null; - - var tlist = getTransformList(selected); - - // remove any unnecessary transforms - if (tlist && tlist.numberOfItems > 0) { - var k = tlist.numberOfItems; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 0) { - tlist.removeItem(k); - } - // remove identity matrices - else if (xform.type === 1) { - if (svgedit.math.isIdentity(xform.matrix)) { - tlist.removeItem(k); - } - } - // remove zero-degree rotations - else if (xform.type === 4) { - if (xform.angle === 0) { - tlist.removeItem(k); - } - } - } - // End here if all it has is a rotation - if(tlist.numberOfItems === 1 && getRotationAngle(selected)) return null; - } - - // if this element had no transforms, we are done - if (!tlist || tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - return null; - } - - // TODO: Make this work for more than 2 - if (tlist) { - var k = tlist.numberOfItems; - var mxs = []; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 1) { - mxs.push([xform.matrix, k]); - } else if(mxs.length) { - mxs = []; - } - } - if(mxs.length === 2) { - var m_new = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])); - tlist.removeItem(mxs[0][1]); - tlist.removeItem(mxs[1][1]); - tlist.insertItemBefore(m_new, mxs[1][1]); - } - - // combine matrix + translate - k = tlist.numberOfItems; - if(k >= 2 && tlist.getItem(k-2).type === 1 && tlist.getItem(k-1).type === 2) { - var mt = svgroot.createSVGTransform(); - - var m = matrixMultiply( - tlist.getItem(k-2).matrix, - tlist.getItem(k-1).matrix - ); - mt.setMatrix(m); - tlist.removeItem(k-2); - tlist.removeItem(k-2); - tlist.appendItem(mt); - } - } - - // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). - switch ( selected.tagName ) { - // Ignore these elements, as they can absorb the [M] - case 'line': - case 'polyline': - case 'polygon': - case 'path': - break; - default: - if( - (tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) - || (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4) - ) { - return null; - } - } - - // Grouped SVG element - var gsvg = $(selected).data('gsvg'); - - // we know we have some transforms, so set up return variable - var batchCmd = new BatchCommand("Transform"); - - // store initial values that will be affected by reducing the transform list - var changes = {}, initial = null, attrs = []; - switch (selected.tagName) - { - case "line": - attrs = ["x1", "y1", "x2", "y2"]; - break; - case "circle": - attrs = ["cx", "cy", "r"]; - break; - case "ellipse": - attrs = ["cx", "cy", "rx", "ry"]; - break; - case "foreignObject": - case "rect": - case "image": - attrs = ["width", "height", "x", "y"]; - break; - case "use": - case "text": - case "tspan": - attrs = ["x", "y"]; - break; - case "polygon": - case "polyline": - initial = {}; - initial["points"] = selected.getAttribute("points"); - var list = selected.points; - var len = list.numberOfItems; - changes["points"] = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes["points"][i] = {x:pt.x,y:pt.y}; - } - break; - case "path": - initial = {}; - initial["d"] = selected.getAttribute("d"); - changes["d"] = selected.getAttribute("d"); - break; - } // switch on element type to get initial values - - if(attrs.length) { - changes = $(selected).attr(attrs); - $.each(changes, function(attr, val) { - changes[attr] = convertToNum(attr, val); - }); - } else if(gsvg) { - // GSVG exception - changes = { - x: $(gsvg).attr('x') || 0, - y: $(gsvg).attr('y') || 0 - }; - } - - // if we haven't created an initial array in polygon/polyline/path, then - // make a copy of initial values and include the transform - if (initial == null) { - initial = $.extend(true, {}, changes); - $.each(initial, function(attr, val) { - initial[attr] = convertToNum(attr, val); - }); - } - // save the start transform value too - initial["transform"] = start_transform ? start_transform : ""; - - // if it's a regular group, we have special processing to flatten transforms - if ((selected.tagName == "g" && !gsvg) || selected.tagName == "a") { - var box = svgedit.utilities.getBBox(selected), - oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix), - m = svgroot.createSVGMatrix(); - - - // temporarily strip off the rotate and save the old center - var gangle = getRotationAngle(selected); - if (gangle) { - var a = gangle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - var tx = 0, ty = 0, - operation = 0, - N = tlist.numberOfItems; - - if(N) { - var first_m = tlist.getItem(0).matrix; - } - - // first, if it was a scale then the second-last transform will be it - if (N >= 3 && tlist.getItem(N-2).type == 3 && - tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2) - { - operation = 3; // scale - - // if the children are unrotated, pass the scale down directly - // otherwise pass the equivalent matrix() down directly - var tm = tlist.getItem(N-3).matrix, - sm = tlist.getItem(N-2).matrix, - tmn = tlist.getItem(N-1).matrix; - - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - tx = 0; - ty = 0; - if (child.nodeType == 1) { - var childTlist = getTransformList(child); - - // some children might not have a transform (<metadata>, <defs>, etc) - 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; - var childxforms = []; - start_transform = child.getAttribute("transform"); - if(angle || hasMatrixTransform(childTlist)) { - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(matrixMultiply(tm, sm, tmn, m)); - childTlist.clear(); - childTlist.appendItem(e2t); - childxforms.push(e2t); - } - // if not rotated or skewed, push the [T][S][-T] down to the child - else { - // update the transform list with translate,scale,translate - - // slide the [T][S][-T] from the front to the back - // [T][S][-T][M] = [M][T2][S2][-T2] - - // (only bringing [-T] to the right of [M]) - // [T][S][-T][M] = [T][S][M][-T2] - // [-T2] = [M_inv][-T][M] - var t2n = matrixMultiply(m.inverse(), tmn, m); - // [T2] is always negative translation of [-T2] - var t2 = svgroot.createSVGMatrix(); - t2.e = -t2n.e; - t2.f = -t2n.f; - - // [T][S][-T][M] = [M][T2][S2][-T2] - // [S2] = [T2_inv][M_inv][T][S][-T][M][-T2_inv] - var s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()); - - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - translateOrigin.setTranslate(t2n.e, t2n.f); - scale.setScale(s2.a, s2.d); - translateBack.setTranslate(t2.e, t2.f); - childTlist.appendItem(translateBack); - childTlist.appendItem(scale); - childTlist.appendItem(translateOrigin); - childxforms.push(translateBack); - childxforms.push(scale); - childxforms.push(translateOrigin); -// logMatrix(translateBack.matrix); -// logMatrix(scale.matrix); - } // not rotated - batchCmd.addSubCommand( recalculateDimensions(child) ); - // TODO: If any <use> have this group as a parent and are - // referencing this child, then we need to impose a reverse - // scale on it so that when it won't get double-translated -// var uses = selected.getElementsByTagNameNS(svgns, "use"); -// var href = "#"+child.id; -// var u = uses.length; -// while (u--) { -// var useElem = uses.item(u); -// if(href == getHref(useElem)) { -// var usexlate = svgroot.createSVGTransform(); -// usexlate.setTranslate(-tx,-ty); -// getTransformList(useElem).insertItemBefore(usexlate,0); -// batchCmd.addSubCommand( recalculateDimensions(useElem) ); -// } -// } - start_transform = old_start_transform; - } // element - } // for each child - // Remove these transforms from group - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } - else if (N >= 3 && tlist.getItem(N-1).type == 1) - { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - } - // next, check if the first transform was a translate - // if we had [ T1 ] [ M ] we want to transform this into [ M ] [ T2 ] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var T_M = transformListToTransform(tlist).matrix; - tlist.removeItem(0); - var M_inv = transformListToTransform(tlist).matrix.inverse(); - var M2 = matrixMultiply( M_inv, T_M ); - - tx = M2.e; - ty = M2.f; - - if (tx != 0 || ty != 0) { - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - - var clipPaths_done = []; - - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - - // Check if child has clip-path - if(child.getAttribute('clip-path')) { - // tx, ty - var attr = child.getAttribute('clip-path'); - if(clipPaths_done.indexOf(attr) === -1) { - updateClipPath(attr, tx, ty); - clipPaths_done.push(attr); - } - } - - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - - var childTlist = getTransformList(child); - // some children might not have a transform (<metadata>, <defs>, etc) - if (childTlist) { - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - batchCmd.addSubCommand( recalculateDimensions(child) ); - // If any <use> have this group as a parent and are - // referencing this child, then impose a reverse translate on it - // so that when it won't get double-translated - var uses = selected.getElementsByTagNameNS(svgns, "use"); - var href = "#"+child.id; - var u = uses.length; - while (u--) { - var useElem = uses.item(u); - if(href == getHref(useElem)) { - var usexlate = svgroot.createSVGTransform(); - usexlate.setTranslate(-tx,-ty); - getTransformList(useElem).insertItemBefore(usexlate,0); - batchCmd.addSubCommand( recalculateDimensions(useElem) ); - } - } - start_transform = old_start_transform; - } - } - } - - clipPaths_done = []; - - start_transform = old_start_transform; - } - } - // else, a matrix imposition from a parent group - // keep pushing it down to the children - else if (N == 1 && tlist.getItem(0).type == 1 && !gangle) { - operation = 1; - var m = tlist.getItem(0).matrix, - children = selected.childNodes, - c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - 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); - childTlist.clear(); - childTlist.appendItem(e2m,0); - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - - // Convert stroke - // TODO: Find out if this should actually happen somewhere else - var sw = child.getAttribute("stroke-width"); - if (child.getAttribute("stroke") !== "none" && !isNaN(sw)) { - var avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; - child.setAttribute('stroke-width', sw * avg); - } - - } - } - tlist.clear(); - } - // else it was just a rotate - else { - if (gangle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (gangle) { - newcenter = { - x: oldcenter.x + first_m.e, - y: oldcenter.y + first_m.f - }; - - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // if it was a resize - else if (operation == 3) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(gangle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(gangle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(), - m_inv = m.inverse(), - extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - tx = extrat.e; - ty = extrat.f; - - if (tx != 0 || ty != 0) { - // now push this transform down to the children - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - var childTlist = getTransformList(child); - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - } - } - } - - if (gangle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } - // else, it's a non-group - else { - - // FIXME: box might be null for some elements (<metadata> etc), need to handle this - var box = svgedit.utilities.getBBox(selected); - - // Paths (and possbly other shapes) will have no BBox while still in <defs>, - // but we still may need to recalculate them (see issue 595). - // TODO: Figure out how to get BBox from these elements in case they - // have a rotation transform - - if(!box && selected.tagName != 'path') return null; - - - var m = svgroot.createSVGMatrix(), - // temporarily strip off the rotate and save the old center - angle = getRotationAngle(selected); - if (angle) { - var oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix); - - var a = angle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - - // 2 = translate, 3 = scale, 4 = rotate, 1 = matrix imposition - var operation = 0; - var N = tlist.numberOfItems; - - // Check if it has a gradient with userSpaceOnUse, in which case - // adjust it by recalculating the matrix transform. - // TODO: Make this work in Webkit using svgedit.transformlist.SVGTransformList - if(!svgedit.browser.isWebkit()) { - var fill = selected.getAttribute('fill'); - if(fill && fill.indexOf('url(') === 0) { - var paint = getRefElem(fill); - var type = 'pattern'; - if(paint.tagName !== type) type = 'gradient'; - var attrVal = paint.getAttribute(type + 'Units'); - if(attrVal === 'userSpaceOnUse') { - //Update the userSpaceOnUse element - m = transformListToTransform(tlist).matrix; - var gtlist = getTransformList(paint); - var gmatrix = transformListToTransform(gtlist).matrix; - m = matrixMultiply(m, gmatrix); - var m_str = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - paint.setAttribute(type + 'Transform', m_str); - } - } - } - - // first, if it was a scale of a non-skewed element, then the second-last - // transform will be the [S] - // 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) - - // Removed this so a <use> 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; - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } // if we had [T][S][-T][M], then this was a skewed element being resized - // Thus, we simply combine it all into one matrix - else if(N == 4 && tlist.getItem(N-1).type == 1) { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - // reset the matrix so that the element is not re-mapped - m = svgroot.createSVGMatrix(); - } // if we had [R][T][S][-T][M], then this was a rotated matrix-element - // if we had [T1][M] we want to transform this into [M][T2] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] and we can push [T2] - // down to the element - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var oldxlate = tlist.getItem(0).matrix, - meq = transformListToTransform(tlist,1).matrix, - meq_inv = meq.inverse(); - m = matrixMultiply( meq_inv, oldxlate, meq ); - tlist.removeItem(0); - } - // else if this child now has a matrix imposition (from a parent group) - // we might be able to simplify - else if (N == 1 && tlist.getItem(0).type == 1 && !angle) { - // Remap all point-based elements - m = transformListToTransform(tlist).matrix; - switch (selected.tagName) { - case 'line': - changes = $(selected).attr(["x1","y1","x2","y2"]); - case 'polyline': - case 'polygon': - changes.points = selected.getAttribute("points"); - if(changes.points) { - var list = selected.points; - var len = list.numberOfItems; - changes.points = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes.points[i] = {x:pt.x,y:pt.y}; - } - } - case 'path': - changes.d = selected.getAttribute("d"); - operation = 1; - tlist.clear(); - break; - default: - break; - } - } - // if it was a rotation, put the rotate back and return without a command - // (this function has zero work to do for a rotate()) - else { - operation = 4; // rotation - if (angle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle,newcenter.x,newcenter.y); - - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate or resize, we need to remap the element and absorb the xform - if (operation == 1 || operation == 2 || operation == 3) { - remapElement(selected,changes,m); - } // if we are remapping - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (angle) { - if(!hasMatrixTransform(tlist)) { - newcenter = { - x: oldcenter.x + m.e, - y: oldcenter.y + m.f - }; - } - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle, newcenter.x, newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // [Rold][M][T][S][-T] became [Rold][M] - // we want it to be [Rnew][M][Tr] where Tr is the - // translation required to re-center it - // Therefore, [Tr] = [M_inv][Rnew_inv][Rold][M] - else if (operation == 3 && angle) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(angle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(angle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(); - var m_inv = m.inverse(); - var extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - remapElement(selected,changes,extrat); - if (angle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } // a non-group - - // if the transform list has been emptied, remove it - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - - batchCmd.addSubCommand(new ChangeElementCommand(selected, initial)); - - return batchCmd; -}; - -// Root Current Transformation Matrix in user units -var root_sctm = null; - -// Group: Selection - -// Function: clearSelection -// Clears the selection. The 'selected' handler is then called. -// Parameters: -// noCall - Optional boolean that when true does not call the "selected" handler -var clearSelection = this.clearSelection = function(noCall) { - if (selectedElements[0] != null) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - selectorManager.releaseSelector(elem); - selectedElements[i] = null; - } -// selectedBBoxes[0] = null; - } - if(!noCall) call("selected", selectedElements); -}; - -// TODO: do we need to worry about selectedBBoxes here? - - -// Function: addToSelection -// Adds a list of elements to the selection. The 'selected' handler is then called. -// -// Parameters: -// elemsToAdd - an array of DOM elements to add to the selection -// showGrips - a boolean flag indicating whether the resize grips should be shown -var addToSelection = this.addToSelection = function(elemsToAdd, showGrips) { - if (elemsToAdd.length == 0) { return; } - // find the first null in our selectedElements array - var j = 0; - - while (j < selectedElements.length) { - if (selectedElements[j] == null) { - break; - } - ++j; - } - - // now add each element consecutively - var i = elemsToAdd.length; - while (i--) { - var elem = elemsToAdd[i]; - if (!elem || !svgedit.utilities.getBBox(elem)) continue; - - if(elem.tagName === 'a' && elem.childNodes.length === 1) { - // Make "a" element's child be the selected element - elem = elem.firstChild; - } - - // if it's not already there, add it - if (selectedElements.indexOf(elem) == -1) { - - selectedElements[j] = elem; - - // only the first selectedBBoxes element is ever used in the codebase these days -// if (j == 0) selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - j++; - var sel = selectorManager.requestSelector(elem); - - if (selectedElements.length > 1) { - sel.showGrips(false); - } - } - } - call("selected", selectedElements); - - if (showGrips || selectedElements.length == 1) { - selectorManager.requestSelector(selectedElements[0]).showGrips(true); - } - else { - selectorManager.requestSelector(selectedElements[0]).showGrips(false); - } - - // make sure the elements are in the correct order - // See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - - selectedElements.sort(function(a,b) { - if(a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); - } else if(a == null) { - return 1; - } - }); - - // Make sure first elements are not null - while(selectedElements[0] == null) selectedElements.shift(0); -}; - -// Function: selectOnly() -// Selects only the given elements, shortcut for clearSelection(); addToSelection() -// -// Parameters: -// elems - an array of DOM elements to be selected -var selectOnly = this.selectOnly = function(elems, showGrips) { - clearSelection(true); - addToSelection(elems, showGrips); -} - -// TODO: could use slice here to make this faster? -// TODO: should the 'selected' handler - -// Function: removeFromSelection -// Removes elements from the selection. -// -// Parameters: -// elemsToRemove - an array of elements to remove from selection -var removeFromSelection = this.removeFromSelection = function(elemsToRemove) { - if (selectedElements[0] == null) { return; } - if (elemsToRemove.length == 0) { return; } - - // find every element and remove it from our array copy - var newSelectedItems = new Array(selectedElements.length); - j = 0, - len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem) { - // keep the item - if (elemsToRemove.indexOf(elem) == -1) { - newSelectedItems[j] = elem; - j++; - } - else { // remove the item and its selector - selectorManager.releaseSelector(elem); - } - } - } - // the copy becomes the master now - selectedElements = newSelectedItems; -}; - -// Function: selectAllInCurrentLayer -// Clears the selection, then adds all elements in the current layer to the selection. -this.selectAllInCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (current_layer) { - current_mode = "select"; - selectOnly($(current_group || current_layer).children()); - } -}; - -// Function: getMouseTarget -// Gets the desired element from a mouse event -// -// Parameters: -// evt - Event object from the mouse event -// -// Returns: -// DOM element we want -var getMouseTarget = this.getMouseTarget = function(evt) { - if (evt == null) { - return null; - } - var mouse_target = evt.target; - - // if it was a <use>, Opera and WebKit return the SVGElementInstance - if (mouse_target.correspondingUseElement) mouse_target = mouse_target.correspondingUseElement; - - // for foreign content, go up until we find the foreignObject - // WebKit browsers set the mouse target to the svgcanvas div - if ([mathns, htmlns].indexOf(mouse_target.namespaceURI) >= 0 && - mouse_target.id != "svgcanvas") - { - while (mouse_target.nodeName != "foreignObject") { - mouse_target = mouse_target.parentNode; - if(!mouse_target) return svgroot; - } - } - - // Get the desired mouse_target with jQuery selector-fu - // If it's root-like, select the root - var current_layer = getCurrentDrawing().getCurrentLayer(); - if([svgroot, container, svgcontent, current_layer].indexOf(mouse_target) >= 0) { - return svgroot; - } - - var $target = $(mouse_target); - - // If it's a selection grip, return the grip parent - if($target.closest('#selectorParentGroup').length) { - // While we could instead have just returned mouse_target, - // this makes it easier to indentify as being a selector grip - return selectorManager.selectorParentGroup; - } - - while (mouse_target.parentNode !== (current_group || current_layer)) { - mouse_target = mouse_target.parentNode; - } - -// -// // go up until we hit a child of a layer -// while (mouse_target.parentNode.parentNode.tagName == 'g') { -// mouse_target = mouse_target.parentNode; -// } - // Webkit bubbles the mouse event all the way up to the div, so we - // set the mouse_target to the svgroot like the other browsers -// if (mouse_target.nodeName.toLowerCase() == "div") { -// mouse_target = svgroot; -// } - - return mouse_target; -}; - -// Mouse events -(function() { - var d_attr = null, - start_x = null, - start_y = null, - r_start_x = null, - r_start_y = null, - init_bbox = {}, - freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - - // - when we are in a create mode, the element is added to the canvas - // but the action is not recorded until mousing up - // - when we are in select mode, select the element, remember the position - // and do nothing else - var mouseDown = function(evt) - { - if(canvas.spaceKey || evt.button === 1) return; - - var right_click = evt.button === 2; - - if(evt.altKey) { // duplicate when dragging - svgCanvas.cloneSelectedElements(0,0); - } - - root_sctm = svgcontent.getScreenCTM().inverse(); - - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom; - - evt.preventDefault(); - - if(right_click) { - current_mode = "select"; - lastClickPoint = pt; - } - - // This would seem to be unnecessary... -// if(['select', 'resize'].indexOf(current_mode) == -1) { -// setGradient(); -// } - - var x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - mouse_target = getMouseTarget(evt); - - if(mouse_target.tagName === 'a' && mouse_target.childNodes.length === 1) { - mouse_target = mouse_target.firstChild; - } - - // real_x/y ignores grid-snap value - var real_x = r_start_x = start_x = x; - var real_y = r_start_y = start_y = y; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - - // if it is a selector grip, then it must be a single element selected, - // set the mouse_target to that and update the mode to rotate/resize - - if (mouse_target == selectorManager.selectorParentGroup && selectedElements[0] != null) { - var grip = evt.target; - var griptype = elData(grip, "type"); - // rotating - if (griptype == "rotate") { - current_mode = "rotate"; - current_rotate_mode = elData(grip, "dir"); - } - // resizing - else if(griptype == "resize") { - current_mode = "resize"; - current_resize_mode = elData(grip, "dir"); - } - mouse_target = selectedElements[0]; - } - - start_transform = mouse_target.getAttribute("transform"); - var tlist = getTransformList(mouse_target); - switch (current_mode) { - case "select": - started = true; - current_resize_mode = "none"; - if(right_click) started = false; - - if (mouse_target != svgroot) { - // if this element is not yet selected, clear selection and select it - if (selectedElements.indexOf(mouse_target) == -1) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) - if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection - clearSelection(true); - } - addToSelection([mouse_target]); - justSelected = mouse_target; - pathActions.clear(); - } - // else if it's a path, go into pathedit mode in mouseup - - if(!right_click) { - // insert a dummy transform so if the element(s) are moved it will have - // a transform to use for its translate - for (var i = 0; i < selectedElements.length; ++i) { - if(selectedElements[i] == null) continue; - var slist = getTransformList(selectedElements[i]); - if(slist.numberOfItems) { - slist.insertItemBefore(svgroot.createSVGTransform(), 0); - } else { - slist.appendItem(svgroot.createSVGTransform()); - } - } - } - } - else if(!right_click){ - clearSelection(); - current_mode = "multiselect"; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - r_start_x *= current_zoom; - r_start_y *= current_zoom; -// console.log('p',[evt.pageX, evt.pageY]); -// console.log('c',[evt.clientX, evt.clientY]); -// console.log('o',[evt.offsetX, evt.offsetY]); -// console.log('s',[start_x, start_y]); - - assignAttributes(rubberBox, { - 'x': r_start_x, - 'y': r_start_y, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - break; - case "zoom": - started = true; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': real_x * current_zoom, - 'y': real_x * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - break; - case "resize": - started = true; - start_x = x; - start_y = y; - - // Getting the BBox from the selection box, since we know we - // want to orient around it - init_bbox = svgedit.utilities.getBBox($('#selectedBox0')[0]); - var bb = {}; - $.each(init_bbox, function(key, val) { - bb[key] = val/current_zoom; - }); - init_bbox = bb; - // append three dummy transforms to the tlist so that - // we can translate,scale,translate in mousemove - var pos = getRotationAngle(mouse_target)?1:0; - - if(hasMatrixTransform(tlist)) { - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - } else { - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - - if(svgedit.browser.supportsNonScalingStroke()) { - //Handle crash for newer Chrome: https://code.google.com/p/svg-edit/issues/detail?id=904 - //Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 - // TODO: Remove this workaround (all isChrome blocks) once vendor fixes the issue - var isChrome = svgedit.browser.isChrome(); - if(isChrome) { - var delayedStroke = function(ele) { - var _stroke = ele.getAttributeNS(null, 'stroke'); - ele.removeAttributeNS(null, 'stroke'); - //Re-apply stroke after delay. Anything higher than 1 seems to cause flicker - setTimeout(function() { ele.setAttributeNS(null, 'stroke', _stroke) }, 1); - } - } - mouse_target.style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(mouse_target); - - var all = mouse_target.getElementsByTagName('*'), - len = all.length; - for(var i = 0; i < len; i++) { - all[i].style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(all[i]); - } - } - } - break; - case "fhellipse": - case "fhrect": - case "fhpath": - started = true; - d_attr = real_x + "," + real_y + " "; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "polyline", - "curStyles": true, - "attr": { - "points": d_attr, - "id": getNextId(), - "fill": "none", - "opacity": cur_shape.opacity / 2, - "stroke-linecap": "round", - "style": "pointer-events:none" - } - }); - freehand.minx = real_x; - freehand.maxx = real_x; - freehand.miny = real_y; - freehand.maxy = real_y; - break; - case "image": - started = true; - var newImage = addSvgElementFromJson({ - "element": "image", - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - } - }); - setHref(newImage, last_good_img_url); - preventClickDefault(newImage); - break; - case "square": - // FIXME: once we create the rect, we lose information that this was a square - // (for resizing purposes this could be important) - case "rect": - started = true; - start_x = x; - start_y = y; - addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "line": - started = true; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "line", - "curStyles": true, - "attr": { - "x1": x, - "y1": y, - "x2": x, - "y2": y, - "id": getNextId(), - "stroke": cur_shape.stroke, - "stroke-width": stroke_w, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill": "none", - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:none" - } - }); - break; - case "circle": - started = true; - addSvgElementFromJson({ - "element": "circle", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "r": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "ellipse": - started = true; - addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "rx": 0, - "ry": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "text": - started = true; - var newText = addSvgElementFromJson({ - "element": "text", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "id": getNextId(), - "fill": cur_text.fill, - "stroke-width": cur_text.stroke_width, - "font-size": cur_text.font_size, - "font-family": cur_text.font_family, - "text-anchor": "middle", - "xml:space": "preserve", - "opacity": cur_shape.opacity - } - }); -// newText.textContent = "text"; - break; - case "path": - // Fall through - case "pathedit": - start_x *= current_zoom; - start_y *= current_zoom; - pathActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "textedit": - start_x *= current_zoom; - start_y *= current_zoom; - textActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "rotate": - started = true; - // we are starting an undoable change (a drag-rotation) - canvas.undoMgr.beginUndoableChange("transform", selectedElements); - document.getElementById("workarea").className = "rotate"; - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseDown", { - event: evt, - start_x: start_x, - start_y: start_y, - selectedElements: selectedElements - }, true); - - $.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 - // any elements that are still being created, moved or resized on the canvas) - var mouseMove = function(evt) - { - if (!started) return; - if(evt.button === 1 || canvas.spaceKey) return; - - var selected = selectedElements[0], - pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - shape = getElem(getId()); - - var real_x = x = mouse_x / current_zoom; - var real_y = y = mouse_y / current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - evt.preventDefault(); - - switch (current_mode) - { - case "select": - // we temporarily use a translate on the element(s) being dragged - // this transform is removed upon mousing up and the element is - // relocated to the new location - if (selectedElements[0] !== null) { - var dx = x - start_x; - var dy = y - start_y; - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - } - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x,y); x=xya.x; y=xya.y; } - - if (dx != 0 || dy != 0) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; -// if (i==0) { -// var box = svgedit.utilities.getBBox(selected); -// selectedBBoxes[i].x = box.x + dx; -// selectedBBoxes[i].y = box.y + dy; -// } - - // update the dummy transform in our transform list - // 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); - } else { - tlist.appendItem(xform); - } - - // update our internal bbox that we're tracking while dragging - selectorManager.requestSelector(selected).resize(); - } - - call("transition", selectedElements); - } - } - break; - case "multiselect": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y) - },100); - - // for each selected: - // - if newList contains selected, do nothing - // - if newList doesn't contain selected, remove it from selected - // - for any newList that was not in selectedElements, add it to selected - var elemsToRemove = [], elemsToAdd = [], - newList = getIntersectionList(), - len = selectedElements.length; - - for (var i = 0; i < len; ++i) { - var ind = newList.indexOf(selectedElements[i]); - if (ind == -1) { - elemsToRemove.push(selectedElements[i]); - } - else { - newList[ind] = null; - } - } - - len = newList.length; - for (i = 0; i < len; ++i) { if (newList[i]) elemsToAdd.push(newList[i]); } - - if (elemsToRemove.length > 0) - canvas.removeFromSelection(elemsToRemove); - - if (elemsToAdd.length > 0) - addToSelection(elemsToAdd); - - break; - case "resize": - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates - var tlist = getTransformList(selected), - hasMatrix = hasMatrixTransform(tlist), - box = hasMatrix ? init_bbox : svgedit.utilities.getBBox(selected), - left=box.x, top=box.y, width=box.width, - height=box.height, dx=(x-start_x), dy=(y-start_y); - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - height = snapToGrid(height); - width = snapToGrid(width); - } - - // if rotated, adjust the dx,dy values - var angle = getRotationAngle(selected); - if (angle) { - var r = Math.sqrt( dx*dx + dy*dy ), - theta = Math.atan2(dy,dx) - angle * Math.PI / 180.0; - dx = r * Math.cos(theta); - dy = r * Math.sin(theta); - } - - // if not stretching in y direction, set dy to 0 - // if not stretching in x direction, set dx to 0 - if(current_resize_mode.indexOf("n")==-1 && current_resize_mode.indexOf("s")==-1) { - dy = 0; - } - if(current_resize_mode.indexOf("e")==-1 && current_resize_mode.indexOf("w")==-1) { - dx = 0; - } - - var ts = null, - tx = 0, ty = 0, - sy = height ? (height+dy)/height : 1, - sx = width ? (width+dx)/width : 1; - // if we are dragging on the north side, then adjust the scale factor and ty - if(current_resize_mode.indexOf("n") >= 0) { - sy = height ? (height-dy)/height : 1; - ty = height; - } - - // if we dragging on the east side, then adjust the scale factor and tx - if(current_resize_mode.indexOf("w") >= 0) { - sx = width ? (width-dx)/width : 1; - tx = width; - } - - // update the transform list with translate,scale,translate - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - - if(curConfig.gridSnapping){ - left = snapToGrid(left); - tx = snapToGrid(tx); - top = snapToGrid(top); - ty = snapToGrid(ty); - } - - translateOrigin.setTranslate(-(left+tx),-(top+ty)); - if(evt.shiftKey) { - if(sx == 1) sx = sy - else sy = sx; - } - scale.setScale(sx,sy); - - translateBack.setTranslate(left+tx,top+ty); - if(hasMatrix) { - var diff = angle?1:0; - tlist.replaceItem(translateOrigin, 2+diff); - tlist.replaceItem(scale, 1+diff); - tlist.replaceItem(translateBack, 0+diff); - } else { - var N = tlist.numberOfItems; - tlist.replaceItem(translateBack, N-3); - tlist.replaceItem(scale, N-2); - tlist.replaceItem(translateOrigin, N-1); - } - - selectorManager.requestSelector(selected).resize(); - - call("transition", selectedElements); - - break; - case "zoom": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - break; - case "text": - assignAttributes(shape,{ - 'x': x, - 'y': y - },1000); - break; - case "line": - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - var x2 = x; - var y2 = y; - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x2,y2); x2=xya.x; y2=xya.y; } - - shape.setAttributeNS(null, "x2", x2); - shape.setAttributeNS(null, "y2", y2); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "foreignObject": - // fall through - case "square": - // fall through - case "rect": - // fall through - case "image": - var square = (current_mode == 'square') || evt.shiftKey, - w = Math.abs(x - start_x), - h = Math.abs(y - start_y), - new_x, new_y; - if(square) { - w = h = Math.max(w, h); - new_x = start_x < x ? start_x : start_x - w; - new_y = start_y < y ? start_y : start_y - h; - } else { - new_x = Math.min(start_x,x); - new_y = Math.min(start_y,y); - } - - if(curConfig.gridSnapping){ - w = snapToGrid(w); - h = snapToGrid(h); - new_x = snapToGrid(new_x); - new_y = snapToGrid(new_y); - } - - assignAttributes(shape,{ - 'width': w, - 'height': h, - 'x': new_x, - 'y': new_y - },1000); - - break; - case "circle": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy, - rad = Math.sqrt( (x-cx)*(x-cx) + (y-cy)*(y-cy) ); - if(curConfig.gridSnapping){ - rad = snapToGrid(rad); - } - shape.setAttributeNS(null, "r", rad); - break; - case "ellipse": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy; - // Opera has a problem with suspendRedraw() apparently - handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - if(curConfig.gridSnapping){ - x = snapToGrid(x); - cx = snapToGrid(cx); - y = snapToGrid(y); - cy = snapToGrid(cy); - } - shape.setAttributeNS(null, "rx", Math.abs(x - cx) ); - var ry = Math.abs(evt.shiftKey?(x - cx):(y - cy)); - shape.setAttributeNS(null, "ry", ry ); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "fhellipse": - case "fhrect": - freehand.minx = Math.min(real_x, freehand.minx); - freehand.maxx = Math.max(real_x, freehand.maxx); - freehand.miny = Math.min(real_y, freehand.miny); - freehand.maxy = Math.max(real_y, freehand.maxy); - // break; missing on purpose - case "fhpath": - d_attr += + real_x + "," + real_y + " "; - shape.setAttributeNS(null, "points", d_attr); - break; - // update path stretch line coordinates - case "path": - // fall through - case "pathedit": - x *= current_zoom; - y *= current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - if(evt.shiftKey) { - var path = svgedit.path.path; - if(path) { - var x1 = path.dragging?path.dragging[0]:start_x; - var y1 = path.dragging?path.dragging[1]:start_y; - } else { - var x1 = start_x; - var y1 = start_y; - } - var xya = snapToAngle(x1,y1,x,y); - x=xya.x; y=xya.y; - } - - if(rubberBox && rubberBox.getAttribute('display') !== 'none') { - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - } - pathActions.mouseMove(evt, x, y); - - break; - case "textedit": - x *= current_zoom; - y *= current_zoom; -// if(rubberBox && rubberBox.getAttribute('display') != 'none') { -// assignAttributes(rubberBox, { -// 'x': Math.min(start_x,x), -// 'y': Math.min(start_y,y), -// 'width': Math.abs(x-start_x), -// 'height': Math.abs(y-start_y) -// },100); -// } - - textActions.mouseMove(mouse_x, mouse_y); - - break; - case "rotate": - var box = svgedit.utilities.getBBox(selected), - cx = box.x + box.width/2, - cy = box.y + box.height/2, - m = getMatrix(selected), - center = transformPoint(cx,cy,m); - cx = center.x; - cy = center.y; - var ccx = box.x // ne - var ccy = box.y // ne - if (current_rotate_mode == "nw") ccx = box.x + box.width; - if (current_rotate_mode == "se") ccy = box.y + box.height; - if (current_rotate_mode == "sw"){ ccx = box.x + box.width; ccy = box.y + box.height; } - compensation_angle = ((Math.atan2(cy-ccy,cx-ccx) * (180/Math.PI))-90) % 360; - var angle = ((Math.atan2(cy-y,cx-x) * (180/Math.PI))-90) % 360; - angle += compensation_angle; - if(curConfig.gridSnapping){ - angle = snapToGrid(angle); - } - if(evt.shiftKey) { // restrict rotations to nice angles (WRS) - var snap = 45; - angle= Math.round(angle/snap)*snap; - } - - canvas.setRotationAngle(angle<-180?(360+angle):angle, true); - call("transition", selectedElements); - break; - default: - break; - } - - runExtensions("mouseMove", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y, - selected: selected - }); - - }; // mouseMove() - - // - in create mode, the element's opacity is set properly, we create an InsertElementCommand - // and store it on the Undo stack - // - in move/resize mode, the element's attributes which were affected by the move/resize are - // identified, a ChangeElementCommand is created and stored on the stack for those attrs - // this is done in when we recalculate the selected dimensions() - var mouseUp = function(evt) - { - if(evt.button === 2) return; - var tempJustSelected = justSelected; - justSelected = null; - if (!started) return; - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - element = getElem(getId()), - keep = false; - - var real_x = x; - var real_y = y; - - // TODO: Make true when in multi-unit mode - var useUnit = false; // (curConfig.baseUnit !== 'px'); - started = false; - switch (current_mode) - { - // intentionally fall-through to select here - case "resize": - case "multiselect": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - curBBoxes = []; - } - current_mode = "select"; - case "select": - if (selectedElements[0] != null) { - // if we only have one selected element - if (selectedElements[1] == null) { - // set our current stroke/fill properties to the element's - var selected = selectedElements[0]; - switch ( selected.tagName ) { - case "g": - case "use": - case "image": - case "foreignObject": - break; - default: - cur_properties.fill = selected.getAttribute("fill"); - cur_properties.fill_opacity = selected.getAttribute("fill-opacity"); - cur_properties.stroke = selected.getAttribute("stroke"); - cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity"); - cur_properties.stroke_width = selected.getAttribute("stroke-width"); - cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray"); - cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin"); - cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap"); - } - - if (selected.tagName == "text") { - cur_text.font_size = selected.getAttribute("font-size"); - cur_text.font_family = selected.getAttribute("font-family"); - } - selectorManager.requestSelector(selected).showGrips(true); - - // This shouldn't be necessary as it was done on mouseDown... -// call("selected", [selected]); - } - // always recalculate dimensions to strip off stray identity transforms - recalculateAllSelectedDimensions(); - // if it was being dragged/resized - if (real_x != r_start_x || real_y != r_start_y) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - if(!selectedElements[i].firstChild) { - // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - selectorManager.requestSelector(selectedElements[i]).resize(); - } - } - } - // no change in position/size, so maybe we should move to pathedit - else { - var t = evt.target; - if (selectedElements[0].nodeName === "path" && selectedElements[1] == null) { - pathActions.select(selectedElements[0]); - } // if it was a path - // else, if it was selected and this is a shift-click, remove it from selection - else if (evt.shiftKey) { - if(tempJustSelected != t) { - canvas.removeFromSelection([t]); - } - } - } // no change in mouse position - - // Remove non-scaling stroke - if(svgedit.browser.supportsNonScalingStroke()) { - var elem = selectedElements[0]; - if (elem) { - elem.removeAttribute('style'); - svgedit.utilities.walkTree(elem, function(elem) { - elem.removeAttribute('style'); - }); - } - } - - } - return; - break; - case "zoom": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - } - var factor = evt.altKey?.5:2; - call("zoomed", { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y), - 'factor': factor - }); - return; - case "fhpath": - // Check that the path contains at least 2 points; a degenerate one-point path - // causes problems. - // Webkit ignores how we set the points attribute with commas and uses space - // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 - var coords = element.getAttribute('points'); - var commaIndex = coords.indexOf(','); - if (commaIndex >= 0) { - keep = coords.indexOf(',', commaIndex+1) >= 0; - } else { - keep = coords.indexOf(' ', coords.indexOf(' ')+1) >= 0; - } - if (keep) { - element = pathActions.smoothPolylineIntoPath(element); - } - break; - case "line": - var attrs = $(element).attr(["x1", "x2", "y1", "y2"]); - keep = (attrs.x1 != attrs.x2 || attrs.y1 != attrs.y2); - break; - case "foreignObject": - case "square": - case "rect": - case "image": - var attrs = $(element).attr(["width", "height"]); - // Image should be kept regardless of size (use inherit dimensions later) - keep = (attrs.width != 0 || attrs.height != 0) || current_mode === "image"; - break; - case "circle": - keep = (element.getAttribute('r') != 0); - break; - case "ellipse": - var attrs = $(element).attr(["rx", "ry"]); - keep = (attrs.rx != null || attrs.ry != null); - break; - case "fhellipse": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": (freehand.minx + freehand.maxx) / 2, - "cy": (freehand.miny + freehand.maxy) / 2, - "rx": (freehand.maxx - freehand.minx) / 2, - "ry": (freehand.maxy - freehand.miny) / 2, - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "fhrect": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": freehand.minx, - "y": freehand.miny, - "width": (freehand.maxx - freehand.minx), - "height": (freehand.maxy - freehand.miny), - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "text": - keep = true; - selectOnly([element]); - textActions.start(element); - break; - case "path": - // set element to null here so that it is not removed nor finalized - element = null; - // continue to be set to true so that mouseMove happens - started = true; - - var res = pathActions.mouseUp(evt, element, mouse_x, mouse_y); - element = res.element - keep = res.keep; - break; - case "pathedit": - keep = true; - element = null; - pathActions.mouseUp(evt); - break; - case "textedit": - keep = false; - element = null; - textActions.mouseUp(evt, mouse_x, mouse_y); - break; - case "rotate": - keep = true; - element = null; - current_mode = "select"; - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } - // perform recalculation to weed out any stray identity transforms that might get stuck - recalculateAllSelectedDimensions(); - call("changed", selectedElements); - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseUp", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y - }, true); - - $.each(ext_result, function(i, r) { - if(r) { - keep = r.keep || keep; - element = r.element; - started = r.started || started; - } - }); - - if (!keep && element != null) { - getCurrentDrawing().releaseId(getId()); - element.parentNode.removeChild(element); - element = null; - - var t = evt.target; - - // if this element is in a group, go up until we reach the top-level group - // just below the layer groups - // TODO: once we implement links, we also would have to check for <a> elements - while (t.parentNode.parentNode.tagName == "g") { - t = t.parentNode; - } - // if we are not in the middle of creating a path, and we've clicked on some shape, - // then go to Select mode. - // WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> - if ( (current_mode != "path" || !drawn_path) && - t.parentNode.id != "selectorParentGroup" && - t.id != "svgcanvas" && t.id != "svgroot") - { - // switch into "select" mode if we've clicked on an element - canvas.setMode("select"); - selectOnly([t], true); - } - - } else if (element != null) { - canvas.addedNew = true; - - if(useUnit) svgedit.units.convertAttrs(element); - - var ani_dur = .2, c_ani; - if(opac_ani.beginElement && element.getAttribute('opacity') != cur_shape.opacity) { - c_ani = $(opac_ani).clone().attr({ - to: cur_shape.opacity, - dur: ani_dur - }).appendTo(element); - try { - // Fails in FF4 on foreignObject - c_ani[0].beginElement(); - } catch(e){} - } else { - ani_dur = 0; - } - - // Ideally this would be done on the endEvent of the animation, - // but that doesn't seem to be supported in Webkit - setTimeout(function() { - if(c_ani) c_ani.remove(); - element.setAttribute("opacity", cur_shape.opacity); - element.setAttribute("style", "pointer-events:inherit"); - cleanupElement(element); - if(current_mode === "path") { - pathActions.toEditMode(element); - } else { - if(curConfig.selectNew) { - selectOnly([element], true); - } - } - // we create the insert command that is stored on the stack - // undo means to call cmd.unapply(), redo means to call cmd.apply() - addCommandToHistory(new InsertElementCommand(element)); - - call("changed",[element]); - }, ani_dur * 1000); - } - - start_transform = null; - }; - - var dblClick = function(evt) { - var evt_target = evt.target; - var parent = evt_target.parentNode; - - // Do nothing if already in current group - if(parent === current_group) return; - - var mouse_target = getMouseTarget(evt); - var tagName = mouse_target.tagName; - - if(tagName === 'text' && current_mode !== 'textedit') { - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ); - textActions.select(mouse_target, pt.x, pt.y); - } - - if((tagName === "g" || tagName === "a") && getRotationAngle(mouse_target)) { - // TODO: Allow method of in-group editing without having to do - // this (similar to editing rotated paths) - - // Ungroup and regroup - pushGroupProperties(mouse_target); - mouse_target = selectedElements[0]; - clearSelection(true); - } - // Reset context - if(current_group) { - leaveContext(); - } - - if((parent.tagName !== 'g' && parent.tagName !== 'a') || - parent === getCurrentDrawing().getCurrentLayer() || - mouse_target === selectorManager.selectorParentGroup) - { - // Escape from in-group edit - return; - } - setContext(mouse_target); - } - - // prevent links from being followed in the canvas - var handleLinkInCanvas = function(e) { - e.preventDefault(); - return false; - }; - - // Added mouseup to the container here. - // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. - $(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp); -// $(window).mouseup(mouseUp); - - $(container).bind("mousewheel DOMMouseScroll", function(e){ - if(!e.shiftKey) return; - e.preventDefault(); - - root_sctm = svgcontent.getScreenCTM().inverse(); - var pt = transformPoint( e.pageX, e.pageY, root_sctm ); - var bbox = { - 'x': pt.x, - 'y': pt.y, - 'width': 0, - 'height': 0 - }; - - // Respond to mouse wheel in IE/Webkit/Opera. - // (It returns up/dn motion in multiples of 120) - if(e.wheelDelta) { - if (e.wheelDelta >= 120) { - bbox.factor = 2; - } else if (e.wheelDelta <= -120) { - bbox.factor = .5; - } - } else if(e.detail) { - if (e.detail > 0) { - bbox.factor = .5; - } else if (e.detail < 0) { - bbox.factor = 2; - } - } - - if(!bbox.factor) return; - call("zoomed", bbox); - }); - -}()); - -// Function: preventClickDefault -// Prevents default browser click behaviour on the given element -// -// Parameters: -// img - The DOM element to prevent the cilck on -var preventClickDefault = function(img) { - $(img).click(function(e){e.preventDefault()}); -} - -// Group: Text edit functions -// Functions relating to editing text elements -var textActions = canvas.textActions = function() { - var curtext; - var textinput; - var cursor; - var selblock; - var blinker; - var chardata = []; - var textbb, transbb; - var matrix; - var last_x, last_y; - var allow_dbl; - - function setCursor(index) { - var empty = (textinput.value === ""); - $(textinput).focus(); - - if(!arguments.length) { - if(empty) { - index = 0; - } else { - if(textinput.selectionEnd !== textinput.selectionStart) return; - index = textinput.selectionEnd; - } - } - - var charbb; - charbb = chardata[index]; - if(!empty) { - textinput.setSelectionRange(index, index); - } - cursor = getElem("text_cursor"); - if (!cursor) { - cursor = document.createElementNS(svgns, "line"); - assignAttributes(cursor, { - 'id': "text_cursor", - 'stroke': "#333", - 'stroke-width': 1 - }); - cursor = getElem("selectorParentGroup").appendChild(cursor); - } - - if(!blinker) { - blinker = setInterval(function() { - var show = (cursor.getAttribute('display') === 'none'); - cursor.setAttribute('display', show?'inline':'none'); - }, 600); - - } - - - var start_pt = ptToScreen(charbb.x, textbb.y); - var end_pt = ptToScreen(charbb.x, (textbb.y + textbb.height)); - - assignAttributes(cursor, { - x1: start_pt.x, - y1: start_pt.y, - x2: end_pt.x, - y2: end_pt.y, - visibility: 'visible', - display: 'inline' - }); - - if(selblock) selblock.setAttribute('d', ''); - } - - function setSelection(start, end, skipInput) { - if(start === end) { - setCursor(end); - return; - } - - if(!skipInput) { - textinput.setSelectionRange(start, end); - } - - selblock = getElem("text_selectblock"); - if (!selblock) { - - selblock = document.createElementNS(svgns, "path"); - assignAttributes(selblock, { - 'id': "text_selectblock", - 'fill': "green", - 'opacity': .5, - 'style': "pointer-events:none" - }); - getElem("selectorParentGroup").appendChild(selblock); - } - - - var startbb = chardata[start]; - - var endbb = chardata[end]; - - cursor.setAttribute('visibility', 'hidden'); - - var tl = ptToScreen(startbb.x, textbb.y), - tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y), - bl = ptToScreen(startbb.x, textbb.y + textbb.height), - br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); - - - var dstr = "M" + tl.x + "," + tl.y - + " L" + tr.x + "," + tr.y - + " " + br.x + "," + br.y - + " " + bl.x + "," + bl.y + "z"; - - assignAttributes(selblock, { - d: dstr, - 'display': 'inline' - }); - } - - function getIndexFromPoint(mouse_x, mouse_y) { - // Position cursor here - var pt = svgroot.createSVGPoint(); - pt.x = mouse_x; - pt.y = mouse_y; - - // No content, so return 0 - if(chardata.length == 1) return 0; - // Determine if cursor should be on left or right of character - var charpos = curtext.getCharNumAtPosition(pt); - if(charpos < 0) { - // Out of text range, look at mouse coords - charpos = chardata.length - 2; - if(mouse_x <= chardata[0].x) { - charpos = 0; - } - } else if(charpos >= chardata.length - 2) { - charpos = chardata.length - 2; - } - var charbb = chardata[charpos]; - var mid = charbb.x + (charbb.width/2); - if(mouse_x > mid) { - charpos++; - } - return charpos; - } - - function setCursorFromPoint(mouse_x, mouse_y) { - setCursor(getIndexFromPoint(mouse_x, mouse_y)); - } - - function setEndSelectionFromPoint(x, y, apply) { - var i1 = textinput.selectionStart; - var i2 = getIndexFromPoint(x, y); - - var start = Math.min(i1, i2); - var end = Math.max(i1, i2); - setSelection(start, end, !apply); - } - - function screenToPt(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - out.x /= current_zoom; - out.y /= current_zoom; - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix.inverse()); - out.x = pt.x; - out.y = pt.y; - } - - return out; - } - - function ptToScreen(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix); - out.x = pt.x; - out.y = pt.y; - } - - out.x *= current_zoom; - out.y *= current_zoom; - - return out; - } - - function hideCursor() { - if(cursor) { - cursor.setAttribute('visibility', 'hidden'); - } - } - - function selectAll(evt) { - setSelection(0, curtext.textContent.length); - $(this).unbind(evt); - } - - function selectWord(evt) { - if(!allow_dbl || !curtext) return; - - var ept = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = ept.x * current_zoom, - mouse_y = ept.y * current_zoom; - var pt = screenToPt(mouse_x, mouse_y); - - var index = getIndexFromPoint(pt.x, pt.y); - var str = curtext.textContent; - var first = str.substr(0, index).replace(/[a-z0-9]+$/i, '').length; - var m = str.substr(index).match(/^[a-z0-9]+/i); - var last = (m?m[0].length:0) + index; - setSelection(first, last); - - // Set tripleclick - $(evt.target).click(selectAll); - setTimeout(function() { - $(evt.target).unbind('click', selectAll); - }, 300); - - } - - return { - select: function(target, x, y) { - curtext = target; - textActions.toEditMode(x, y); - }, - start: function(elem) { - curtext = elem; - textActions.toEditMode(); - }, - mouseDown: function(evt, mouse_target, start_x, start_y) { - var pt = screenToPt(start_x, start_y); - - textinput.focus(); - setCursorFromPoint(pt.x, pt.y); - last_x = start_x; - last_y = start_y; - - // TODO: Find way to block native selection - }, - mouseMove: function(mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - setEndSelectionFromPoint(pt.x, pt.y); - }, - mouseUp: function(evt, mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - - setEndSelectionFromPoint(pt.x, pt.y, true); - - // TODO: Find a way to make this work: Use transformed BBox instead of evt.target -// if(last_x === mouse_x && last_y === mouse_y -// && !svgedit.math.rectsIntersect(transbb, {x: pt.x, y: pt.y, width:0, height:0})) { -// textActions.toSelectMode(true); -// } - - if( - evt.target !== curtext - && mouse_x < last_x + 2 - && mouse_x > last_x - 2 - && mouse_y < last_y + 2 - && mouse_y > last_y - 2) { - - textActions.toSelectMode(true); - } - - }, - setCursor: setCursor, - toEditMode: function(x, y) { - 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'); - -// if(svgedit.browser.supportsEditableText()) { -// curtext.setAttribute('editable', 'simple'); -// return; -// } - - if(!arguments.length) { - setCursor(); - } else { - var pt = screenToPt(x, y); - setCursorFromPoint(pt.x, pt.y); - } - - setTimeout(function() { - allow_dbl = true; - }, 300); - }, - toSelectMode: function(selectElem) { - current_mode = "select"; - clearInterval(blinker); - blinker = null; - if(selblock) $(selblock).attr('display','none'); - if(cursor) $(cursor).attr('visibility','hidden'); - $(curtext).css('cursor', 'move'); - - if(selectElem) { - clearSelection(); - $(curtext).css('cursor', 'move'); - - call("selected", [curtext]); - addToSelection([curtext], true); - } - if(curtext && !curtext.textContent.length) { - // No content, so delete - canvas.deleteSelectedElements(); - } - - $(textinput).blur(); - - curtext = false; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.removeAttribute('editable'); -// } - }, - setInputElem: function(elem) { - textinput = elem; -// $(textinput).blur(hideCursor); - }, - clear: function() { - if(current_mode == "textedit") { - textActions.toSelectMode(); - } - }, - init: function(inputElem) { - if(!curtext) return; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.select(); -// return; -// } - - if(!curtext.parentNode) { - // Result of the ffClone, need to get correct element - curtext = selectedElements[0]; - selectorManager.requestSelector(curtext).showGrips(false); - } - - var str = curtext.textContent; - var len = str.length; - - var xform = curtext.getAttribute('transform'); - - textbb = svgedit.utilities.getBBox(curtext); - - matrix = xform?getMatrix(curtext):null; - - chardata = Array(len); - textinput.focus(); - - $(curtext).unbind('dblclick', selectWord).dblclick(selectWord); - - if(!len) { - var end = {x: textbb.x + (textbb.width/2), width: 0}; - } - - for(var i=0; i<len; i++) { - var start = curtext.getStartPositionOfChar(i); - var end = curtext.getEndPositionOfChar(i); - - if(!svgedit.browser.supportsGoodTextCharPos()) { - var offset = canvas.contentW * current_zoom; - start.x -= offset; - end.x -= offset; - - start.x /= current_zoom; - end.x /= current_zoom; - } - - // Get a "bbox" equivalent for each character. Uses the - // bbox data of the actual text for y, height purposes - - // TODO: Decide if y, width and height are actually necessary - chardata[i] = { - x: start.x, - y: textbb.y, // start.y? - width: end.x - start.x, - height: textbb.height - }; - } - - // Add a last bbox for cursor at end of text - chardata.push({ - x: end.x, - width: 0 - }); - setSelection(textinput.selectionStart, textinput.selectionEnd, true); - } - } -}(); - -// TODO: Migrate all of this code into path.js -// Group: Path edit functions -// Functions relating to editing path elements -var pathActions = canvas.pathActions = function() { - - var subpath = false; - var current_path; - var newPoint, firstCtrl; - - function resetD(p) { - p.setAttribute("d", pathActions.convertPath(p)); - } - - // TODO: Move into path.js - svgedit.path.Path.prototype.endChanges = function(text) { - if(svgedit.browser.isWebkit()) resetD(this.elem); - var cmd = new ChangeElementCommand(this.elem, {d: this.last_d}, text); - addCommandToHistory(cmd); - call("changed", [this.elem]); - } - - svgedit.path.Path.prototype.addPtsToSelection = function(indexes) { - if(!$.isArray(indexes)) indexes = [indexes]; - for(var i=0; i< indexes.length; i++) { - var index = indexes[i]; - var seg = this.segs[index]; - if(seg.ptgrip) { - if(this.selected_pts.indexOf(index) == -1 && index >= 0) { - this.selected_pts.push(index); - } - } - }; - this.selected_pts.sort(); - var i = this.selected_pts.length, - grips = new Array(i); - // Loop through points to be selected and highlight each - while(i--) { - var pt = this.selected_pts[i]; - var seg = this.segs[pt]; - seg.select(true); - grips[i] = seg.ptgrip; - } - // TODO: Correct this: - pathActions.canDeleteNodes = true; - - pathActions.closed_subpath = this.subpathIsClosed(this.selected_pts[0]); - - call("selected", grips); - } - - var current_path = null, - drawn_path = null, - hasMoved = false; - - // This function converts a polyline (created by the fh_path tool) into - // a path element and coverts every three line segments into a single bezier - // curve in an attempt to smooth out the free-hand - var smoothPolylineIntoPath = function(element) { - var points = element.points; - var N = points.numberOfItems; - if (N >= 4) { - // loop through every 3 points and convert to a cubic bezier curve segment - // - // NOTE: this is cheating, it means that every 3 points has the potential to - // be a corner instead of treating each point in an equal manner. In general, - // this technique does not look that good. - // - // I am open to better ideas! - // - // Reading: - // - http://www.efg2.com/Lab/Graphics/Jean-YvesQueinecBezierCurves.htm - // - http://www.codeproject.com/KB/graphics/BezierSpline.aspx?msg=2956963 - // - http://www.ian-ko.com/ET_GeoWizards/UserGuide/smooth.htm - // - http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html - var curpos = points.getItem(0), prevCtlPt = null; - var d = []; - d.push(["M",curpos.x,",",curpos.y," C"].join("")); - for (var i = 1; i <= (N-4); i += 3) { - var ct1 = points.getItem(i); - var ct2 = points.getItem(i+1); - var end = points.getItem(i+2); - - // if the previous segment had a control point, we want to smooth out - // the control points on both sides - if (prevCtlPt) { - var newpts = svgedit.path.smoothControlPoints( prevCtlPt, ct1, curpos ); - if (newpts && newpts.length == 2) { - var prevArr = d[d.length-1].split(','); - prevArr[2] = newpts[0].x; - prevArr[3] = newpts[0].y; - d[d.length-1] = prevArr.join(','); - ct1 = newpts[1]; - } - } - - d.push([ct1.x,ct1.y,ct2.x,ct2.y,end.x,end.y].join(',')); - - curpos = end; - prevCtlPt = ct2; - } - // handle remaining line segments - d.push("L"); - for(;i < N;++i) { - var pt = points.getItem(i); - d.push([pt.x,pt.y].join(",")); - } - d = d.join(" "); - - // create new path element - element = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "id": getId(), - "d": d, - "fill": "none" - } - }); - // No need to call "changed", as this is already done under mouseUp - } - return element; - }; - - return { - mouseDown: function(evt, mouse_target, start_x, start_y) { - if(current_mode === "path") { - mouse_x = start_x; - mouse_y = start_y; - - var x = mouse_x/current_zoom, - y = mouse_y/current_zoom, - stretchy = getElem("path_stretch_line"); - newPoint = [x, y]; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - mouse_x = snapToGrid(mouse_x); - mouse_y = snapToGrid(mouse_y); - } - - if (!stretchy) { - stretchy = document.createElementNS(svgns, "path"); - assignAttributes(stretchy, { - 'id': "path_stretch_line", - 'stroke': "#22C", - 'stroke-width': "0.5", - 'fill': 'none' - }); - stretchy = getElem("selectorParentGroup").appendChild(stretchy); - } - stretchy.setAttribute("display", "inline"); - - var keep = null; - - // if pts array is empty, create path element with M at current point - if (!drawn_path) { - d_attr = "M" + x + "," + y + " "; - drawn_path = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "d": d_attr, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - // set stretchy line to first point - stretchy.setAttribute('d', ['M', mouse_x, mouse_y, mouse_x, mouse_y].join(' ')); - var index = subpath ? svgedit.path.path.segs.length : 0; - svgedit.path.addPointGrip(index, mouse_x, mouse_y); - } - else { - // determine if we clicked on an existing point - var seglist = drawn_path.pathSegList; - var i = seglist.numberOfItems; - var FUZZ = 6/current_zoom; - var clickOnPoint = false; - while(i) { - i --; - var item = seglist.getItem(i); - var px = item.x, py = item.y; - // found a matching point - if ( x >= (px-FUZZ) && x <= (px+FUZZ) && y >= (py-FUZZ) && y <= (py+FUZZ) ) { - clickOnPoint = true; - break; - } - } - - // get path element that we are in the process of creating - var id = getId(); - - // Remove previous path object if previously created - svgedit.path.removePath_(id); - - var newpath = getElem(id); - - var len = seglist.numberOfItems; - // if we clicked on an existing point, then we are done this path, commit it - // (i,i+1) are the x,y that were clicked on - if (clickOnPoint) { - // if clicked on any other point but the first OR - // the first point was clicked on and there are less than 3 points - // then leave the path open - // otherwise, close the path - if (i <= 1 && len >= 2) { - // Create end segment - var abs_x = seglist.getItem(0).x; - var abs_y = seglist.getItem(0).y; - - - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(abs_x, abs_y); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - abs_x, - abs_y, - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - abs_x, - abs_y - ); - } - - var endseg = drawn_path.createSVGPathSegClosePath(); - seglist.appendItem(newseg); - seglist.appendItem(endseg); - } else if(len < 3) { - keep = false; - return keep; - } - $(stretchy).remove(); - - // this will signal to commit the path - element = newpath; - drawn_path = null; - started = false; - - if(subpath) { - if(svgedit.path.path.matrix) { - remapElement(newpath, {}, svgedit.path.path.matrix.inverse()); - } - - var new_d = newpath.getAttribute("d"); - var orig_d = $(svgedit.path.path.elem).attr("d"); - $(svgedit.path.path.elem).attr("d", orig_d + new_d); - $(newpath).remove(); - if(svgedit.path.path.matrix) { - svgedit.path.recalcRotatedPath(); - } - svgedit.path.path.init(); - pathActions.toEditMode(svgedit.path.path.elem); - svgedit.path.path.selectPt(); - return false; - } - } - // else, create a new point, update path element - else { - // Checks if current target or parents are #svgcontent - if(!$.contains(container, getMouseTarget(evt))) { - // Clicked outside canvas, so don't make point - console.log("Clicked outside canvas"); - return false; - } - - var num = drawn_path.pathSegList.numberOfItems; - var last = drawn_path.pathSegList.getItem(num -1); - var lastx = last.x, lasty = last.y; - - if(evt.shiftKey) { var xya = snapToAngle(lastx,lasty,x,y); x=xya.x; y=xya.y; } - - // Use the segment defined by stretchy - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(round(x), round(y)); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - round(x), - round(y), - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - s_seg.x2 / current_zoom, - s_seg.y2 / current_zoom - ); - } - - drawn_path.pathSegList.appendItem(newseg); - - x *= current_zoom; - y *= current_zoom; - - // set stretchy line to latest point - stretchy.setAttribute('d', ['M', x, y, x, y].join(' ')); - var index = num; - if(subpath) index += svgedit.path.path.segs.length; - svgedit.path.addPointGrip(index, x, y); - } -// keep = true; - } - - return; - } - - // TODO: Make sure current_path isn't null at this point - if(!svgedit.path.path) return; - - svgedit.path.path.storeD(); - - var id = evt.target.id; - if (id.substr(0,14) == "pathpointgrip_") { - // Select this point - var cur_pt = svgedit.path.path.cur_pt = parseInt(id.substr(14)); - svgedit.path.path.dragging = [start_x, start_y]; - var seg = svgedit.path.path.segs[cur_pt]; - - // only clear selection if shift is not pressed (otherwise, add - // node to selection) - if (!evt.shiftKey) { - if(svgedit.path.path.selected_pts.length <= 1 || !seg.selected) { - svgedit.path.path.clearSelection(); - } - svgedit.path.path.addPtsToSelection(cur_pt); - } else if(seg.selected) { - svgedit.path.path.removePtFromSelection(cur_pt); - } else { - svgedit.path.path.addPtsToSelection(cur_pt); - } - } else if(id.indexOf("ctrlpointgrip_") == 0) { - svgedit.path.path.dragging = [start_x, start_y]; - - var parts = id.split('_')[1].split('c'); - var cur_pt = parts[0]-0; - var ctrl_num = parts[1]-0; - svgedit.path.path.selectPt(cur_pt, ctrl_num); - } - - // Start selection box - if(!svgedit.path.path.dragging) { - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': start_x * current_zoom, - 'y': start_y * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - }, - mouseMove: function(evt, mouse_x, mouse_y) { - hasMoved = true; - if(current_mode === "path") { - if(!drawn_path) return; - var seglist = drawn_path.pathSegList; - var index = seglist.numberOfItems - 1; - - if(newPoint) { - // First point -// if(!index) return; - - // Set control points - var pointGrip1 = svgedit.path.addCtrlGrip('1c1'); - var pointGrip2 = svgedit.path.addCtrlGrip('0c2'); - - // dragging pointGrip1 - pointGrip1.setAttribute('cx', mouse_x); - pointGrip1.setAttribute('cy', mouse_y); - pointGrip1.setAttribute('display', 'inline'); - - var pt_x = newPoint[0]; - var pt_y = newPoint[1]; - - // set curve - var seg = seglist.getItem(index); - var cur_x = mouse_x / current_zoom; - var cur_y = mouse_y / current_zoom; - var alt_x = (pt_x + (pt_x - cur_x)); - var alt_y = (pt_y + (pt_y - cur_y)); - - if (!evt.altKey) { - pointGrip2.setAttribute('cx', alt_x * current_zoom); - pointGrip2.setAttribute('cy', alt_y * current_zoom); - pointGrip2.setAttribute('display', 'inline'); - } - - var ctrlLine = svgedit.path.getCtrlLine(1); - var ctrlLine2 = svgedit.path.getCtrlLine(2); - assignAttributes(ctrlLine, { - x1: mouse_x, - y1: mouse_y, - x2: pt_x, - y2: pt_y, - display: 'inline' - }); - - if (!evt.altKey) { - assignAttributes(ctrlLine2, { - x1: alt_x * current_zoom, - y1: alt_y * current_zoom, - x2: pt_x, - y2: pt_y, - display: 'inline' - }); - } - - if(index === 0) { - firstCtrl = [mouse_x, mouse_y]; - } else { - var last_x, last_y; - - var last = seglist.getItem(index - 1); - var last_x = last.x; - var last_y = last.y - - if(last.pathSegType === 6) { - last_x += (last_x - last.x2); - last_y += (last_y - last.y2); - } else if(firstCtrl) { - last_x = firstCtrl[0]/current_zoom; - last_y = firstCtrl[1]/current_zoom; - } - svgedit.path.replacePathSeg(6, index, [pt_x, pt_y, last_x, last_y, alt_x, alt_y], drawn_path); - } - } else { - var stretchy = getElem("path_stretch_line"); - if (stretchy) { - var prev = seglist.getItem(index); - if(prev.pathSegType === 6) { - var prev_x = prev.x + (prev.x - prev.x2); - var prev_y = prev.y + (prev.y - prev.y2); - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, prev_x * current_zoom, prev_y * current_zoom, mouse_x, mouse_y], stretchy); - } else if(firstCtrl) { - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, firstCtrl[0], firstCtrl[1], mouse_x, mouse_y], stretchy); - } else { - svgedit.path.replacePathSeg(4, 1, [mouse_x, mouse_y], stretchy); - } - } - } - return; - } - // if we are dragging a point, let's move it - if (svgedit.path.path.dragging) { - var pt = svgedit.path.getPointFromGrip({ - x: svgedit.path.path.dragging[0], - y: svgedit.path.path.dragging[1] - }, svgedit.path.path); - var mpt = svgedit.path.getPointFromGrip({ - x: mouse_x, - y: mouse_y - }, svgedit.path.path); - var diff_x = mpt.x - pt.x; - var diff_y = mpt.y - pt.y; - svgedit.path.path.dragging = [mouse_x, mouse_y]; - - if(svgedit.path.path.dragctrl) { - svgedit.path.path.moveCtrl(diff_x, diff_y); - } else { - svgedit.path.path.movePts(diff_x, diff_y); - } - } else { - svgedit.path.path.selected_pts = []; - svgedit.path.path.eachSeg(function(i) { - var seg = this; - if(!seg.next && !seg.prev) return; - - var item = seg.item; - var rbb = rubberBox.getBBox(); - - var pt = svgedit.path.getGripPt(seg); - var pt_bb = { - x: pt.x, - y: pt.y, - width: 0, - height: 0 - }; - - var sel = svgedit.math.rectsIntersect(rbb, pt_bb); - - this.select(sel); - //Note that addPtsToSelection is not being run - if(sel) svgedit.path.path.selected_pts.push(seg.index); - }); - - } - }, - mouseUp: function(evt, element, mouse_x, mouse_y) { - - // Create mode - if(current_mode === "path") { - newPoint = null; - if(!drawn_path) { - element = getElem(getId()); - started = false; - firstCtrl = null; - } - - return { - keep: true, - element: element - } - } - - // Edit mode - - if (svgedit.path.path.dragging) { - var last_pt = svgedit.path.path.cur_pt; - - svgedit.path.path.dragging = false; - svgedit.path.path.dragctrl = false; - svgedit.path.path.update(); - - - if(hasMoved) { - svgedit.path.path.endChanges("Move path point(s)"); - } - - if(!evt.shiftKey && !hasMoved) { - svgedit.path.path.selectPt(last_pt); - } - } - else if(rubberBox && rubberBox.getAttribute('display') != 'none') { - // Done with multi-node-select - rubberBox.setAttribute("display", "none"); - - if(rubberBox.getAttribute('width') <= 2 && rubberBox.getAttribute('height') <= 2) { - pathActions.toSelectMode(evt.target); - } - - // else, move back to select mode - } else { - pathActions.toSelectMode(evt.target); - } - hasMoved = false; - }, - toEditMode: function(element) { - svgedit.path.path = svgedit.path.getPath_(element); - current_mode = "pathedit"; - clearSelection(); - svgedit.path.path.show(true).update(); - svgedit.path.path.oldbbox = svgedit.utilities.getBBox(svgedit.path.path.elem); - subpath = false; - }, - toSelectMode: function(elem) { - var selPath = (elem == svgedit.path.path.elem); - current_mode = "select"; - svgedit.path.path.show(false); - current_path = false; - clearSelection(); - - if(svgedit.path.path.matrix) { - // Rotated, so may need to re-calculate the center - svgedit.path.recalcRotatedPath(); - } - - if(selPath) { - call("selected", [elem]); - addToSelection([elem], true); - } - }, - addSubPath: function(on) { - if(on) { - // Internally we go into "path" mode, but in the UI it will - // still appear as if in "pathedit" mode. - current_mode = "path"; - subpath = true; - } else { - pathActions.clear(true); - pathActions.toEditMode(svgedit.path.path.elem); - } - }, - select: function(target) { - if (current_path === target) { - pathActions.toEditMode(target); - current_mode = "pathedit"; - } // going into pathedit mode - else { - current_path = target; - } - }, - reorient: function() { - var elem = selectedElements[0]; - if(!elem) return; - var angle = getRotationAngle(elem); - if(angle == 0) return; - - var batchCmd = new BatchCommand("Reorient path"); - var changes = { - d: elem.getAttribute('d'), - transform: elem.getAttribute('transform') - }; - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - clearSelection(); - this.resetOrientation(elem); - - addCommandToHistory(batchCmd); - - // Set matrix to null - svgedit.path.getPath_(elem).show(false).matrix = null; - - this.clear(); - - addToSelection([elem], true); - call("changed", selectedElements); - }, - - clear: function(remove) { - current_path = null; - if (drawn_path) { - var elem = getElem(getId()); - $(getElem("path_stretch_line")).remove(); - $(elem).remove(); - $(getElem("pathpointgrip_container")).find('*').attr('display', 'none'); - drawn_path = firstCtrl = null; - started = false; - } else if (current_mode == "pathedit") { - this.toSelectMode(); - } - if(svgedit.path.path) svgedit.path.path.init().show(false); - }, - resetOrientation: function(path) { - if(path == null || path.nodeName != 'path') return false; - var tlist = getTransformList(path); - var m = transformListToTransform(tlist).matrix; - tlist.clear(); - path.removeAttribute("transform"); - var segList = path.pathSegList; - - // Opera/win/non-EN throws an error here. - // TODO: Find out why! - // Presumed fixed in Opera 10.5, so commented out for now - -// try { - var len = segList.numberOfItems; -// } catch(err) { -// var fixed_d = pathActions.convertPath(path); -// path.setAttribute('d', fixed_d); -// segList = path.pathSegList; -// var len = segList.numberOfItems; -// } - var last_x, last_y; - - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - var type = seg.pathSegType; - if(type == 1) continue; - var pts = []; - $.each(['',1,2], function(j, n) { - var x = seg['x'+n], y = seg['y'+n]; - if(x !== undefined && y !== undefined) { - var pt = transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); - } - }); - svgedit.path.replacePathSeg(type, i, pts, path); - } - - reorientGrads(path, m); - - - }, - zoomChange: function() { - if(current_mode == "pathedit") { - svgedit.path.path.update(); - } - }, - getNodePoint: function() { - var sel_pt = svgedit.path.path.selected_pts.length ? svgedit.path.path.selected_pts[0] : 1; - - var seg = svgedit.path.path.segs[sel_pt]; - return { - x: seg.item.x, - y: seg.item.y, - type: seg.type - }; - }, - linkControlPoints: function(linkPoints) { - svgedit.path.setLinkControlPoints(linkPoints); - }, - clonePathNode: function() { - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var segs = svgedit.path.path.segs; - - var i = sel_pts.length; - var nums = []; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.addSeg(pt); - - nums.push(pt + i); - nums.push(pt + i + 1); - } - svgedit.path.path.init().addPtsToSelection(nums); - - svgedit.path.path.endChanges("Clone path node(s)"); - }, - opencloseSubPath: function() { - var sel_pts = svgedit.path.path.selected_pts; - // Only allow one selected node for now - if(sel_pts.length !== 1) return; - - var elem = svgedit.path.path.elem; - var list = elem.pathSegList; - - var len = list.numberOfItems; - - var index = sel_pts[0]; - - var open_pt = null; - var start_item = null; - - // Check if subpath is already open - svgedit.path.path.eachSeg(function(i) { - if(this.type === 2 && i <= index) { - start_item = this.item; - } - if(i <= index) return true; - if(this.type === 2) { - // Found M first, so open - open_pt = i; - return false; - } else if(this.type === 1) { - // Found Z first, so closed - open_pt = false; - return false; - } - }); - - if(open_pt == null) { - // Single path, so close last seg - open_pt = svgedit.path.path.segs.length - 1; - } - - if(open_pt !== false) { - // Close this path - - // Create a line going to the previous "M" - var newseg = elem.createSVGPathSegLinetoAbs(start_item.x, start_item.y); - - var closer = elem.createSVGPathSegClosePath(); - if(open_pt == svgedit.path.path.segs.length - 1) { - list.appendItem(newseg); - list.appendItem(closer); - } else { - svgedit.path.insertItemBefore(elem, closer, open_pt); - svgedit.path.insertItemBefore(elem, newseg, open_pt); - } - - svgedit.path.path.init().selectPt(open_pt+1); - return; - } - - - - // M 1,1 L 2,2 L 3,3 L 1,1 z // open at 2,2 - // M 2,2 L 3,3 L 1,1 - - // M 1,1 L 2,2 L 1,1 z M 4,4 L 5,5 L6,6 L 5,5 z - // M 1,1 L 2,2 L 1,1 z [M 4,4] L 5,5 L(M)6,6 L 5,5 z - - var seg = svgedit.path.path.segs[index]; - - if(seg.mate) { - list.removeItem(index); // Removes last "L" - list.removeItem(index); // Removes the "Z" - svgedit.path.path.init().selectPt(index - 1); - return; - } - - var last_m, z_seg; - - // Find this sub-path's closing point and remove - for(var i=0; i<list.numberOfItems; i++) { - var item = list.getItem(i); - - if(item.pathSegType === 2) { - // Find the preceding M - last_m = i; - } else if(i === index) { - // Remove it - list.removeItem(last_m); -// index--; - } else if(item.pathSegType === 1 && index < i) { - // Remove the closing seg of this subpath - z_seg = i-1; - list.removeItem(i); - break; - } - } - - var num = (index - last_m) - 1; - - while(num--) { - svgedit.path.insertItemBefore(elem, list.getItem(last_m), z_seg); - } - - var pt = list.getItem(last_m); - - // Make this point the new "M" - svgedit.path.replacePathSeg(2, last_m, [pt.x, pt.y]); - - var i = index - - svgedit.path.path.init().selectPt(0); - }, - deletePathNode: function() { - if(!pathActions.canDeleteNodes) return; - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var i = sel_pts.length; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.deleteSeg(pt); - } - - // Cleanup - var cleanup = function() { - var segList = svgedit.path.path.elem.pathSegList; - var len = segList.numberOfItems; - - var remItems = function(pos, count) { - while(count--) { - segList.removeItem(pos); - } - } - - if(len <= 1) return true; - - while(len--) { - var item = segList.getItem(len); - if(item.pathSegType === 1) { - var prev = segList.getItem(len-1); - var nprev = segList.getItem(len-2); - if(prev.pathSegType === 2) { - remItems(len-1, 2); - cleanup(); - break; - } else if(nprev.pathSegType === 2) { - remItems(len-2, 3); - cleanup(); - break; - } - - } else if(item.pathSegType === 2) { - if(len > 0) { - var prev_type = segList.getItem(len-1).pathSegType; - // Path has M M - if(prev_type === 2) { - remItems(len-1, 1); - cleanup(); - break; - // Entire path ends with Z M - } else if(prev_type === 1 && segList.numberOfItems-1 === len) { - remItems(len, 1); - cleanup(); - break; - } - } - } - } - return false; - } - - cleanup(); - - // Completely delete a path with 1 or 0 segments - if(svgedit.path.path.elem.pathSegList.numberOfItems <= 1) { - pathActions.toSelectMode(svgedit.path.path.elem); - canvas.deleteSelectedElements(); - return; - } - - svgedit.path.path.init(); - - svgedit.path.path.clearSelection(); - - // TODO: Find right way to select point now - // path.selectPt(sel_pt); - if(window.opera) { // Opera repaints incorrectly - var cp = $(svgedit.path.path.elem); cp.attr('d',cp.attr('d')); - } - svgedit.path.path.endChanges("Delete path node(s)"); - }, - smoothPolylineIntoPath: smoothPolylineIntoPath, - setSegType: function(v) { - svgedit.path.path.setSegType(v); - }, - moveNode: function(attr, newValue) { - var sel_pts = svgedit.path.path.selected_pts; - if(!sel_pts.length) return; - - svgedit.path.path.storeD(); - - // Get first selected point - var seg = svgedit.path.path.segs[sel_pts[0]]; - var diff = {x:0, y:0}; - diff[attr] = newValue - seg.item[attr]; - - seg.move(diff.x, diff.y); - svgedit.path.path.endChanges("Move path point"); - }, - fixEnd: function(elem) { - // Adds an extra segment if the last seg before a Z doesn't end - // at its M point - // M0,0 L0,100 L100,100 z - var segList = elem.pathSegList; - var len = segList.numberOfItems; - var last_m; - for (var i = 0; i < len; ++i) { - var item = segList.getItem(i); - if(item.pathSegType === 2) { - last_m = item; - } - - if(item.pathSegType === 1) { - var prev = segList.getItem(i-1); - if(prev.x != last_m.x || prev.y != last_m.y) { - // Add an L segment here - var newseg = elem.createSVGPathSegLinetoAbs(last_m.x, last_m.y); - svgedit.path.insertItemBefore(elem, newseg, i); - // Can this be done better? - pathActions.fixEnd(elem); - break; - } - - } - } - if(svgedit.browser.isWebkit()) resetD(elem); - }, - // Convert a path to one with only absolute or relative values - convertPath: function(path, toRel) { - var segList = path.pathSegList; - var len = segList.numberOfItems; - var curx = 0, cury = 0; - var d = ""; - var last_m = null; - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - // if these properties are not in the segment, set them to zero - var x = seg.x || 0, - y = seg.y || 0, - x1 = seg.x1 || 0, - y1 = seg.y1 || 0, - x2 = seg.x2 || 0, - y2 = seg.y2 || 0; - - var type = seg.pathSegType; - var letter = pathMap[type]['to'+(toRel?'Lower':'Upper')+'Case'](); - - var addToD = function(pnts, more, last) { - var str = ''; - var more = more?' '+more.join(' '):''; - var last = last?' '+svgedit.units.shortFloat(last):''; - $.each(pnts, function(i, pnt) { - pnts[i] = svgedit.units.shortFloat(pnt); - }); - d += letter + pnts.join(' ') + more + last; - } - - switch (type) { - case 1: // z,Z closepath (Z/z) - d += "z"; - break; - case 12: // absolute horizontal line (H) - x -= curx; - case 13: // relative horizontal line (h) - if(toRel) { - curx += x; - letter = 'l'; - } else { - x += curx; - curx = x; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[x, cury]]); - break; - case 14: // absolute vertical line (V) - y -= cury; - case 15: // relative vertical line (v) - if(toRel) { - cury += y; - letter = 'l'; - } else { - y += cury; - cury = y; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[curx, y]]); - break; - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - x -= curx; - y -= cury; - case 5: // relative line (l) - case 3: // relative move (m) - // If the last segment was a "z", this must be relative to - if(last_m && segList.getItem(i-1).pathSegType === 1 && !toRel) { - curx = last_m[0]; - cury = last_m[1]; - } - - case 19: // relative smooth quad (t) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - if(type === 3) last_m = [curx, cury]; - - addToD([[x,y]]); - break; - case 6: // absolute cubic (C) - x -= curx; x1 -= curx; x2 -= curx; - y -= cury; y1 -= cury; y2 -= cury; - case 7: // relative cubic (c) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; x2 += curx; - y += cury; y1 += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x2,y2],[x,y]]); - break; - case 8: // absolute quad (Q) - x -= curx; x1 -= curx; - y -= cury; y1 -= cury; - case 9: // relative quad (q) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; - y += cury; y1 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x,y]]); - break; - case 10: // absolute elliptical arc (A) - x -= curx; - y -= cury; - case 11: // relative elliptical arc (a) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - addToD([[seg.r1,seg.r2]], [ - seg.angle, - (seg.largeArcFlag ? 1 : 0), - (seg.sweepFlag ? 1 : 0) - ],[x,y] - ); - break; - case 16: // absolute smooth cubic (S) - x -= curx; x2 -= curx; - y -= cury; y2 -= cury; - case 17: // relative smooth cubic (s) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x2 += curx; - y += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x2,y2],[x,y]]); - break; - } // switch on path segment type - } // for each segment - return d; - } - } -}(); -// end pathActions - -// Group: Serialization - -// Function: removeUnusedDefElems -// Looks at DOM elements inside the <defs> to see if they are referred to, -// removes them from the DOM if they are not. -// -// Returns: -// The amount of elements that were removed -var removeUnusedDefElems = this.removeUnusedDefElems = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if(!defs || !defs.length) return 0; - -// if(!defs.firstChild) return; - - var defelem_uses = [], - numRemoved = 0; - var attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']; - var alen = attrs.length; - - var all_els = svgcontent.getElementsByTagNameNS(svgns, '*'); - var all_len = all_els.length; - - for(var i=0; i<all_len; i++) { - var el = all_els[i]; - for(var j = 0; j < alen; j++) { - var ref = getUrlFromAttr(el.getAttribute(attrs[j])); - if(ref) { - defelem_uses.push(ref.substr(1)); - } - } - - // gradients can refer to other gradients - var href = getHref(el); - if (href && href.indexOf('#') === 0) { - defelem_uses.push(href.substr(1)); - } - }; - - var defelems = $(defs).find("linearGradient, radialGradient, filter, marker, svg, symbol"); - defelem_ids = [], - i = defelems.length; - while (i--) { - var defelem = defelems[i]; - var id = defelem.id; - if(defelem_uses.indexOf(id) < 0) { - // Not found, so remove (but remember) - removedElements[id] = defelem; - defelem.parentNode.removeChild(defelem); - numRemoved++; - } - } - - return numRemoved; -} - -// Function: svgCanvasToString -// Main function to set up the SVG content for output -// -// Returns: -// String containing the SVG image for output -this.svgCanvasToString = function() { - // keep calling it until there are none to remove - while (removeUnusedDefElems() > 0) {}; - - pathActions.clear(true); - - // Keep SVG-Edit comment on top - $.each(svgcontent.childNodes, function(i, node) { - if(i && node.nodeType === 8 && node.data.indexOf('Created with') >= 0) { - svgcontent.insertBefore(node, svgcontent.firstChild); - } - }); - - // Move out of in-group editing mode - if(current_group) { - leaveContext(); - selectOnly([current_group]); - } - - var naked_svgs = []; - - // Unwrap gsvg if it has no special attributes (only id and style) - $(svgcontent).find('g:data(gsvg)').each(function() { - var attrs = this.attributes; - var len = attrs.length; - for(var i=0; i<len; i++) { - if(attrs[i].nodeName == 'id' || attrs[i].nodeName == 'style') { - len--; - } - } - // No significant attributes, so ungroup - if(len <= 0) { - var svg = this.firstChild; - naked_svgs.push(svg); - $(this).replaceWith(svg); - } - }); - var output = this.svgToString(svgcontent, 0); - - // Rewrap gsvg - if(naked_svgs.length) { - $(naked_svgs).each(function() { - groupSvgElem(this); - }); - } - - return output; -}; - -// Function: svgToString -// Sub function ran on each SVG element to convert it to a string as desired -// -// Parameters: -// elem - The SVG element to convert -// indent - Integer with the amount of spaces to indent this tag -// -// Returns: -// String with the given element as an SVG tag -this.svgToString = function(elem, indent) { - var out = new Array(), toXml = svgedit.utilities.toXml; - var unit = curConfig.baseUnit; - var unit_re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - - if (elem) { - cleanupElement(elem); - var attrs = elem.attributes, - attr, - i, - childs = elem.childNodes; - - for (var i=0; i<indent; i++) out.push(" "); - out.push("<"); out.push(elem.nodeName); - if(elem.id === 'svgcontent') { - // Process root element separately - var res = getResolution(); - - var vb = ""; - // TODO: Allow this by dividing all values by current baseVal - // Note that this also means we should properly deal with this on import -// if(curConfig.baseUnit !== "px") { -// var unit = curConfig.baseUnit; -// var unit_m = svgedit.units.getTypeMap()[unit]; -// res.w = svgedit.units.shortFloat(res.w / unit_m) -// res.h = svgedit.units.shortFloat(res.h / unit_m) -// vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"'; -// res.w += unit; -// res.h += unit; -// } - - if(unit !== "px") { - res.w = svgedit.units.convertUnit(res.w, unit) + unit; - res.h = svgedit.units.convertUnit(res.h, unit) + unit; - } - - out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="'+svgns+'"'); - - var nsuris = {}; - - // Check elements for namespaces, add if found - $(elem).find('*').andSelf().each(function() { - var el = this; - $.each(this.attributes, function(i, attr) { - var uri = attr.namespaceURI; - if(uri && !nsuris[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml' ) { - nsuris[uri] = true; - out.push(" xmlns:" + nsMap[uri] + '="' + uri +'"'); - } - }); - }); - - var i = attrs.length; - var attr_names = ['width','height','xmlns','x','y','viewBox','id','overflow']; - while (i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - - // Namespaces have already been dealt with, so skip - if(attr.nodeName.indexOf('xmlns:') === 0) continue; - - // only serialize attributes we don't use internally - if (attrVal != "" && attr_names.indexOf(attr.localName) == -1) - { - - if(!attr.namespaceURI || nsMap[attr.namespaceURI]) { - out.push(' '); - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } else { - // Skip empty defs - if(elem.nodeName === 'defs' && !elem.firstChild) return; - - var moz_attrs = ['-moz-math-font-style', '_moz-math-font-style']; - for (var i=attrs.length-1; i>=0; i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - //remove bogus attributes added by Gecko - if (moz_attrs.indexOf(attr.localName) >= 0) continue; - if (attrVal != "") { - if(attrVal.indexOf('pointer-events') === 0) continue; - if(attr.localName === "class" && attrVal.indexOf('se_') === 0) continue; - out.push(" "); - if(attr.localName === 'd') attrVal = pathActions.convertPath(elem, true); - if(!isNaN(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal); - } else if(unit_re.test(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal) + unit; - } - - // Embed images when saving - if(save_options.apply - && elem.nodeName === 'image' - && attr.localName === 'href' - && save_options.images - && save_options.images === 'embed') - { - var img = encodableImages[attrVal]; - if(img) attrVal = img; - } - - // map various namespaces to our fixed namespace prefixes - // (the default xmlns attribute itself does not get a prefix) - if(!attr.namespaceURI || attr.namespaceURI == svgns || nsMap[attr.namespaceURI]) { - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } - - if (elem.hasChildNodes()) { - out.push(">"); - indent++; - var bOneLine = false; - - for (var i=0; i<childs.length; i++) - { - var child = childs.item(i); - switch(child.nodeType) { - case 1: // element node - out.push("\n"); - out.push(this.svgToString(childs.item(i), indent)); - break; - case 3: // text node - var str = child.nodeValue.replace(/^\s+|\s+$/g, ""); - if (str != "") { - bOneLine = true; - out.push(toXml(str) + ""); - } - break; - case 4: // cdata node - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<![CDATA["); - out.push(child.nodeValue); - out.push("]]>"); - break; - case 8: // comment - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<!--"); - out.push(child.data); - out.push("-->"); - break; - } // switch on node type - } - indent--; - if (!bOneLine) { - out.push("\n"); - for (var i=0; i<indent; i++) out.push(" "); - } - out.push("</"); out.push(elem.nodeName); out.push(">"); - } else { - out.push("/>"); - } - } - return out.join(''); -}; // end svgToString() - -// Function: embedImage -// Converts a given image file to a data URL when possible, then runs a given callback -// -// Parameters: -// val - String with the path/URL of the image -// callback - Optional function to run when image data is found, supplies the -// result (data URL or false) as first parameter. -this.embedImage = function(val, callback) { - - // load in the image and once it's loaded, get the dimensions - $(new Image()).load(function() { - // create a canvas the same size as the raster image - var canvas = document.createElement("canvas"); - canvas.width = this.width; - canvas.height = this.height; - // load the raster image into the canvas - canvas.getContext("2d").drawImage(this,0,0); - // retrieve the data: URL - try { - var urldata = ';svgedit_url=' + encodeURIComponent(val); - urldata = canvas.toDataURL().replace(';base64',urldata+';base64'); - encodableImages[val] = urldata; - } catch(e) { - encodableImages[val] = false; - } - last_good_img_url = val; - if(callback) callback(encodableImages[val]); - }).attr('src',val); -} - -// Function: setGoodImage -// Sets a given URL to be a "last good image" URL -this.setGoodImage = function(val) { - last_good_img_url = val; -} - -this.open = function() { - // Nothing by default, handled by optional widget/extension -}; - -// Function: save -// Serializes the current drawing into SVG XML text and returns it to the 'saved' handler. -// This function also includes the XML prolog. Clients of the SvgCanvas bind their save -// function to the 'saved' event. -// -// Returns: -// Nothing -this.save = function(opts) { - // remove the selected outline before serializing - clearSelection(); - // Update save options if provided - if(opts) $.extend(save_options, opts); - save_options.apply = true; - - // no need for doctype, see http://jwatt.org/svg/authoring/#doctype-declaration - var str = this.svgCanvasToString(); - call("saved", str); -}; - -// Function: rasterExport -// Generates a PNG Data URL based on the current image, then calls "exported" -// with an object including the string and any issues found -this.rasterExport = function() { - // remove the selected outline before serializing - clearSelection(); - - // Check for known CanVG issues - var issues = []; - - // Selector and notice - var issue_list = { - 'feGaussianBlur': uiStrings.exportNoBlur, - 'foreignObject': uiStrings.exportNoforeignObject, - '[stroke-dasharray]': uiStrings.exportNoDashArray - }; - var content = $(svgcontent); - - // Add font/text check if Canvas Text API is not implemented - if(!("font" in $('<canvas>')[0].getContext('2d'))) { - issue_list['text'] = uiStrings.exportNoText; - } - - $.each(issue_list, function(sel, descr) { - if(content.find(sel).length) { - issues.push(descr); - } - }); - - var str = this.svgCanvasToString(); - call("exported", {svg: str, issues: issues}); -}; - -// Function: getSvgString -// Returns the current drawing as raw SVG XML text. -// -// Returns: -// The current drawing as raw SVG XML text. -this.getSvgString = function() { - save_options.apply = false; - return this.svgCanvasToString(); -}; - -// Function: randomizeIds -// This function determines whether to use a nonce in the prefix, when -// generating IDs for future documents in SVG-Edit. -// -// Parameters: -// an opional boolean, which, if true, adds a nonce to the prefix. Thus -// svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true) -// -// if you're controlling SVG-Edit externally, and want randomized IDs, call -// this BEFORE calling svgCanvas.setSvgString -// -this.randomizeIds = function() { - if (arguments.length > 0 && arguments[0] == false) { - svgedit.draw.randomizeIds(false, getCurrentDrawing()); - } else { - svgedit.draw.randomizeIds(true, getCurrentDrawing()); - } -}; - -// Function: uniquifyElems -// Ensure each element has a unique ID -// -// Parameters: -// g - The parent element of the tree to give unique IDs -var uniquifyElems = this.uniquifyElems = function(g) { - var ids = {}; - // TODO: Handle markers and connectors. These are not yet re-identified properly - // as their referring elements do not get remapped. - // - // <marker id='se_marker_end_svg_7'/> - // <polyline id='svg_7' se:connector='svg_1 svg_6' marker-end='url(#se_marker_end_svg_7)'/> - // - // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute - // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute - var ref_elems = ["filter", "linearGradient", "pattern", "radialGradient", "symbol", "textPath", "use"]; - - svgedit.utilities.walkTree(g, function(n) { - // if it's an element node - if (n.nodeType == 1) { - // and the element has an ID - if (n.id) { - // and we haven't tracked this ID yet - if (!(n.id in ids)) { - // add this id to our map - ids[n.id] = {elem:null, attrs:[], hrefs:[]}; - } - ids[n.id]["elem"] = n; - } - - // now search for all attributes on this element that might refer - // to other elements - $.each(ref_attrs,function(i,attr) { - var attrnode = n.getAttributeNode(attr); - if (attrnode) { - // the incoming file has been sanitized, so we should be able to safely just strip off the leading # - var url = svgedit.utilities.getUrlFromAttr(attrnode.value), - refid = url ? url.substr(1) : null; - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["attrs"].push(attrnode); - } - } - }); - - // check xlink:href now - var href = svgedit.utilities.getHref(n); - // TODO: what if an <image> or <a> element refers to an element internally? - if(href && ref_elems.indexOf(n.nodeName) >= 0) - { - var refid = href.substr(1); - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["hrefs"].push(n); - } - } - } - }); - - // in ids, we now have a map of ids, elements and attributes, let's re-identify - for (var oldid in ids) { - if (!oldid) continue; - var elem = ids[oldid]["elem"]; - if (elem) { - var newid = getNextId(); - - // assign element its new id - elem.id = newid; - - // remap all url() attributes - var attrs = ids[oldid]["attrs"]; - var j = attrs.length; - while (j--) { - var attr = attrs[j]; - attr.ownerElement.setAttribute(attr.name, "url(#" + newid + ")"); - } - - // remap all href attributes - var hreffers = ids[oldid]["hrefs"]; - var k = hreffers.length; - while (k--) { - var hreffer = hreffers[k]; - svgedit.utilities.setHref(hreffer, "#"+newid); - } - } - } -} - -// Function setUseData -// Assigns reference data for each use element -var setUseData = this.setUseData = function(parent) { - var elems = $(parent); - - if(parent.tagName !== 'use') { - elems = elems.find('use'); - } - - elems.each(function() { - var id = getHref(this).substr(1); - var ref_elem = getElem(id); - if(!ref_elem) return; - $(this).data('ref', ref_elem); - if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') { - $(this).data('symbol', ref_elem).data('ref', ref_elem); - } - }); -} - -// Function convertGradients -// Converts gradients from userSpaceOnUse to objectBoundingBox -var convertGradients = this.convertGradients = function(elem) { - var elems = $(elem).find('linearGradient, radialGradient'); - if(!elems.length && svgedit.browser.isWebkit()) { - // Bug in webkit prevents regular *Gradient selector search - elems = $(elem).find('*').filter(function() { - return (this.tagName.indexOf('Gradient') >= 0); - }); - } - - elems.each(function() { - var grad = this; - if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { - // TODO: Support more than one element with this ref by duplicating parent grad - var elems = $(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - if(!elems.length) return; - - // get object's bounding box - var bb = svgedit.utilities.getBBox(elems[0]); - - // This will occur if the element is inside a <defs> or a <symbol>, - // in which we shouldn't need to convert anyway. - if(!bb) return; - - if(grad.tagName === 'linearGradient') { - var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); - - // If has transform, convert - var tlist = grad.gradientTransform.baseVal; - if(tlist && tlist.numberOfItems > 0) { - var m = transformListToTransform(tlist).matrix; - var pt1 = transformPoint(g_coords.x1, g_coords.y1, m); - var pt2 = transformPoint(g_coords.x2, g_coords.y2, m); - - g_coords.x1 = pt1.x; - g_coords.y1 = pt1.y; - g_coords.x2 = pt2.x; - g_coords.y2 = pt2.y; - grad.removeAttribute('gradientTransform'); - } - - $(grad).attr({ - x1: (g_coords.x1 - bb.x) / bb.width, - y1: (g_coords.y1 - bb.y) / bb.height, - x2: (g_coords.x2 - bb.x) / bb.width, - y2: (g_coords.y2 - bb.y) / bb.height - }); - grad.removeAttribute('gradientUnits'); - } else { - // Note: radialGradient elements cannot be easily converted - // because userSpaceOnUse will keep circular gradients, while - // objectBoundingBox will x/y scale the gradient according to - // its bbox. - - // For now we'll do nothing, though we should probably have - // the gradient be updated as the element is moved, as - // inkscape/illustrator do. - -// var g_coords = $(grad).attr(['cx', 'cy', 'r']); -// -// $(grad).attr({ -// cx: (g_coords.cx - bb.x) / bb.width, -// cy: (g_coords.cy - bb.y) / bb.height, -// r: g_coords.r -// }); -// -// grad.removeAttribute('gradientUnits'); - } - - - } - }); -} - -// Function: convertToGroup -// Converts selected/given <use> 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']); - - var vb = elem.getAttribute('viewBox'); - - if(vb) { - var nums = vb.split(' '); - pos.x -= +nums[0]; - pos.y -= +nums[1]; - } - - // Not ideal, but works - ts += " translate(" + (pos.x || 0) + "," + (pos.y || 0) + ")"; - - var prev = $elem.prev(); - - // Remove <use> element - batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].nextSibling, $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)); - } - - // Duplicate the gradients for Gecko, since they weren't included in the <symbol> - if(svgedit.browser.isGecko()) { - var dupeGrads = $(findDefs()).children('linearGradient,radialGradient,pattern').clone(); - $(g).append(dupeGrads); - } - - if (ts) { - g.setAttribute("transform", ts); - } - - var parent = elem.parentNode; - - uniquifyElems(g); - - // Put the dupe gradients back into <defs> (after uniquifying them) - if(svgedit.browser.isGecko()) { - $(findDefs()).append( $(g).find('linearGradient,radialGradient,pattern') ); - } - - // now give the g itself a new id - g.id = getNextId(); - - prev.after(g); - - if(parent) { - if(!has_more) { - // remove symbol/svg element - var nextSibling = elem.nextSibling; - parent.removeChild(elem); - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - } - - setUseData(g); - - if(svgedit.browser.isGecko()) { - convertGradients(findDefs()); - } else { - convertGradients(g); - } - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - // Give ID for any visible element missing one - $(g).find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - selectOnly([g]); - - var cm = pushGroupProperties(g, true); - if(cm) { - batchCmd.addSubCommand(cm); - } - - addCommandToHistory(batchCmd); - - } else { - console.log('Unexpected element to ungroup:', elem); - } -} - -// -// Function: setSvgString -// This function sets the current drawing as the input SVG XML. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the set was unsuccessful, true otherwise. -this.setSvgString = function(xmlString) { - try { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - var batchCmd = new BatchCommand("Change Source"); - - // remove old svg document - var nextSibling = svgcontent.nextSibling; - var oldzoom = svgroot.removeChild(svgcontent); - batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgroot)); - - // set new svg document - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svgcontent = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svgcontent = svgdoc.importNode(newDoc.documentElement, true); - } - - svgroot.appendChild(svgcontent); - var content = $(svgcontent); - - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - - // retrieve or set the nonce - var nonce = getCurrentDrawing().getNonce(); - if (nonce) { - call("setnonce", nonce); - } else { - call("unsetnonce"); - } - - // change image href vals if possible - content.find('image').each(function() { - var image = this; - preventClickDefault(image); - var val = getHref(this); - 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); - }); - - // Wrap child SVGs in group elements - content.find('svg').each(function() { - // Skip if it's in a <defs> - if($(this).closest('defs').length) return; - - uniquifyElems(this); - - // Check if it already has a gsvg group - var pa = this.parentNode; - if(pa.childNodes.length === 1 && pa.nodeName === 'g') { - $(pa).data('gsvg', this); - pa.id = pa.id || getNextId(); - } else { - groupSvgElem(this); - } - }); - - // For Firefox: Put all paint elems in defs - if(svgedit.browser.isGecko()) { - content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); - } - - - // Set ref element for <use> elements - - // TODO: This should also be done if the object is re-added through "redo" - setUseData(content); - - convertGradients(content[0]); - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - var attrs = { - id: 'svgcontent', - overflow: curConfig.show_outside_canvas?'visible':'hidden' - }; - - var percs = false; - - // determine proper size - if (content.attr("viewBox")) { - var vb = content.attr("viewBox").split(' '); - attrs.width = vb[2]; - attrs.height = vb[3]; - } - // handle content that doesn't have a viewBox - else { - $.each(['width', 'height'], function(i, dim) { - // Set to 100 if not given - var val = content.attr(dim); - - if(!val) val = '100%'; - - if((val+'').substr(-1) === "%") { - // Use user units if percentage given - percs = true; - } else { - attrs[dim] = convertToNum(dim, val); - } - }); - } - - // identify layers - identifyLayers(); - - // Give ID for any visible layer children missing one - content.children().find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - // Percentage width/height, so let's base it on visible elements - if(percs) { - var bb = getStrokedBBox(); - attrs.width = bb.width + bb.x; - attrs.height = bb.height + bb.y; - } - - // Just in case negative numbers are given or - // result from the percs calculation - if(attrs.width <= 0) attrs.width = 100; - if(attrs.height <= 0) attrs.height = 100; - - content.attr(attrs); - this.contentW = attrs['width']; - this.contentH = attrs['height']; - - batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); - // update root to the correct size - var changes = content.attr(["width", "height"]); - batchCmd.addSubCommand(new ChangeElementCommand(svgroot, changes)); - - // reset zoom - current_zoom = 1; - - // reset transform lists - svgedit.transformlist.resetListMap(); - clearSelection(); - svgedit.path.clearData(); - svgroot.appendChild(selectorManager.selectorParentGroup); - - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// Function: importSvgString -// This function imports the input SVG XML as a <symbol> in the <defs>, then adds a -// <use> to the current layer. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the import was unsuccessful, true otherwise. -// TODO: -// * properly handle if namespace is introduced by imported content (must add to svgcontent -// and update all prefixes in the imported node) -// * properly handle recalculating dimensions, recalculateDimensions() doesn't handle -// arbitrary transform lists, but makes some assumptions about how the transform list -// was obtained -// * import should happen in top-left of current zoomed viewport -this.importSvgString = function(xmlString) { - - try { - // Get unique ID - var uid = svgedit.utilities.encode64(xmlString.length + xmlString).substr(0,32); - - var useExisting = false; - - // Look for symbol and make sure symbol exists in image - if(import_ids[uid]) { - if( $(import_ids[uid].symbol).parents('#svgroot').length ) { - useExisting = true; - } - } - - var batchCmd = new BatchCommand("Import SVG"); - - if(useExisting) { - var symbol = import_ids[uid].symbol; - var ts = import_ids[uid].xform; - } else { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - // import new svg document into our document - var svg; - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svg = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svg = svgdoc.importNode(newDoc.documentElement, true); - } - - uniquifyElems(svg); - - 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) - vb[j] = +(vb[j]); - - // TODO: properly handle preserveAspectRatio - var canvasw = +svgcontent.getAttribute("width"), - canvash = +svgcontent.getAttribute("height"); - // imported content should be 1/3 of the canvas on its largest dimension - - if (innerh > innerw) { - var ts = "scale(" + (canvash/3)/vb[3] + ")"; - } - else { - var ts = "scale(" + (canvash/3)/vb[2] + ")"; - } - - // Hack to make recalculateDimensions understand how to scale - ts = "translate(0) " + ts + " translate(0)"; - - var symbol = svgdoc.createElementNS(svgns, "symbol"); - var defs = findDefs(); - - if(svgedit.browser.isGecko()) { - // Move all gradients into root for Firefox, workaround for this bug: - // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 - // TODO: Make this properly undo-able. - $(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); - } - - while (svg.firstChild) { - var first = svg.firstChild; - symbol.appendChild(first); - } - var attrs = svg.attributes; - for(var i=0; i < attrs.length; i++) { - var attr = attrs[i]; - symbol.setAttribute(attr.nodeName, attr.nodeValue); - } - symbol.id = getNextId(); - - // Store data - import_ids[uid] = { - symbol: symbol, - xform: ts - } - - findDefs().appendChild(symbol); - batchCmd.addSubCommand(new InsertElementCommand(symbol)); - } - - - var use_el = svgdoc.createElementNS(svgns, "use"); - use_el.id = getNextId(); - setHref(use_el, "#" + symbol.id); - - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(use_el); - batchCmd.addSubCommand(new InsertElementCommand(use_el)); - clearSelection(); - - use_el.setAttribute("transform", ts); - recalculateDimensions(use_el); - $(use_el).data('symbol', symbol).data('ref', symbol); - addToSelection([use_el]); - - // 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; - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// TODO(codedread): Move all layer/context functions in draw.js -// Layer API Functions - -// Group: Layers - -// Function: identifyLayers -// Updates layer system -var identifyLayers = canvas.identifyLayers = function() { - leaveContext(); - getCurrentDrawing().identifyLayers(); -}; - -// Function: createLayer -// Creates a new top-level layer in the drawing with the given name, sets the current layer -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.createLayer = function(name) { - var batchCmd = new BatchCommand("Create Layer"); - var new_layer = getCurrentDrawing().createLayer(name); - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [new_layer]); -}; - -// Function: cloneLayer -// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.cloneLayer = function(name) { - var batchCmd = new BatchCommand("Duplicate Layer"); - var new_layer = svgdoc.createElementNS(svgns, "g"); - var layer_title = svgdoc.createElementNS(svgns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - var current_layer = getCurrentDrawing().getCurrentLayer(); - $(current_layer).after(new_layer); - var childs = current_layer.childNodes; - for(var i = 0; i < childs.length; i++) { - var ch = childs[i]; - if(ch.localName == 'title') continue; - new_layer.appendChild(copyElem(ch)); - } - - clearSelection(); - identifyLayers(); - - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - canvas.setCurrentLayer(name); - call("changed", [new_layer]); -}; - -// Function: deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -this.deleteCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - var nextSibling = current_layer.nextSibling; - var parent = current_layer.parentNode; - current_layer = getCurrentDrawing().deleteCurrentLayer(); - if (current_layer) { - var batchCmd = new BatchCommand("Delete Layer"); - // store in our Undo History - batchCmd.addSubCommand(new RemoveElementCommand(current_layer, nextSibling, parent)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [parent]); - return true; - } - return false; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -this.setCurrentLayer = function(name) { - var result = getCurrentDrawing().setCurrentLayer(svgedit.utilities.toXml(name)); - if (result) { - clearSelection(); - } - return result; -}; - -// Function: renameCurrentLayer -// Renames the current layer. If the layer name is not valid (i.e. unique), then this function -// does nothing and returns false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// newname - the new name you want to give the current layer. This name must be unique -// among all layer names. -// -// Returns: -// true if the rename succeeded, false otherwise. -this.renameCurrentLayer = function(newname) { - 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 batchCmd = new BatchCommand("Rename Layer"); - // find the index of the layer - for (var 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 (var 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 ChangeElementCommand(child, {"#text":oldname})); - addCommandToHistory(batchCmd); - call("changed", [oldLayer]); - return true; - } - } - } - drawing.current_layer = oldLayer; - } - return false; -}; - -// Function: setCurrentLayerPosition -// Changes the position of the current layer to the new value. If the new index is not valid, -// this function does nothing and returns false, otherwise it returns true. This is an -// undo-able action. -// -// Parameters: -// newpos - The zero-based index of the new position of the layer. This should be between -// 0 and (number of layers - 1) -// -// Returns: -// true if the current layer position was changed, false otherwise. -this.setCurrentLayerPosition = function(newpos) { - var drawing = getCurrentDrawing(); - if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) { - for (var 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 MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent)); - - identifyLayers(); - canvas.setCurrentLayer(drawing.getLayerName(newpos)); - - return true; - } - } - - return false; -}; - -// Function: setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// true if the layer's visibility was set, false otherwise -this.setLayerVisibility = function(layername, bVisible) { - var drawing = getCurrentDrawing(); - var prevVisibility = drawing.getLayerVisibility(layername); - var layer = drawing.setLayerVisibility(layername, bVisible); - if (layer) { - var oldDisplay = prevVisibility ? 'inline' : 'none'; - addCommandToHistory(new ChangeElementCommand(layer, {'display':oldDisplay}, 'Layer Visibility')); - } else { - return false; - } - - if (layer == drawing.getCurrentLayer()) { - clearSelection(); - pathActions.clear(); - } -// call("changed", [selected]); - return true; -}; - -// Function: moveSelectedToLayer -// Moves the selected elements to layername. If the name is not a valid layer name, then false -// is returned. Otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer you want to which you want to move the selected elements -// -// Returns: -// true if the selected elements were moved to the layer, false otherwise. -this.moveSelectedToLayer = function(layername) { - // find the layer - var layer = null; - var drawing = getCurrentDrawing(); - for (var i = 0; i < drawing.getNumLayers(); ++i) { - if (drawing.getLayerName(i) == layername) { - layer = drawing.all_layers[i][1]; - break; - } - } - if (!layer) return false; - - var batchCmd = new BatchCommand("Move Elements to Layer"); - - // loop for each selected element and move it - var selElems = selectedElements; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (!elem) continue; - var oldNextSibling = elem.nextSibling; - // TODO: this is pretty brittle! - var oldLayer = elem.parentNode; - layer.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); - } - - addCommandToHistory(batchCmd); - - return true; -}; - -this.mergeLayer = function(skipHistory) { - var batchCmd = new 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 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 RemoveElementCommand(ch, chNextSibling, drawing.current_layer)); - drawing.current_layer.removeChild(ch); - continue; - } - var oldNextSibling = ch.nextSibling; - prev.appendChild(ch); - batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, drawing.current_layer)); - } - - // Remove current layer - svgcontent.removeChild(drawing.current_layer); - - if(!skipHistory) { - clearSelection(); - identifyLayers(); - - call("changed", [svgcontent]); - - addCommandToHistory(batchCmd); - } - - drawing.current_layer = prev; - return batchCmd; -} - -this.mergeAllLayers = function() { - var batchCmd = new 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)); - } - - clearSelection(); - identifyLayers(); - call("changed", [svgcontent]); - addCommandToHistory(batchCmd); -} - -// Function: leaveContext -// Return from a group context to the regular kind, make any previously -// disabled elements enabled again -var leaveContext = this.leaveContext = function() { - var len = disabled_elems.length; - if(len) { - for(var i = 0; i < len; i++) { - var elem = disabled_elems[i]; - - var orig = elData(elem, 'orig_opac'); - if(orig !== 1) { - elem.setAttribute('opacity', orig); - } else { - elem.removeAttribute('opacity'); - } - elem.setAttribute('style', 'pointer-events: inherit'); - } - disabled_elems = []; - clearSelection(true); - call("contextset", null); - } - current_group = null; -} - -// Function: setContext -// Set the current context (for in-group editing) -var setContext = this.setContext = function(elem) { - leaveContext(); - if(typeof elem === 'string') { - elem = getElem(elem); - } - - // Edit inside this group - current_group = elem; - - // Disable other elements - $(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function() { - var opac = this.getAttribute('opacity') || 1; - // Store the original's opacity - elData(this, 'orig_opac', opac); - this.setAttribute('opacity', opac * .33); - this.setAttribute('style', 'pointer-events: none'); - disabled_elems.push(this); - }); - - clearSelection(); - call("contextset", current_group); -} - -// Group: Document functions - -// Function: clear -// Clears the current document. This is not an undoable action. -this.clear = function() { - pathActions.clear(); - - clearSelection(); - - // clear the svgcontent node - canvas.clearSvgContentElement(); - - // create new document - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent); - - // create empty first layer - canvas.createLayer("Layer 1"); - - // clear the undo stack - canvas.undoMgr.resetUndoStack(); - - // reset the selector manager - selectorManager.initGroup(); - - // reset the rubber band box - rubberBox = selectorManager.getRubberBandBox(); - - call("cleared"); -}; - -// Function: linkControlPoints -// Alias function -this.linkControlPoints = pathActions.linkControlPoints; - -// Function: getContentElem -// Returns the content DOM element -this.getContentElem = function() { return svgcontent; }; - -// Function: getRootElem -// Returns the root DOM element -this.getRootElem = function() { return svgroot; }; - -// Function: getSelectedElems -// Returns the array with selected DOM elements -this.getSelectedElems = function() { return selectedElements; }; - -// Function: getResolution -// Returns the current dimensions and zoom level in an object -var getResolution = this.getResolution = function() { -// var vb = svgcontent.getAttribute("viewBox").split(' '); -// return {'w':vb[2], 'h':vb[3], 'zoom': current_zoom}; - - var width = svgcontent.getAttribute("width")/current_zoom; - var height = svgcontent.getAttribute("height")/current_zoom; - - return { - 'w': width, - 'h': height, - 'zoom': current_zoom - }; -}; - -// Function: getZoom -// Returns the current zoom level -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: 2082 $)"; -}; - -// Function: setUiStrings -// Update interface strings with given values -// -// Parameters: -// strs - Object with strings (see uiStrings for examples) -this.setUiStrings = function(strs) { - $.extend(uiStrings, strs.notification); -} - -// Function: setConfig -// Update configuration options with given values -// -// Parameters: -// opts - Object with options (see curConfig for examples) -this.setConfig = function(opts) { - $.extend(curConfig, opts); -} - -// Function: getTitle -// 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<childs.length; i++) { - if(childs[i].nodeName == 'title') { - return childs[i].textContent; - } - } - return ''; -} - -// Function: setGroupTitle -// Sets the group/SVG's title content -// TODO: Combine this with setDocumentTitle -this.setGroupTitle = function(val) { - var elem = selectedElements[0]; - elem = $(elem).data('gsvg') || elem; - - var ts = $(elem).children('title'); - - var batchCmd = new BatchCommand("Set Label"); - - if(!val.length) { - // Remove title element - var tsNextSibling = ts.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)); - ts.remove(); - } else if(ts.length) { - // Change title contents - var title = ts[0]; - batchCmd.addSubCommand(new ChangeElementCommand(title, {'#text': title.textContent})); - title.textContent = val; - } else { - // Add title element - title = svgdoc.createElementNS(svgns, "title"); - title.textContent = val; - $(elem).prepend(title); - batchCmd.addSubCommand(new InsertElementCommand(title)); - } - - addCommandToHistory(batchCmd); -} - -// Function: getDocumentTitle -// Returns the current document title or an empty string if not found -this.getDocumentTitle = function() { - return canvas.getTitle(svgcontent); -} - -// Function: setDocumentTitle -// Adds/updates a title element for the document with the given name. -// This is an undoable action -// -// Parameters: -// newtitle - String with the new title -this.setDocumentTitle = function(newtitle) { - var childs = svgcontent.childNodes, doc_title = false, old_title = ''; - - var batchCmd = new BatchCommand("Change Image Title"); - - for (var i=0; i<childs.length; i++) { - if(childs[i].nodeName == 'title') { - doc_title = childs[i]; - old_title = doc_title.textContent; - break; - } - } - if(!doc_title) { - doc_title = svgdoc.createElementNS(svgns, "title"); - svgcontent.insertBefore(doc_title, svgcontent.firstChild); - } - - if(newtitle.length) { - doc_title.textContent = newtitle; - } else { - // No title given, so element is not necessary - doc_title.parentNode.removeChild(doc_title); - } - batchCmd.addSubCommand(new ChangeElementCommand(doc_title, {'#text': old_title})); - addCommandToHistory(batchCmd); -} - -// Function: getEditorNS -// Returns the editor's namespace URL, optionally adds it to root element -// -// Parameters: -// add - Boolean to indicate whether or not to add the namespace value -this.getEditorNS = function(add) { - if(add) { - svgcontent.setAttribute('xmlns:se', se_ns); - } - return se_ns; -} - -// Function: setResolution -// Changes the document's dimensions to the given size -// -// Parameters: -// x - Number with the width of the new dimensions in user units. -// Can also be the string "fit" to indicate "fit to content" -// y - Number with the height of the new dimensions in user units. -// -// Returns: -// Boolean to indicate if resolution change was succesful. -// It will fail on "fit to content" option with no content to fit to. -this.setResolution = function(x, y) { - var res = getResolution(); - var w = res.w, h = res.h; - var batchCmd; - - if(x == 'fit') { - // Get bounding box - var bbox = getStrokedBBox(); - - if(bbox) { - batchCmd = new BatchCommand("Fit Canvas to Content"); - var visEls = getVisibleElements(); - addToSelection(visEls); - var dx = [], dy = []; - $.each(visEls, function(i, item) { - dx.push(bbox.x*-1); - dy.push(bbox.y*-1); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - clearSelection(); - - x = Math.round(bbox.width); - y = Math.round(bbox.height); - } else { - return false; - } - } - if (x != w || y != h) { - var handle = svgroot.suspendRedraw(1000); - if(!batchCmd) { - batchCmd = new BatchCommand("Change Image Dimensions"); - } - - x = convertToNum('width', x); - y = convertToNum('height', y); - - svgcontent.setAttribute('width', x); - svgcontent.setAttribute('height', y); - - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"width":w, "height":h})); - - svgcontent.setAttribute("viewBox", [0, 0, x/current_zoom, y/current_zoom].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"viewBox": ["0 0", w, h].join(' ')})); - - addCommandToHistory(batchCmd); - svgroot.unsuspendRedraw(handle); - call("changed", [svgcontent]); - } - return true; -}; - -// Function: getOffset -// Returns an object with x, y values indicating the svgcontent element's -// position in the editor's canvas. -this.getOffset = function() { - return $(svgcontent).attr(['x', 'y']); -} - -// Function: setBBoxZoom -// Sets the zoom level on the canvas-side based on the given value -// -// Parameters: -// val - Bounding box object to zoom to or string indicating zoom option -// editor_w - Integer with the editor's workarea box's width -// editor_h - Integer with the editor's workarea box's height -this.setBBoxZoom = function(val, editor_w, editor_h) { - var spacer = .85; - var bb; - var calcZoom = function(bb) { - if(!bb) return false; - var w_zoom = Math.round((editor_w / bb.width)*100 * spacer)/100; - var h_zoom = Math.round((editor_h / bb.height)*100 * spacer)/100; - var zoomlevel = Math.min(w_zoom,h_zoom); - canvas.setZoom(zoomlevel); - return {'zoom': zoomlevel, 'bbox': bb}; - } - - if(typeof val == 'object') { - bb = val; - if(bb.width == 0 || bb.height == 0) { - var newzoom = bb.zoom?bb.zoom:current_zoom * bb.factor; - canvas.setZoom(newzoom); - return {'zoom': current_zoom, 'bbox': bb}; - } - return calcZoom(bb); - } - - switch (val) { - case 'selection': - if(!selectedElements[0]) return; - var sel_elems = $.map(selectedElements, function(n){ if(n) return n; }); - bb = getStrokedBBox(sel_elems); - break; - case 'canvas': - var res = getResolution(); - spacer = .95; - bb = {width:res.w, height:res.h ,x:0, y:0}; - break; - case 'content': - bb = getStrokedBBox(); - break; - case 'layer': - bb = getStrokedBBox(getVisibleElements(getCurrentDrawing().getCurrentLayer())); - break; - default: - return; - } - return calcZoom(bb); -} - -// Function: setZoom -// Sets the zoom to the given level -// -// Parameters: -// zoomlevel - Float indicating the zoom level to change to -this.setZoom = function(zoomlevel) { - var res = getResolution(); - svgcontent.setAttribute("viewBox", "0 0 " + res.w/zoomlevel + " " + res.h/zoomlevel); - current_zoom = zoomlevel; - $.each(selectedElements, function(i, elem) { - if(!elem) return; - selectorManager.requestSelector(elem).resize(); - }); - pathActions.zoomChange(); - runExtensions("zoomChanged", zoomlevel); -} - -// Function: getMode -// Returns the current editor mode string -this.getMode = function() { - return current_mode; -}; - -// Function: setMode -// Sets the editor's mode to the given string -// -// Parameters: -// name - String with the new mode to change to -this.setMode = function(name) { - pathActions.clear(true); - textActions.clear(); - $("#workarea").attr("class", name); - cur_properties = (selectedElements[0] && selectedElements[0].nodeName == 'text') ? cur_text : cur_shape; - current_mode = name; -}; - -// Group: Element Styling - -// Function: getColor -// Returns the current fill/stroke option -this.getColor = function(type) { - return cur_properties[type]; -}; - -// Function: setColor -// Change the current stroke/fill color/gradient value -// -// Parameters: -// type - String indicating fill or stroke -// val - The value to set the stroke attribute to -// preventUndo - Boolean indicating whether or not this should be and undoable option -this.setColor = function(type, val, preventUndo) { - cur_shape[type] = val; - cur_properties[type + '_paint'] = {type:"solidColor"}; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else { - if(type == 'fill') { - if(elem.tagName != "polyline" && elem.tagName != "line") { - elems.push(elem); - } - } else { - elems.push(elem); - } - } - } - } - if (elems.length > 0) { - if (!preventUndo) { - changeSelectedAttribute(type, val, elems); - call("changed", elems); - } else - changeSelectedAttributeNoUndo(type, val, elems); - } -} - - -// Function: findDefs -// Return the document's <defs> element, create it first if necessary -var findDefs = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - defs = svgdoc.createElementNS(svgns, "defs" ); - if(svgcontent.firstChild) { - // first child is a comment, so call nextSibling - svgcontent.insertBefore( defs, svgcontent.firstChild.nextSibling); - } else { - svgcontent.appendChild(defs); - } - } - return defs; -}; - -// Function: setGradient -// Apply the current gradient to selected element's fill or stroke -// -// Parameters -// type - String indicating "fill" or "stroke" to apply to an element -var setGradient = this.setGradient = function(type) { - if(!cur_properties[type + '_paint'] || cur_properties[type + '_paint'].type == "solidColor") return; - var grad = canvas[type + 'Grad']; - // find out if there is a duplicate gradient already in the defs - var duplicate_grad = findDuplicateGradient(grad); - var defs = findDefs(); - // no duplicate found, so import gradient into defs - if (!duplicate_grad) { - var orig_grad = grad; - grad = defs.appendChild( svgdoc.importNode(grad, true) ); - // get next id and set it on the grad - grad.id = getNextId(); - } - else { // use existing gradient - grad = duplicate_grad; - } - canvas.setColor(type, "url(#" + grad.id + ")"); -} - -// Function: findDuplicateGradient -// Check if exact gradient already exists -// -// Parameters: -// grad - The gradient DOM element to compare to others -// -// Returns: -// The existing gradient if found, null if not -var findDuplicateGradient = function(grad) { - var defs = findDefs(); - var existing_grads = $(defs).find("linearGradient, radialGradient"); - var i = existing_grads.length; - var rad_attrs = ['r','cx','cy','fx','fy']; - while (i--) { - var og = existing_grads[i]; - if(grad.tagName == "linearGradient") { - if (grad.getAttribute('x1') != og.getAttribute('x1') || - grad.getAttribute('y1') != og.getAttribute('y1') || - grad.getAttribute('x2') != og.getAttribute('x2') || - grad.getAttribute('y2') != og.getAttribute('y2')) - { - continue; - } - } else { - var grad_attrs = $(grad).attr(rad_attrs); - var og_attrs = $(og).attr(rad_attrs); - - var diff = false; - $.each(rad_attrs, function(i, attr) { - if(grad_attrs[attr] != og_attrs[attr]) diff = true; - }); - - if(diff) continue; - } - - // else could be a duplicate, iterate through stops - var stops = grad.getElementsByTagNameNS(svgns, "stop"); - var ostops = og.getElementsByTagNameNS(svgns, "stop"); - - if (stops.length != ostops.length) { - continue; - } - - var j = stops.length; - while(j--) { - var stop = stops[j]; - var ostop = ostops[j]; - - if (stop.getAttribute('offset') != ostop.getAttribute('offset') || - stop.getAttribute('stop-opacity') != ostop.getAttribute('stop-opacity') || - stop.getAttribute('stop-color') != ostop.getAttribute('stop-color')) - { - break; - } - } - - if (j == -1) { - return og; - } - } // for each gradient in defs - - return null; -}; - -function reorientGrads(elem, m) { - var bb = svgedit.utilities.getBBox(elem); - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = elem.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - var grad = getRefElem(attrVal); - if(grad.tagName === 'linearGradient') { - var x1 = grad.getAttribute('x1') || 0; - var y1 = grad.getAttribute('y1') || 0; - var x2 = grad.getAttribute('x2') || 1; - var y2 = grad.getAttribute('y2') || 0; - - // Convert to USOU points - x1 = (bb.width * x1) + bb.x; - y1 = (bb.height * y1) + bb.y; - x2 = (bb.width * x2) + bb.x; - y2 = (bb.height * y2) + bb.y; - - // Transform those points - var pt1 = transformPoint(x1, y1, m); - var pt2 = transformPoint(x2, y2, m); - - // Convert back to BB points - var g_coords = {}; - - g_coords.x1 = (pt1.x - bb.x) / bb.width; - g_coords.y1 = (pt1.y - bb.y) / bb.height; - g_coords.x2 = (pt2.x - bb.x) / bb.width; - g_coords.y2 = (pt2.y - bb.y) / bb.height; - - var newgrad = grad.cloneNode(true); - $(newgrad).attr(g_coords); - - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - elem.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - } - } -} - -// Function: setPaint -// Set a color/gradient to a fill/stroke -// -// Parameters: -// type - String with "fill" or "stroke" -// paint - The jGraduate paint object to apply -this.setPaint = function(type, paint) { - // make a copy - var p = new $.jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha/100, true); - - // now set the current paint object - cur_properties[type + '_paint'] = p; - switch ( p.type ) { - case "solidColor": - - if (p.solidColor != "none") { - this.setColor(type, "#"+p.solidColor) - } - else { - this.setColor(type, "none"); - var selector = (type == "fill") ? "#fill_color rect" : "#stroke_color rect" - document.querySelector(selector).setAttribute('fill', 'transparent'); - } - break; - case "linearGradient": - case "radialGradient": - canvas[type + 'Grad'] = p[p.type]; - setGradient(type); - break; - default: -// console.log("none!"); - } -}; - - -// this.setStrokePaint = function(p) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setStrokeOpacity(p.alpha/100); -// -// // now set the current paint object -// cur_properties.stroke_paint = p; -// switch ( p.type ) { -// case "solidColor": -// this.setColor('stroke', p.solidColor != "none" ? "#"+p.solidColor : "none");; -// break; -// case "linearGradient" -// case "radialGradient" -// canvas.strokeGrad = p[p.type]; -// setGradient(type); -// default: -// // console.log("none!"); -// } -// }; -// -// this.setFillPaint = function(p, addGrad) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setFillOpacity(p.alpha/100, true); -// -// // now set the current paint object -// cur_properties.fill_paint = p; -// if (p.type == "solidColor") { -// this.setColor('fill', p.solidColor != "none" ? "#"+p.solidColor : "none"); -// } -// else if(p.type == "linearGradient") { -// canvas.fillGrad = p.linearGradient; -// if(addGrad) setGradient(); -// } -// else if(p.type == "radialGradient") { -// canvas.fillGrad = p.radialGradient; -// if(addGrad) setGradient(); -// } -// else { -// // console.log("none!"); -// } -// }; - -// Function: getStrokeWidth -// Returns the current stroke-width value -this.getStrokeWidth = function() { - return cur_properties.stroke_width; -}; - -// Function: setStrokeWidth -// Sets the stroke width for the current selected elements -// When attempting to set a line's width to 0, this changes it to 1 instead -// -// Parameters: -// val - A Float indicating the new stroke width value -this.setStrokeWidth = function(val) { - if(val == 0 && ['line', 'path'].indexOf(current_mode) >= 0) { - canvas.setStrokeWidth(1); - return; - } - cur_properties.stroke_width = val; - - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute("stroke-width", val, elems); - call("changed", selectedElements); - } -}; - -// Function: setStrokeAttr -// Set the given stroke-related attribute the given value for selected elements -// -// Parameters: -// attr - String with the attribute name -// val - String or number with the attribute value -this.setStrokeAttr = function(attr, val) { - cur_shape[attr.replace('-','_')] = val; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute(attr, val, elems); - call("changed", selectedElements); - } -}; - -// Function: getStyle -// Returns current style options -this.getStyle = function() { - return cur_shape; -} - -// Function: getOpacity -// Returns the current opacity -this.getOpacity = function() { - return cur_shape.opacity; -}; - -// Function: setOpacity -// Sets the given opacity to the current selected elements -this.setOpacity = function(val) { - cur_shape.opacity = val; - changeSelectedAttribute("opacity", val); -}; - -// Function: getOpacity -// Returns the current fill opacity -this.getFillOpacity = function() { - return cur_shape.fill_opacity; -}; - -// Function: getStrokeOpacity -// Returns the current stroke opacity -this.getStrokeOpacity = function() { - return cur_shape.stroke_opacity; -}; - -// Function: setPaintOpacity -// Sets the current fill/stroke opacity -// -// Parameters: -// type - String with "fill" or "stroke" -// val - Float with the new opacity value -// preventUndo - Boolean indicating whether or not this should be an undoable action -this.setPaintOpacity = function(type, val, preventUndo) { - cur_shape[type + '_opacity'] = val; - if (!preventUndo) - changeSelectedAttribute(type + "-opacity", val); - else - changeSelectedAttributeNoUndo(type + "-opacity", val); -}; - -// Function: getBlur -// Gets the stdDeviation blur value of the given element -// -// Parameters: -// elem - The element to check the blur value for -this.getBlur = function(elem) { - var val = 0; -// var elem = selectedElements[0]; - - if(elem) { - var filter_url = elem.getAttribute('filter'); - if(filter_url) { - var blur = getElem(elem.id + '_blur'); - if(blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } - } - } - return val; -}; - -(function() { - var cur_command = null; - var filter = null; - var filterHidden = false; - - // Function: setBlurNoUndo - // Sets the stdDeviation blur value on the selected element without being undoable - // - // Parameters: - // val - The new stdDeviation value - canvas.setBlurNoUndo = function(val) { - if(!filter) { - canvas.setBlur(val); - return; - } - if(val === 0) { - // Don't change the StdDev, as that will hide the element. - // Instead, just remove the value for "filter" - changeSelectedAttributeNoUndo("filter", ""); - filterHidden = true; - } else { - var elem = selectedElements[0]; - if(filterHidden) { - changeSelectedAttributeNoUndo("filter", 'url(#' + elem.id + '_blur)'); - } - if(svgedit.browser.isWebkit()) { - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); - } - changeSelectedAttributeNoUndo("stdDeviation", val, [filter.firstChild]); - canvas.setBlurOffsets(filter, val); - } - } - - function finishChange() { - var bCmd = canvas.undoMgr.finishUndoableChange(); - cur_command.addSubCommand(bCmd); - addCommandToHistory(cur_command); - cur_command = null; - filter = null; - } - - // Function: setBlurOffsets - // Sets the x, y, with, height values of the filter element in order to - // make the blur not be clipped. Removes them if not neeeded - // - // Parameters: - // filter - The filter DOM element to update - // stdDev - The standard deviation value on which to base the offset size - canvas.setBlurOffsets = function(filter, stdDev) { - if(stdDev > 3) { - // TODO: Create algorithm here where size is based on expected blur - assignAttributes(filter, { - x: '-50%', - y: '-50%', - width: '200%', - height: '200%' - }, 100); - } else { - // Removing these attributes hides text in Chrome (see Issue 579) - if(!svgedit.browser.isWebkit()) { - filter.removeAttribute('x'); - filter.removeAttribute('y'); - filter.removeAttribute('width'); - filter.removeAttribute('height'); - } - } - } - - // Function: setBlur - // Adds/updates the blur filter to the selected element - // - // Parameters: - // val - Float with the new stdDeviation blur value - // complete - Boolean indicating whether or not the action should be completed (to add to the undo manager) - canvas.setBlur = function(val, complete) { - if(cur_command) { - finishChange(); - return; - } - - // Looks for associated blur, creates one if not found - var elem = selectedElements[0]; - var elem_id = elem.id; - filter = getElem(elem_id + '_blur'); - - val -= 0; - - var batchCmd = new BatchCommand(); - - // Blur found! - if(filter) { - if(val === 0) { - filter = null; - } - } else { - // Not found, so create - var newblur = addSvgElementFromJson({ "element": "feGaussianBlur", - "attr": { - "in": 'SourceGraphic', - "stdDeviation": val - } - }); - - filter = addSvgElementFromJson({ "element": "filter", - "attr": { - "id": elem_id + '_blur' - } - }); - - filter.appendChild(newblur); - findDefs().appendChild(filter); - - batchCmd.addSubCommand(new InsertElementCommand(filter)); - } - - var changes = {filter: elem.getAttribute('filter')}; - - if(val === 0) { - elem.removeAttribute("filter"); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - return; - } else { - changeSelectedAttribute("filter", 'url(#' + elem_id + '_blur)'); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - - canvas.setBlurOffsets(filter, val); - } - - cur_command = batchCmd; - canvas.undoMgr.beginUndoableChange("stdDeviation", [filter?filter.firstChild:null]); - if(complete) { - canvas.setBlurNoUndo(val); - finishChange(); - } - }; -}()); - -// Function: getBold -// Check whether selected element is bold or not -// -// Returns: -// Boolean indicating whether or not element is bold -this.getBold = function() { - // should only have one element selected - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-weight") == "bold"); - } - return false; -}; - -// Function: setBold -// Make the selected element bold or normal -// -// Parameters: -// b - Boolean indicating bold (true) or normal (false) -this.setBold = function(b) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-weight", b ? "bold" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getItalic -// Check whether selected element is italic or not -// -// Returns: -// Boolean indicating whether or not element is italic -this.getItalic = function() { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-style") == "italic"); - } - return false; -}; - -// Function: setItalic -// Make the selected element italic or normal -// -// Parameters: -// b - Boolean indicating italic (true) or normal (false) -this.setItalic = function(i) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-style", i ? "italic" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getFontFamily -// Returns the current font family -this.getFontFamily = function() { - return cur_text.font_family; -}; - -// Function: setFontFamily -// Set the new font family -// -// Parameters: -// val - String with the new font family -this.setFontFamily = function(val) { - cur_text.font_family = val; - changeSelectedAttribute("font-family", val); - if(selectedElements[0] && !selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - - -// Function: setFontColor -// Set the new font color -// -// Parameters: -// val - String with the new font color -this.setFontColor = function(val) { - cur_text.fill = val; - changeSelectedAttribute("fill", val); -}; - -// Function: getFontColor -// Returns the current font color -this.getFontSize = function() { - return cur_text.fill; -}; - -// Function: getFontSize -// Returns the current font size -this.getFontSize = function() { - return cur_text.font_size; -}; - -// Function: setFontSize -// Applies the given font size to the selected element -// -// Parameters: -// val - Float with the new font size -this.setFontSize = function(val) { - cur_text.font_size = val; - changeSelectedAttribute("font-size", val); - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getText -// Returns the current text (textContent) of the selected element -this.getText = function() { - var selected = selectedElements[0]; - if (selected == null) { return ""; } - return selected.textContent; -}; - -// Function: setTextContent -// Updates the text element with the given string -// -// Parameters: -// val - String with the new text -this.setTextContent = function(val) { - changeSelectedAttribute("#text", val); - textActions.init(val); - textActions.setCursor(); -}; - -// Function: setImageURL -// Sets the new image URL for the selected image element. Updates its size if -// a new URL is given -// -// Parameters: -// val - String with the image URL/path -this.setImageURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - - var attrs = $(elem).attr(['width', 'height']); - var setsize = (!attrs.width || !attrs.height); - - var cur_href = getHref(elem); - - // Do nothing if no URL change or size change - if(cur_href !== val) { - setsize = true; - } else if(!setsize) return; - - var batchCmd = new BatchCommand("Change Image URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - if(setsize) { - $(new Image()).load(function() { - var changes = $(elem).attr(['width', 'height']); - - $(elem).attr({ - width: this.width, - height: this.height - }); - - selectorManager.requestSelector(elem).resize(); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - addCommandToHistory(batchCmd); - call("changed", [elem]); - }).attr('src',val); - } else { - addCommandToHistory(batchCmd); - } -}; - -// Function: setLinkURL -// Sets the new link URL for the selected anchor element. -// -// Parameters: -// val - String with the link URL/path -this.setLinkURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - if(elem.tagName !== 'a') { - // See if parent is an anchor - var parents_a = $(elem).parents('a'); - if(parents_a.length) { - elem = parents_a[0]; - } else { - return; - } - } - - var cur_href = getHref(elem); - - if(cur_href === val) return; - - var batchCmd = new BatchCommand("Change Link URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - addCommandToHistory(batchCmd); -}; - - -// Function: setRectRadius -// Sets the rx & ry values to the selected rect element to change its corner radius -// -// Parameters: -// val - The new radius -this.setRectRadius = function(val) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "rect") { - var r = selected.getAttribute("rx"); - if (r != val) { - selected.setAttribute("rx", val); - selected.setAttribute("ry", val); - addCommandToHistory(new ChangeElementCommand(selected, {"rx":r, "ry":r}, "Radius")); - call("changed", [selected]); - } - } -}; - -// Function: makeHyperlink -// Wraps the selected element(s) in an anchor element or converts group to one -this.makeHyperlink = function(url) { - canvas.groupSelectedElements('a', url); - - // TODO: If element is a single "g", convert to "a" - // if(selectedElements.length > 1 && selectedElements[1]) { - -} - -// Function: removeHyperlink -this.removeHyperlink = function() { - canvas.ungroupSelectedElement(); -} - -// Group: Element manipulation - -// Function: setSegType -// Sets the new segment type to the selected segment(s). -// -// Parameters: -// new_type - Integer with the new segment type -// See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list -this.setSegType = function(new_type) { - pathActions.setSegType(new_type); -} - -// TODO(codedread): Remove the getBBox argument and split this function into two. -// Function: convertToPath -// Convert selected element to a path, or get the BBox of an element-as-path -// -// Parameters: -// elem - The DOM element to be converted -// getBBox - Boolean on whether or not to only return the path's BBox -// -// Returns: -// If the getBBox flag is true, the resulting path's bounding box object. -// Otherwise the resulting path element is returned. -this.convertToPath = function(elem, getBBox) { - if(elem == null) { - var elems = selectedElements; - $.each(selectedElements, function(i, elem) { - if(elem) canvas.convertToPath(elem); - }); - return; - } - - if(!getBBox) { - var batchCmd = new BatchCommand("Convert element to Path"); - } - - var attrs = getBBox?{}:{ - "fill": cur_shape.fill, - "fill-opacity": cur_shape.fill_opacity, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "opacity": cur_shape.opacity, - "visibility":"hidden" - }; - - // any attribute on the element not covered by the above - // TODO: make this list global so that we can properly maintain it - // TODO: what about @transform, @clip-rule, @fill-rule, etc? - $.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function() { - if (elem.getAttribute(this)) { - attrs[this] = elem.getAttribute(this); - } - }); - - var path = addSvgElementFromJson({ - "element": "path", - "attr": attrs - }); - - var eltrans = elem.getAttribute("transform"); - if(eltrans) { - path.setAttribute("transform",eltrans); - } - - var id = elem.id; - var parent = elem.parentNode; - if(elem.nextSibling) { - parent.insertBefore(path, elem); - } else { - parent.appendChild(path); - } - - var d = ''; - - var joinSegs = function(segs) { - $.each(segs, function(j, seg) { - var l = seg[0], pts = seg[1]; - d += l; - for(var i=0; i < pts.length; i+=2) { - d += (pts[i] +','+pts[i+1]) + ' '; - } - }); - } - - // Possibly the cubed root of 6, but 1.81 works best - var num = 1.81; - - switch (elem.tagName) { - case 'ellipse': - case 'circle': - var a = $(elem).attr(['rx', 'ry', 'cx', 'cy']); - var cx = a.cx, cy = a.cy, rx = a.rx, ry = a.ry; - if(elem.tagName == 'circle') { - rx = ry = $(elem).attr('r'); - } - - joinSegs([ - ['M',[(cx-rx),(cy)]], - ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]], - ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]], - ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]], - ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]], - ['Z',[]] - ]); - break; - case 'path': - d = elem.getAttribute('d'); - break; - case 'line': - var a = $(elem).attr(["x1", "y1", "x2", "y2"]); - d = "M"+a.x1+","+a.y1+"L"+a.x2+","+a.y2; - break; - case 'polyline': - case 'polygon': - d = "M" + elem.getAttribute('points'); - break; - case 'rect': - var r = $(elem).attr(['rx', 'ry']); - var rx = r.rx, ry = r.ry; - var b = elem.getBBox(); - var x = b.x, y = b.y, w = b.width, h = b.height; - var num = 4-num; // Why? Because! - - if(!rx && !ry) { - // Regular rect - joinSegs([ - ['M',[x, y]], - ['L',[x+w, y]], - ['L',[x+w, y+h]], - ['L',[x, y+h]], - ['L',[x, y]], - ['Z',[]] - ]); - } else { - joinSegs([ - ['M',[x, y+ry]], - ['C',[x,y+ry/num, x+rx/num,y, x+rx,y]], - ['L',[x+w-rx, y]], - ['C',[x+w-rx/num,y, x+w,y+ry/num, x+w,y+ry]], - ['L',[x+w, y+h-ry]], - ['C',[x+w, y+h-ry/num, x+w-rx/num,y+h, x+w-rx,y+h]], - ['L',[x+rx, y+h]], - ['C',[x+rx/num, y+h, x,y+h-ry/num, x,y+h-ry]], - ['L',[x, y+ry]], - ['Z',[]] - ]); - } - break; - default: - path.parentNode.removeChild(path); - break; - } - - if(d) { - path.setAttribute('d',d); - } - - if(!getBBox) { - // Replace the current element with the converted one - - // Reorient if it has a matrix - if(eltrans) { - var tlist = getTransformList(path); - if(hasMatrixTransform(tlist)) { - pathActions.resetOrientation(path); - } - } - - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - batchCmd.addSubCommand(new InsertElementCommand(path)); - - clearSelection(); - elem.parentNode.removeChild(elem) - path.setAttribute('id', id); - path.removeAttribute("visibility"); - addToSelection([path], true); - - addCommandToHistory(batchCmd); - - } else { - // Get the correct BBox of the new path, then discard it - pathActions.resetOrientation(path); - var bb = false; - try { - bb = path.getBBox(); - } catch(e) { - // Firefox fails - } - path.parentNode.removeChild(path); - return bb; - } -}; - - -// Function: changeSelectedAttributeNoUndo -// This function makes the changes to the elements. It does not add the change -// to the history stack. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttributeNoUndo = function(attr, newValue, elems) { - var handle = svgroot.suspendRedraw(1000); - if(current_mode == 'pathedit') { - // Editing node - pathActions.moveNode(attr, newValue); - } - var elems = elems || selectedElements; - var i = elems.length; - var no_xy_elems = ['g', 'polyline', 'path']; - var good_g_attrs = ['transform', 'opacity', 'filter']; - - while (i--) { - var elem = elems[i]; - if (elem == null) continue; - - // Go into "select" mode for text changes - if(current_mode === "textedit" && attr !== "#text" && elem.textContent.length) { - textActions.toSelectMode(elem); - } - - // Set x,y vals on elements that don't have them - if((attr === 'x' || attr === 'y') && no_xy_elems.indexOf(elem.tagName) >= 0) { - var bbox = getStrokedBBox([elem]); - var diff_x = attr === 'x' ? newValue - bbox.x : 0; - var diff_y = attr === 'y' ? newValue - bbox.y : 0; - canvas.moveSelectedElements(diff_x*current_zoom, diff_y*current_zoom, true); - continue; - } - - // only allow the transform/opacity/filter attribute to change on <g> elements, slightly hacky - // if (elem.tagName === "g" && good_g_attrs.indexOf(attr) >= 0); - var oldval = attr === "#text" ? elem.textContent : elem.getAttribute(attr); - if (oldval == null) oldval = ""; - if (oldval !== String(newValue)) { - if (attr == "#text") { - var old_w = svgedit.utilities.getBBox(elem).width; - elem.textContent = newValue; - - // FF bug occurs on on rotated elements - if(/rotate/.test(elem.getAttribute('transform'))) { - elem = ffClone(elem); - } - - // Hoped to solve the issue of moving text with text-anchor="start", - // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd - -// var box=getBBox(elem), left=box.x, top=box.y, width=box.width, -// height=box.height, dx = width - old_w, dy=0; -// var angle = getRotationAngle(elem, true); -// if (angle) { -// var r = Math.sqrt( dx*dx + dy*dy ); -// var theta = Math.atan2(dy,dx) - angle; -// dx = r * Math.cos(theta); -// dy = r * Math.sin(theta); -// -// elem.setAttribute('x', elem.getAttribute('x')-dx); -// elem.setAttribute('y', elem.getAttribute('y')-dy); -// } - - } else if (attr == "#href") { - setHref(elem, newValue); - } - else elem.setAttribute(attr, newValue); -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - // Use the Firefox ffClone hack for text elements with gradients or - // where other text attributes are changed. - if(svgedit.browser.isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) { - if((newValue+'').indexOf('url') === 0 || ['font-size','font-family','x','y'].indexOf(attr) >= 0 && elem.textContent) { - elem = ffClone(elem); - } - } - // Timeout needed for Opera & Firefox - // codedread: it is now possible for this function to be called with elements - // that are not in the selectedElements array, we need to only request a - // selector if the element is in that array - if (selectedElements.indexOf(elem) >= 0) { - setTimeout(function() { - // Due to element replacement, this element may no longer - // be part of the DOM - if(!elem.parentNode) return; - selectorManager.requestSelector(elem).resize(); - },0); - } - // if this element was rotated, and we changed the position of this element - // we need to update the rotational transform attribute - var angle = getRotationAngle(elem); - if (angle != 0 && attr != "transform") { - var tlist = getTransformList(elem); - var n = tlist.numberOfItems; - while (n--) { - var xform = tlist.getItem(n); - if (xform.type == 4) { - // remove old rotate - tlist.removeItem(n); - - var box = svgedit.utilities.getBBox(elem); - var center = transformPoint(box.x+box.width/2, box.y+box.height/2, transformListToTransform(tlist).matrix); - var cx = center.x, - cy = center.y; - var newrot = svgroot.createSVGTransform(); - newrot.setRotate(angle, cx, cy); - tlist.insertItemBefore(newrot, n); - break; - } - } - } - } // if oldValue != newValue - } // for each elem - svgroot.unsuspendRedraw(handle); -}; - -// Function: changeSelectedAttribute -// Change the given/selected element and add the original value to the history stack -// If you want to change all selectedElements, ignore the elems argument. -// If you want to change only a subset of selectedElements, then send the -// subset to this function in the elems argument. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttribute = this.changeSelectedAttribute = function(attr, val, elems) { - var elems = elems || selectedElements; - canvas.undoMgr.beginUndoableChange(attr, elems); - var i = elems.length; - - changeSelectedAttributeNoUndo(attr, val, elems); - - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } -}; - -// Function: deleteSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack -this.deleteSelectedElements = function() { - var batchCmd = new BatchCommand("Delete Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - // Get the parent if it's a single-child anchor - if(parent.tagName === 'a' && parent.childNodes.length === 1) { - t = parent; - parent = parent.parentNode; - } - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); -}; - -// Function: cutSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack. Remembers removed elements on the clipboard - -// TODO: Combine similar code with deleteSelectedElements -this.cutSelectedElements = function() { - var batchCmd = new BatchCommand("Cut Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); - - canvas.clipBoard = selectedCopy; -}; - -// Function: copySelectedElements -// Remembers the current selected elements on the clipboard -this.copySelectedElements = function() { - canvas.clipBoard = $.merge([], selectedElements); -}; - -this.pasteElements = function(type, x, y) { - var cb = canvas.clipBoard; - var len = cb.length; - if(!len) return; - - var pasted = []; - var batchCmd = new BatchCommand('Paste elements'); - - // Move elements to lastClickPoint - - while (len--) { - var elem = cb[len]; - if(!elem) continue; - var copy = copyElem(elem); - - // See if elem with elem ID is in the DOM already - if(!getElem(elem.id)) copy.id = elem.id; - pasted.push(copy); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(copy); - batchCmd.addSubCommand(new InsertElementCommand(copy)); - } - - selectOnly(pasted); - if(type != 'in_place') { - if(lastClickPoint == null) { - lastClickPoint.x = 0; - lastClickPoint.y = 0; - } - var ctr_x, ctr_y; - if(!type) { - ctr_x = lastClickPoint.x; - ctr_y = lastClickPoint.y; - } else if(type === 'point') { - ctr_x = x; - ctr_y = y; - } - - var bbox = getStrokedBBox(pasted); - var cx = ctr_x - (bbox.x + bbox.width/2), - cy = ctr_y - (bbox.y + bbox.height/2), - dx = [], - dy = []; - - $.each(pasted, function(i, item) { - dx.push(cx); - dy.push(cy); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, false); - batchCmd.addSubCommand(cmd); - } - - - - addCommandToHistory(batchCmd); - call("changed", pasted); -} - -// Function: groupSelectedElements -// Wraps all the selected elements in a group (g) element - -// Parameters: -// type - type of element to group into, defaults to <g> -this.groupSelectedElements = function(type) { - if(!type) type = 'g'; - var cmd_str = ''; - - switch ( type ) { - case "a": - cmd_str = "Make hyperlink"; - var url = ''; - if(arguments.length > 1) { - url = arguments[1]; - } - break; - default: - type = 'g'; - cmd_str = "Group Elements"; - break; - } - - var batchCmd = new BatchCommand(cmd_str); - - // create and insert the group element - var g = addSvgElementFromJson({ - "element": type, - "attr": { - "id": getNextId() - } - }); - if(type === 'a') { - setHref(g, url); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - - // now move all children into the group - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem == null) continue; - - if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { - elem = elem.parentNode; - } - - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - g.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - selectOnly([g], true); -}; - - -// Function: pushGroupProperties -// Pushes all appropriate parent group properties down to its children, then -// removes them from the group -var pushGroupProperties = this.pushGroupProperties = function(g, undoable) { - - var children = g.childNodes; - var len = children.length; - var xform = g.getAttribute("transform"); - - var glist = getTransformList(g); - var m = transformListToTransform(glist).matrix; - - var batchCmd = new BatchCommand("Push group properties"); - - // TODO: get all fill/stroke properties from the group that we are about to destroy - // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", - // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", - // "stroke-width" - // and then for each child, if they do not have the attribute (or the value is 'inherit') - // then set the child's attribute - - var i = 0; - var gangle = getRotationAngle(g); - - var gattrs = $(g).attr(['filter', 'opacity']); - var gfilter, gblur; - - for(var i = 0; i < len; i++) { - var elem = children[i]; - - if(elem.nodeType !== 1) continue; - - if(gattrs.opacity !== null && gattrs.opacity !== 1) { - var c_opac = elem.getAttribute('opacity') || 1; - var new_opac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100)/100; - changeSelectedAttribute('opacity', new_opac, [elem]); - } - - if(gattrs.filter) { - var cblur = this.getBlur(elem); - var orig_cblur = cblur; - if(!gblur) gblur = this.getBlur(g); - if(cblur) { - // Is this formula correct? - cblur = (gblur-0) + (cblur-0); - } else if(cblur === 0) { - cblur = gblur; - } - - // If child has no current filter, get group's filter or clone it. - if(!orig_cblur) { - // Set group's filter to use first child's ID - if(!gfilter) { - gfilter = getRefElem(gattrs.filter); - } else { - // Clone the group's filter - gfilter = copyElem(gfilter); - findDefs().appendChild(gfilter); - } - } else { - gfilter = getRefElem(elem.getAttribute('filter')); - } - - // Change this in future for different filters - var suffix = (gfilter.firstChild.tagName === 'feGaussianBlur')?'blur':'filter'; - gfilter.id = elem.id + '_' + suffix; - changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); - - // Update blur value - if(cblur) { - changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); - canvas.setBlurOffsets(gfilter, cblur); - } - } - - var chtlist = getTransformList(elem); - - // Don't process gradient transforms - if(~elem.tagName.indexOf('Gradient')) chtlist = null; - - // Hopefully not a problem to add this. Necessary for elements like <desc/> - if(!chtlist) continue; - - // Apparently <defs> can get get a transformlist, but we don't want it to have one! - if(elem.tagName === 'defs') 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 - // out any translates) - if (gangle && glist.numberOfItems == 1) { - // [Rg] [Rc] [Mc] - // we want [Tr] [Rc2] [Mc] where: - // - [Rc2] is at the child's current center but has the - // sum of the group and child's rotation angles - // - [Tr] is the equivalent translation that this child - // undergoes if the group wasn't there - - // [Tr] = [Rg] [Rc] [Rc2_inv] - - // get group's rotation matrix (Rg) - var rgm = glist.getItem(0).matrix; - - // get child's rotation matrix (Rc) - var rcm = svgroot.createSVGMatrix(); - var cangle = getRotationAngle(elem); - if (cangle) { - rcm = chtlist.getItem(0).matrix; - } - - // get child's old center of rotation - var cbox = svgedit.utilities.getBBox(elem); - var ceqm = transformListToTransform(chtlist).matrix; - var coldc = transformPoint(cbox.x+cbox.width/2, cbox.y+cbox.height/2,ceqm); - - // sum group and child's angles - var sangle = gangle + cangle; - - // get child's rotation at the old center (Rc2_inv) - var r2 = svgroot.createSVGTransform(); - r2.setRotate(sangle, coldc.x, coldc.y); - - // calculate equivalent translate - var trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); - - // set up tlist - if (cangle) { - chtlist.removeItem(0); - } - - if (sangle) { - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(r2, 0); - } else { - chtlist.appendItem(r2); - } - } - - if (trm.e || trm.f) { - var tr = svgroot.createSVGTransform(); - tr.setTranslate(trm.e, trm.f); - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(tr, 0); - } else { - chtlist.appendItem(tr); - } - } - } - else { // more complicated than just a rotate - - // transfer the group's transform down to each child and then - // call recalculateDimensions() - var oldxform = elem.getAttribute("transform"); - var changes = {}; - changes["transform"] = oldxform ? oldxform : ""; - - var newxform = svgroot.createSVGTransform(); - - // [ gm ] [ chm ] = [ chm ] [ gm' ] - // [ gm' ] = [ chm_inv ] [ gm ] [ chm ] - var chm = transformListToTransform(chtlist).matrix, - chm_inv = chm.inverse(); - var gm = matrixMultiply( chm_inv, m, chm ); - newxform.setMatrix(gm); - chtlist.appendItem(newxform); - } - var cmd = recalculateDimensions(elem); - if(cmd) batchCmd.addSubCommand(cmd); - } - } - - - // remove transform and make it undo-able - if (xform) { - var changes = {}; - changes["transform"] = xform; - g.setAttribute("transform", ""); - g.removeAttribute("transform"); - batchCmd.addSubCommand(new ChangeElementCommand(g, changes)); - } - - if (undoable && !batchCmd.isEmpty()) { - return batchCmd; - } -} - - -// Function: ungroupSelectedElement -// Unwraps all the elements in a selected group (g) element. This requires -// significant recalculations to apply group's transforms, etc to its children -this.ungroupSelectedElement = function() { - var g = selectedElements[0]; - if($(g).data('gsvg') || $(g).data('symbol')) { - // Is svg, so actually convert to group - - convertToGroup(g); - return; - } else if(g.tagName === 'use') { - // Somehow doesn't have data set, so retrieve - var symbol = getElem(getHref(g).substr(1)); - $(g).data('symbol', symbol).data('ref', symbol); - convertToGroup(g); - return; - } - var parents_a = $(g).parents('a'); - if(parents_a.length) { - g = parents_a[0]; - } - - // Look for parent "a" - if (g.tagName === "g" || g.tagName === "a") { - - var batchCmd = new BatchCommand("Ungroup Elements"); - var cmd = pushGroupProperties(g, true); - if(cmd) batchCmd.addSubCommand(cmd); - - var parent = g.parentNode; - var anchor = g.nextSibling; - var children = new Array(g.childNodes.length); - - var i = 0; - - while (g.firstChild) { - var elem = g.firstChild; - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - - // Remove child title elements - if(elem.tagName === 'title') { - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent)); - oldParent.removeChild(elem); - continue; - } - - children[i++] = elem = parent.insertBefore(elem, anchor); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - - // remove the group from the selection - clearSelection(); - - // delete the group element (but make undo-able) - var gNextSibling = g.nextSibling; - g = parent.removeChild(g); - batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)); - - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - addToSelection(children); - } -}; - -// Function: moveToTopSelectedElement -// Repositions the selected element to the bottom in the DOM to appear on top of -// other elements -this.moveToTopSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - t = t.parentNode.appendChild(t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "top")); - call("changed", [t]); - } - } -}; - -// Function: moveToBottomSelectedElement -// Repositions the selected element to the top in the DOM to appear under -// other elements -this.moveToBottomSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - var firstChild = t.parentNode.firstChild; - if (firstChild.tagName == 'title') { - firstChild = firstChild.nextSibling; - } - // This can probably be removed, as the defs should not ever apppear - // inside a layer group - if (firstChild.tagName == 'defs') { - firstChild = firstChild.nextSibling; - } - t = t.parentNode.insertBefore(t, firstChild); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "bottom")); - call("changed", [t]); - } - } -}; - -// Function: moveUpDownSelected -// Moves the select element up or down the stack, based on the visibly -// intersecting elements -// -// Parameters: -// dir - String that's either 'Up' or 'Down' -this.moveUpDownSelected = function(dir) { - var selected = selectedElements[0]; - if (!selected) return; - - curBBoxes = []; - var closest, found_cur; - // jQuery sorts this list - var list = $(getIntersectionList(getStrokedBBox([selected]))).toArray(); - if(dir == 'Down') list.reverse(); - - $.each(list, function() { - if(!found_cur) { - if(this == selected) { - found_cur = true; - } - return; - } - closest = this; - return false; - }); - if(!closest) return; - - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - $(closest)[dir == 'Down'?'before':'after'](t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "Move " + dir)); - call("changed", [t]); - } -}; - -// Function: moveSelectedElements -// Moves selected elements on the X/Y axis -// -// Parameters: -// dx - Float with the distance to move on the x-axis -// dy - Float with the distance to move on the y-axis -// undoable - Boolean indicating whether or not the action should be undoable -// -// Returns: -// Batch command for the move -this.moveSelectedElements = function(dx, dy, undoable) { - // if undoable is not sent, default to true - // if single values, scale them to the zoom - if (dx.constructor != Array) { - dx /= current_zoom; - dy /= current_zoom; - } - var undoable = undoable || true; - var batchCmd = new BatchCommand("position"); - var i = selectedElements.length; - while (i--) { - var selected = selectedElements[i]; - if (selected != null) { -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(selected); - -// var b = {}; -// for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; -// selectedBBoxes[i] = b; - - var xform = svgroot.createSVGTransform(); - var tlist = getTransformList(selected); - - // dx and dy could be arrays - if (dx.constructor == Array) { -// if (i==0) { -// selectedBBoxes[0].x += dx[0]; -// selectedBBoxes[0].y += dy[0]; -// } - xform.setTranslate(dx[i],dy[i]); - } else { -// if (i==0) { -// selectedBBoxes[0].x += dx; -// selectedBBoxes[0].y += dy; -// } - xform.setTranslate(dx,dy); - } - - if(tlist.numberOfItems) { - tlist.insertItemBefore(xform, 0); - } else { - tlist.appendItem(xform); - } - - var cmd = recalculateDimensions(selected); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - - selectorManager.requestSelector(selected).resize(); - } - } - if (!batchCmd.isEmpty()) { - if (undoable) - addCommandToHistory(batchCmd); - call("changed", selectedElements); - return batchCmd; - } -}; - -// Function: cloneSelectedElements -// Create deep DOM copies (clones) of all selected elements and move them slightly -// from their originals -this.cloneSelectedElements = function(x,y) { - var batchCmd = new BatchCommand("Clone Elements"); - // find all the elements selected (stop at first null) - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - } - // use slice to quickly get the subset of elements we need - var copiedElements = selectedElements.slice(0,i); - this.clearSelection(true); - // note that we loop in the reverse way because of the way elements are added - // to the selectedElements array (top-first) - var i = copiedElements.length; - while (i--) { - // clone each element and replace it within copiedElements - var elem = copiedElements[i] = copyElem(copiedElements[i]); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(elem); - batchCmd.addSubCommand(new InsertElementCommand(elem)); - } - - if (!batchCmd.isEmpty()) { - addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - this.moveSelectedElements(x,y,false); - addCommandToHistory(batchCmd); - } -}; - -// Function: alignSelectedElements -// Aligns selected elements -// -// Parameters: -// type - String with single character indicating the alignment type -// relative_to - String that must be one of the following: -// "selected", "largest", "smallest", "page" -this.alignSelectedElements = function(type, relative_to) { - var bboxes = [], angles = []; - var minx = Number.MAX_VALUE, maxx = Number.MIN_VALUE, miny = Number.MAX_VALUE, maxy = Number.MIN_VALUE; - var curwidth = Number.MIN_VALUE, curheight = Number.MIN_VALUE; - var len = selectedElements.length; - if (!len) return; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - bboxes[i] = getStrokedBBox([elem]); - - // now bbox is axis-aligned and handles rotation - switch (relative_to) { - case 'smallest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth > bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight > bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - case 'largest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth < bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight < bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - default: // 'selected' - if (bboxes[i].x < minx) minx = bboxes[i].x; - if (bboxes[i].y < miny) miny = bboxes[i].y; - if (bboxes[i].x + bboxes[i].width > maxx) maxx = bboxes[i].x + bboxes[i].width; - if (bboxes[i].y + bboxes[i].height > maxy) maxy = bboxes[i].y + bboxes[i].height; - break; - } - } // loop for each element to find the bbox and adjust min/max - - if (relative_to == 'page') { - minx = 0; - miny = 0; - maxx = canvas.contentW; - maxy = canvas.contentH; - } - - var dx = new Array(len); - var dy = new Array(len); - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - var bbox = bboxes[i]; - dx[i] = 0; - dy[i] = 0; - switch (type) { - case 'l': // left (horizontal) - dx[i] = minx - bbox.x; - break; - case 'c': // center (horizontal) - dx[i] = (minx+maxx)/2 - (bbox.x + bbox.width/2); - break; - case 'r': // right (horizontal) - dx[i] = maxx - (bbox.x + bbox.width); - break; - case 't': // top (vertical) - dy[i] = miny - bbox.y; - break; - case 'm': // middle (vertical) - dy[i] = (miny+maxy)/2 - (bbox.y + bbox.height/2); - break; - case 'b': // bottom (vertical) - dy[i] = maxy - (bbox.y + bbox.height); - break; - } - } - this.moveSelectedElements(dx,dy); -}; - -// Group: Additional editor tools - -this.contentW = getResolution().w; -this.contentH = getResolution().h; - -// Function: updateCanvas -// Updates the editor canvas width/height/position after a zoom has occurred -// -// Parameters: -// w - Float with the new width -// h - Float with the new height -// -// Returns: -// Object with the following values: -// * x - The canvas' new x coordinate -// * y - The canvas' new y coordinate -// * old_x - The canvas' old x coordinate -// * old_y - The canvas' old y coordinate -// * d_x - The x position difference -// * d_y - The y position difference -this.updateCanvas = function(w, h) { - svgroot.setAttribute("width", w); - svgroot.setAttribute("height", h); - var bg = $('#canvasBackground')[0]; - var old_x = svgcontent.getAttribute('x'); - var old_y = svgcontent.getAttribute('y'); - var x = (w/2 - this.contentW*current_zoom/2); - var y = (h/2 - this.contentH*current_zoom/2); - - assignAttributes(svgcontent, { - width: this.contentW*current_zoom, - height: this.contentH*current_zoom, - 'x': x, - 'y': y, - "viewBox" : "0 0 " + this.contentW + " " + this.contentH - }); - - assignAttributes(bg, { - width: svgcontent.getAttribute('width'), - height: svgcontent.getAttribute('height'), - x: x, - y: y - }); - - var bg_img = getElem('background_image'); - if (bg_img) { - assignAttributes(bg_img, { - 'width': '100%', - 'height': '100%' - }); - } - - selectorManager.selectorParentGroup.setAttribute("transform","translate(" + x + "," + y + ")"); - - return {x:x, y:y, old_x:old_x, old_y:old_y, d_x:x - old_x, d_y:y - old_y}; -} - -// Function: setBackground -// Set the background of the editor (NOT the actual document) -// -// Parameters: -// color - String with fill color to apply -// url - URL or path to image to use -this.setBackground = function(color, url) { - var bg = getElem('canvasBackground'); - var border = $(bg).find('rect')[0]; - var bg_img = getElem('background_image'); - border.setAttribute('fill',color); - if(url) { - if(!bg_img) { - bg_img = svgdoc.createElementNS(svgns, "image"); - assignAttributes(bg_img, { - 'id': 'background_image', - 'width': '100%', - 'height': '100%', - 'preserveAspectRatio': 'xMinYMin', - 'style':'pointer-events:none' - }); - } - setHref(bg_img, url); - bg.appendChild(bg_img); - } else if(bg_img) { - bg_img.parentNode.removeChild(bg_img); - } -} - -// Function: cycleElement -// Select the next/previous element within the current layer -// -// Parameters: -// next - Boolean where true = next and false = previous element -this.cycleElement = function(next) { - var cur_elem = selectedElements[0]; - var elem = false; - var all_elems = getVisibleElements(current_group || getCurrentDrawing().getCurrentLayer()); - if(!all_elems.length) return; - if (cur_elem == null) { - var num = next?all_elems.length-1:0; - elem = all_elems[num]; - } else { - var i = all_elems.length; - while(i--) { - if(all_elems[i] == cur_elem) { - var num = next?i-1:i+1; - if(num >= all_elems.length) { - num = 0; - } else if(num < 0) { - num = all_elems.length-1; - } - elem = all_elems[num]; - break; - } - } - } - selectOnly([elem], true); - call("selected", selectedElements); -} - -this.clear(); - - -// DEPRECATED: getPrivateMethods -// Since all methods are/should be public somehow, this function should be removed - -// Being able to access private methods publicly seems wrong somehow, -// but currently appears to be the best way to allow testing and provide -// access to them to plugins. -this.getPrivateMethods = function() { - var obj = { - addCommandToHistory: addCommandToHistory, - setGradient: setGradient, - addSvgElementFromJson: addSvgElementFromJson, - assignAttributes: assignAttributes, - BatchCommand: BatchCommand, - call: call, - ChangeElementCommand: ChangeElementCommand, - copyElem: copyElem, - ffClone: ffClone, - findDefs: findDefs, - findDuplicateGradient: findDuplicateGradient, - getElem: getElem, - getId: getId, - getIntersectionList: getIntersectionList, - getMouseTarget: getMouseTarget, - getNextId: getNextId, - getPathBBox: getPathBBox, - getUrlFromAttr: getUrlFromAttr, - hasMatrixTransform: hasMatrixTransform, - identifyLayers: identifyLayers, - InsertElementCommand: InsertElementCommand, - isIdentity: svgedit.math.isIdentity, - logMatrix: logMatrix, - matrixMultiply: matrixMultiply, - MoveElementCommand: MoveElementCommand, - preventClickDefault: preventClickDefault, - recalculateAllSelectedDimensions: recalculateAllSelectedDimensions, - recalculateDimensions: recalculateDimensions, - remapElement: remapElement, - RemoveElementCommand: RemoveElementCommand, - removeUnusedDefElems: removeUnusedDefElems, - round: round, - runExtensions: runExtensions, - sanitizeSvg: sanitizeSvg, - SVGEditTransformList: svgedit.transformlist.SVGTransformList, - toString: toString, - transformBox: svgedit.math.transformBox, - transformListToTransform: transformListToTransform, - transformPoint: transformPoint, - walkTree: svgedit.utilities.walkTree - } - return obj; -}; - -} diff --git a/build/firefox/content/editor/svgedit.compiled.js b/build/firefox/content/editor/svgedit.compiled.js deleted file mode 100644 index 56075ab..0000000 --- a/build/firefox/content/editor/svgedit.compiled.js +++ /dev/null @@ -1,527 +0,0 @@ -(function(a){function H(h){if(typeof h.data==="string"){var i=h.handler,u=h.data.toLowerCase().split(" ");h.handler=function(E){if(!(this!==E.target&&(/textarea|select/i.test(E.target.nodeName)||E.target.type==="text"))){var e=E.type!=="keypress"&&a.hotkeys.specialKeys[E.which],f=String.fromCharCode(E.which).toLowerCase(),g="",p={};if(E.altKey&&e!=="alt")g+="alt+";if(E.ctrlKey&&e!=="ctrl")g+="ctrl+";if(E.metaKey&&!E.ctrlKey&&e!=="meta")g+="meta+";if(E.shiftKey&&e!=="shift")g+="shift+";if(e)p[g+e]= -true;else{p[g+f]=true;p[g+a.hotkeys.shiftNums[f]]=true;if(g==="shift+")p[a.hotkeys.shiftNums[f]]=true}e=0;for(f=u.length;e<f;e++)if(p[u[e]])return i.apply(this,arguments)}}}}a.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9", -106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta",219:"[",221:"]"},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};a.each(["keydown","keyup","keypress"],function(){a.event.special[this]={add:H}})})(jQuery);(function(a,H){function h(U){return typeof U==="string"}function i(U){var Z=g.call(arguments,1);return function(){return U.apply(this,Z.concat(g.call(arguments)))}}function u(U,Z,ea,ra,ja){var la;if(ra!==f){Z=ea.match(U?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);ea=Z[3]||"";if(ja===2&&h(ra))ra=ra.replace(U?va:Na,"");else{la=q(Z[2]);ra=h(ra)?q[U?X:ka](ra):ra;ra=ja===2?ra:ja===1?a.extend({},ra,la):a.extend({},la,ra);ra=z(ra);if(U)ra=ra.replace(ha,p)}U=Z[1]+(U?"#":ra||!Z[1]?"?":"")+ra+ea}else U= -Z(ea!==f?ea:H[qa][ga]);return U}function E(U,Z,ea){if(Z===f||typeof Z==="boolean"){ea=Z;Z=z[U?X:ka]()}else Z=h(Z)?Z.replace(U?va:Na,""):Z;return q(Z,ea)}function e(U,Z,ea,ra){if(!h(ea)&&typeof ea!=="object"){ra=ea;ea=Z;Z=f}return this.each(function(){var ja=a(this),la=Z||ma()[(this.nodeName||"").toLowerCase()]||"",T=la&&ja.attr(la)||"";ja.attr(la,z[U](T,ea,ra))})}var f,g=Array.prototype.slice,p=decodeURIComponent,z=a.param,D,q,M,ba=a.bbq=a.bbq||{},N,I,ma,ia=a.event.special,ka="querystring",X="fragment", -qa="location",ga="href",Na=/^.*\?|#.*$/g,va=/^.*\#/,ha,Ra={};z[ka]=i(u,0,function(U){return U.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")});z[X]=D=i(u,1,function(U){return U.replace(/^[^#]*#?(.*)$/,"$1")});D.noEscape=function(U){U=U||"";U=a.map(U.split(""),encodeURIComponent);ha=RegExp(U.join("|"),"g")};D.noEscape(",/");a.deparam=q=function(U,Z){var ea={},ra={"true":true,"false":false,"null":null};a.each(U.replace(/\+/g," ").split("&"),function(ja,la){var T=la.split("="),wa=p(T[0]),Da=ea,Ma=0,Fa=wa.split("]["), -Oa=Fa.length-1;if(/\[/.test(Fa[0])&&/\]$/.test(Fa[Oa])){Fa[Oa]=Fa[Oa].replace(/\]$/,"");Fa=Fa.shift().split("[").concat(Fa);Oa=Fa.length-1}else Oa=0;if(T.length===2){T=p(T[1]);if(Z)T=T&&!isNaN(T)?+T:T==="undefined"?f:ra[T]!==f?ra[T]:T;if(Oa)for(;Ma<=Oa;Ma++){wa=Fa[Ma]===""?Da.length:Fa[Ma];Da=Da[wa]=Ma<Oa?Da[wa]||(Fa[Ma+1]&&isNaN(Fa[Ma+1])?{}:[]):T}else if(a.isArray(ea[wa]))ea[wa].push(T);else ea[wa]=ea[wa]!==f?[ea[wa],T]:T}else if(wa)ea[wa]=Z?f:""});return ea};q[ka]=i(E,0);q[X]=M=i(E,1);a.elemUrlAttr|| -(a.elemUrlAttr=function(U){return a.extend(Ra,U)})({a:ga,base:ga,iframe:"src",img:"src",input:"src",form:"action",link:ga,script:"src"});ma=a.elemUrlAttr;a.fn[ka]=i(e,ka);a.fn[X]=i(e,X);ba.pushState=N=function(U,Z){if(h(U)&&/^#/.test(U)&&Z===f)Z=2;var ea=U!==f;ea=D(H[qa][ga],ea?U:{},ea?Z:2);H[qa][ga]=ea+(/#/.test(ea)?"":"#")};ba.getState=I=function(U,Z){return U===f||typeof U==="boolean"?M(U):M(Z)[U]};ba.removeState=function(U){var Z={};if(U!==f){Z=I();a.each(a.isArray(U)?U:arguments,function(ea, -ra){delete Z[ra]})}N(Z,2)};ia.hashchange=a.extend(ia.hashchange,{add:function(U){function Z(ra){var ja=ra[X]=D();ra.getState=function(la,T){return la===f||typeof la==="boolean"?q(ja,la):q(ja,T)[la]};ea.apply(this,arguments)}var ea;if(a.isFunction(U)){ea=U;return Z}else{ea=U.handler;U.handler=Z}}})})(jQuery,this); -(function(a,H,h){function i(D){D=D||H[e][f];return D.replace(/^[^#]*#?(.*)$/,"$1")}var u,E=a.event.special,e="location",f="href",g=document.documentMode,p=a.browser.msie&&(g===h||g<8),z="onhashchange"in H&&!p;a.hashchangeDelay=100;E.hashchange=a.extend(E.hashchange,{setup:function(){if(z)return false;a(u.start)},teardown:function(){if(z)return false;a(u.stop)}});u=function(){function D(){N=I=function(ma){return ma};if(p){ba=a('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow; -I=function(){return i(ba.document[e][f])};N=function(ma,ia){if(ma!==ia){var ka=ba.document;ka.open().close();ka[e].hash="#"+ma}};N(i())}}var q={},M,ba,N,I;q.start=function(){if(!M){var ma=i();N||D();(function ia(){var ka=i(),X=I(ma);if(ka!==ma){N(ma=ka,X);a(H).trigger("hashchange")}else if(X!==ma)H[e][f]=H[e][f].replace(/#.*/,"")+"#"+X;M=setTimeout(ia,a.hashchangeDelay)})()}};q.stop=function(){if(!ba){M&&clearTimeout(M);M=0}};return q}()})(jQuery,this);(function(a){var H={},h;a.svgIcons=function(i,u){function E(U,Z){if(U!=="ajax"){if(ma)return;var ea=(ba=ga[0].contentDocument)&&ba.getElementById("svg_eof");if(!ea&&!(Z&&ea)){ia++;if(ia<50)setTimeout(E,20);else{f();ma=true}return}ma=true}M=a(ba.firstChild).children();if(u.no_img)setTimeout(function(){I||e()},500);else{ea=qa+"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D";N=a(new Image).attr({src:ea,width:0,height:0}).appendTo("body").load(function(){e(true)}).error(function(){e()})}} -function e(U,Z){if(!I){if(u.no_img)U=false;if(U){var ea=a(document.createElement("div"));ea.hide().appendTo("body")}if(Z){var ra=u.fallback_path?u.fallback_path:"";a.each(Z,function(Oa,Qa){a("#"+Oa);var Ga=a(new Image).attr({"class":"svg_icon",src:ra+Qa,width:D,height:q,alt:"icon"});Ra(Ga,Oa)})}else for(var ja=M.length,la=0;la<ja;la++){var T=M[la],wa=T.id;if(wa==="svg_eof")break;a("#"+wa);T=T.getElementsByTagNameNS(p,"svg")[0];var Da=document.createElementNS(p,"svg");Da.setAttributeNS(p,"viewBox", -[0,0,D,q].join(" "));var Ma=T.getAttribute("width"),Fa=T.getAttribute("height");T.removeAttribute("width");T.removeAttribute("height");T.getAttribute("viewBox")||T.setAttribute("viewBox",[0,0,Ma,Fa].join(" "));Da.setAttribute("xmlns",p);Da.setAttribute("width",D);Da.setAttribute("height",q);Da.setAttribute("xmlns:xlink",z);Da.setAttribute("class","svg_icon");X||(T=T.cloneNode(true));Da.appendChild(T);if(U){X||Da.cloneNode(true);ea.empty().append(Da);T=qa+g(ea.html());T=a(new Image).attr({"class":"svg_icon", -src:T})}else T=h(a(Da),la);Ra(T,wa)}u.placement&&a.each(u.placement,function(Oa,Qa){H[Qa]&&a(Oa).each(function(Ga){var Ca=H[Qa].clone();if(Ga>0&&!U)Ca=h(Ca,Ga,true);ha(a(this),Ca,Qa)})});if(!Z){U&&ea.remove();ga&&ga.remove();N&&N.remove()}u.resize&&a.resizeSvgIcons(u.resize);I=true;u.callback&&u.callback(H)}}function f(){if(i.indexOf(".svgz")!=-1){var U=i.replace(".svgz",".svg");window.console&&console.log(".svgz failed, trying with .svg");a.svgIcons(U,u)}else u.fallback&&e(false,u.fallback)}function g(U){if(window.btoa)return window.btoa(U); -var Z=Array(Math.floor((U.length+2)/3)*4),ea,ra,ja,la,T,wa,Da=0,Ma=0;do{ea=U.charCodeAt(Da++);ra=U.charCodeAt(Da++);ja=U.charCodeAt(Da++);la=ea>>2;ea=(ea&3)<<4|ra>>4;T=(ra&15)<<2|ja>>6;wa=ja&63;if(isNaN(ra))T=wa=64;else if(isNaN(ja))wa=64;Z[Ma++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(la);Z[Ma++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(ea);Z[Ma++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(T);Z[Ma++]= -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(wa)}while(Da<U.length);return Z.join("")}var p="http://www.w3.org/2000/svg",z="http://www.w3.org/1999/xlink",D=u.w?u.w:24,q=u.h?u.h:24,M,ba,N,I=false,ma=false,ia=0,ka=navigator.userAgent,X=!!window.opera;ka.indexOf("Safari/")>-1&&ka.indexOf("Chrome/");var qa="data:image/svg+xml;charset=utf-8;base64,";if(u.svgz){var ga=a('<object data="'+i+'" type=image/svg+xml>').appendTo("body").hide();try{ba=ga[0].contentDocument;ga.load(E); -E(0,true)}catch(Na){f()}}else{var va=new DOMParser;a.ajax({url:i,dataType:"string",success:function(U){if(U){ba=va.parseFromString(U,"text/xml");a(function(){E("ajax")})}else a(f)},error:function(U){if(window.opera)a(function(){f()});else if(U.responseText){ba=va.parseFromString(U.responseText,"text/xml");ba.childNodes.length||a(f);a(function(){E("ajax")})}else a(f)}})}var ha=function(U,Z,ea,ra){X&&Z.css("visibility","hidden");if(u.replace){ra&&Z.attr("id",ea);(ea=U.attr("class"))&&Z.attr("class", -"svg_icon "+ea);U.replaceWith(Z)}else U.append(Z);X&&setTimeout(function(){Z.removeAttr("style")},1)},Ra=function(U,Z){if(u.id_match===undefined||u.id_match!==false)ha(holder,U,Z,true);H[Z]=U};h=function(U,Z){var ea=U.find("defs");if(!ea.length)return U;ea=X?ea.find("*").filter(function(){return!!this.id}):ea.find("[id]");var ra=U[0].getElementsByTagName("*"),ja=ra.length;ea.each(function(la){var T=this.id;a(ba).find("#"+T);this.id=la="x"+T+Z+la;T="url(#"+T+")";var wa="url(#"+la+")";for(la=0;la<ja;la++){var Da= -ra[la];Da.getAttribute("fill")===T&&Da.setAttribute("fill",wa);Da.getAttribute("stroke")===T&&Da.setAttribute("stroke",wa);Da.getAttribute("filter")===T&&Da.setAttribute("filter",wa)}});return U}};a.getSvgIcon=function(i,u){var E=H[i];if(u&&E)E=h(E,0,true).clone(true);return E};a.resizeSvgIcons=function(i){var u=!a(".svg_icon:first").length;a.each(i,function(E,e){var f=a.isArray(e),g=f?e[0]:e,p=f?e[1]:e;if(u)E=E.replace(/\.svg_icon/g,"svg");a(E).each(function(){this.setAttribute("width",g);this.setAttribute("height", -p);if(window.opera&&window.widget){this.parentNode.style.width=g+"px";this.parentNode.style.height=p+"px"}})})}})(jQuery);(function(){function a(i,u,E){i=document.createElementNS(H.svg,i);if(h)for(var e in u)i.setAttribute(e,u[e]);else for(e in u){var f=u[e],g=i[e];if(g&&g.constructor==="SVGLength")g.baseVal.value=f;else i.setAttribute(e,f)}E&&E.appendChild(i);return i}var H={svg:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};if(!window.console)window.console=new function(){this.log=function(){};this.dir=function(){}};$.jGraduate={Paint:function(i){i=i||{};this.alpha=isNaN(i.alpha)?100:i.alpha;if(i.copy){this.type= -i.copy.type;this.alpha=i.copy.alpha;this.radialGradient=this.linearGradient=this.solidColor=null;switch(this.type){case "solidColor":this.solidColor=i.copy.solidColor;break;case "linearGradient":this.linearGradient=i.copy.linearGradient.cloneNode(true);break;case "radialGradient":this.radialGradient=i.copy.radialGradient.cloneNode(true)}}else if(i.linearGradient){this.type="linearGradient";this.radialGradient=this.solidColor=null;this.linearGradient=i.linearGradient.cloneNode(true)}else if(i.radialGradient){this.type= -"radialGradient";this.linearGradient=this.solidColor=null;this.radialGradient=i.radialGradient.cloneNode(true)}else if(i.solidColor){this.type="solidColor";this.solidColor=i.solidColor}else{this.type="none";this.radialGradient=this.linearGradient=this.solidColor=null}}};jQuery.fn.jGraduateDefaults={paint:new $.jGraduate.Paint,window:{pickerTitle:"Drag markers to pick a paint"},images:{clientPath:"images/"},newstop:"inverse"};var h=navigator.userAgent.indexOf("Gecko/")>=0;jQuery.fn.jGraduate=function(i){var u= -arguments;return this.each(function(){function E(pa,V,ua,ya,aa){var Sa=aa||a("stop",{"stop-color":V,"stop-opacity":ua,offset:pa},va);if(aa){V=aa.getAttribute("stop-color");ua=aa.getAttribute("stop-opacity");pa=aa.getAttribute("offset")}else va.appendChild(Sa);if(ua===null)ua=1;aa=a("path",{d:"M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z",fill:"url(#jGraduate_trans)",transform:"translate("+(10+pa*X)+", 26)"},zb); -var Eb=a("path",{d:"M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z",fill:V,"fill-opacity":ua,transform:"translate("+(10+pa*X)+", 26)",stroke:"#000","stroke-width":1.5},zb);$(Eb).mousedown(function(Ab){e(this);Va=gb;ma.mousemove(p).mouseup(f);Bb=Pb.offset();Ab.preventDefault();return false}).data("stop",Sa).data("bg",aa).dblclick(function(){$("div.jGraduate_LightBox").show();for(var Ab=this,wb=+Sa.getAttribute("stop-opacity")|| -1,tb=Sa.getAttribute("stop-color")||1,Fb=(parseFloat(wb)*255).toString(16);Fb.length<2;)Fb="0"+Fb;V=tb.substr(1)+Fb;$("#"+q+"_jGraduate_stopPicker").css({left:100,bottom:15}).jPicker({window:{title:"Pick the start color and opacity for the gradient"},images:{clientPath:D.images.clientPath},color:{active:V,alphaSupport:true}},function(Qb){tb=Qb.val("hex")?"#"+Qb.val("hex"):"none";wb=Qb.val("a")!==null?Qb.val("a")/256:1;Ab.setAttribute("fill",tb);Ab.setAttribute("fill-opacity",wb);Sa.setAttribute("stop-color", -tb);Sa.setAttribute("stop-opacity",wb);$("div.jGraduate_LightBox").hide();$("#"+q+"_jGraduate_stopPicker").hide()},null,function(){$("div.jGraduate_LightBox").hide();$("#"+q+"_jGraduate_stopPicker").hide()})});$(va).find("stop").each(function(){var Ab=$(this);if(+this.getAttribute("offset")>pa){if(!V){var wb=this.getAttribute("stop-color"),tb=this.getAttribute("stop-opacity");Sa.setAttribute("stop-color",wb);Eb.setAttribute("fill",wb);Sa.setAttribute("stop-opacity",tb===null?1:tb);Eb.setAttribute("fill-opacity", -tb===null?1:tb)}Ab.before(Sa);return false}});ya&&e(Eb);return Sa}function e(pa){gb&&gb.setAttribute("stroke","#000");pa.setAttribute("stroke","blue");gb=pa;gb.parentNode.appendChild(gb)}function f(){ma.unbind("mousemove",p);if(ub.getAttribute("display")!=="none"){ub.setAttribute("display","none");var pa=$(gb),V=pa.data("stop");pa=pa.data("bg");$([gb,V,pa]).remove()}Va=null}function g(){var pa=Wa?"rotate("+Wa+","+Ia+","+kb+") ":"";Ua===1&&Ja===1?va.removeAttribute("gradientTransform"):va.setAttribute("gradientTransform", -pa+"translate("+-Ia*(Ua-1)+","+-kb*(Ja-1)+") scale("+Ua+","+Ja+")")}function p(pa){var V=pa.pageX-Bb.left;pa=pa.pageY-Bb.top;V=V<10?10:V>X+10?X+10:V;var ua="translate("+V+", 26)";if(pa<-60||pa>130){ub.setAttribute("display","block");ub.setAttribute("transform",ua)}else ub.setAttribute("display","none");Va.setAttribute("transform",ua);$.data(Va,"bg").setAttribute("transform",ua);$.data(Va,"stop").setAttribute("offset",(V-10)/X);var ya=0;$(va).find("stop").each(function(){var aa=this.getAttribute("offset"), -Sa=$(this);if(aa<ya){Sa.prev().before(Sa);Aa=$(va).find("stop")}ya=aa})}var z=$(this),D=$.extend(true,{},jQuery.fn.jGraduateDefaults,i),q=z.attr("id"),M="#"+z.attr("id")+" ";if(M){var ba=function(){switch(z.paint.type){case "radialGradient":z.paint.linearGradient=null;break;case "linearGradient":z.paint.radialGradient=null;break;case "solidColor":z.paint.radialGradient=z.paint.linearGradient=null}$.isFunction(z.okCallback)&&z.okCallback(z.paint);z.hide()},N=function(){$.isFunction(z.cancelCallback)&& -z.cancelCallback();z.hide()};$.extend(true,z,{paint:new $.jGraduate.Paint({copy:D.paint}),okCallback:$.isFunction(u[1])&&u[1]||null,cancelCallback:$.isFunction(u[2])&&u[2]||null});z.position();var I=null,ma=$(window);if(z.paint.type=="none")z.paint=$.jGraduate.Paint({solidColor:"ffffff"});z.addClass("jGraduate_Picker");z.html('<ul class="jGraduate_tabs"><li class="jGraduate_tab_color jGraduate_tab_current" data-type="col">Solid Color</li><li class="jGraduate_tab_lingrad" data-type="lg">Linear Gradient</li><li class="jGraduate_tab_radgrad" data-type="rg">Radial Gradient</li></ul><div class="jGraduate_colPick"></div><div class="jGraduate_gradPick"></div><div class="jGraduate_LightBox"></div><div id="'+ -q+'_jGraduate_stopPicker" class="jGraduate_stopPicker"></div>');var ia=$(M+"> .jGraduate_colPick"),ka=$(M+"> .jGraduate_gradPick");ka.html('<div id="'+q+'_jGraduate_Swatch" class="jGraduate_Swatch"><h2 class="jGraduate_Title">'+D.window.pickerTitle+'</h2><div id="'+q+'_jGraduate_GradContainer" class="jGraduate_GradContainer"></div><div id="'+q+'_jGraduate_StopSlider" class="jGraduate_StopSlider"></div></div><div class="jGraduate_Form jGraduate_Points jGraduate_lg_field"><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Begin Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+ -q+'_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+q+'_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/></div></div><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">End Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+q+'_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+ -q+'_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/></div></div></div><div class="jGraduate_Form jGraduate_Points jGraduate_rg_field"><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Center Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+q+'_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+q+'_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/></div></div><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Focal Point</label><div class="jGraduate_Form_Section"><label>Match center: <input type="checkbox" checked="checked" id="'+ -q+'_jGraduate_match_ctr"/></label><br/><label>x:</label><input type="text" id="'+q+'_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+q+'_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/></div></div></div><div class="jGraduate_StopSection jGraduate_SpreadMethod"><label class="jGraduate_Form_Heading">Spread method</label><div class="jGraduate_Form_Section"><select class="jGraduate_spreadMethod"><option value=pad selected>Pad</option><option value=reflect>Reflect</option><option value=repeat>Repeat</option></select></div></div><div class="jGraduate_Form"><div class="jGraduate_Slider jGraduate_RadiusField jGraduate_rg_field"><label class="prelabel">Radius:</label><div id="'+ -q+'_jGraduate_Radius" class="jGraduate_SliderBar jGraduate_Radius" title="Click to set radius"><img id="'+q+'_jGraduate_RadiusArrows" class="jGraduate_RadiusArrows" src="'+D.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_RadiusInput" size="3" value="100"/>%</label></div><div class="jGraduate_Slider jGraduate_EllipField jGraduate_rg_field"><label class="prelabel">Ellip:</label><div id="'+q+'_jGraduate_Ellip" class="jGraduate_SliderBar jGraduate_Ellip" title="Click to set Ellip"><img id="'+ -q+'_jGraduate_EllipArrows" class="jGraduate_EllipArrows" src="'+D.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_EllipInput" size="3" value="0"/>%</label></div><div class="jGraduate_Slider jGraduate_AngleField jGraduate_rg_field"><label class="prelabel">Angle:</label><div id="'+q+'_jGraduate_Angle" class="jGraduate_SliderBar jGraduate_Angle" title="Click to set Angle"><img id="'+q+'_jGraduate_AngleArrows" class="jGraduate_AngleArrows" src="'+D.images.clientPath+ -'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_AngleInput" size="3" value="0"/>\u00ba </label></div><div class="jGraduate_Slider jGraduate_OpacField"><label class="prelabel">Opac:</label><div id="'+q+'_jGraduate_Opac" class="jGraduate_SliderBar jGraduate_Opac" title="Click to set Opac"><img id="'+q+'_jGraduate_OpacArrows" class="jGraduate_OpacArrows" src="'+D.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_OpacInput" size="3" value="100"/>%</label></div></div><div class="jGraduate_OkCancel"><input type="button" id="'+ -q+'_jGraduate_Ok" class="jGraduate_Ok" value="OK"/><input type="button" id="'+q+'_jGraduate_Cancel" class="jGraduate_Cancel" value="Cancel"/></div>');var X=256,qa=X-0,ga=X-0,Na,va,ha,Ra={};$(".jGraduate_SliderBar").width(145);var U=$("#"+q+"_jGraduate_GradContainer")[0],Z=a("svg",{id:q+"_jgraduate_svg",width:X,height:X,xmlns:H.svg},U);Na=Na||z.paint.type;var ea=va=z.paint[Na],ra=z.paint.alpha,ja=Na==="solidColor";switch(Na){case "solidColor":case "linearGradient":if(!ja){va.id=q+"_lg_jgraduate_grad"; -ea=va=Z.appendChild(va)}a("radialGradient",{id:q+"_rg_jgraduate_grad"},Z);if(Na==="linearGradient")break;case "radialGradient":if(!ja){va.id=q+"_rg_jgraduate_grad";ea=va=Z.appendChild(va)}a("linearGradient",{id:q+"_lg_jgraduate_grad"},Z)}if(ja){ea=va=$("#"+q+"_lg_jgraduate_grad")[0];I=z.paint[Na];E(0,"#"+I,1);var la=typeof D.newstop;if(la==="string")switch(D.newstop){case "same":E(1,"#"+I,1);break;case "inverse":la="";for(var T=0;T<6;T+=2){I.substr(T,2);var wa=(255-parseInt(I.substr(T,2),16)).toString(16); -if(wa.length<2)wa=0+wa;la+=wa}E(1,"#"+la,1);break;case "white":E(1,"#ffffff",1);break;case "black":E(1,"#000000",1)}else if(la==="object")E(1,D.newstop.color||"#"+I,"opac"in D.newstop?D.newstop.opac:1)}I=parseFloat(ea.getAttribute("x1")||0);la=parseFloat(ea.getAttribute("y1")||0);T=parseFloat(ea.getAttribute("x2")||1);wa=parseFloat(ea.getAttribute("y2")||0);var Da=parseFloat(ea.getAttribute("cx")||0.5),Ma=parseFloat(ea.getAttribute("cy")||0.5),Fa=parseFloat(ea.getAttribute("fx")||Da),Oa=parseFloat(ea.getAttribute("fy")|| -Ma);ha=a("rect",{id:q+"_jgraduate_rect",x:0,y:0,width:qa,height:ga,fill:"url(#"+q+"_jgraduate_grad)","fill-opacity":ra/100},Z);var Qa=$("<div/>").attr({"class":"grad_coord jGraduate_lg_field",title:"Begin Stop"}).text(1).css({top:la*X,left:I*X}).data("coord","start").appendTo(U),Ga=Qa.clone().text(2).css({top:wa*X,left:T*X}).attr("title","End stop").data("coord","end").appendTo(U),Ca=$("<div/>").attr({"class":"grad_coord jGraduate_rg_field",title:"Center stop"}).text("C").css({top:Ma*X,left:Da*X}).data("coord", -"center").appendTo(U),Ha=Ca.clone().text("F").css({top:Oa*X,left:Fa*X,display:"none"}).attr("title","Focus point").data("coord","focus").appendTo(U);Ha[0].id=q+"_jGraduate_focusCoord";$(M+" .grad_coord");$.each(["x1","y1","x2","y2","cx","cy","fx","fy"],function(pa,V){var ua=va.getAttribute(V),ya=isNaN(V[1]);ua||(ua=ya?"0.5":V==="x2"?"1.0":"0.0");Ra[V]=$("#"+q+"_jGraduate_"+V).val(ua).change(function(){if(isNaN(parseFloat(this.value))||this.value<0)this.value=0;else if(this.value>1)this.value=1;if(!(V[0]=== -"f"&&!lb))if(ya&&Na==="radialGradient"||!ya&&Na==="linearGradient")va.setAttribute(V,this.value);var aa=ya?V[0]==="c"?Ca:Ha:V[1]==="1"?Qa:Ga,Sa=V.indexOf("x")>=0?"left":"top";aa.css(Sa,this.value*X)}).change()});var Aa,zb,Pb=$("#"+q+"_jGraduate_StopSlider"),gb,mb,Va,ub=a("path",{d:"m9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5",fill:"none",stroke:"#D00","stroke-width":5,display:"none"},mb),Bb,Ua=1,Ja=1,Wa=0,Ia=Da,kb=Ma;mb=a("svg",{width:"100%",height:45},Pb[0]);U=a("pattern",{width:16,height:16,patternUnits:"userSpaceOnUse", -id:"jGraduate_trans"},mb);a("image",{width:16,height:16},U).setAttributeNS(H.xlink,"xlink:href",D.images.clientPath+"map-opacity.png");$(mb).click(function(pa){Bb=Pb.offset();if(pa.target.tagName!=="path"){var V=pa.pageX-Bb.left-8;V=V<10?10:V>X+10?X+10:V;E(V/X,0,0,true);pa.stopPropagation()}});$(mb).mouseover(function(){mb.appendChild(ub)});zb=a("g",{},mb);a("line",{x1:10,y1:15,x2:X+10,y2:15,"stroke-width":2,stroke:"#000"},mb);var Cb=ka.find(".jGraduate_spreadMethod").change(function(){va.setAttribute("spreadMethod", -$(this).val())}),ab=null,cb=function(pa){var V=pa.pageX-vb.left,ua=pa.pageY-vb.top;V=V<0?0:V>X?X:V;ua=ua<0?0:ua>X?X:ua;ab.css("left",V).css("top",ua);V/=qa;ua/=ga;var ya=ab.data("coord"),aa=va;switch(ya){case "start":Ra.x1.val(V);Ra.y1.val(ua);aa.setAttribute("x1",V);aa.setAttribute("y1",ua);break;case "end":Ra.x2.val(V);Ra.y2.val(ua);aa.setAttribute("x2",V);aa.setAttribute("y2",ua);break;case "center":Ra.cx.val(V);Ra.cy.val(ua);aa.setAttribute("cx",V);aa.setAttribute("cy",ua);Ia=V;kb=ua;g();break; -case "focus":Ra.fx.val(V);Ra.fy.val(ua);aa.setAttribute("fx",V);aa.setAttribute("fy",ua);g()}pa.preventDefault()},db=function(){ab=null;ma.unbind("mousemove",cb).unbind("mouseup",db)};Aa=va.getElementsByTagNameNS(H.svg,"stop");if(za<2){for(;za<2;){va.appendChild(document.createElementNS(H.svg,"stop"));++za}Aa=va.getElementsByTagNameNS(H.svg,"stop")}var za=Aa.length;for(T=0;T<za;T++)E(0,0,0,0,Aa[T]);Cb.val(va.getAttribute("spreadMethod")||"pad");var vb,lb=false;ha.setAttribute("fill-opacity",ra/100); -$("#"+q+" div.grad_coord").mousedown(function(pa){pa.preventDefault();ab=$(this);ab.offset();vb=ab.parent().offset();ma.mousemove(cb).mouseup(db)});$("#"+q+"_jGraduate_Ok").bind("click",function(){z.paint.type=Na;z.paint[Na]=va.cloneNode(true);z.paint.solidColor=null;ba()});$("#"+q+"_jGraduate_Cancel").bind("click",function(){N()});if(Na==="radialGradient")if(lb)Ha.show();else{Ha.hide();Ra.fx.val("");Ra.fy.val("")}$("#"+q+"_jGraduate_match_ctr")[0].checked=!lb;var xb,Jb;$("#"+q+"_jGraduate_match_ctr").change(function(){lb= -!this.checked;Ha.toggle(lb);Ra.fx.val("");Ra.fy.val("");var pa=va;if(lb){var V=xb||0.5,ua=Jb||0.5;pa.setAttribute("fx",V);pa.setAttribute("fy",ua);Ra.fx.val(V);Ra.fy.val(ua)}else{xb=pa.getAttribute("fx");Jb=pa.getAttribute("fy");pa.removeAttribute("fx");pa.removeAttribute("fy")}});Aa=va.getElementsByTagNameNS(H.svg,"stop");za=Aa.length;if(za<2){for(;za<2;){va.appendChild(document.createElementNS(H.svg,"stop"));++za}Aa=va.getElementsByTagNameNS(H.svg,"stop")}var pb;ra=ka=0;if(Na==="radialGradient"){Z= -va.gradientTransform.baseVal;if(Z.numberOfItems===2){za=Z.getItem(0);Z=Z.getItem(1);if(za.type===2&&Z.type===3){za=Z.matrix;if(za.a!==1)ka=Math.round(-(1-za.a)*100);else if(za.d!==1)ka=Math.round((1-za.d)*100)}}else if(Z.numberOfItems===3){U=Z.getItem(0);za=Z.getItem(1);Z=Z.getItem(2);if(U.type===4&&za.type===2&&Z.type===3){ra=Math.round(U.angle);za=Z.matrix;if(za.a!==1)ka=Math.round(-(1-za.a)*100);else if(za.d!==1)ka=Math.round((1-za.d)*100)}}}ka={radius:{handle:"#"+q+"_jGraduate_RadiusArrows",input:"#"+ -q+"_jGraduate_RadiusInput",val:(va.getAttribute("r")||0.5)*100},opacity:{handle:"#"+q+"_jGraduate_OpacArrows",input:"#"+q+"_jGraduate_OpacInput",val:z.paint.alpha||100},ellip:{handle:"#"+q+"_jGraduate_EllipArrows",input:"#"+q+"_jGraduate_EllipInput",val:ka},angle:{handle:"#"+q+"_jGraduate_AngleArrows",input:"#"+q+"_jGraduate_AngleInput",val:ra}};$.each(ka,function(pa,V){var ua=$(V.handle);ua.mousedown(function(ya){var aa=ua.parent();pb={type:pa,elem:ua,input:$(V.input),parent:aa,offset:aa.offset()}; -ma.mousemove(Kb).mouseup(Rb);ya.preventDefault()});$(V.input).val(V.val).change(function(){var ya=+this.value,aa=0,Sa=Na==="radialGradient";switch(pa){case "radius":Sa&&va.setAttribute("r",ya/100);aa=Math.pow(ya/100,0.4)/2*145;break;case "opacity":z.paint.alpha=ya;ha.setAttribute("fill-opacity",ya/100);aa=ya*1.45;break;case "ellip":Ua=Ja=1;if(ya===0){aa=72.5;break}if(ya>99.5)ya=99.5;if(ya>0)Ja=1-ya/100;else Ua=-(ya/100)-1;aa=145*((ya+100)/2)/100;Sa&&g();break;case "angle":Wa=ya;aa=Wa/180;aa+=0.5; -aa*=145;Sa&&g()}if(aa>145)aa=145;else if(aa<0)aa=0;ua.css({"margin-left":aa-5})}).change()});var Kb=function(pa){var V=pa.pageX-pb.offset.left-parseInt(pb.parent.css("border-left-width"));if(V>145)V=145;if(V<=0)V=0;var ua=V-5;V/=145;switch(pb.type){case "radius":V=Math.pow(V*2,2.5);if(V>0.98&&V<1.02)V=1;if(V<=0.01)V=0.01;va.setAttribute("r",V);break;case "opacity":z.paint.alpha=parseInt(V*100);ha.setAttribute("fill-opacity",V);break;case "ellip":Ja=Ua=1;if(V<0.5){V/=0.5;Ua=V<=0?0.01:V}else if(V>0.5){V/= -0.5;V=2-V;Ja=V<=0?0.01:V}g();V-=1;if(Ja===V+1)V=Math.abs(V);break;case "angle":V-=0.5;Wa=V*=180;g();V/=100}pb.elem.css({"margin-left":ua});V=Math.round(V*100);pb.input.val(V);pa.preventDefault()},Rb=function(){ma.unbind("mousemove",Kb).unbind("mouseup",Rb);pb=null};for(ka=(z.paint.alpha*255/100).toString(16);ka.length<2;)ka="0"+ka;ka=ka.split(".")[0];I=z.paint.solidColor=="none"?"":z.paint.solidColor+ka;ja||(I=Aa[0].getAttribute("stop-color"));$.extend($.fn.jPicker.defaults.window,{alphaSupport:true, -effects:{type:"show",speed:0}});ia.jPicker({window:{title:D.window.pickerTitle},images:{clientPath:D.images.clientPath},color:{active:I,alphaSupport:true}},function(pa){z.paint.type="solidColor";z.paint.alpha=pa.val("ahex")?Math.round(pa.val("a")/255*100):100;z.paint.solidColor=pa.val("hex")?pa.val("hex"):"none";z.paint.radialGradient=null;ba()},null,function(){N()});var Lb=$(M+" .jGraduate_tabs li");Lb.click(function(){Lb.removeClass("jGraduate_tab_current");$(this).addClass("jGraduate_tab_current"); -$(M+" > div").hide();var pa=$(this).attr("data-type");$(M+" .jGraduate_gradPick").show();if(pa==="rg"||pa==="lg"){$(".jGraduate_"+pa+"_field").show();$(".jGraduate_"+(pa==="lg"?"rg":"lg")+"_field").hide();$("#"+q+"_jgraduate_rect")[0].setAttribute("fill","url(#"+q+"_"+pa+"_jgraduate_grad)");Na=pa==="lg"?"linearGradient":"radialGradient";$("#"+q+"_jGraduate_OpacInput").val(z.paint.alpha).change();var V=$("#"+q+"_"+pa+"_jgraduate_grad")[0];if(va!==V){var ua=$(va).find("stop");$(V).empty().append(ua); -va=V;V=Cb.val();va.setAttribute("spreadMethod",V)}lb=pa==="rg"&&va.getAttribute("fx")!=null&&!(Da==Fa&&Ma==Oa);$("#"+q+"_jGraduate_focusCoord").toggle(lb);if(lb)$("#"+q+"_jGraduate_match_ctr")[0].checked=false}else{$(M+" .jGraduate_gradPick").hide();$(M+" .jGraduate_colPick").show()}});$(M+" > div").hide();Lb.removeClass("jGraduate_tab_current");var Sb;switch(z.paint.type){case "linearGradient":Sb=$(M+" .jGraduate_tab_lingrad");break;case "radialGradient":Sb=$(M+" .jGraduate_tab_radgrad");break;default:Sb= -$(M+" .jGraduate_tab_color")}z.show();setTimeout(function(){Sb.addClass("jGraduate_tab_current").click()},10)}else alert("Container element must have an id attribute to maintain unique id strings for sub-elements.")})}})();$.fn.SpinButton=function(a){function H(h,i){for(var u=h[i],E=document.body;(h=h.offsetParent)&&h!=E;)if(!$.browser.msie||h.currentStyle.position!="relative")u+=h[i];return u}return this.each(function(){this.repeating=false;this.spinCfg={min:a&&!isNaN(parseFloat(a.min))?Number(a.min):null,max:a&&!isNaN(parseFloat(a.max))?Number(a.max):null,step:a&&a.step?Number(a.step):1,stepfunc:a&&a.stepfunc?a.stepfunc:false,page:a&&a.page?Number(a.page):10,upClass:a&&a.upClass?a.upClass:"up",downClass:a&&a.downClass? -a.downClass:"down",reset:a&&a.reset?a.reset:this.value,delay:a&&a.delay?Number(a.delay):500,interval:a&&a.interval?Number(a.interval):100,_btn_width:20,_direction:null,_delay:null,_repeat:null,callback:a&&a.callback?a.callback:null};this.spinCfg.smallStep=a&&a.smallStep?a.smallStep:this.spinCfg.step/2;this.adjustValue=function(h){h=isNaN(this.value)?this.spinCfg.reset:$.isFunction(this.spinCfg.stepfunc)?this.spinCfg.stepfunc(this,h):Number((Number(this.value)+Number(h)).toFixed(5));if(this.spinCfg.min!== -null)h=Math.max(h,this.spinCfg.min);if(this.spinCfg.max!==null)h=Math.min(h,this.spinCfg.max);this.value=h;$.isFunction(this.spinCfg.callback)&&this.spinCfg.callback(this)};$(this).addClass(a&&a.spinClass?a.spinClass:"spin-button").mousemove(function(h){var i=h.pageX||h.x,u=h.pageY||h.y;h=h.target||h.srcElement;var E=svgEditor.tool_scale||1,e=$(h).height()/2;i=i>H(h,"offsetLeft")+h.offsetWidth*E-this.spinCfg._btn_width?u<H(h,"offsetTop")+e*E?1:-1:0;if(i!==this.spinCfg._direction){switch(i){case 1:$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass); -break;case -1:$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);break;default:$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass)}this.spinCfg._direction=i}}).mouseout(function(){$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);this.spinCfg._direction=null;window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).mousedown(function(h){if(h.button===0&&this.spinCfg._direction!=0){var i=this, -u=h.shiftKey?i.spinCfg.smallStep:i.spinCfg.step,E=function(){i.adjustValue(i.spinCfg._direction*u)};E();i.spinCfg._delay=window.setTimeout(function(){E();i.spinCfg._repeat=window.setInterval(E,i.spinCfg.interval)},i.spinCfg.delay)}}).mouseup(function(){window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).dblclick(function(){$.browser.msie&&this.adjustValue(this.spinCfg._direction*this.spinCfg.step)}).keydown(function(h){switch(h.keyCode){case 38:this.adjustValue(this.spinCfg.step); -break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}}).keypress(function(h){if(this.repeating)switch(h.keyCode){case 38:this.adjustValue(this.spinCfg.step);break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}else this.repeating=true}).keyup(function(h){this.repeating=false;switch(h.keyCode){case 38:case 40:case 33:case 34:case 13:this.adjustValue(0)}}).bind("mousewheel", -function(h){if(h.wheelDelta>=120)this.adjustValue(this.spinCfg.step);else h.wheelDelta<=-120&&this.adjustValue(-this.spinCfg.step);h.preventDefault()}).change(function(){this.adjustValue(0)});this.addEventListener&&this.addEventListener("DOMMouseScroll",function(h){if(h.detail>0)this.adjustValue(-this.spinCfg.step);else h.detail<0&&this.adjustValue(this.spinCfg.step);h.preventDefault()},false)})};function touchHandler(a){var H=a.changedTouches,h=H[0],i="";switch(a.type){case "touchstart":i="mousedown";break;case "touchmove":i="mousemove";break;case "touchend":i="mouseup";break;default:return}var u=document.createEvent("MouseEvent");u.initMouseEvent(i,true,true,window,1,h.screenX,h.screenY,h.clientX,h.clientY,false,false,false,false,0,null);if(H.length<2){h.target.dispatchEvent(u);a.preventDefault()}};jQuery&&function(){var a=$(window),H=$(document);$.extend($.fn,{contextMenu:function(h,i){if(h.menu==undefined)return false;if(h.inSpeed==undefined)h.inSpeed=150;if(h.outSpeed==undefined)h.outSpeed=75;if(h.inSpeed==0)h.inSpeed=-1;if(h.outSpeed==0)h.outSpeed=-1;$(this).each(function(){var u=$(this),E=$(u).offset(),e=$("#"+h.menu);e.addClass("contextMenu");$(this).bind("mousedown",function(f){$(this).mouseup(function(g){var p=$(this);p.unbind("mouseup");$(".contextMenu").hide();if(f.button===2||h.allowLeft|| -f.ctrlKey&&svgedit.browser.isMac()){g.stopPropagation();if(u.hasClass("disabled"))return false;var z=g.pageX,D=g.pageY;g=a.width()-e.width();var q=a.height()-e.height();if(z>g-15)z=g-15;if(D>q-30)D=q-30;H.unbind("click");e.css({top:D,left:z}).fadeIn(h.inSpeed);e.find("A").mouseover(function(){e.find("LI.hover").removeClass("hover");$(this).parent().addClass("hover")}).mouseout(function(){e.find("LI.hover").removeClass("hover")});H.keypress(function(M){switch(M.keyCode){case 38:if(e.find("LI.hover").length){e.find("LI.hover").removeClass("hover").prevAll("LI:not(.disabled)").eq(0).addClass("hover"); -e.find("LI.hover").length||e.find("LI:last").addClass("hover")}else e.find("LI:last").addClass("hover");break;case 40:if(e.find("LI.hover").length==0)e.find("LI:first").addClass("hover");else{e.find("LI.hover").removeClass("hover").nextAll("LI:not(.disabled)").eq(0).addClass("hover");e.find("LI.hover").length||e.find("LI:first").addClass("hover")}break;case 13:e.find("LI.hover A").trigger("click");break;case 27:H.trigger("click")}});e.find("A").unbind("mouseup");e.find("LI:not(.disabled) A").mouseup(function(){H.unbind("click").unbind("keypress"); -$(".contextMenu").hide();i&&i($(this).attr("href").substr(1),$(p),{x:z-E.left,y:D-E.top,docX:z,docY:D});return false});setTimeout(function(){H.click(function(){H.unbind("click").unbind("keypress");e.fadeOut(h.outSpeed);return false})},0)}})});if($.browser.mozilla)$("#"+h.menu).each(function(){$(this).css({MozUserSelect:"none"})});else $.browser.msie?$("#"+h.menu).each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})}):$("#"+h.menu).each(function(){$(this).bind("mousedown.disableTextSelect", -function(){return false})});$(u).add($("UL.contextMenu")).bind("contextmenu",function(){return false})});return $(this)},disableContextMenuItems:function(h){if(h==undefined){$(this).find("LI").addClass("disabled");return $(this)}$(this).each(function(){if(h!=undefined)for(var i=h.split(","),u=0;u<i.length;u++)$(this).find('A[href="'+i[u]+'"]').parent().addClass("disabled")});return $(this)},enableContextMenuItems:function(h){if(h==undefined){$(this).find("LI.disabled").removeClass("disabled");return $(this)}$(this).each(function(){if(h!= -undefined)for(var i=h.split(","),u=0;u<i.length;u++)$(this).find('A[href="'+i[u]+'"]').parent().removeClass("disabled")});return $(this)},disableContextMenu:function(){$(this).each(function(){$(this).addClass("disabled")});return $(this)},enableContextMenu:function(){$(this).each(function(){$(this).removeClass("disabled")});return $(this)},destroyContextMenu:function(){$(this).each(function(){$(this).unbind("mousedown").unbind("mouseup")});return $(this)}})}(jQuery);var svgedit=svgedit||{}; -(function(){if(!svgedit.browser)svgedit.browser={};var a=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect;svgedit.browser.supportsSvg=function(){return a};if(svgedit.browser.supportsSvg()){var H=navigator.userAgent,h=document.createElementNS("http://www.w3.org/2000/svg","svg"),i=!!window.opera,u=H.indexOf("AppleWebKit")>=0,E=H.indexOf("Gecko/")>=0,e=H.indexOf("MSIE")>=0,f=H.indexOf("Chrome/")>=0,g=H.indexOf("Windows")>=0,p=H.indexOf("Macintosh")>= -0,z="ontouchstart"in window,D=!!h.querySelector,q=!!document.evaluate,M=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","path");qa.setAttribute("d","M0,0 10,10");var ga=qa.pathSegList;qa=qa.createSVGPathSegLinetoAbs(5,5);try{ga.replaceItem(qa,0);return true}catch(Na){}return false}(),ba=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","path");qa.setAttribute("d","M0,0 10,10");var ga=qa.pathSegList;qa=qa.createSVGPathSegLinetoAbs(5,5);try{ga.insertItemBefore(qa, -0);return true}catch(Na){}return false}(),N=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","svg"),ga=document.createElementNS("http://www.w3.org/2000/svg","svg");document.documentElement.appendChild(qa);ga.setAttribute("x",5);qa.appendChild(ga);var Na=document.createElementNS("http://www.w3.org/2000/svg","text");Na.textContent="a";ga.appendChild(Na);ga=Na.getStartPositionOfChar(0).x;document.documentElement.removeChild(qa);return ga===0}(),I=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg", -"svg");document.documentElement.appendChild(qa);var ga=document.createElementNS("http://www.w3.org/2000/svg","path");ga.setAttribute("d","M0,0 C0,0 10,10 10,0");qa.appendChild(ga);ga=ga.getBBox();document.documentElement.removeChild(qa);return ga.height>4&&ga.height<5}(),ma=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","svg");document.documentElement.appendChild(qa);var ga=document.createElementNS("http://www.w3.org/2000/svg","path");ga.setAttribute("d","M0,0 10,0");var Na= -document.createElementNS("http://www.w3.org/2000/svg","path");Na.setAttribute("d","M5,0 15,0");var va=document.createElementNS("http://www.w3.org/2000/svg","g");va.appendChild(ga);va.appendChild(Na);qa.appendChild(va);ga=va.getBBox();document.documentElement.removeChild(qa);return ga.width==15}(),ia=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","rect");qa.setAttribute("x",0.1);(qa=qa.cloneNode(false).getAttribute("x").indexOf(",")==-1)||$.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\t\tPlease upgrade to the <a href='http://opera.com'>latest version</a> in which the problems have been fixed."); -return qa}(),ka=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","rect");qa.setAttribute("style","vector-effect:non-scaling-stroke");return qa.style.vectorEffect==="non-scaling-stroke"}(),X=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","rect").transform.baseVal,ga=h.createSVGTransform();qa.appendItem(ga);return qa.getItem(0)==ga}();svgedit.browser.isOpera=function(){return i};svgedit.browser.isWebkit=function(){return u};svgedit.browser.isGecko=function(){return E}; -svgedit.browser.isIE=function(){return e};svgedit.browser.isChrome=function(){return f};svgedit.browser.isWindows=function(){return g};svgedit.browser.isMac=function(){return p};svgedit.browser.isTouch=function(){return z};svgedit.browser.supportsSelectors=function(){return D};svgedit.browser.supportsXpath=function(){return q};svgedit.browser.supportsPathReplaceItem=function(){return M};svgedit.browser.supportsPathInsertItemBefore=function(){return ba};svgedit.browser.supportsPathBBox=function(){return I}; -svgedit.browser.supportsHVLineContainerBBox=function(){return ma};svgedit.browser.supportsGoodTextCharPos=function(){return N};svgedit.browser.supportsEditableText=function(){return i};svgedit.browser.supportsGoodDecimals=function(){return ia};svgedit.browser.supportsNonScalingStroke=function(){return ka};svgedit.browser.supportsNativeTransformLists=function(){return X}}else window.location="browser-not-supported.html"})();svgedit=svgedit||{}; -(function(){if(!svgedit.transformlist)svgedit.transformlist={};var a=document.createElementNS("http://www.w3.org/2000/svg","svg"),H={};svgedit.transformlist.SVGTransformList=function(h){this._elem=h||null;this._xforms=[];this._update=function(){var i="";a.createSVGMatrix();for(var u=0;u<this.numberOfItems;++u){var E=this._list.getItem(u);i=i;E=E;var e=E.matrix,f="";switch(E.type){case 1:f="matrix("+[e.a,e.b,e.c,e.d,e.e,e.f].join(",")+")";break;case 2:f="translate("+e.e+","+e.f+")";break;case 3:f= -e.a==e.d?"scale("+e.a+")":"scale("+e.a+","+e.d+")";break;case 4:var g=0;f=0;if(E.angle!=0){g=1-e.a;f=(g*e.f+e.b*e.e)/(g*g+e.b*e.b);g=(e.e-e.b*f)/g}f="rotate("+E.angle+" "+g+","+f+")"}i=i+(f+" ")}this._elem.setAttribute("transform",i)};this._list=this;this._init=function(){var i=this._elem.getAttribute("transform");if(i)for(var u=/\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/,E=true;E;){E=i.match(u);i=i.replace(u,"");if(E&&E[1]){var e=E[1].split(/\s*\(/),f=e[0];e=e[1].match(/\s*(.*?)\s*\)/); -e[1]=e[1].replace(/(\d)-/g,"$1 -");var g=e[1].split(/[, ]+/),p="abcdef".split(""),z=a.createSVGMatrix();$.each(g,function(M,ba){g[M]=parseFloat(ba);if(f=="matrix")z[p[M]]=g[M]});e=a.createSVGTransform();var D="set"+f.charAt(0).toUpperCase()+f.slice(1),q=f=="matrix"?[z]:g;if(f=="scale"&&q.length==1)q.push(q[0]);else if(f=="translate"&&q.length==1)q.push(0);else if(f=="rotate"&&q.length==1){q.push(0);q.push(0)}e[D].apply(e,q);this._list.appendItem(e)}}};this._removeFromOtherLists=function(i){if(i){var u= -false,E;for(E in H){for(var e=H[E],f=0,g=e._xforms.length;f<g;++f)if(e._xforms[f]==i){u=true;e.removeItem(f);break}if(u)break}}};this.numberOfItems=0;this.clear=function(){this.numberOfItems=0;this._xforms=[]};this.initialize=function(i){this.numberOfItems=1;this._removeFromOtherLists(i);this._xforms=[i]};this.getItem=function(i){if(i<this.numberOfItems&&i>=0)return this._xforms[i];throw{code:1};};this.insertItemBefore=function(i,u){var E=null;if(u>=0)if(u<this.numberOfItems){this._removeFromOtherLists(i); -E=Array(this.numberOfItems+1);for(var e=0;e<u;++e)E[e]=this._xforms[e];E[e]=i;for(var f=e+1;e<this.numberOfItems;++f,++e)E[f]=this._xforms[e];this.numberOfItems++;this._xforms=E;E=i;this._list._update()}else E=this._list.appendItem(i);return E};this.replaceItem=function(i,u){var E=null;if(u<this.numberOfItems&&u>=0){this._removeFromOtherLists(i);E=this._xforms[u]=i;this._list._update()}return E};this.removeItem=function(i){if(i<this.numberOfItems&&i>=0){for(var u=this._xforms[i],E=Array(this.numberOfItems- -1),e=0;e<i;++e)E[e]=this._xforms[e];for(i=e;i<this.numberOfItems-1;++i,++e)E[i]=this._xforms[e+1];this.numberOfItems--;this._xforms=E;this._list._update();return u}else throw{code:1};};this.appendItem=function(i){this._removeFromOtherLists(i);this._xforms.push(i);this.numberOfItems++;this._list._update();return i}};svgedit.transformlist.resetListMap=function(){H={}};svgedit.transformlist.removeElementFromListMap=function(h){h.id&&H[h.id]&&delete H[h.id]};svgedit.transformlist.getTransformList=function(h){if(svgedit.browser.supportsNativeTransformLists())if(h.transform)return h.transform.baseVal; -else if(h.gradientTransform)return h.gradientTransform.baseVal;else{if(h.patternTransform)return h.patternTransform.baseVal}else{var i=h.id;i||(i="temp");var u=H[i];if(!u||i=="temp"){H[i]=new svgedit.transformlist.SVGTransformList(h);H[i]._init();u=H[i]}return u}return null}})();svgedit=svgedit||{}; -(function(){if(!svgedit.math)svgedit.math={};var a=document.createElementNS("http://www.w3.org/2000/svg","svg");svgedit.math.transformPoint=function(H,h,i){return{x:i.a*H+i.c*h+i.e,y:i.b*H+i.d*h+i.f}};svgedit.math.isIdentity=function(H){return H.a===1&&H.b===0&&H.c===0&&H.d===1&&H.e===0&&H.f===0};svgedit.math.matrixMultiply=function(){for(var H=arguments,h=H.length,i=H[h-1];h-- >1;)i=H[h-1].multiply(i);if(Math.abs(i.a)<1.0E-14)i.a=0;if(Math.abs(i.b)<1.0E-14)i.b=0;if(Math.abs(i.c)<1.0E-14)i.c=0;if(Math.abs(i.d)< -1.0E-14)i.d=0;if(Math.abs(i.e)<1.0E-14)i.e=0;if(Math.abs(i.f)<1.0E-14)i.f=0;return i};svgedit.math.hasMatrixTransform=function(H){if(!H)return false;for(var h=H.numberOfItems;h--;){var i=H.getItem(h);if(i.type==1&&!svgedit.math.isIdentity(i.matrix))return true}return false};svgedit.math.transformBox=function(H,h,i,u,E){var e={x:H,y:h},f={x:H+i,y:h};i={x:H+i,y:h+u};H={x:H,y:h+u};h=svgedit.math.transformPoint;e=h(e.x,e.y,E);var g=u=e.x,p=e.y,z=e.y;f=h(f.x,f.y,E);u=Math.min(u,f.x);g=Math.max(g,f.x); -p=Math.min(p,f.y);z=Math.max(z,f.y);H=h(H.x,H.y,E);u=Math.min(u,H.x);g=Math.max(g,H.x);p=Math.min(p,H.y);z=Math.max(z,H.y);i=h(i.x,i.y,E);u=Math.min(u,i.x);g=Math.max(g,i.x);p=Math.min(p,i.y);z=Math.max(z,i.y);return{tl:e,tr:f,bl:H,br:i,aabox:{x:u,y:p,width:g-u,height:z-p}}};svgedit.math.transformListToTransform=function(H,h,i){if(H==null)return a.createSVGTransformFromMatrix(a.createSVGMatrix());h=h==undefined?0:h;i=i==undefined?H.numberOfItems-1:i;h=parseInt(h);i=parseInt(i);if(h>i){var u=i;i=h; -h=u}u=a.createSVGMatrix();for(h=h;h<=i;++h){var E=h>=0&&h<H.numberOfItems?H.getItem(h).matrix:a.createSVGMatrix();u=svgedit.math.matrixMultiply(u,E)}return a.createSVGTransformFromMatrix(u)};svgedit.math.getMatrix=function(H){H=svgedit.transformlist.getTransformList(H);return svgedit.math.transformListToTransform(H).matrix};svgedit.math.snapToAngle=function(H,h,i,u){var E=Math.PI/4;i=i-H;var e=u-h;u=Math.sqrt(i*i+e*e);E=Math.round(Math.atan2(e,i)/E)*E;return{x:H+u*Math.cos(E),y:h+u*Math.sin(E),a:E}}; -svgedit.math.rectsIntersect=function(H,h){return h.x<H.x+H.width&&h.x+h.width>H.x&&h.y<H.y+H.height&&h.y+h.height>H.y}})();svgedit=svgedit||{}; -(function(){if(!svgedit.units)svgedit.units={};var a=["x","x1","cx","rx","width"],H=["y","y1","cy","ry","height"],h=$.merge(["r","radius"],a);$.merge(h,H);var i,u={px:1};svgedit.units.init=function(e){i=e;e=document.createElementNS("http://www.w3.org/2000/svg","svg");document.body.appendChild(e);var f=document.createElementNS("http://www.w3.org/2000/svg","rect");f.setAttribute("width","1em");f.setAttribute("height","1ex");f.setAttribute("x","1in");e.appendChild(f);f=f.getBBox();document.body.removeChild(e); -e=f.x;u.em=f.width;u.ex=f.height;u["in"]=e;u.cm=e/2.54;u.mm=e/25.4;u.pt=e/72;u.pc=e/6;u["%"]=0};svgedit.units.getTypeMap=function(){return u};svgedit.units.shortFloat=function(e){var f=i.getRoundDigits();if(isNaN(e)){if($.isArray(e))return svgedit.units.shortFloat(e[0])+","+svgedit.units.shortFloat(e[1])}else return+(+e).toFixed(f);return parseFloat(e).toFixed(f)-0};svgedit.units.convertUnit=function(e,f){f=f||i.getBaseUnit();return svgedit.unit.shortFloat(e/u[f])};svgedit.units.setUnitAttr=function(e, -f,g){isNaN(g)||e.getAttribute(f);e.setAttribute(f,g)};var E={line:["x1","x2","y1","y2"],circle:["cx","cy","r"],ellipse:["cx","cy","rx","ry"],foreignObject:["x","y","width","height"],rect:["x","y","width","height"],image:["x","y","width","height"],use:["x","y","width","height"],text:["x","y"]};svgedit.units.convertAttrs=function(e){var f=e.tagName,g=i.getBaseUnit();if(f=E[f])for(var p=f.length,z=0;z<p;z++){var D=f[z],q=e.getAttribute(D);if(q)isNaN(q)||e.setAttribute(D,q/u[g]+g)}};svgedit.units.convertToNum= -function(e,f){if(!isNaN(f))return f-0;if(f.substr(-1)==="%"){var g=f.substr(0,f.length-1)/100,p=i.getWidth(),z=i.getHeight();return a.indexOf(e)>=0?g*p:H.indexOf(e)>=0?g*z:g*Math.sqrt(p*p+z*z)/Math.sqrt(2)}else{p=f.substr(-2);g=f.substr(0,f.length-2);return g*u[p]}};svgedit.units.isValidUnit=function(e,f,g){var p=false;if(h.indexOf(e)>=0)if(isNaN(f)){f=f.toLowerCase();$.each(u,function(q){if(!p)if(RegExp("^-?[\\d\\.]+"+q+"$").test(f))p=true})}else p=true;else if(e=="id"){e=false;try{var z=i.getElement(f); -e=z==null||z===g}catch(D){}return e}else p=true;return p}})();svgedit=svgedit||{}; -(function(){function a(e){if(svgedit.browser.supportsHVLineContainerBBox())try{return e.getBBox()}catch(f){}var g=$.data(e,"ref"),p=null;if(g){var z=$(g).children().clone().attr("visibility","hidden");$(E).append(z);p=z.filter("line, path")}else p=$(e).find("line, path");var D=false;if(p.length){p.each(function(){var q=this.getBBox();if(!q.width||!q.height)D=true});if(D){e=g?z:$(e).children();ret=getStrokedBBox(e)}else ret=e.getBBox()}else ret=e.getBBox();g&&z.remove();return ret}if(!svgedit.utilities)svgedit.utilities= -{};var H="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use".split(","),h=null,i=null,u=null,E=null;svgedit.utilities.init=function(e){h=e;i=e.getDOMDocument();u=e.getDOMContainer();E=e.getSVGRoot()};svgedit.utilities.toXml=function(e){return $("<p/>").text(e).html()};svgedit.utilities.fromXml=function(e){return $("<p/>").html(e).text()};svgedit.utilities.encode64=function(e){e=svgedit.utilities.convertToXMLReferences(e);if(window.btoa)return window.btoa(e); -var f=Array(Math.floor((e.length+2)/3)*4),g,p,z,D,q,M,ba=0,N=0;do{g=e.charCodeAt(ba++);p=e.charCodeAt(ba++);z=e.charCodeAt(ba++);D=g>>2;g=(g&3)<<4|p>>4;q=(p&15)<<2|z>>6;M=z&63;if(isNaN(p))q=M=64;else if(isNaN(z))M=64;f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(D);f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(g);f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(q);f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(M)}while(ba< -e.length);return f.join("")};svgedit.utilities.decode64=function(e){if(window.atob)return window.atob(e);var f="",g,p,z="",D,q="",M=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++));p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++));D="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++));q="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++)); -g=g<<2|p>>4;p=(p&15)<<4|D>>2;z=(D&3)<<6|q;f+=String.fromCharCode(g);if(D!=64)f+=String.fromCharCode(p);if(q!=64)f+=String.fromCharCode(z)}while(M<e.length);return unescape(f)};svgedit.utilities.convertToXMLReferences=function(e){for(var f="",g=0;g<e.length;g++){var p=e.charCodeAt(g);if(p<128)f+=e[g];else if(p>127)f+="&#"+p+";"}return f};svgedit.utilities.text2xml=function(e){if(e.indexOf("<svg:svg")>=0)e=e.replace(/<(\/?)svg:/g,"<$1").replace("xmlns:svg","xmlns");var f;try{var g=window.DOMParser? -new DOMParser:new ActiveXObject("Microsoft.XMLDOM");g.async=false}catch(p){throw Error("XML Parser could not be instantiated");}try{f=g.loadXML?g.loadXML(e)?g:false:g.parseFromString(e,"text/xml")}catch(z){throw Error("Error parsing XML string");}return f};svgedit.utilities.bboxToObj=function(e){return{x:e.x,y:e.y,width:e.width,height:e.height}};svgedit.utilities.walkTree=function(e,f){if(e&&e.nodeType==1){f(e);for(var g=e.childNodes.length;g--;)svgedit.utilities.walkTree(e.childNodes.item(g),f)}}; -svgedit.utilities.walkTreePost=function(e,f){if(e&&e.nodeType==1){for(var g=e.childNodes.length;g--;)svgedit.utilities.walkTree(e.childNodes.item(g),f);f(e)}};svgedit.utilities.getUrlFromAttr=function(e){if(e)if(e.indexOf('url("')===0)return e.substring(5,e.indexOf('"',6));else if(e.indexOf("url('")===0)return e.substring(5,e.indexOf("'",6));else if(e.indexOf("url(")===0)return e.substring(4,e.indexOf(")"));return null};svgedit.utilities.getHref=function(e){return e.getAttributeNS("http://www.w3.org/1999/xlink", -"href")};svgedit.utilities.setHref=function(e,f){e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",f)};svgedit.utilities.findDefs=function(e){e=h.getSVGContent().documentElement;var f=e.getElementsByTagNameNS("http://www.w3.org/2000/svg","defs");return f=f.length>0?f[0]:e.insertBefore(e.ownerDocument.createElementNS("http://www.w3.org/2000/svg","defs"),e.firstChild.nextSibling)};svgedit.utilities.getPathBBox=function(e){var f=e.pathSegList,g=f.numberOfItems;e=[[],[]];var p=f.getItem(0), -z=[p.x,p.y];for(p=0;p<g;p++){var D=f.getItem(p);if(typeof D.x!="undefined"){e[0].push(z[0]);e[1].push(z[1]);if(D.x1){for(var q=[D.x1,D.y1],M=[D.x2,D.y2],ba=[D.x,D.y],N=0;N<2;N++){D=function(X){return Math.pow(1-X,3)*z[N]+3*Math.pow(1-X,2)*X*q[N]+3*(1-X)*Math.pow(X,2)*M[N]+Math.pow(X,3)*ba[N]};var I=6*z[N]-12*q[N]+6*M[N],ma=-3*z[N]+9*q[N]-9*M[N]+3*ba[N],ia=3*q[N]-3*z[N];if(ma==0){if(I!=0){I=-ia/I;0<I&&I<1&&e[N].push(D(I))}}else{ia=Math.pow(I,2)-4*ia*ma;if(!(ia<0)){var ka=(-I+Math.sqrt(ia))/(2*ma); -0<ka&&ka<1&&e[N].push(D(ka));I=(-I-Math.sqrt(ia))/(2*ma);0<I&&I<1&&e[N].push(D(I))}}}z=ba}else{e[0].push(D.x);e[1].push(D.y)}}}f=Math.min.apply(null,e[0]);g=Math.max.apply(null,e[0])-f;p=Math.min.apply(null,e[1]);e=Math.max.apply(null,e[1])-p;return{x:f,y:p,width:g,height:e}};svgedit.utilities.getBBox=function(e){var f=e||h.geSelectedElements()[0];if(e.nodeType!=1)return null;e=null;var g=f.nodeName;switch(g){case "text":if(f.textContent===""){f.textContent="a";e=f.getBBox();f.textContent=""}else try{e= -f.getBBox()}catch(p){}break;case "path":if(svgedit.browser.supportsPathBBox())try{e=f.getBBox()}catch(z){}else e=svgedit.utilities.getPathBBox(f);break;case "g":case "a":e=a(f);break;default:if(g==="use")e=a(f,true);if(g==="use"){e||(e=f.getBBox());if(!svgedit.browser.isWebkit()){g={};g.width=e.width;g.height=e.height;g.x=e.x+parseFloat(f.getAttribute("x")||0);g.y=e.y+parseFloat(f.getAttribute("y")||0);e=g}}else if(~H.indexOf(g))try{e=f.getBBox()}catch(D){f=$(f).closest("foreignObject");if(f.length)try{e= -f[0].getBBox()}catch(q){e=null}else e=null}}if(e)e=svgedit.utilities.bboxToObj(e);return e};svgedit.utilities.getRotationAngle=function(e,f){var g=e||h.getSelectedElements()[0];g=svgedit.transformlist.getTransformList(g);if(!g)return 0;for(var p=g.numberOfItems,z=0;z<p;++z){var D=g.getItem(z);if(D.type==4)return f?D.angle*Math.PI/180:D.angle}return 0};svgedit.utilities.getElem=svgedit.browser.supportsSelectors()?function(e){return E.querySelector("#"+e)}:svgedit.browser.supportsXpath()?function(e){return i.evaluate('svg:svg[@id="svgroot"]//svg:*[@id="'+ -e+'"]',u,function(){return"http://www.w3.org/2000/svg"},9,null).singleNodeValue}:function(e){return $(E).find("[id="+e+"]")[0]};svgedit.utilities.assignAttributes=function(e,f,g,p){g||(g=0);svgedit.browser.isOpera()||E.suspendRedraw(g);for(var z in f)if(g=z.substr(0,4)==="xml:"?"http://www.w3.org/XML/1998/namespace":z.substr(0,6)==="xlink:"?"http://www.w3.org/1999/xlink":null)e.setAttributeNS(g,z,f[z]);else p?svgedit.units.setUnitAttr(e,z,f[z]):e.setAttribute(z,f[z]);svgedit.browser.isOpera()||E.unsuspendRedraw(null)}; -svgedit.utilities.cleanupElement=function(e){var f=E.suspendRedraw(60),g={"fill-opacity":1,"stop-opacity":1,opacity:1,stroke:"none","stroke-dasharray":"none","stroke-linejoin":"miter","stroke-linecap":"butt","stroke-opacity":1,"stroke-width":1,rx:0,ry:0},p;for(p in g){var z=g[p];e.getAttribute(p)==z&&e.removeAttribute(p)}E.unsuspendRedraw(f)}})();svgedit=svgedit||{}; -(function(){if(!svgedit.sanitize)svgedit.sanitize={};var a={};a["http://www.w3.org/1999/xlink"]="xlink";a["http://www.w3.org/XML/1998/namespace"]="xml";a["http://www.w3.org/2000/xmlns/"]="xmlns";a["http://svg-edit.googlecode.com"]="se";a["http://www.w3.org/1999/xhtml"]="xhtml";a["http://www.w3.org/1998/Math/MathML"]="mathml";var H={};$.each(a,function(u,E){H[E]=u});var h={a:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","id","mask","opacity","stroke","stroke-dasharray", -"stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","xlink:href","xlink:title"],circle:["class","clip-path","clip-rule","cx","cy","fill","fill-opacity","fill-rule","filter","id","mask","opacity","r","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],clipPath:["class", -"clipPathUnits","id"],defs:[],style:["type"],desc:[],ellipse:["class","clip-path","clip-rule","cx","cy","fill","fill-opacity","fill-rule","filter","id","mask","opacity","requiredFeatures","rx","ry","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],feGaussianBlur:["class","color-interpolation-filters","id","requiredFeatures","stdDeviation"],filter:["class","color-interpolation-filters", -"filterRes","filterUnits","height","id","primitiveUnits","requiredFeatures","width","x","xlink:href","y"],foreignObject:["class","font-size","height","id","opacity","requiredFeatures","style","transform","width","x","y"],g:["class","clip-path","clip-rule","id","display","fill","fill-opacity","fill-rule","filter","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage", -"transform","font-family","font-size","font-style","font-weight","text-anchor"],image:["class","clip-path","clip-rule","filter","height","id","mask","opacity","requiredFeatures","style","systemLanguage","transform","width","x","xlink:href","xlink:title","y"],line:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","id","marker-end","marker-mid","marker-start","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin", -"stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","x1","x2","y1","y2"],linearGradient:["class","id","gradientTransform","gradientUnits","requiredFeatures","spreadMethod","systemLanguage","x1","x2","xlink:href","y1","y2"],marker:["id","class","markerHeight","markerUnits","markerWidth","orient","preserveAspectRatio","refX","refY","systemLanguage","viewBox"],mask:["class","height","id","maskContentUnits","maskUnits","width","x","y"],metadata:["class","id"],path:["class", -"clip-path","clip-rule","d","fill","fill-opacity","fill-rule","filter","id","marker-end","marker-mid","marker-start","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],pattern:["class","height","id","patternContentUnits","patternTransform","patternUnits","requiredFeatures","style","systemLanguage","viewBox","width","x","xlink:href","y"],polygon:["class", -"clip-path","clip-rule","id","fill","fill-opacity","fill-rule","filter","id","class","marker-end","marker-mid","marker-start","mask","opacity","points","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],polyline:["class","clip-path","clip-rule","id","fill","fill-opacity","fill-rule","filter","marker-end","marker-mid","marker-start","mask","opacity","points", -"requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],radialGradient:["class","cx","cy","fx","fy","gradientTransform","gradientUnits","id","r","requiredFeatures","spreadMethod","systemLanguage","xlink:href"],rect:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","height","id","mask","opacity","requiredFeatures","rx","ry","stroke","stroke-dasharray", -"stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","width","x","y"],stop:["class","id","offset","requiredFeatures","stop-color","stop-opacity","style","systemLanguage"],svg:["class","clip-path","clip-rule","filter","id","height","mask","preserveAspectRatio","requiredFeatures","style","systemLanguage","viewBox","width","x","xmlns","xmlns:se","xmlns:xlink","y"],"switch":["class","id","requiredFeatures","systemLanguage"], -symbol:["class","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight","id","opacity","preserveAspectRatio","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","viewBox"],text:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight","id","mask","opacity", -"requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","text-anchor","transform","x","xml:space","y"],textPath:["class","id","method","requiredFeatures","spacing","startOffset","style","systemLanguage","transform","xlink:href"],title:[],tspan:["class","clip-path","clip-rule","dx","dy","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight", -"id","mask","opacity","requiredFeatures","rotate","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","text-anchor","textLength","transform","x","xml:space","y"],use:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","height","id","mask","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width", -"style","transform","width","x","xlink:href","y"],annotation:["encoding"],"annotation-xml":["encoding"],maction:["actiontype","other","selection"],math:["class","id","display","xmlns"],menclose:["notation"],merror:[],mfrac:["linethickness"],mi:["mathvariant"],mmultiscripts:[],mn:[],mo:["fence","lspace","maxsize","minsize","rspace","stretchy"],mover:[],mpadded:["lspace","width","height","depth","voffset"],mphantom:[],mprescripts:[],mroot:[],mrow:["xlink:href","xlink:type","xmlns:xlink"],mspace:["depth", -"height","width"],msqrt:[],mstyle:["displaystyle","mathbackground","mathcolor","mathvariant","scriptlevel"],msub:[],msubsup:[],msup:[],mtable:["align","columnalign","columnlines","columnspacing","displaystyle","equalcolumns","equalrows","frame","rowalign","rowlines","rowspacing","width"],mtd:["columnalign","columnspan","rowalign","rowspan"],mtext:[],mtr:["columnalign","rowalign"],munder:[],munderover:[],none:[],semantics:[]},i={};$.each(h,function(u,E){var e={};$.each(E,function(f,g){if(g.indexOf(":")>= -0){var p=g.split(":");e[p[1]]=H[p[0]]}else e[g]=g=="xmlns"?"http://www.w3.org/2000/xmlns/":null});i[u]=e});svgedit.sanitize.getNSMap=function(){return a};svgedit.sanitize.sanitizeSvg=function(u){if(u.nodeType==3){u.nodeValue=u.nodeValue.replace(/^\s+|\s+$/g,"");u.nodeValue.length||u.parentNode.removeChild(u)}if(u.nodeType==1){var E=u.parentNode;if(u.ownerDocument&&E){var e=h[u.nodeName],f=i[u.nodeName];if(e!=undefined){for(var g=[],p=u.attributes.length;p--;){var z=u.attributes.item(p),D=z.nodeName, -q=z.localName,M=z.namespaceURI;if(!(f.hasOwnProperty(q)&&M==f[q]&&M!="http://www.w3.org/2000/xmlns/")&&!(M=="http://www.w3.org/2000/xmlns/"&&a[z.nodeValue])){D.indexOf("se:")==0&&g.push([D,z.nodeValue]);u.removeAttributeNS(M,q)}if(svgedit.browser.isGecko())switch(D){case "transform":case "gradientTransform":case "patternTransform":q=z.nodeValue.replace(/(\d)-/g,"$1 -");u.setAttribute(D,q)}if(D=="style"){z=z.nodeValue.split(";");for(D=z.length;D--;){q=z[D].split(":");e.indexOf(q[0])>=0&&u.setAttribute(q[0], -q[1])}u.removeAttribute("style")}}$.each(g,function(ba,N){u.setAttributeNS("http://svg-edit.googlecode.com",N[0],N[1])});if((p=svgedit.utilities.getHref(u))&&["filter","linearGradient","pattern","radialGradient","textPath","use"].indexOf(u.nodeName)>=0)if(p[0]!="#"){svgedit.utilities.setHref(u,"");u.removeAttributeNS("http://www.w3.org/1999/xlink","href")}if(u.nodeName=="use"&&!svgedit.utilities.getHref(u))E.removeChild(u);else{$.each(["clip-path","fill","filter","marker-end","marker-mid","marker-start", -"mask","stroke"],function(ba,N){var I=u.getAttribute(N);if(I)if((I=svgedit.utilities.getUrlFromAttr(I))&&I[0]!=="#"){u.setAttribute(N,"");u.removeAttribute(N)}});for(p=u.childNodes.length;p--;)svgedit.sanitize.sanitizeSvg(u.childNodes.item(p))}}else{for(e=[];u.hasChildNodes();)e.push(E.insertBefore(u.firstChild,u));E.removeChild(u);for(p=e.length;p--;)svgedit.sanitize.sanitizeSvg(e[p])}}}}})();svgedit=svgedit||{}; -(function(){if(!svgedit.history)svgedit.history={};svgedit.history.HistoryEventTypes={BEFORE_APPLY:"before_apply",AFTER_APPLY:"after_apply",BEFORE_UNAPPLY:"before_unapply",AFTER_UNAPPLY:"after_unapply"};svgedit.history.MoveElementCommand=function(a,H,h,i){this.elem=a;this.text=i?"Move "+a.tagName+" to "+i:"Move "+a.tagName;this.oldNextSibling=H;this.oldParent=h;this.newNextSibling=a.nextSibling;this.newParent=a.parentNode};svgedit.history.MoveElementCommand.type=function(){return"svgedit.history.MoveElementCommand"};svgedit.history.MoveElementCommand.prototype.type= -svgedit.history.MoveElementCommand.type;svgedit.history.MoveElementCommand.prototype.getText=function(){return this.text};svgedit.history.MoveElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);this.elem=this.newParent.insertBefore(this.elem,this.newNextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.MoveElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, -this);this.elem=this.oldParent.insertBefore(this.elem,this.oldNextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.MoveElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.InsertElementCommand=function(a,H){this.elem=a;this.text=H||"Create "+a.tagName;this.parent=a.parentNode;this.nextSibling=this.elem.nextSibling};svgedit.history.InsertElementCommand.type=function(){return"svgedit.history.InsertElementCommand"};svgedit.history.InsertElementCommand.prototype.type= -svgedit.history.InsertElementCommand.type;svgedit.history.InsertElementCommand.prototype.getText=function(){return this.text};svgedit.history.InsertElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);this.elem=this.parent.insertBefore(this.elem,this.nextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.InsertElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, -this);this.parent=this.elem.parentNode;this.elem=this.elem.parentNode.removeChild(this.elem);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.InsertElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.RemoveElementCommand=function(a,H,h,i){this.elem=a;this.text=i||"Delete "+a.tagName;this.nextSibling=H;this.parent=h;svgedit.transformlist.removeElementFromListMap(a)};svgedit.history.RemoveElementCommand.type=function(){return"svgedit.history.RemoveElementCommand"}; -svgedit.history.RemoveElementCommand.prototype.type=svgedit.history.RemoveElementCommand.type;svgedit.history.RemoveElementCommand.prototype.getText=function(){return this.text};svgedit.history.RemoveElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);svgedit.transformlist.removeElementFromListMap(this.elem);this.parent=this.elem.parentNode;this.elem=this.parent.removeChild(this.elem);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, -this)};svgedit.history.RemoveElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);svgedit.transformlist.removeElementFromListMap(this.elem);this.nextSibling==null&&window.console&&console.log("Error: reference element was lost");this.parent.insertBefore(this.elem,this.nextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.RemoveElementCommand.prototype.elements=function(){return[this.elem]}; -svgedit.history.ChangeElementCommand=function(a,H,h){this.elem=a;this.text=h?"Change "+a.tagName+" "+h:"Change "+a.tagName;this.newValues={};this.oldValues=H;for(var i in H)this.newValues[i]=i=="#text"?a.textContent:i=="#href"?svgedit.utilities.getHref(a):a.getAttribute(i)};svgedit.history.ChangeElementCommand.type=function(){return"svgedit.history.ChangeElementCommand"};svgedit.history.ChangeElementCommand.prototype.type=svgedit.history.ChangeElementCommand.type;svgedit.history.ChangeElementCommand.prototype.getText= -function(){return this.text};svgedit.history.ChangeElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);var H=false,h;for(h in this.newValues){if(this.newValues[h])if(h=="#text")this.elem.textContent=this.newValues[h];else h=="#href"?svgedit.utilities.setHref(this.elem,this.newValues[h]):this.elem.setAttribute(h,this.newValues[h]);else if(h=="#text")this.elem.textContent="";else{this.elem.setAttribute(h,"");this.elem.removeAttribute(h)}if(h== -"transform")H=true}if(!H)if(H=svgedit.utilities.getRotationAngle(this.elem)){h=elem.getBBox();H=["rotate(",H," ",h.x+h.width/2,",",h.y+h.height/2,")"].join("");H!=elem.getAttribute("transform")&&elem.setAttribute("transform",H)}a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this);return true};svgedit.history.ChangeElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);var H=false,h;for(h in this.oldValues){if(this.oldValues[h])if(h== -"#text")this.elem.textContent=this.oldValues[h];else h=="#href"?svgedit.utilities.setHref(this.elem,this.oldValues[h]):this.elem.setAttribute(h,this.oldValues[h]);else if(h=="#text")this.elem.textContent="";else this.elem.removeAttribute(h);if(h=="transform")H=true}if(!H)if(H=svgedit.utilities.getRotationAngle(this.elem)){h=elem.getBBox();H=["rotate(",H," ",h.x+h.width/2,",",h.y+h.height/2,")"].join("");H!=elem.getAttribute("transform")&&elem.setAttribute("transform",H)}svgedit.transformlist.removeElementFromListMap(this.elem); -a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this);return true};svgedit.history.ChangeElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.BatchCommand=function(a){this.text=a||"Batch Command";this.stack=[]};svgedit.history.BatchCommand.type=function(){return"svgedit.history.BatchCommand"};svgedit.history.BatchCommand.prototype.type=svgedit.history.BatchCommand.type;svgedit.history.BatchCommand.prototype.getText=function(){return this.text};svgedit.history.BatchCommand.prototype.apply= -function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);for(var H=this.stack.length,h=0;h<H;++h)this.stack[h].apply(a);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.BatchCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);for(var H=this.stack.length-1;H>=0;H--)this.stack[H].unapply(a);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, -this)};svgedit.history.BatchCommand.prototype.elements=function(){for(var a=[],H=this.stack.length;H--;)for(var h=this.stack[H].elements(),i=h.length;i--;)a.indexOf(h[i])==-1&&a.push(h[i]);return a};svgedit.history.BatchCommand.prototype.addSubCommand=function(a){this.stack.push(a)};svgedit.history.BatchCommand.prototype.isEmpty=function(){return this.stack.length==0};svgedit.history.UndoManager=function(a){this.handler_=a||null;this.undoStackPointer=0;this.undoStack=[];this.undoChangeStackPointer= --1;this.undoableChangeStack=[]};svgedit.history.UndoManager.prototype.resetUndoStack=function(){this.undoStack=[];this.undoStackPointer=0};svgedit.history.UndoManager.prototype.getUndoStackSize=function(){return this.undoStackPointer};svgedit.history.UndoManager.prototype.getRedoStackSize=function(){return this.undoStack.length-this.undoStackPointer};svgedit.history.UndoManager.prototype.getNextUndoCommandText=function(){return this.undoStackPointer>0?this.undoStack[this.undoStackPointer-1].getText(): -""};svgedit.history.UndoManager.prototype.getNextRedoCommandText=function(){return this.undoStackPointer<this.undoStack.length?this.undoStack[this.undoStackPointer].getText():""};svgedit.history.UndoManager.prototype.undo=function(){this.undoStackPointer>0&&this.undoStack[--this.undoStackPointer].unapply(this.handler_)};svgedit.history.UndoManager.prototype.redo=function(){this.undoStackPointer<this.undoStack.length&&this.undoStack.length>0&&this.undoStack[this.undoStackPointer++].apply(this.handler_)}; -svgedit.history.UndoManager.prototype.addCommandToHistory=function(a){if(this.undoStackPointer<this.undoStack.length&&this.undoStack.length>0)this.undoStack=this.undoStack.splice(0,this.undoStackPointer);this.undoStack.push(a);this.undoStackPointer=this.undoStack.length};svgedit.history.UndoManager.prototype.beginUndoableChange=function(a,H){for(var h=++this.undoChangeStackPointer,i=H.length,u=Array(i),E=Array(i);i--;){var e=H[i];if(e!=null){E[i]=e;u[i]=e.getAttribute(a)}}this.undoableChangeStack[h]= -{attrName:a,oldValues:u,elements:E}};svgedit.history.UndoManager.prototype.finishUndoableChange=function(){for(var a=this.undoChangeStackPointer--,H=this.undoableChangeStack[a],h=H.elements.length,i=H.attrName,u=new svgedit.history.BatchCommand("Change "+i);h--;){var E=H.elements[h];if(E!=null){var e={};e[i]=H.oldValues[h];e[i]!=E.getAttribute(i)&&u.addSubCommand(new svgedit.history.ChangeElementCommand(E,e,i))}}this.undoableChangeStack[a]=null;return u}})();svgedit=svgedit||{}; -(function(){if(!svgedit.select)svgedit.select={};var a,H,h;svgedit.select.Selector=function(i,u){this.id=i;this.selectedElement=u;this.locked=true;this.selectorGroup=a.createSVGElement({element:"g",attr:{id:"selectorGroup"+this.id}});this.selectorRect=this.selectorGroup.appendChild(a.createSVGElement({element:"path",attr:{id:"selectedBox"+this.id,fill:"none",stroke:"#4F80FF","stroke-width":"1",style:"pointer-events:none"}}));this.gripCoords={nw:null,n:null,ne:null,e:null,se:null,s:null,sw:null,w:null}; -this.reset(this.selectedElement)};svgedit.select.Selector.prototype.reset=function(i){this.locked=true;this.selectedElement=i;this.resize();this.selectorGroup.setAttribute("display","inline")};svgedit.select.Selector.prototype.updateGripCursors=function(i){var u=[];i=Math.round(i/45);if(i<0)i+=8;for(var E in h.selectorGrips)u.push(E);for(;i>0;){u.push(u.shift());i--}i=0;for(E in h.selectorGrips){h.selectorGrips[E].setAttribute("style","cursor:"+u[i]+"-resize");i++}};svgedit.select.Selector.prototype.showGrips= -function(i){h.selectorGripsGroup.setAttribute("display",i?"inline":"none");var u=this.selectedElement;this.hasGrips=i;if(u&&i){this.selectorGroup.appendChild(h.selectorGripsGroup);this.updateGripCursors(svgedit.utilities.getRotationAngle(u))}};svgedit.select.Selector.prototype.resize=function(){var i=this.selectorRect,u=h,E=u.selectorGrips,e=this.selectedElement,f=e.getAttribute("stroke-width"),g=a.currentZoom(),p=1/g;if(e.getAttribute("stroke")!=="none"&&!isNaN(f))p+=f/2;var z=e.tagName;if(z==="text")p+= -2/g;f=svgedit.transformlist.getTransformList(e);f=svgedit.math.transformListToTransform(f).matrix;f.e*=g;f.f*=g;var D=svgedit.utilities.getBBox(e);if(z==="g"&&!$.data(e,"gsvg"))if(z=a.getStrokedBBox(e.childNodes))D=z;z=D.x;var q=D.y,M=D.width;D=D.height;p*=g;g=svgedit.math.transformBox(z*g,q*g,M*g,D*g,f);f=g.aabox;z=f.x-p;q=f.y-p;M=f.width+p*2;var ba=f.height+p*2;f=z+M/2;D=q+ba/2;if(e=svgedit.utilities.getRotationAngle(e)){z=a.svgRoot().createSVGTransform();z.setRotate(-e,f,D);z=z.matrix;g.tl=svgedit.math.transformPoint(g.tl.x, -g.tl.y,z);g.tr=svgedit.math.transformPoint(g.tr.x,g.tr.y,z);g.bl=svgedit.math.transformPoint(g.bl.x,g.bl.y,z);g.br=svgedit.math.transformPoint(g.br.x,g.br.y,z);z=g.tl;M=z.x;ba=z.y;var N=z.x,I=z.y;z=Math.min;q=Math.max;M=z(M,z(g.tr.x,z(g.bl.x,g.br.x)))-p;ba=z(ba,z(g.tr.y,z(g.bl.y,g.br.y)))-p;N=q(N,q(g.tr.x,q(g.bl.x,g.br.x)))+p;I=q(I,q(g.tr.y,q(g.bl.y,g.br.y)))+p;z=M;q=ba;M=N-M;ba=I-ba}p=a.svgRoot().suspendRedraw(100);i.setAttribute("d","M"+z+","+q+" L"+(z+M)+","+q+" "+(z+M)+","+(q+ba)+" "+z+","+(q+ -ba)+"z");this.selectorGroup.setAttribute("transform",e?"rotate("+[e,f,D].join(",")+")":"");z-=3.5;q-=3.5;this.gripCoords={nw:[z,q],ne:[z+M,q],sw:[z,q+ba],se:[z+M,q+ba],n:[z+M/2,q],w:[z,q+ba/2],e:[z+M,q+ba/2],s:[z+M/2,q+ba]};for(var ma in this.gripCoords){i=this.gripCoords[ma];E[ma].setAttribute("x",i[0]);E[ma].setAttribute("y",i[1])}this.rotateCoords={nw:[z,q],ne:[z+M+8,q],sw:[z,q+ba+8],se:[z+M+8,q+ba+8]};for(ma in this.rotateCoords){i=this.rotateCoords[ma];u.rotateGrips[ma].setAttribute("cx",i[0]); -u.rotateGrips[ma].setAttribute("cy",i[1])}a.svgRoot().unsuspendRedraw(p)};svgedit.select.SelectorManager=function(){this.rubberBandBox=this.selectorParentGroup=null;this.selectors=[];this.selectorMap={};this.selectorGrips={nw:null,n:null,ne:null,e:null,se:null,s:null,sw:null,w:null};this.selectorGripsGroup=null;this.rotateGrips={nw:null,ne:null,se:null,sw:null};this.initGroup()};svgedit.select.SelectorManager.prototype.initGroup=function(){this.selectorParentGroup&&this.selectorParentGroup.parentNode&& -this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);this.selectorParentGroup=a.createSVGElement({element:"g",attr:{id:"selectorParentGroup"}});this.selectorGripsGroup=a.createSVGElement({element:"g",attr:{display:"none"}});this.selectorParentGroup.appendChild(this.selectorGripsGroup);a.svgRoot().appendChild(this.selectorParentGroup);this.selectorMap={};this.selectors=[];this.rubberBandBox=null;for(var i in this.rotateGrips){var u=a.createSVGElement({element:"circle",attr:{id:"selectorGrip_rotate_"+ -i,fill:"transparent",r:8,stroke:"transparent","stroke-width":0,style:"cursor:url("+H.imgPath+"rotate.png) 12 12, auto;"}});$.data(u,"dir",i);$.data(u,"type","rotate");this.rotateGrips[i]=this.selectorGripsGroup.appendChild(u)}for(i in this.selectorGrips){u=a.createSVGElement({element:"rect",attr:{id:"selectorGrip_resize_"+i,width:7,height:7,fill:"#4F80FF",stroke:"transparent","stroke-width":2,style:"cursor:"+i+"-resize","pointer-events":"all"}});$.data(u,"dir",i);$.data(u,"type","resize");this.selectorGrips[i]= -this.selectorGripsGroup.appendChild(u)}if(!$("#canvasBackground").length){i=H.dimensions;i=a.createSVGElement({element:"svg",attr:{id:"canvasBackground",width:i[0],height:i[1],x:0,y:0,overflow:svgedit.browser.isWebkit()?"none":"visible",style:"pointer-events:none"}});u=a.createSVGElement({element:"rect",attr:{width:"100%",height:"100%",x:0,y:0,"stroke-width":1,stroke:"#000",fill:"#FFF",style:"pointer-events:none"}});i.appendChild(u);a.svgRoot().insertBefore(i,a.svgContent())}};svgedit.select.SelectorManager.prototype.requestSelector= -function(i){if(i==null)return null;var u=this.selectors.length;if(typeof this.selectorMap[i.id]=="object"){this.selectorMap[i.id].locked=true;return this.selectorMap[i.id]}for(var E=0;E<u;++E)if(this.selectors[E]&&!this.selectors[E].locked){this.selectors[E].locked=true;this.selectors[E].reset(i);this.selectorMap[i.id]=this.selectors[E];return this.selectors[E]}this.selectors[u]=new svgedit.select.Selector(u,i);this.selectorParentGroup.appendChild(this.selectors[u].selectorGroup);this.selectorMap[i.id]= -this.selectors[u];return this.selectors[u]};svgedit.select.SelectorManager.prototype.releaseSelector=function(i){if(i!=null)for(var u=this.selectors.length,E=this.selectorMap[i.id],e=0;e<u;++e)if(this.selectors[e]&&this.selectors[e]==E){E.locked==false&&console.log("WARNING! selector was released but was already unlocked");delete this.selectorMap[i.id];E.locked=false;E.selectedElement=null;E.showGrips(false);try{E.selectorGroup.setAttribute("display","none")}catch(f){}break}};svgedit.select.SelectorManager.prototype.getRubberBandBox= -function(){if(!this.rubberBandBox)this.rubberBandBox=this.selectorParentGroup.appendChild(a.createSVGElement({element:"rect",attr:{id:"selectorRubberBand",fill:"transparent",stroke:"#666","stroke-width":1,"stroke-dasharray":"3,2",display:"none",style:"pointer-events:none"}}));return this.rubberBandBox};svgedit.select.init=function(i,u){H=i;a=u;h=new svgedit.select.SelectorManager};svgedit.select.getSelectorManager=function(){return h}})();svgedit=svgedit||{}; -(function(){if(!svgedit.draw)svgedit.draw={};var a="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use".split(","),H={LET_DOCUMENT_DECIDE:0,ALWAYS_RANDOMIZE:1,NEVER_RANDOMIZE:2},h=H.LET_DOCUMENT_DECIDE;svgedit.draw.Layer=function(i,u){this.name_=i;this.group_=u};svgedit.draw.Layer.prototype.getName=function(){return this.name_};svgedit.draw.Layer.prototype.getGroup=function(){return this.group_};svgedit.draw.randomizeIds=function(i,u){h=i==false?H.NEVER_RANDOMIZE: -H.ALWAYS_RANDOMIZE;if(h==H.ALWAYS_RANDOMIZE&&!u.getNonce())u.setNonce(Math.floor(Math.random()*100001));else h==H.NEVER_RANDOMIZE&&u.getNonce()&&u.clearNonce()};svgedit.draw.Drawing=function(i,u){if(!i||!i.tagName||!i.namespaceURI||i.tagName!="svg"||i.namespaceURI!="http://www.w3.org/2000/svg")throw"Error: svgedit.draw.Drawing instance initialized without a <svg> element";this.svgElem_=i;this.obj_num=0;this.idPrefix=u||"svg_";this.releasedNums=[];this.all_layers=[];this.current_layer=null;this.nonce_= -"";var E=this.svgElem_.getAttributeNS("http://svg-edit.googlecode.com","nonce");if(E&&h!=H.NEVER_RANDOMIZE)this.nonce_=E;else h==H.ALWAYS_RANDOMIZE&&this.setNonce(Math.floor(Math.random()*100001))};svgedit.draw.Drawing.prototype.getElem_=function(i){return this.svgElem_.querySelector?this.svgElem_.querySelector("#"+i):$(this.svgElem_).find("[id="+i+"]")[0]};svgedit.draw.Drawing.prototype.getSvgElem=function(){return this.svgElem_};svgedit.draw.Drawing.prototype.getNonce=function(){return this.nonce_}; -svgedit.draw.Drawing.prototype.setNonce=function(i){this.svgElem_.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:se","http://svg-edit.googlecode.com");this.svgElem_.setAttributeNS("http://svg-edit.googlecode.com","se:nonce",i);this.nonce_=i};svgedit.draw.Drawing.prototype.clearNonce=function(){this.nonce_=""};svgedit.draw.Drawing.prototype.getId=function(){return this.nonce_?this.idPrefix+this.nonce_+"_"+this.obj_num:this.idPrefix+this.obj_num};svgedit.draw.Drawing.prototype.getNextId=function(){var i= -this.obj_num,u=false;if(this.releasedNums.length>0){this.obj_num=this.releasedNums.pop();u=true}else this.obj_num++;for(var E=this.getId();this.getElem_(E);){if(u){this.obj_num=i;u=false}this.obj_num++;E=this.getId()}if(u)this.obj_num=i;return E};svgedit.draw.Drawing.prototype.releaseId=function(i){var u=this.idPrefix+(this.nonce_?this.nonce_+"_":"");if(typeof i!="string"||i.indexOf(u)!=0)return false;i=parseInt(i.substr(u.length));if(typeof i!="number"||i<=0||this.releasedNums.indexOf(i)!=-1)return false; -this.releasedNums.push(i);return true};svgedit.draw.Drawing.prototype.getNumLayers=function(){return this.all_layers.length};svgedit.draw.Drawing.prototype.hasLayer=function(i){for(var u=0;u<this.getNumLayers();u++)if(this.all_layers[u][0]==i)return true;return false};svgedit.draw.Drawing.prototype.getLayerName=function(i){if(i>=0&&i<this.getNumLayers())return this.all_layers[i][0];return""};svgedit.draw.Drawing.prototype.getCurrentLayer=function(){return this.current_layer};svgedit.draw.Drawing.prototype.getCurrentLayerName= -function(){for(var i=0;i<this.getNumLayers();++i)if(this.all_layers[i][1]==this.current_layer)return this.getLayerName(i);return""};svgedit.draw.Drawing.prototype.setCurrentLayer=function(i){for(var u=0;u<this.getNumLayers();++u)if(i==this.getLayerName(u)){if(this.current_layer!=this.all_layers[u][1]){this.current_layer.setAttribute("style","pointer-events:none");this.current_layer=this.all_layers[u][1];this.current_layer.setAttribute("style","pointer-events:all")}return true}return false};svgedit.draw.Drawing.prototype.deleteCurrentLayer= -function(){if(this.current_layer&&this.getNumLayers()>1){var i=this.current_layer.parentNode.removeChild(this.current_layer);this.identifyLayers();return i}return null};svgedit.draw.Drawing.prototype.identifyLayers=function(){this.all_layers=[];for(var i=this.svgElem_.childNodes.length,u=[],E=[],e=null,f=false,g=0;g<i;++g){var p=this.svgElem_.childNodes.item(g);if(p&&p.nodeType==1)if(p.tagName=="g"){f=true;var z=$("title",p).text();if(!z&&svgedit.browser.isOpera()&&p.querySelectorAll)z=$(p.querySelectorAll("title")).text(); -if(z){E.push(z);this.all_layers.push([z,p]);e=p;svgedit.utilities.walkTree(p,function(D){D.setAttribute("style","pointer-events:inherit")});e.setAttribute("style","pointer-events:none")}else u.push(p)}else if(~a.indexOf(p.nodeName)){svgedit.utilities.getBBox(p);u.push(p)}}i=this.svgElem_.ownerDocument;if(u.length>0||!f){for(g=1;E.indexOf("Layer "+g)>=0;)g++;E="Layer "+g;e=i.createElementNS("http://www.w3.org/2000/svg","g");f=i.createElementNS("http://www.w3.org/2000/svg","title");f.textContent=E; -e.appendChild(f);for(f=0;f<u.length;++f)e.appendChild(u[f]);this.svgElem_.appendChild(e);this.all_layers.push([E,e])}svgedit.utilities.walkTree(e,function(D){D.setAttribute("style","pointer-events:inherit")});this.current_layer=e;this.current_layer.setAttribute("style","pointer-events:all")};svgedit.draw.Drawing.prototype.createLayer=function(i){var u=this.svgElem_.ownerDocument,E=u.createElementNS("http://www.w3.org/2000/svg","g");u=u.createElementNS("http://www.w3.org/2000/svg","title");u.textContent= -i;E.appendChild(u);this.svgElem_.appendChild(E);this.identifyLayers();return E};svgedit.draw.Drawing.prototype.getLayerVisibility=function(i){for(var u=null,E=0;E<this.getNumLayers();++E)if(this.getLayerName(E)==i){u=this.all_layers[E][1];break}if(!u)return false;return u.getAttribute("display")!="none"};svgedit.draw.Drawing.prototype.setLayerVisibility=function(i,u){if(typeof u!="boolean")return null;for(var E=null,e=0;e<this.getNumLayers();++e)if(this.getLayerName(e)==i){E=this.all_layers[e][1]; -break}if(!E)return null;E.getAttribute("display");E.setAttribute("display",u?"inline":"none");return E};svgedit.draw.Drawing.prototype.getLayerOpacity=function(i){for(var u=0;u<this.getNumLayers();++u)if(this.getLayerName(u)==i){(i=this.all_layers[u][1].getAttribute("opacity"))||(i="1.0");return parseFloat(i)}return null};svgedit.draw.Drawing.prototype.setLayerOpacity=function(i,u){if(!(typeof u!="number"||u<0||u>1))for(var E=0;E<this.getNumLayers();++E)if(this.getLayerName(E)==i){this.all_layers[E][1].setAttribute("opacity", -u);break}}})();svgedit=svgedit||{}; -(function(){if(!svgedit.path)svgedit.path={};var a={pathNodeTooltip:"Drag node to move it. Double-click node to change segment type",pathCtrlPtTooltip:"Drag control point to adjust curve properties"},H={2:["x","y"],4:["x","y"],6:["x","y","x1","y1","x2","y2"],8:["x","y","x1","y1"],10:["x","y","r1","r2","angle","largeArcFlag","sweepFlag"],12:["x"],14:["y"],16:["x","y","x2","y2"],18:["x","y"]},h=[],i=true,u={};svgedit.path.setLinkControlPoints=function(f){i=f};var E=svgedit.path.path=null;svgedit.path.init= -function(f){E=f;h=[0,"ClosePath"];$.each(["Moveto","Lineto","CurvetoCubic","CurvetoQuadratic","Arc","LinetoHorizontal","LinetoVertical","CurvetoCubicSmooth","CurvetoQuadraticSmooth"],function(g,p){h.push(p+"Abs");h.push(p+"Rel")})};svgedit.path.insertItemBefore=function(f,g,p){f=f.pathSegList;if(svgedit.browser.supportsPathInsertItemBefore())f.insertItemBefore(g,p);else{for(var z=f.numberOfItems,D=[],q=0;q<z;q++){var M=f.getItem(q);D.push(M)}f.clear();for(q=0;q<z;q++){q==p&&f.appendItem(g);f.appendItem(D[q])}}}; -svgedit.path.ptObjToArr=function(f,g){for(var p=H[f],z=p.length,D=Array(z),q=0;q<z;q++)D[q]=g[p[q]];return D};svgedit.path.getGripPt=function(f,g){var p={x:g?g.x:f.item.x,y:g?g.y:f.item.y},z=f.path;if(z.matrix)p=svgedit.math.transformPoint(p.x,p.y,z.matrix);p.x*=E.getCurrentZoom();p.y*=E.getCurrentZoom();return p};svgedit.path.getPointFromGrip=function(f,g){var p={x:f.x,y:f.y};if(g.matrix){f=svgedit.math.transformPoint(p.x,p.y,g.imatrix);p.x=f.x;p.y=f.y}p.x/=E.getCurrentZoom();p.y/=E.getCurrentZoom(); -return p};svgedit.path.addPointGrip=function(f,g,p){var z=svgedit.path.getGripContainer(),D=svgedit.utilities.getElem("pathpointgrip_"+f);if(!D){D=document.createElementNS("http://www.w3.org/2000/svg","rect");svgedit.utilities.assignAttributes(D,{id:"pathpointgrip_"+f,display:"none",width:5,height:5,fill:"#fff",stroke:"#4F80FF","stroke-width":1,cursor:"move",style:"pointer-events:all","xlink:title":a.pathNodeTooltip});D=z.appendChild(D);$("#pathpointgrip_"+f).dblclick(function(){svgedit.path.path&& -svgedit.path.path.setSegType()})}g&&p&&svgedit.utilities.assignAttributes(D,{x:g-2.5,y:p-2.5,display:"inline"});return D};svgedit.path.getGripContainer=function(){var f=svgedit.utilities.getElem("pathpointgrip_container");if(!f){f=svgedit.utilities.getElem("selectorParentGroup").appendChild(document.createElementNS("http://www.w3.org/2000/svg","g"));f.id="pathpointgrip_container"}return f};svgedit.path.addCtrlGrip=function(f){var g=svgedit.utilities.getElem("ctrlpointgrip_"+f);if(g)return g;g=document.createElementNS("http://www.w3.org/2000/svg", -"circle");svgedit.utilities.assignAttributes(g,{id:"ctrlpointgrip_"+f,display:"none",r:3,fill:"#4F80FF",cursor:"move",style:"pointer-events:all","xlink:title":a.pathCtrlPtTooltip});svgedit.path.getGripContainer().appendChild(g);return g};svgedit.path.getCtrlLine=function(f){var g=svgedit.utilities.getElem("ctrlLine_"+f);if(g)return g;g=document.createElementNS("http://www.w3.org/2000/svg","line");svgedit.utilities.assignAttributes(g,{id:"ctrlLine_"+f,stroke:"#4F80FF","stroke-width":1,style:"pointer-events:none"}); -svgedit.path.getGripContainer().appendChild(g);return g};svgedit.path.getPointGrip=function(f,g){var p=svgedit.path.addPointGrip(f.index);if(g){var z=svgedit.path.getGripPt(f);svgedit.utilities.assignAttributes(p,{cx:z.x,cy:z.y,display:"inline"})}return p};svgedit.path.getControlPoints=function(f){var g=f.item,p=f.index;if(!("x1"in g)||!("x2"in g))return null;var z={};svgedit.path.getGripContainer();for(var D=[svgedit.path.path.segs[p-1].item,g],q=1;q<3;q++){var M=p+"c"+q,ba=z["c"+q+"_line"]=svgedit.path.getCtrlLine(M), -N=svgedit.path.getGripPt(f,{x:g["x"+q],y:g["y"+q]}),I=svgedit.path.getGripPt(f,{x:D[q-1].x,y:D[q-1].y});svgedit.utilities.assignAttributes(ba,{x1:N.x,y1:N.y,x2:I.x,y2:I.y,display:"inline"});z["c"+q+"_line"]=ba;pointGrip=z["c"+q]=svgedit.path.addCtrlGrip(M);svgedit.utilities.assignAttributes(pointGrip,{cx:N.x,cy:N.y,display:"inline"});z["c"+q]=pointGrip}return z};svgedit.path.replacePathSeg=function(f,g,p,z){z=z||svgedit.path.path.elem;f=z["createSVGPathSeg"+h[f]].apply(z,p);if(svgedit.browser.supportsPathReplaceItem())z.pathSegList.replaceItem(f, -g);else{p=z.pathSegList;z=p.numberOfItems;for(var D=[],q=0;q<z;q++){var M=p.getItem(q);D.push(M)}p.clear();for(q=0;q<z;q++)q==g?p.appendItem(f):p.appendItem(D[q])}};svgedit.path.getSegSelector=function(f,g){var p=f.index,z=svgedit.utilities.getElem("segline_"+p);if(!z){var D=svgedit.path.getGripContainer();z=document.createElementNS("http://www.w3.org/2000/svg","path");svgedit.utilities.assignAttributes(z,{id:"segline_"+p,display:"none",fill:"none",stroke:"#0FF","stroke-width":2,style:"pointer-events:none", -d:"M0,0 0,0"});D.appendChild(z)}if(g){p=f.prev;if(!p){z.setAttribute("display","none");return z}p=svgedit.path.getGripPt(p);svgedit.path.replacePathSeg(2,0,[p.x,p.y],z);D=svgedit.path.ptObjToArr(f.type,f.item,true);for(var q=0;q<D.length;q+=2){p=svgedit.path.getGripPt(f,{x:D[q],y:D[q+1]});D[q]=p.x;D[q+1]=p.y}svgedit.path.replacePathSeg(f.type,1,D,z)}return z};svgedit.path.smoothControlPoints=this.smoothControlPoints=function(f,g,p){var z=f.x-p.x,D=f.y-p.y,q=g.x-p.x,M=g.y-p.y;if((z!=0||D!=0)&&(q!= -0||M!=0)){f=Math.atan2(D,z);g=Math.atan2(M,q);z=Math.sqrt(z*z+D*D);q=Math.sqrt(q*q+M*M);D=E.getSVGRoot().createSVGPoint();M=E.getSVGRoot().createSVGPoint();if(f<0)f+=2*Math.PI;if(g<0)g+=2*Math.PI;var ba=Math.abs(f-g),N=Math.abs(Math.PI-ba)/2;if(f-g>0){f=ba<Math.PI?f+N:f-N;g=ba<Math.PI?g-N:g+N}else{f=ba<Math.PI?f-N:f+N;g=ba<Math.PI?g+N:g-N}D.x=z*Math.cos(f)+p.x;D.y=z*Math.sin(f)+p.y;M.x=q*Math.cos(g)+p.x;M.y=q*Math.sin(g)+p.y;return[D,M]}};svgedit.path.Segment=function(f,g){this.selected=false;this.index= -f;this.item=g;this.type=g.pathSegType;this.ctrlpts=[];this.segsel=this.ptgrip=null};svgedit.path.Segment.prototype.showCtrlPts=function(f){for(var g in this.ctrlpts)this.ctrlpts[g].setAttribute("display",f?"inline":"none")};svgedit.path.Segment.prototype.selectCtrls=function(){$("#ctrlpointgrip_"+this.index+"c1, #ctrlpointgrip_"+this.index+"c2").attr("fill","#4F80FF")};svgedit.path.Segment.prototype.show=function(f){if(this.ptgrip){this.ptgrip.setAttribute("display",f?"inline":"none");this.segsel.setAttribute("display", -f?"inline":"none");this.showCtrlPts(f)}};svgedit.path.Segment.prototype.select=function(f){if(this.ptgrip){this.ptgrip.setAttribute("stroke",f?"#0FF":"#00F");this.segsel.setAttribute("display",f?"inline":"none");this.ctrlpts&&this.selectCtrls(f);this.selected=f}};svgedit.path.Segment.prototype.addGrip=function(){this.ptgrip=svgedit.path.getPointGrip(this,true);this.ctrlpts=svgedit.path.getControlPoints(this,true);this.segsel=svgedit.path.getSegSelector(this,true)};svgedit.path.Segment.prototype.update= -function(f){if(this.ptgrip){var g=svgedit.path.getGripPt(this);svgedit.utilities.assignAttributes(this.ptgrip,this.ptgrip.nodeName=="rect"?{x:g.x-2.5,y:g.y-2.5}:{cx:g.x,cy:g.y});svgedit.path.getSegSelector(this,true);if(this.ctrlpts){if(f){this.item=svgedit.path.path.elem.pathSegList.getItem(this.index);this.type=this.item.pathSegType}svgedit.path.getControlPoints(this)}}};svgedit.path.Segment.prototype.move=function(f,g){var p=this.item;p=this.ctrlpts?[p.x+=f,p.y+=g,p.x1,p.y1,p.x2+=f,p.y2+=g]:[p.x+= -f,p.y+=g];svgedit.path.replacePathSeg(this.type,this.index,p);if(this.next&&this.next.ctrlpts){p=this.next.item;p=[p.x,p.y,p.x1+=f,p.y1+=g,p.x2,p.y2];svgedit.path.replacePathSeg(this.next.type,this.next.index,p)}if(this.mate){p=this.mate.item;p=[p.x+=f,p.y+=g];svgedit.path.replacePathSeg(this.mate.type,this.mate.index,p)}this.update(true);this.next&&this.next.update(true)};svgedit.path.Segment.prototype.setLinked=function(f){var g,p,z;if(f==2){p=1;g=this.next;if(!g)return;z=this.item}else{p=2;g=this.prev; -if(!g)return;z=g.item}var D=g.item;D["x"+p]=z.x+(z.x-this.item["x"+f]);D["y"+p]=z.y+(z.y-this.item["y"+f]);svgedit.path.replacePathSeg(g.type,g.index,[D.x,D.y,D.x1,D.y1,D.x2,D.y2]);g.update(true)};svgedit.path.Segment.prototype.moveCtrl=function(f,g,p){var z=this.item;z["x"+f]+=g;z["y"+f]+=p;svgedit.path.replacePathSeg(this.type,this.index,[z.x,z.y,z.x1,z.y1,z.x2,z.y2]);this.update(true)};svgedit.path.Segment.prototype.setType=function(f,g){svgedit.path.replacePathSeg(f,this.index,g);this.type=f; -this.item=svgedit.path.path.elem.pathSegList.getItem(this.index);this.showCtrlPts(f===6);this.ctrlpts=svgedit.path.getControlPoints(this);this.update(true)};svgedit.path.Path=function(f){if(!f||f.tagName!=="path")throw"svgedit.path.Path constructed without a <path> element";this.elem=f;this.segs=[];this.selected_pts=[];svgedit.path.path=this;this.init()};svgedit.path.Path.prototype.init=function(){$(svgedit.path.getGripContainer()).find("*").attr("display","none");var f=this.elem.pathSegList,g=f.numberOfItems; -this.segs=[];this.selected_pts=[];this.first_seg=null;for(var p=0;p<g;p++){var z=f.getItem(p);z=new svgedit.path.Segment(p,z);z.path=this;this.segs.push(z)}f=this.segs;z=null;for(p=0;p<g;p++){var D=f[p],q=p+1>=g?null:f[p+1],M=p-1<0?null:f[p-1];if(D.type===2){if(M&&M.type!==1){q=f[z];q.next=f[z+1];q.next.prev=q;q.addGrip()}z=p}else if(q&&q.type===1){D.next=f[z+1];D.next.prev=D;D.mate=f[z];D.addGrip();if(this.first_seg==null)this.first_seg=D}else if(q){if(D.type!==1){D.addGrip();if(q&&q.type!==2){D.next= -q;D.next.prev=D}}}else if(D.type!==1){q=f[z];q.next=f[z+1];q.next.prev=q;q.addGrip();D.addGrip();if(!this.first_seg)this.first_seg=f[z]}}return this};svgedit.path.Path.prototype.eachSeg=function(f){for(var g=this.segs.length,p=0;p<g;p++)if(f.call(this.segs[p],p)===false)break};svgedit.path.Path.prototype.addSeg=function(f){var g=this.segs[f];if(g.prev){var p=g.prev,z;switch(g.item.pathSegType){case 4:var D=(g.item.x+p.item.x)/2,q=(g.item.y+p.item.y)/2;z=this.elem.createSVGPathSegLinetoAbs(D,q);break; -case 6:z=(p.item.x+g.item.x1)/2;var M=(g.item.x1+g.item.x2)/2,ba=(g.item.x2+g.item.x)/2,N=(z+M)/2;M=(M+ba)/2;D=(N+M)/2;var I=(p.item.y+g.item.y1)/2,ma=(g.item.y1+g.item.y2)/2;p=(g.item.y2+g.item.y)/2;var ia=(I+ma)/2;ma=(ma+p)/2;q=(ia+ma)/2;z=this.elem.createSVGPathSegCurvetoCubicAbs(D,q,z,I,N,ia);svgedit.path.replacePathSeg(g.type,f,[g.item.x,g.item.y,M,ma,ba,p])}svgedit.path.insertItemBefore(this.elem,z,f)}};svgedit.path.Path.prototype.deleteSeg=function(f){var g=this.segs[f],p=this.elem.pathSegList; -g.show(false);var z=g.next;if(g.mate){var D=[z.item.x,z.item.y];svgedit.path.replacePathSeg(2,z.index,D);svgedit.path.replacePathSeg(4,g.index,D);p.removeItem(g.mate.index)}else{if(!g.prev){D=[z.item.x,z.item.y];svgedit.path.replacePathSeg(2,g.next.index,D)}p.removeItem(f)}};svgedit.path.Path.prototype.subpathIsClosed=function(f){var g=false;svgedit.path.path.eachSeg(function(p){if(p<=f)return true;if(this.type===2)return false;else if(this.type===1){g=true;return false}});return g};svgedit.path.Path.prototype.removePtFromSelection= -function(f){var g=this.selected_pts.indexOf(f);if(g!=-1){this.segs[f].select(false);this.selected_pts.splice(g,1)}};svgedit.path.Path.prototype.clearSelection=function(){this.eachSeg(function(){this.select(false)});this.selected_pts=[]};svgedit.path.Path.prototype.storeD=function(){this.last_d=this.elem.getAttribute("d")};svgedit.path.Path.prototype.show=function(f){this.eachSeg(function(){this.show(f)});f&&this.selectPt(this.first_seg.index);return this};svgedit.path.Path.prototype.movePts=function(f, -g){for(var p=this.selected_pts.length;p--;)this.segs[this.selected_pts[p]].move(f,g)};svgedit.path.Path.prototype.moveCtrl=function(f,g){var p=this.segs[this.selected_pts[0]];p.moveCtrl(this.dragctrl,f,g);i&&p.setLinked(this.dragctrl)};svgedit.path.Path.prototype.setSegType=function(f){this.storeD();for(var g=this.selected_pts.length,p;g--;){var z=this.segs[this.selected_pts[g]],D=z.prev;if(D){if(!f){p="Toggle Path Segment Type";f=z.type==6?4:6}f-=0;var q=z.item.x,M=z.item.y,ba=D.item.x;D=D.item.y; -var N;switch(f){case 6:if(z.olditem){ba=z.olditem;N=[q,M,ba.x1,ba.y1,ba.x2,ba.y2]}else{N=q-ba;var I=M-D;N=[q,M,ba+N/3,D+I/3,q-N/3,M-I/3]}break;case 4:N=[q,M];z.olditem=z.item}z.setType(f,N)}}svgedit.path.path.endChanges(p)};svgedit.path.Path.prototype.selectPt=function(f,g){this.clearSelection();f==null&&this.eachSeg(function(p){if(this.prev)f=p});this.addPtsToSelection(f);if(g){this.dragctrl=g;i&&this.segs[f].setLinked(g)}};svgedit.path.Path.prototype.update=function(){var f=this.elem;if(svgedit.utilities.getRotationAngle(f)){this.matrix= -svgedit.math.getMatrix(f);this.imatrix=this.matrix.inverse()}else this.imatrix=this.matrix=null;this.eachSeg(function(g){this.item=f.pathSegList.getItem(g);this.update()});return this};svgedit.path.getPath_=function(f){var g=u[f.id];g||(g=u[f.id]=new svgedit.path.Path(f));return g};svgedit.path.removePath_=function(f){f in u&&delete u[f]};var e=function(f,g){dx=f-oldcx;dy=g-oldcy;r=Math.sqrt(dx*dx+dy*dy);theta=Math.atan2(dy,dx)+angle;dx=r*Math.cos(theta)+oldcx;dy=r*Math.sin(theta)+oldcy;dx-=newcx; -dy-=newcy;r=Math.sqrt(dx*dx+dy*dy);theta=Math.atan2(dy,dx)-angle;return{x:(r*Math.cos(theta)+newcx)/1,y:(r*Math.sin(theta)+newcy)/1}};svgedit.path.recalcRotatedPath=function(){var f=svgedit.path.path.elem,g=svgedit.utilities.getRotationAngle(f,true);if(g){var p=svgedit.utilities.getBBox(f),z=svgedit.path.path.oldbbox,D=z.x+z.width/2,q=z.y+z.height/2;z=p.x+p.width/2;p=p.y+p.height/2;z=z-D;var M=p-q;p=Math.sqrt(z*z+M*M);M=Math.atan2(M,z)+g;z=p*Math.cos(M)+D;p=p*Math.sin(M)+q;D=f.pathSegList;for(q=D.numberOfItems;q;){q-= -1;M=D.getItem(q);var ba=M.pathSegType;if(ba!=1){var N=e(M.x,M.y);N=[N.x,N.y];if(M.x1!=null&&M.x2!=null){c_vals1=e(M.x1,M.y1);c_vals2=e(M.x2,M.y2);N.splice(N.length,0,c_vals1.x,c_vals1.y,c_vals2.x,c_vals2.y)}svgedit.path.replacePathSeg(ba,q,N)}}svgedit.utilities.getBBox(f);D=svgroot.createSVGTransform();f=svgedit.transformlist.getTransformList(f);D.setRotate(g*180/Math.PI,z,p);f.replaceItem(D,0)}};svgedit.path.clearData=function(){u={}}})();if(!window.console){window.console={};window.console.log=function(){};window.console.dir=function(){}}if(window.opera){window.console.log=function(a){opera.postError(a)};window.console.dir=function(){}} -(function(){var a=jQuery.fn.attr;jQuery.fn.attr=function(H,h){var i=this.length;if(!i)return a.apply(this,arguments);for(var u=0;u<i;u++){var E=this[u];if(E.namespaceURI==="http://www.w3.org/2000/svg")if(h!==undefined)E.setAttribute(H,h);else if($.isArray(H)){i=H.length;for(u={};i--;){var e=H[i],f=E.getAttribute(e);if(f||f==="0")f=isNaN(f)?f:f-0;u[e]=f}return u}else if(typeof H==="object")for(e in H)E.setAttribute(e,H[e]);else{if((f=E.getAttribute(H))||f==="0")f=isNaN(f)?f:f-0;return f}else return a.apply(this, -arguments)}return this}})(); -$.SvgCanvas=function(a,H){function h(b,c){for(var d=svgedit.utilities.getBBox(b),n=0;n<2;n++){var m=n===0?"fill":"stroke",A=b.getAttribute(m);if(A&&A.indexOf("url(")===0){A=Sa(A);if(A.tagName==="linearGradient"){var o=A.getAttribute("x1")||0,l=A.getAttribute("y1")||0,s=A.getAttribute("x2")||1,B=A.getAttribute("y2")||0;o=d.width*o+d.x;l=d.height*l+d.y;s=d.width*s+d.x;B=d.height*B+d.y;o=ka(o,l,c);B=ka(s,B,c);s={};s.x1=(o.x-d.x)/d.width;s.y1=(o.y-d.y)/d.height;s.x2=(B.x-d.x)/d.width;s.y2=(B.y-d.y)/d.height; -A=A.cloneNode(true);$(A).attr(s);A.id=ya();ib().appendChild(A);b.setAttribute(m,"url(#"+A.id+")")}}}}var i="http://www.w3.org/2000/svg",u={show_outside_canvas:true,selectNew:true,dimensions:[640,480]};H&&$.extend(u,H);var E=u.dimensions,e=this,f=a.ownerDocument,g=f.importNode(svgedit.utilities.text2xml('<svg id="svgroot" xmlns="'+i+'" xlinkns="http://www.w3.org/1999/xlink" width="'+E[0]+'" height="'+E[1]+'" x="'+E[0]+'" y="'+E[1]+'" overflow="visible"><defs><filter id="canvashadow" filterUnits="objectBoundingBox"><feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/><feOffset in="blur" dx="5" dy="5" result="offsetBlur"/><feMerge><feMergeNode in="offsetBlur"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs></svg>').documentElement, -true);a.appendChild(g);var p=f.createElementNS(i,"svg");(e.clearSvgContentElement=function(){for(;p.firstChild;)p.removeChild(p.firstChild);$(p).attr({id:"svgcontent",width:E[0],height:E[1],x:E[0],y:E[1],overflow:u.show_outside_canvas?"visible":"hidden",xmlns:i,"xmlns:se":"http://svg-edit.googlecode.com","xmlns:xlink":"http://www.w3.org/1999/xlink"}).appendTo(g);var b=f.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");p.appendChild(b)})();var z="svg_";e.setIdPrefix=function(b){z= -b};e.current_drawing_=new svgedit.draw.Drawing(p,z);var D=e.getCurrentDrawing=function(){return e.current_drawing_},q=1,M=null,ba={shape:{fill:(u.initFill.color=="none"?"":"#")+u.initFill.color,fill_paint:null,fill_opacity:u.initFill.opacity,stroke:"#"+u.initStroke.color,stroke_paint:null,stroke_opacity:u.initStroke.opacity,stroke_width:u.initStroke.width,stroke_dasharray:"none",stroke_linejoin:"miter",stroke_linecap:"butt",opacity:u.initOpacity}};ba.text=$.extend(true,{},ba.shape);$.extend(ba.text, -{fill:"#000000",stroke_width:0,font_size:24,font_family:"Junction"});var N=ba.shape,I=Array(1),ma=this.addSvgElementFromJson=function(b){var c=svgedit.utilities.getElem(b.attr.id),d=D().getCurrentLayer();if(c&&b.element!=c.tagName){d.removeChild(c);c=null}if(!c){c=f.createElementNS(i,b.element);if(d)(M||d).appendChild(c)}b.curStyles&&svgedit.utilities.assignAttributes(c,{fill:N.fill,stroke:N.stroke,"stroke-width":N.stroke_width,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin, -"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,"fill-opacity":N.fill_opacity,opacity:N.opacity/2,style:"pointer-events:inherit"},100);svgedit.utilities.assignAttributes(c,b.attr,100);svgedit.utilities.cleanupElement(c);return c},ia=e.getTransformList=svgedit.transformlist.getTransformList,ka=svgedit.math.transformPoint,X=e.matrixMultiply=svgedit.math.matrixMultiply,qa=e.hasMatrixTransform=svgedit.math.hasMatrixTransform,ga=e.transformListToTransform=svgedit.math.transformListToTransform, -Na=svgedit.math.snapToAngle,va=svgedit.math.getMatrix;svgedit.units.init({getBaseUnit:function(){return u.baseUnit},getElement:svgedit.utilities.getElem,getHeight:function(){return p.getAttribute("height")/q},getWidth:function(){return p.getAttribute("width")/q},getRoundDigits:function(){return Ua.round_digits}});var ha=e.convertToNum=svgedit.units.convertToNum;svgedit.utilities.init({getDOMDocument:function(){return f},getDOMContainer:function(){return a},getSVGRoot:function(){return g},getSelectedElements:function(){return I}, -getSVGContent:function(){return p}});var Ra=e.getUrlFromAttr=svgedit.utilities.getUrlFromAttr,U=e.getHref=svgedit.utilities.getHref,Z=e.setHref=svgedit.utilities.setHref,ea=svgedit.utilities.getPathBBox;e.getBBox=svgedit.utilities.getBBox;var ra=e.getRotationAngle=svgedit.utilities.getRotationAngle,ja=e.getElem=svgedit.utilities.getElem,la=e.assignAttributes=svgedit.utilities.assignAttributes,T=this.cleanupElement=svgedit.utilities.cleanupElement,wa=svgedit.sanitize.getNSMap(),Da=e.sanitizeSvg=svgedit.sanitize.sanitizeSvg, -Ma=svgedit.history.MoveElementCommand,Fa=svgedit.history.InsertElementCommand,Oa=svgedit.history.RemoveElementCommand,Qa=svgedit.history.ChangeElementCommand,Ga=svgedit.history.BatchCommand;e.undoMgr=new svgedit.history.UndoManager({handleHistoryEvent:function(b,c){var d=svgedit.history.HistoryEventTypes;if(b==d.BEFORE_UNAPPLY||b==d.BEFORE_APPLY)e.clearSelection();else if(b==d.AFTER_APPLY||b==d.AFTER_UNAPPLY){var n=c.elements();e.pathActions.clear();aa("changed",n);n=c.type();d=b==d.AFTER_APPLY;if(n== -Ma.type()){d=d?c.newParent:c.oldParent;d==p&&e.identifyLayers()}else if(n==Fa.type()||n==Oa.type()){c.parent==p&&e.identifyLayers();if(n==Fa.type())d&&mb(c.elem);else d||mb(c.elem);c.elem.tagName==="use"&&Tb(c.elem)}else if(n==Qa.type()){c.elem.tagName=="title"&&c.elem.parentNode.parentNode==p&&e.identifyLayers();d=d?c.newValues:c.oldValues;d.stdDeviation&&e.setBlurOffsets(c.elem.parentNode,d.stdDeviation);if(c.elem.tagName==="use"&&svgedit.browser.isWebkit()){n=c.elem;if(!n.getAttribute("x")&&!n.getAttribute("y")){d= -n.parentNode;var m=n.nextSibling;d.removeChild(n);d.insertBefore(n,m)}}}}}});var Ca=function(b){e.undoMgr.addCommandToHistory(b)};svgedit.select.init(u,{createSVGElement:function(b){return e.addSvgElementFromJson(b)},svgRoot:function(){return g},svgContent:function(){return p},currentZoom:function(){return q},getStrokedBBox:function(b){return e.getStrokedBBox([b])}});var Ha=this.selectorManager=svgedit.select.getSelectorManager();svgedit.path.init({getCurrentZoom:function(){return q},getSVGRoot:function(){return g}}); -svgedit.utilities.snapToGrid=function(b){var c=u.snappingStep,d=u.baseUnit;if(d!=="px")c*=svgedit.units.getTypeMap()[d];return b=Math.round(b/c)*c};var Aa=svgedit.utilities.snapToGrid,zb={exportNoBlur:"Blurred elements will appear as un-blurred",exportNoforeignObject:"foreignObject elements will not appear",exportNoDashArray:"Strokes will appear filled",exportNoText:"Text may not appear as expected"},Pb=["clip-path","fill","filter","marker-end","marker-mid","marker-start","mask","stroke"],gb=$.data, -mb=function(b){var c=$(b).attr(Pb),d;for(d in c){var n=c[d];if(n&&n.indexOf("url(")===0){n=Ra(n).substr(1);if(!ja(n)){ib().appendChild(Jb[n]);delete Jb[n]}}}b=b.getElementsByTagName("*");if(b.length){c=0;for(d=b.length;c<d;c++)mb(b[c])}},Va={},ub=u.imgPath+"logo.png",Bb=[],Ua={round_digits:5},Ja=false,Wa=null,Ia="select",kb="none",Cb={},ab=ba.text,cb=N,db=null,za=null,vb=[],lb={},xb=null,Jb={};e.clipBoard=[];var pb=this.runExtensions=function(b,c,d){var n=false;if(d)n=[];$.each(lb,function(m,A){if(b in -A)if(d)n.push(A[b](c));else n=A[b](c)});return n};this.addExtension=function(b,c){if(b in lb)console.log('Cannot add extension "'+b+'", an extension by that name already exists"');else{var d=$.isFunction(c)?c($.extend(e.getPrivateMethods(),{svgroot:g,svgcontent:p,nonce:D().getNonce(),selectorManager:Ha})):c;lb[b]=d;aa("extension_added",d)}};var Kb=this.round=function(b){return parseInt(b*q)/q},Rb=this.getIntersectionList=function(b){if(za==null)return null;var c=M||D().getCurrentLayer();vb.length|| -(vb=Sb(c));var d=null;try{d=c.getIntersectionList(b,null)}catch(n){}if(d==null||typeof d.item!="function"){d=[];if(b)b=b;else{b=za.getBBox();c={};for(var m in b)c[m]=b[m]/q;b=c}for(m=vb.length;m--;)b.width&&b.width&&svgedit.math.rectsIntersect(b,vb[m].bbox)&&d.push(vb[m].elem)}return d};getStrokedBBox=this.getStrokedBBox=function(b){b||(b=Lb());if(!b.length)return false;var c=function(B){try{var w=svgedit.utilities.getBBox(B),v=svgedit.utilities.getRotationAngle(B);if(v&&v%90||svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(B))){v= -false;if(["ellipse","path","line","polyline","polygon"].indexOf(B.tagName)>=0)w=v=e.convertToPath(B,true);else if(B.tagName=="rect"){var C=B.getAttribute("rx"),F=B.getAttribute("ry");if(C||F)w=v=e.convertToPath(B,true)}if(!v){var J=B.cloneNode(true),K=document.createElementNS(i,"g"),P=B.parentNode;P.appendChild(K);K.appendChild(J);w=svgedit.utilities.bboxToObj(K.getBBox());P.removeChild(K)}}return w}catch(ca){console.log(B,ca);return null}},d;$.each(b,function(){if(!d)if(this.parentNode)d=c(this)}); -if(d==null)return null;var n=d.x+d.width,m=d.y+d.height,A=d.x,o=d.y,l=function(B){var w=B.getAttribute("stroke-width"),v=0;if(B.getAttribute("stroke")!="none"&&!isNaN(w))v+=w/2;return v},s=[];$.each(b,function(B,w){var v=c(w);if(v){var C=l(w);A=Math.min(A,v.x-C);o=Math.min(o,v.y-C);s.push(v)}});d.x=A;d.y=o;$.each(b,function(B,w){var v=s[B];if(v&&w.nodeType==1){var C=l(w);n=Math.max(n,v.x+v.width+C);m=Math.max(m,v.y+v.height+C)}});d.width=n-A;d.height=m-o;return d};var Lb=this.getVisibleElements=function(b){b|| -(b=$(p).children());var c=[];$(b).children().each(function(d,n){try{n.getBBox()&&c.push(n)}catch(m){}});return c.reverse()},Sb=this.getVisibleElementsAndBBoxes=function(b){b||(b=$(p).children());var c=[];$(b).children().each(function(d,n){try{n.getBBox()&&c.push({elem:n,bbox:getStrokedBBox([n])})}catch(m){}});return c.reverse()},pa=this.groupSvgElem=function(b){var c=document.createElementNS(i,"g");b.parentNode.replaceChild(c,b);$(c).append(b).data("gsvg",b)[0].id=ya()},V=function(b){var c=document.createElementNS(b.namespaceURI, -b.nodeName);c.removeAttribute("id");$.each(b.attributes,function(n,m){m.localName!="-moz-math-font-style"&&c.setAttributeNS(m.namespaceURI,m.nodeName,m.nodeValue)});if(svgedit.browser.isWebkit()&&b.nodeName=="path"){var d=La.convertPath(b);c.setAttribute("d",d)}$.each(b.childNodes,function(n,m){switch(m.nodeType){case 1:c.appendChild(V(m));break;case 3:c.textContent=m.nodeValue}});if($(b).data("gsvg"))$(c).data("gsvg",c.firstChild);else if($(b).data("symbol")){b=$(b).data("symbol");$(c).data("ref", -b).data("symbol",b)}else c.tagName=="image"&&Yb(c);c.id=ya();console.log(c);return c},ua,ya,aa;(function(b){var c={};ua=b.getId=function(){return D().getId()};ya=b.getNextId=function(){return D().getNextId()};aa=b.call=function(d,n){if(c[d])return c[d](this,n)};b.bind=function(d,n){var m=c[d];c[d]=n;return m}})(e);this.prepareSvg=function(b){this.sanitizeSvg(b.documentElement);b=b.getElementsByTagNameNS(i,"path");for(var c=0,d=b.length;c<d;++c){var n=b[c];n.setAttribute("d",La.convertPath(n));La.fixEnd(n)}}; -var Sa=this.getRefElem=function(b){return ja(Ra(b).substr(1))},Eb=function(b){if(!svgedit.browser.isGecko())return b;var c=b.cloneNode(true);b.parentNode.insertBefore(c,b);b.parentNode.removeChild(b);Ha.releaseSelector(b);I[0]=c;Ha.requestSelector(c).showGrips(true);return c};this.setRotationAngle=function(b,c){b=parseFloat(b);var d=I[0],n=d.getAttribute("transform"),m=svgedit.utilities.getBBox(d),A=m.x+m.width/2,o=m.y+m.height/2;m=ia(d);m.numberOfItems>0&&m.getItem(0).type==4&&m.removeItem(0);if(b!= -0){A=ka(A,o,ga(m).matrix);o=g.createSVGTransform();o.setRotate(b,A.x,A.y);m.numberOfItems?m.insertItemBefore(o,0):m.appendItem(o)}else m.numberOfItems==0&&d.removeAttribute("transform");if(!c){m=d.getAttribute("transform");d.setAttribute("transform",n);jb("transform",m,I);aa("changed",I)}ja("pathpointgrip_container");d=Ha.requestSelector(I[0]);d.resize();d.updateGripCursors(b)};var Ab=this.recalculateAllSelectedDimensions=function(){for(var b=new Ga(kb=="none"?"position":"size"),c=I.length;c--;){var d= -nb(I[c]);d&&b.addSubCommand(d)}if(!b.isEmpty()){Ca(b);aa("changed",I)}},wb=[0,"z","M","m","L","l","C","c","Q","q","A","a","H","h","V","v","S","s","T","t"],tb=function(b){console.log([b.a,b.b,b.c,b.d,b.e,b.f])},Fb=this.remapElement=function(b,c,d){var n=u.gridSnapping&&b.parentNode.parentNode.localName==="svg",m=function(){if(n)for(var v in c)c[v]=Aa(c[v]);la(b,c,1E3,true)};box=svgedit.utilities.getBBox(b);for(var A=0;A<2;A++){var o=A===0?"fill":"stroke",l=b.getAttribute(o);if(l&&l.indexOf("url(")=== -0)if(d.a<0||d.d<0){l=Sa(l).cloneNode(true);if(d.a<0){var s=l.getAttribute("x1"),B=l.getAttribute("x2");l.setAttribute("x1",-(s-1));l.setAttribute("x2",-(B-1))}if(d.d<0){s=l.getAttribute("y1");B=l.getAttribute("y2");l.setAttribute("y1",-(s-1));l.setAttribute("y2",-(B-1))}l.id=ya();ib().appendChild(l);b.setAttribute(o,"url(#"+l.id+")")}}A=b.tagName;if(A==="g"||A==="text"||A==="use")if(d.a==1&&d.b==0&&d.c==0&&d.d==1&&(d.e!=0||d.f!=0)){o=ga(b).matrix;o=X(o.inverse(),d,o);c.x=parseFloat(c.x)+o.e;c.y=parseFloat(c.y)+ -o.f}else{o=ia(b);l=g.createSVGTransform();l.setMatrix(X(ga(o).matrix,d));o.clear();o.appendItem(l)}switch(A){case "foreignObject":case "rect":case "image":if(A==="image"&&(d.a<0||d.d<0)){o=ia(b);l=g.createSVGTransform();l.setMatrix(X(ga(o).matrix,d));o.clear();o.appendItem(l)}else{o=ka(c.x,c.y,d);c.width=d.a*c.width;c.height=d.d*c.height;c.x=o.x+Math.min(0,c.width);c.y=o.y+Math.min(0,c.height);c.width=Math.abs(c.width);c.height=Math.abs(c.height)}m();break;case "ellipse":A=ka(c.cx,c.cy,d);c.cx=A.x; -c.cy=A.y;c.rx=d.a*c.rx;c.ry=d.d*c.ry;c.rx=Math.abs(c.rx);c.ry=Math.abs(c.ry);m();break;case "circle":A=ka(c.cx,c.cy,d);c.cx=A.x;c.cy=A.y;A=svgedit.math.transformBox(box.x,box.y,box.width,box.height,d);c.r=Math.min((A.tr.x-A.tl.x)/2,(A.bl.y-A.tl.y)/2);if(c.r)c.r=Math.abs(c.r);m();break;case "line":o=ka(c.x1,c.y1,d);s=ka(c.x2,c.y2,d);c.x1=o.x;c.y1=o.y;c.x2=s.x;c.y2=s.y;case "text":d=b.querySelectorAll("tspan");for(A=d.length;A--;){o=ha("x",b.getAttribute("x"));l=ha("x",d[A].getAttribute("x"));s=ha("y", -b.getAttribute("y"));B=ha("y",d[A].getAttribute("y"));var w={};if(!isNaN(o)&&!isNaN(l)&&o!=0&&l!=0&&c.x)w.x=c.x-(o-l);if(!isNaN(s)&&!isNaN(B)&&s!=0&&B!=0&&c.y)w.y=c.y-(s-B);if(w.x||w.y)la(d[A],w,1E3,true)}m();break;case "use":m();break;case "g":(m=$(b).data("gsvg"))&&la(m,c,1E3,true);break;case "polyline":case "polygon":m=c.points.length;for(A=0;A<m;++A){B=c.points[A];B=ka(B.x,B.y,d);c.points[A].x=B.x;c.points[A].y=B.y}m=c.points.length;d="";for(A=0;A<m;++A){B=c.points[A];d+=B.x+","+B.y+" "}b.setAttribute("points", -d);break;case "path":o=b.pathSegList;m=o.numberOfItems;c.d=Array(m);for(A=0;A<m;++A){l=o.getItem(A);c.d[A]={type:l.pathSegType,x:l.x,y:l.y,x1:l.x1,y1:l.y1,x2:l.x2,y2:l.y2,r1:l.r1,r2:l.r2,angle:l.angle,largeArcFlag:l.largeArcFlag,sweepFlag:l.sweepFlag}}m=c.d.length;A=c.d[0];w=ka(A.x,A.y,d);c.d[0].x=w.x;c.d[0].y=w.y;for(A=1;A<m;++A){l=c.d[A];o=l.type;if(o%2==0){B=ka(l.x!=undefined?l.x:w.x,l.y!=undefined?l.y:w.y,d);o=ka(l.x1,l.y1,d);s=ka(l.x2,l.y2,d);l.x=B.x;l.y=B.y;l.x1=o.x;l.y1=o.y;l.x2=s.x;l.y2=s.y}else{l.x= -d.a*l.x;l.y=d.d*l.y;l.x1=d.a*l.x1;l.y1=d.d*l.y1;l.x2=d.a*l.x2;l.y2=d.d*l.y2}l.r1=d.a*l.r1;l.r2=d.d*l.r2}d="";m=c.d.length;for(A=0;A<m;++A){l=c.d[A];o=l.type;d+=wb[o];switch(o){case 13:case 12:d+=l.x+" ";break;case 15:case 14:d+=l.y+" ";break;case 3:case 5:case 19:case 2:case 4:case 18:d+=l.x+","+l.y+" ";break;case 7:case 6:d+=l.x1+","+l.y1+" "+l.x2+","+l.y2+" "+l.x+","+l.y+" ";break;case 9:case 8:d+=l.x1+","+l.y1+" "+l.x+","+l.y+" ";break;case 11:case 10:d+=l.r1+","+l.r2+" "+l.angle+" "+ +l.largeArcFlag+ -" "+ +l.sweepFlag+" "+l.x+","+l.y+" ";break;case 17:case 16:d+=l.x2+","+l.y2+" "+l.x+","+l.y+" "}}b.setAttribute("d",d)}},Qb=function(b,c,d){b=Sa(b).firstChild;var n=ia(b),m=g.createSVGTransform();m.setTranslate(c,d);n.appendItem(m);nb(b)},nb=this.recalculateDimensions=function(b){if(b==null)return null;var c=ia(b);if(c&&c.numberOfItems>0){for(var d=c.numberOfItems;d--;){var n=c.getItem(d);if(n.type===0)c.removeItem(d);else if(n.type===1)svgedit.math.isIdentity(n.matrix)&&c.removeItem(d);else n.type=== -4&&n.angle===0&&c.removeItem(d)}if(c.numberOfItems===1&&ra(b))return null}if(!c||c.numberOfItems==0){b.removeAttribute("transform");return null}if(c){d=c.numberOfItems;for(var m=[];d--;){n=c.getItem(d);if(n.type===1)m.push([n.matrix,d]);else if(m.length)m=[]}if(m.length===2){d=g.createSVGTransformFromMatrix(X(m[1][0],m[0][0]));c.removeItem(m[0][1]);c.removeItem(m[1][1]);c.insertItemBefore(d,m[1][1])}d=c.numberOfItems;if(d>=2&&c.getItem(d-2).type===1&&c.getItem(d-1).type===2){m=g.createSVGTransform(); -n=X(c.getItem(d-2).matrix,c.getItem(d-1).matrix);m.setMatrix(n);c.removeItem(d-2);c.removeItem(d-2);c.appendItem(m)}}switch(b.tagName){case "line":case "polyline":case "polygon":case "path":break;default:if(c.numberOfItems===1&&c.getItem(0).type===1||c.numberOfItems===2&&c.getItem(0).type===1&&c.getItem(0).type===4)return null}var A=$(b).data("gsvg");d=new Ga("Transform");var o={},l=null;n=[];switch(b.tagName){case "line":n=["x1","y1","x2","y2"];break;case "circle":n=["cx","cy","r"];break;case "ellipse":n= -["cx","cy","rx","ry"];break;case "foreignObject":case "rect":case "image":n=["width","height","x","y"];break;case "use":case "text":case "tspan":n=["x","y"];break;case "polygon":case "polyline":l={};l.points=b.getAttribute("points");m=b.points;var s=m.numberOfItems;o.points=Array(s);for(var B=0;B<s;++B){var w=m.getItem(B);o.points[B]={x:w.x,y:w.y}}break;case "path":l={};l.d=b.getAttribute("d");o.d=b.getAttribute("d")}if(n.length){o=$(b).attr(n);$.each(o,function(yb,Gb){o[yb]=ha(yb,Gb)})}else if(A)o= -{x:$(A).attr("x")||0,y:$(A).attr("y")||0};if(l==null){l=$.extend(true,{},o);$.each(l,function(yb,Gb){l[yb]=ha(yb,Gb)})}l.transform=Wa?Wa:"";if(b.tagName=="g"&&!A||b.tagName=="a"){m=svgedit.utilities.getBBox(b);var v={x:m.x+m.width/2,y:m.y+m.height/2},C=ka(m.x+m.width/2,m.y+m.height/2,ga(c).matrix);n=g.createSVGMatrix();if(m=ra(b)){B=m*Math.PI/180;s=Math.abs(B)>1.0E-10?Math.sin(B)/(1-Math.cos(B)):2/B;for(B=0;B<c.numberOfItems;++B){n=c.getItem(B);if(n.type==4){n=n.matrix;v.y=(s*n.e+n.f)/2;v.x=(n.e- -s*n.f)/2;c.removeItem(B);break}}}B=n=A=0;var F=c.numberOfItems;if(F)var J=c.getItem(0).matrix;if(F>=3&&c.getItem(F-2).type==3&&c.getItem(F-3).type==2&&c.getItem(F-1).type==2){B=3;var K=c.getItem(F-3).matrix,P=c.getItem(F-2).matrix,ca=c.getItem(F-1).matrix;s=b.childNodes;for(w=s.length;w--;){var fa=s.item(w);n=A=0;if(fa.nodeType==1){var R=ia(fa);if(R){n=ga(R).matrix;A=ra(fa);var W=Wa,Y=[];Wa=fa.getAttribute("transform");if(A||qa(R)){var na=g.createSVGTransform();na.setMatrix(X(K,P,ca,n));R.clear(); -R.appendItem(na);Y.push(na)}else{A=X(n.inverse(),ca,n);na=g.createSVGMatrix();na.e=-A.e;na.f=-A.f;n=X(na.inverse(),n.inverse(),K,P,ca,n,A.inverse());var Xa=g.createSVGTransform(),qb=g.createSVGTransform(),Hb=g.createSVGTransform();Xa.setTranslate(A.e,A.f);qb.setScale(n.a,n.d);Hb.setTranslate(na.e,na.f);R.appendItem(Hb);R.appendItem(qb);R.appendItem(Xa);Y.push(Hb);Y.push(qb);Y.push(Xa)}d.addSubCommand(nb(fa));Wa=W}}}c.removeItem(F-1);c.removeItem(F-2);c.removeItem(F-3)}else if(F>=3&&c.getItem(F-1).type== -1){B=3;n=ga(c).matrix;na=g.createSVGTransform();na.setMatrix(n);c.clear();c.appendItem(na)}else if((F==1||F>1&&c.getItem(1).type!=3)&&c.getItem(0).type==2){B=2;A=ga(c).matrix;c.removeItem(0);n=ga(c).matrix.inverse();n=X(n,A);A=n.e;n=n.f;if(A!=0||n!=0){s=b.childNodes;w=s.length;for(F=[];w--;){fa=s.item(w);if(fa.nodeType==1){if(fa.getAttribute("clip-path")){W=fa.getAttribute("clip-path");if(F.indexOf(W)===-1){Qb(W,A,n);F.push(W)}}W=Wa;Wa=fa.getAttribute("transform");if(R=ia(fa)){K=g.createSVGTransform(); -K.setTranslate(A,n);R.numberOfItems?R.insertItemBefore(K,0):R.appendItem(K);d.addSubCommand(nb(fa));R=b.getElementsByTagNameNS(i,"use");fa="#"+fa.id;for(K=R.length;K--;){P=R.item(K);if(fa==U(P)){ca=g.createSVGTransform();ca.setTranslate(-A,-n);ia(P).insertItemBefore(ca,0);d.addSubCommand(nb(P))}}Wa=W}}}F=[];Wa=W}}else if(F==1&&c.getItem(0).type==1&&!m){B=1;n=c.getItem(0).matrix;s=b.childNodes;for(w=s.length;w--;){fa=s.item(w);if(fa.nodeType==1){W=Wa;Wa=fa.getAttribute("transform");if(R=ia(fa)){A= -X(n,ga(R).matrix);F=g.createSVGTransform();F.setMatrix(A);R.clear();R.appendItem(F,0);d.addSubCommand(nb(fa));Wa=W;W=fa.getAttribute("stroke-width");fa.getAttribute("stroke")!=="none"&&!isNaN(W)&&fa.setAttribute("stroke-width",W*((Math.abs(A.a)+Math.abs(A.d))/2))}}}c.clear()}else{if(m){v=g.createSVGTransform();v.setRotate(m,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}c.numberOfItems==0&&b.removeAttribute("transform");return null}if(B==2){if(m){C={x:v.x+J.e,y:v.y+J.f};v=g.createSVGTransform(); -v.setRotate(m,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}else if(B==3){n=ga(c).matrix;J=g.createSVGTransform();J.setRotate(m,v.x,v.y);J=J.matrix;v=g.createSVGTransform();v.setRotate(m,C.x,C.y);C=v.matrix.inverse();W=n.inverse();C=X(W,C,J,n);A=C.e;n=C.f;if(A!=0||n!=0){s=b.childNodes;for(w=s.length;w--;){fa=s.item(w);if(fa.nodeType==1){W=Wa;Wa=fa.getAttribute("transform");R=ia(fa);K=g.createSVGTransform();K.setTranslate(A,n);R.numberOfItems?R.insertItemBefore(K,0):R.appendItem(K); -d.addSubCommand(nb(fa));Wa=W}}}if(m)c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}else{m=svgedit.utilities.getBBox(b);if(!m&&b.tagName!="path")return null;n=g.createSVGMatrix();if(A=ra(b)){v={x:m.x+m.width/2,y:m.y+m.height/2};C=ka(m.x+m.width/2,m.y+m.height/2,ga(c).matrix);B=A*Math.PI/180;s=Math.abs(B)>1.0E-10?Math.sin(B)/(1-Math.cos(B)):2/B;for(B=0;B<c.numberOfItems;++B){n=c.getItem(B);if(n.type==4){n=n.matrix;v.y=(s*n.e+n.f)/2;v.x=(n.e-s*n.f)/2;c.removeItem(B);break}}}B=0;F=c.numberOfItems; -if(!svgedit.browser.isWebkit())if((J=b.getAttribute("fill"))&&J.indexOf("url(")===0){J=Sa(J);W="pattern";if(J.tagName!==W)W="gradient";if(J.getAttribute(W+"Units")==="userSpaceOnUse"){n=ga(c).matrix;m=ia(J);m=ga(m).matrix;n=X(n,m);m="matrix("+[n.a,n.b,n.c,n.d,n.e,n.f].join(",")+")";J.setAttribute(W+"Transform",m)}}if(F>=3&&c.getItem(F-2).type==3&&c.getItem(F-3).type==2&&c.getItem(F-1).type==2){B=3;n=ga(c,F-3,F-1).matrix;c.removeItem(F-1);c.removeItem(F-2);c.removeItem(F-3)}else if(F==4&&c.getItem(F- -1).type==1){B=3;n=ga(c).matrix;na=g.createSVGTransform();na.setMatrix(n);c.clear();c.appendItem(na);n=g.createSVGMatrix()}else if((F==1||F>1&&c.getItem(1).type!=3)&&c.getItem(0).type==2){B=2;J=c.getItem(0).matrix;W=ga(c,1).matrix;m=W.inverse();n=X(m,J,W);c.removeItem(0)}else if(F==1&&c.getItem(0).type==1&&!A){n=ga(c).matrix;switch(b.tagName){case "line":o=$(b).attr(["x1","y1","x2","y2"]);case "polyline":case "polygon":o.points=b.getAttribute("points");if(o.points){m=b.points;s=m.numberOfItems;o.points= -Array(s);for(B=0;B<s;++B){w=m.getItem(B);o.points[B]={x:w.x,y:w.y}}}case "path":o.d=b.getAttribute("d");B=1;c.clear()}}else{B=4;if(A){v=g.createSVGTransform();v.setRotate(A,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}c.numberOfItems==0&&b.removeAttribute("transform");return null}if(B==1||B==2||B==3)Fb(b,o,n);if(B==2){if(A){qa(c)||(C={x:v.x+n.e,y:v.y+n.f});v=g.createSVGTransform();v.setRotate(A,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}else if(B==3&&A){n= -ga(c).matrix;J=g.createSVGTransform();J.setRotate(A,v.x,v.y);J=J.matrix;v=g.createSVGTransform();v.setRotate(A,C.x,C.y);C=v.matrix.inverse();W=n.inverse();C=X(W,C,J,n);Fb(b,o,C);if(A)c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}c.numberOfItems==0&&b.removeAttribute("transform");d.addSubCommand(new Qa(b,l));return d},Mb=null,Ta=this.clearSelection=function(b){if(I[0]!=null)for(var c=I.length,d=0;d<c;++d){var n=I[d];if(n==null)break;Ha.releaseSelector(n);I[d]=null}b||aa("selected",I)},eb= -this.addToSelection=function(b,c){if(b.length!=0){for(var d=0;d<I.length;){if(I[d]==null)break;++d}for(var n=b.length;n--;){var m=b[n];if(m&&svgedit.utilities.getBBox(m)){if(m.tagName==="a"&&m.childNodes.length===1)m=m.firstChild;if(I.indexOf(m)==-1){I[d]=m;d++;m=Ha.requestSelector(m);I.length>1&&m.showGrips(false)}}}aa("selected",I);c||I.length==1?Ha.requestSelector(I[0]).showGrips(true):Ha.requestSelector(I[0]).showGrips(false);for(I.sort(function(A,o){if(A&&o&&A.compareDocumentPosition)return 3- -(o.compareDocumentPosition(A)&6);else if(A==null)return 1});I[0]==null;)I.shift(0)}},Ib=this.selectOnly=function(b,c){Ta(true);eb(b,c)};this.removeFromSelection=function(b){if(I[0]!=null)if(b.length!=0){var c=Array(I.length);j=0;len=I.length;for(var d=0;d<len;++d){var n=I[d];if(n)if(b.indexOf(n)==-1){c[j]=n;j++}else Ha.releaseSelector(n)}I=c}};this.selectAllInCurrentLayer=function(){var b=D().getCurrentLayer();if(b){Ia="select";Ib($(M||b).children())}};var Zb=this.getMouseTarget=function(b){if(b== -null)return null;b=b.target;if(b.correspondingUseElement)b=b.correspondingUseElement;if(["http://www.w3.org/1998/Math/MathML","http://www.w3.org/1999/xhtml"].indexOf(b.namespaceURI)>=0&&b.id!="svgcanvas")for(;b.nodeName!="foreignObject";){b=b.parentNode;if(!b)return g}var c=D().getCurrentLayer();if([g,a,p,c].indexOf(b)>=0)return g;if($(b).closest("#selectorParentGroup").length)return Ha.selectorParentGroup;for(;b.parentNode!==(M||c);)b=b.parentNode;return b};(function(){var b=null,c=null,d=null,n= -null,m=null,A={},o={minx:null,miny:null,maxx:null,maxy:null};$(a).mousedown(function(l){if(!(e.spaceKey||l.button===1)){var s=l.button===2;l.altKey&&svgCanvas.cloneSelectedElements(0,0);Mb=p.getScreenCTM().inverse();var B=ka(l.pageX,l.pageY,Mb),w=B.x*q,v=B.y*q;l.preventDefault();if(s){Ia="select";xb=B}B=w/q;v=v/q;var C=Zb(l);if(C.tagName==="a"&&C.childNodes.length===1)C=C.firstChild;w=n=c=B;var F=m=d=v;if(u.gridSnapping){B=Aa(B);v=Aa(v);c=Aa(c);d=Aa(d)}if(C==Ha.selectorParentGroup&&I[0]!=null){C= -l.target;var J=gb(C,"type");if(J=="rotate"){Ia="rotate";current_rotate_mode=gb(C,"dir")}else if(J=="resize"){Ia="resize";kb=gb(C,"dir")}C=I[0]}Wa=C.getAttribute("transform");J=ia(C);switch(Ia){case "select":Ja=true;kb="none";if(s)Ja=false;if(C!=g){if(I.indexOf(C)==-1){l.shiftKey||Ta(true);eb([C]);db=C;La.clear()}if(!s)for(s=0;s<I.length;++s)if(I[s]!=null){var K=ia(I[s]);K.numberOfItems?K.insertItemBefore(g.createSVGTransform(),0):K.appendItem(g.createSVGTransform())}}else if(!s){Ta();Ia="multiselect"; -if(za==null)za=Ha.getRubberBandBox();n*=q;m*=q;la(za,{x:n,y:m,width:0,height:0,display:"inline"},100)}break;case "zoom":Ja=true;if(za==null)za=Ha.getRubberBandBox();la(za,{x:w*q,y:w*q,width:0,height:0,display:"inline"},100);break;case "resize":Ja=true;c=B;d=v;A=svgedit.utilities.getBBox($("#selectedBox0")[0]);var P={};$.each(A,function(ca,fa){P[ca]=fa/q});A=P;s=ra(C)?1:0;if(qa(J)){J.insertItemBefore(g.createSVGTransform(),s);J.insertItemBefore(g.createSVGTransform(),s);J.insertItemBefore(g.createSVGTransform(), -s)}else{J.appendItem(g.createSVGTransform());J.appendItem(g.createSVGTransform());J.appendItem(g.createSVGTransform());if(svgedit.browser.supportsNonScalingStroke()){if(B=svgedit.browser.isChrome())K=function(ca){var fa=ca.getAttributeNS(null,"stroke");ca.removeAttributeNS(null,"stroke");setTimeout(function(){ca.setAttributeNS(null,"stroke",fa)},1)};C.style.vectorEffect="non-scaling-stroke";B&&K(C);v=C.getElementsByTagName("*");w=v.length;for(s=0;s<w;s++){v[s].style.vectorEffect="non-scaling-stroke"; -B&&K(v[s])}}}break;case "fhellipse":case "fhrect":case "fhpath":Ja=true;b=w+","+F+" ";K=N.stroke_width==0?1:N.stroke_width;ma({element:"polyline",curStyles:true,attr:{points:b,id:ya(),fill:"none",opacity:N.opacity/2,"stroke-linecap":"round",style:"pointer-events:none"}});o.minx=w;o.maxx=w;o.miny=F;o.maxy=F;break;case "image":Ja=true;K=ma({element:"image",attr:{x:B,y:v,width:0,height:0,id:ya(),opacity:N.opacity/2,style:"pointer-events:inherit"}});Z(K,ub);Yb(K);break;case "square":case "rect":Ja=true; -c=B;d=v;ma({element:"rect",curStyles:true,attr:{x:B,y:v,width:0,height:0,id:ya(),opacity:N.opacity/2}});break;case "line":Ja=true;K=N.stroke_width==0?1:N.stroke_width;ma({element:"line",curStyles:true,attr:{x1:B,y1:v,x2:B,y2:v,id:ya(),stroke:N.stroke,"stroke-width":K,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,fill:"none",opacity:N.opacity/2,style:"pointer-events:none"}});break;case "circle":Ja=true; -ma({element:"circle",curStyles:true,attr:{cx:B,cy:v,r:0,id:ya(),opacity:N.opacity/2}});break;case "ellipse":Ja=true;ma({element:"ellipse",curStyles:true,attr:{cx:B,cy:v,rx:0,ry:0,id:ya(),opacity:N.opacity/2}});break;case "text":Ja=true;ma({element:"text",curStyles:true,attr:{x:B,y:v,id:ya(),fill:ab.fill,"stroke-width":ab.stroke_width,"font-size":ab.font_size,"font-family":ab.font_family,"text-anchor":"middle","xml:space":"preserve",opacity:N.opacity}});break;case "path":case "pathedit":c*=q;d*=q; -La.mouseDown(l,C,c,d);Ja=true;break;case "textedit":c*=q;d*=q;fb.mouseDown(l,C,c,d);Ja=true;break;case "rotate":Ja=true;e.undoMgr.beginUndoableChange("transform",I);document.getElementById("workarea").className="rotate"}l=pb("mouseDown",{event:l,start_x:c,start_y:d,selectedElements:I},true);$.each(l,function(ca,fa){if(fa&&fa.started)Ja=true})}}).mousemove(function(l){if(Ja)if(!(l.button===1||e.spaceKey)){var s=I[0],B=ka(l.pageX,l.pageY,Mb),w=B.x*q;B=B.y*q;var v=ja(ua()),C=x=w/q,F=y=B/q;if(u.gridSnapping){x= -Aa(x);y=Aa(y)}l.preventDefault();switch(Ia){case "select":if(I[0]!==null){C=x-c;var J=y-d;if(u.gridSnapping){C=Aa(C);J=Aa(J)}if(l.shiftKey){var K=Na(c,d,x,y);x=K.x;y=K.y}if(C!=0||J!=0){K=I.length;for(F=0;F<K;++F){s=I[F];if(s==null)break;var P=g.createSVGTransform();v=ia(s);P.setTranslate(C,J);v.numberOfItems?v.replaceItem(P,0):v.appendItem(P);Ha.requestSelector(s).resize()}aa("transition",I)}}break;case "multiselect":C*=q;F*=q;la(za,{x:Math.min(n,C),y:Math.min(m,F),width:Math.abs(C-n),height:Math.abs(F- -m)},100);v=[];C=[];P=Rb();K=I.length;for(F=0;F<K;++F){J=P.indexOf(I[F]);if(J==-1)v.push(I[F]);else P[J]=null}K=P.length;for(F=0;F<K;++F)P[F]&&C.push(P[F]);v.length>0&&e.removeFromSelection(v);C.length>0&&eb(C);break;case "resize":v=ia(s);C=(K=qa(v))?A:svgedit.utilities.getBBox(s);F=C.x;P=C.y;var ca=C.width,fa=C.height;C=x-c;J=y-d;if(u.gridSnapping){C=Aa(C);J=Aa(J);fa=Aa(fa);ca=Aa(ca)}var R=ra(s);if(R){var W=Math.sqrt(C*C+J*J);J=Math.atan2(J,C)-R*Math.PI/180;C=W*Math.cos(J);J=W*Math.sin(J)}if(kb.indexOf("n")== --1&&kb.indexOf("s")==-1)J=0;if(kb.indexOf("e")==-1&&kb.indexOf("w")==-1)C=0;var Y=W=0,na=fa?(fa+J)/fa:1,Xa=ca?(ca+C)/ca:1;if(kb.indexOf("n")>=0){na=fa?(fa-J)/fa:1;Y=fa}if(kb.indexOf("w")>=0){Xa=ca?(ca-C)/ca:1;W=ca}C=g.createSVGTransform();J=g.createSVGTransform();ca=g.createSVGTransform();if(u.gridSnapping){F=Aa(F);W=Aa(W);P=Aa(P);Y=Aa(Y)}C.setTranslate(-(F+W),-(P+Y));if(l.shiftKey)if(Xa==1)Xa=na;else na=Xa;J.setScale(Xa,na);ca.setTranslate(F+W,P+Y);if(K){K=R?1:0;v.replaceItem(C,2+K);v.replaceItem(J, -1+K);v.replaceItem(ca,0+K)}else{K=v.numberOfItems;v.replaceItem(ca,K-3);v.replaceItem(J,K-2);v.replaceItem(C,K-1)}Ha.requestSelector(s).resize();aa("transition",I);break;case "zoom":C*=q;F*=q;la(za,{x:Math.min(n*q,C),y:Math.min(m*q,F),width:Math.abs(C-n*q),height:Math.abs(F-m*q)},100);break;case "text":la(v,{x:x,y:y},1E3);break;case "line":C=null;window.opera||g.suspendRedraw(1E3);if(u.gridSnapping){x=Aa(x);y=Aa(y)}F=x;K=y;if(l.shiftKey){K=Na(c,d,F,K);F=K.x;K=K.y}v.setAttributeNS(null,"x2",F);v.setAttributeNS(null, -"y2",K);window.opera||g.unsuspendRedraw(C);break;case "foreignObject":case "square":case "rect":case "image":C=Math.abs(x-c);K=Math.abs(y-d);if(Ia=="square"||l.shiftKey){C=K=Math.max(C,K);F=c<x?c:c-C;P=d<y?d:d-K}else{F=Math.min(c,x);P=Math.min(d,y)}if(u.gridSnapping){C=Aa(C);K=Aa(K);F=Aa(F);P=Aa(P)}la(v,{width:C,height:K,x:F,y:P},1E3);break;case "circle":C=$(v).attr(["cx","cy"]);K=C.cx;F=C.cy;C=Math.sqrt((x-K)*(x-K)+(y-F)*(y-F));if(u.gridSnapping)C=Aa(C);v.setAttributeNS(null,"r",C);break;case "ellipse":C= -$(v).attr(["cx","cy"]);K=C.cx;F=C.cy;C=null;window.opera||g.suspendRedraw(1E3);if(u.gridSnapping){x=Aa(x);K=Aa(K);y=Aa(y);F=Aa(F)}v.setAttributeNS(null,"rx",Math.abs(x-K));v.setAttributeNS(null,"ry",Math.abs(l.shiftKey?x-K:y-F));window.opera||g.unsuspendRedraw(C);break;case "fhellipse":case "fhrect":o.minx=Math.min(C,o.minx);o.maxx=Math.max(C,o.maxx);o.miny=Math.min(F,o.miny);o.maxy=Math.max(F,o.maxy);case "fhpath":b+=+C+","+F+" ";v.setAttributeNS(null,"points",b);break;case "path":case "pathedit":x*= -q;y*=q;if(u.gridSnapping){x=Aa(x);y=Aa(y);c=Aa(c);d=Aa(d)}if(l.shiftKey){if(K=svgedit.path.path){v=K.dragging?K.dragging[0]:c;K=K.dragging?K.dragging[1]:d}else{v=c;K=d}K=Na(v,K,x,y);x=K.x;y=K.y}if(za&&za.getAttribute("display")!=="none"){C*=q;F*=q;la(za,{x:Math.min(n*q,C),y:Math.min(m*q,F),width:Math.abs(C-n*q),height:Math.abs(F-m*q)},100)}La.mouseMove(l,x,y);break;case "textedit":x*=q;y*=q;fb.mouseMove(w,B);break;case "rotate":C=svgedit.utilities.getBBox(s);K=C.x+C.width/2;F=C.y+C.height/2;v=va(s); -v=ka(K,F,v);K=v.x;F=v.y;v=C.x;P=C.y;if(current_rotate_mode=="nw")v=C.x+C.width;if(current_rotate_mode=="se")P=C.y+C.height;if(current_rotate_mode=="sw"){v=C.x+C.width;P=C.y+C.height}compensation_angle=(Math.atan2(F-P,K-v)*(180/Math.PI)-90)%360;R=(Math.atan2(F-y,K-x)*(180/Math.PI)-90)%360;R+=compensation_angle;if(u.gridSnapping)R=Aa(R);if(l.shiftKey)R=Math.round(R/45)*45;e.setRotationAngle(R<-180?360+R:R,true);aa("transition",I)}pb("mouseMove",{event:l,mouse_x:w,mouse_y:B,selected:s})}}).click(function(l){l.preventDefault(); -return false}).dblclick(function(l){var s=l.target.parentNode;if(s!==M){var B=Zb(l),w=B.tagName;if(w==="text"&&Ia!=="textedit"){l=ka(l.pageX,l.pageY,Mb);fb.select(B,l.x,l.y)}if((w==="g"||w==="a")&&ra(B)){ec(B);B=I[0];Ta(true)}M&&$b();s.tagName!=="g"&&s.tagName!=="a"||s===D().getCurrentLayer()||B===Ha.selectorParentGroup||mc(B)}}).mouseup(function(l){if(l.button!==2){var s=db;db=null;if(Ja){var B=ka(l.pageX,l.pageY,Mb),w=B.x*q;B=B.y*q;var v=w/q,C=B/q,F=ja(ua()),J=false;Ja=false;switch(Ia){case "resize":case "multiselect":if(za!= -null){za.setAttribute("display","none");vb=[]}Ia="select";case "select":if(I[0]!=null){if(I[1]==null){w=I[0];switch(w.tagName){case "g":case "use":case "image":case "foreignObject":break;default:cb.fill=w.getAttribute("fill");cb.fill_opacity=w.getAttribute("fill-opacity");cb.stroke=w.getAttribute("stroke");cb.stroke_opacity=w.getAttribute("stroke-opacity");cb.stroke_width=w.getAttribute("stroke-width");cb.stroke_dasharray=w.getAttribute("stroke-dasharray");cb.stroke_linejoin=w.getAttribute("stroke-linejoin"); -cb.stroke_linecap=w.getAttribute("stroke-linecap")}if(w.tagName=="text"){ab.font_size=w.getAttribute("font-size");ab.font_family=w.getAttribute("font-family")}Ha.requestSelector(w).showGrips(true)}Ab();if(v!=n||C!=m){l=I.length;for(w=0;w<l;++w){if(I[w]==null)break;I[w].firstChild||Ha.requestSelector(I[w]).resize()}}else{w=l.target;if(I[0].nodeName==="path"&&I[1]==null)La.select(I[0]);else l.shiftKey&&s!=w&&e.removeFromSelection([w])}if(svgedit.browser.supportsNonScalingStroke())if(l=I[0]){l.removeAttribute("style"); -svgedit.utilities.walkTree(l,function(ca){ca.removeAttribute("style")})}}return;case "zoom":za!=null&&za.setAttribute("display","none");aa("zoomed",{x:Math.min(n,v),y:Math.min(m,C),width:Math.abs(v-n),height:Math.abs(C-m),factor:l.altKey?0.5:2});return;case "fhpath":s=F.getAttribute("points");v=s.indexOf(",");if(J=v>=0?s.indexOf(",",v+1)>=0:s.indexOf(" ",s.indexOf(" ")+1)>=0)F=La.smoothPolylineIntoPath(F);break;case "line":s=$(F).attr(["x1","x2","y1","y2"]);J=s.x1!=s.x2||s.y1!=s.y2;break;case "foreignObject":case "square":case "rect":case "image":s= -$(F).attr(["width","height"]);J=s.width!=0||s.height!=0||Ia==="image";break;case "circle":J=F.getAttribute("r")!=0;break;case "ellipse":s=$(F).attr(["rx","ry"]);J=s.rx!=null||s.ry!=null;break;case "fhellipse":if(o.maxx-o.minx>0&&o.maxy-o.miny>0){F=ma({element:"ellipse",curStyles:true,attr:{cx:(o.minx+o.maxx)/2,cy:(o.miny+o.maxy)/2,rx:(o.maxx-o.minx)/2,ry:(o.maxy-o.miny)/2,id:ua()}});aa("changed",[F]);J=true}break;case "fhrect":if(o.maxx-o.minx>0&&o.maxy-o.miny>0){F=ma({element:"rect",curStyles:true, -attr:{x:o.minx,y:o.miny,width:o.maxx-o.minx,height:o.maxy-o.miny,id:ua()}});aa("changed",[F]);J=true}break;case "text":J=true;Ib([F]);fb.start(F);break;case "path":F=null;Ja=true;s=La.mouseUp(l,F,w,B);F=s.element;J=s.keep;break;case "pathedit":J=true;F=null;La.mouseUp(l);break;case "textedit":J=false;F=null;fb.mouseUp(l,w,B);break;case "rotate":J=true;F=null;Ia="select";s=e.undoMgr.finishUndoableChange();s.isEmpty()||Ca(s);Ab();aa("changed",I)}w=pb("mouseUp",{event:l,mouse_x:w,mouse_y:B},true);$.each(w, -function(ca,fa){if(fa){J=fa.keep||J;F=fa.element;Ja=fa.started||Ja}});if(!J&&F!=null){D().releaseId(ua());F.parentNode.removeChild(F);F=null;for(w=l.target;w.parentNode.parentNode.tagName=="g";)w=w.parentNode;if((Ia!="path"||!drawn_path)&&w.parentNode.id!="selectorParentGroup"&&w.id!="svgcanvas"&&w.id!="svgroot"){e.setMode("select");Ib([w],true)}}else if(F!=null){e.addedNew=true;l=0.2;var K;if(false.beginElement&&F.getAttribute("opacity")!=N.opacity){K=$(false).clone().attr({to:N.opacity,dur:l}).appendTo(F); -try{K[0].beginElement()}catch(P){}}else l=0;setTimeout(function(){K&&K.remove();F.setAttribute("opacity",N.opacity);F.setAttribute("style","pointer-events:inherit");T(F);if(Ia==="path")La.toEditMode(F);else u.selectNew&&Ib([F],true);Ca(new Fa(F));aa("changed",[F])},l*1E3)}Wa=null}}});$(a).bind("mousewheel DOMMouseScroll",function(l){if(l.shiftKey){l.preventDefault();Mb=p.getScreenCTM().inverse();var s=ka(l.pageX,l.pageY,Mb);s={x:s.x,y:s.y,width:0,height:0};if(l.wheelDelta)if(l.wheelDelta>=120)s.factor= -2;else{if(l.wheelDelta<=-120)s.factor=0.5}else if(l.detail)if(l.detail>0)s.factor=0.5;else if(l.detail<0)s.factor=2;s.factor&&aa("zoomed",s)}})})();var Yb=function(b){$(b).click(function(c){c.preventDefault()})},fb=e.textActions=function(){function b(R){var W=B.value==="";$(B).focus();if(!arguments.length)if(W)R=0;else{if(B.selectionEnd!==B.selectionStart)return;R=B.selectionEnd}var Y;Y=F[R];W||B.setSelectionRange(R,R);w=ja("text_cursor");if(!w){w=document.createElementNS(i,"line");la(w,{id:"text_cursor", -stroke:"#333","stroke-width":1});w=ja("selectorParentGroup").appendChild(w)}C||(C=setInterval(function(){var na=w.getAttribute("display")==="none";w.setAttribute("display",na?"inline":"none")},600));W=A(Y.x,J.y);Y=A(Y.x,J.y+J.height);la(w,{x1:W.x,y1:W.y,x2:Y.x,y2:Y.y,visibility:"visible",display:"inline"});v&&v.setAttribute("d","")}function c(R,W,Y){if(R===W)b(W);else{Y||B.setSelectionRange(R,W);v=ja("text_selectblock");if(!v){v=document.createElementNS(i,"path");la(v,{id:"text_selectblock",fill:"green", -opacity:0.5,style:"pointer-events:none"});ja("selectorParentGroup").appendChild(v)}R=F[R];var na=F[W];w.setAttribute("visibility","hidden");W=A(R.x,J.y);Y=A(R.x+(na.x-R.x),J.y);var Xa=A(R.x,J.y+J.height);R=A(R.x+(na.x-R.x),J.y+J.height);la(v,{d:"M"+W.x+","+W.y+" L"+Y.x+","+Y.y+" "+R.x+","+R.y+" "+Xa.x+","+Xa.y+"z",display:"inline"})}}function d(R,W){var Y=g.createSVGPoint();Y.x=R;Y.y=W;if(F.length==1)return 0;Y=s.getCharNumAtPosition(Y);if(Y<0){Y=F.length-2;if(R<=F[0].x)Y=0}else if(Y>=F.length-2)Y= -F.length-2;var na=F[Y];R>na.x+na.width/2&&Y++;return Y}function n(R,W,Y){var na=B.selectionStart;R=d(R,W);c(Math.min(na,R),Math.max(na,R),!Y)}function m(R,W){var Y={x:R,y:W};Y.x/=q;Y.y/=q;if(K){var na=ka(Y.x,Y.y,K.inverse());Y.x=na.x;Y.y=na.y}return Y}function A(R,W){var Y={x:R,y:W};if(K){var na=ka(Y.x,Y.y,K);Y.x=na.x;Y.y=na.y}Y.x*=q;Y.y*=q;return Y}function o(R){c(0,s.textContent.length);$(this).unbind(R)}function l(R){if(fa&&s){var W=ka(R.pageX,R.pageY,Mb);W=m(W.x*q,W.y*q);W=d(W.x,W.y);var Y=s.textContent, -na=Y.substr(0,W).replace(/[a-z0-9]+$/i,"").length;Y=Y.substr(W).match(/^[a-z0-9]+/i);c(na,(Y?Y[0].length:0)+W);$(R.target).click(o);setTimeout(function(){$(R.target).unbind("click",o)},300)}}var s,B,w,v,C,F=[],J,K,P,ca,fa;return{select:function(R,W,Y){s=R;fb.toEditMode(W,Y)},start:function(R){s=R;fb.toEditMode()},mouseDown:function(R,W,Y,na){R=m(Y,na);B.focus();b(d(R.x,R.y));P=Y;ca=na},mouseMove:function(R,W){var Y=m(R,W);n(Y.x,Y.y)},mouseUp:function(R,W,Y){var na=m(W,Y);n(na.x,na.y,true);R.target!== -s&&W<P+2&&W>P-2&&Y<ca+2&&Y>ca-2&&fb.toSelectMode(true)},setCursor:b,toEditMode:function(R,W){fa=false;Ia="textedit";Ha.requestSelector(s).showGrips(false);Ha.requestSelector(s);fb.init();$(s).css("cursor","text");if(arguments.length){var Y=m(R,W);b(d(Y.x,Y.y))}else b();setTimeout(function(){fa=true},300)},toSelectMode:function(R){Ia="select";clearInterval(C);C=null;v&&$(v).attr("display","none");w&&$(w).attr("visibility","hidden");$(s).css("cursor","move");if(R){Ta();$(s).css("cursor","move");aa("selected", -[s]);eb([s],true)}s&&!s.textContent.length&&e.deleteSelectedElements();$(B).blur();s=false},setInputElem:function(R){B=R},clear:function(){Ia=="textedit"&&fb.toSelectMode()},init:function(){if(s){if(!s.parentNode){s=I[0];Ha.requestSelector(s).showGrips(false)}var R=s.textContent.length,W=s.getAttribute("transform");J=svgedit.utilities.getBBox(s);K=W?va(s):null;F=Array(R);B.focus();$(s).unbind("dblclick",l).dblclick(l);if(!R)var Y={x:J.x+J.width/2,width:0};for(W=0;W<R;W++){var na=s.getStartPositionOfChar(W); -Y=s.getEndPositionOfChar(W);if(!svgedit.browser.supportsGoodTextCharPos()){var Xa=e.contentW*q;na.x-=Xa;Y.x-=Xa;na.x/=q;Y.x/=q}F[W]={x:na.x,y:J.y,width:Y.x-na.x,height:J.height}}F.push({x:Y.x,width:0});c(B.selectionStart,B.selectionEnd,true)}}}}(),La=e.pathActions=function(){var b=false,c,d,n;svgedit.path.Path.prototype.endChanges=function(o){if(svgedit.browser.isWebkit()){var l=this.elem;l.setAttribute("d",La.convertPath(l))}o=new Qa(this.elem,{d:this.last_d},o);Ca(o);aa("changed",[this.elem])}; -svgedit.path.Path.prototype.addPtsToSelection=function(o){$.isArray(o)||(o=[o]);for(var l=0;l<o.length;l++){var s=o[l],B=this.segs[s];B.ptgrip&&this.selected_pts.indexOf(s)==-1&&s>=0&&this.selected_pts.push(s)}this.selected_pts.sort();l=this.selected_pts.length;for(o=Array(l);l--;){B=this.segs[this.selected_pts[l]];B.select(true);o[l]=B.ptgrip}La.canDeleteNodes=true;La.closed_subpath=this.subpathIsClosed(this.selected_pts[0]);aa("selected",o)};var m=c=null,A=false;return{mouseDown:function(o,l,s, -B){if(Ia==="path"){mouse_x=s;mouse_y=B;B=mouse_x/q;l=mouse_y/q;s=ja("path_stretch_line");d=[B,l];if(u.gridSnapping){B=Aa(B);l=Aa(l);mouse_x=Aa(mouse_x);mouse_y=Aa(mouse_y)}if(!s){s=document.createElementNS(i,"path");la(s,{id:"path_stretch_line",stroke:"#22C","stroke-width":"0.5",fill:"none"});s=ja("selectorParentGroup").appendChild(s)}s.setAttribute("display","inline");var w=null;if(m){w=m.pathSegList;for(var v=w.numberOfItems,C=6/q,F=false;v;){v--;var J=w.getItem(v),K=J.x;J=J.y;if(B>=K-C&&B<=K+C&& -l>=J-C&&l<=J+C){F=true;break}}C=ua();svgedit.path.removePath_(C);C=ja(C);K=w.numberOfItems;if(F){if(v<=1&&K>=2){B=w.getItem(0).x;l=w.getItem(0).y;o=s.pathSegList.getItem(1);o=o.pathSegType===4?m.createSVGPathSegLinetoAbs(B,l):m.createSVGPathSegCurvetoCubicAbs(B,l,o.x1/q,o.y1/q,B,l);B=m.createSVGPathSegClosePath();w.appendItem(o);w.appendItem(B)}else if(K<3)return w=false;$(s).remove();element=C;m=null;Ja=false;if(b){svgedit.path.path.matrix&&Fb(C,{},svgedit.path.path.matrix.inverse());s=C.getAttribute("d"); -o=$(svgedit.path.path.elem).attr("d");$(svgedit.path.path.elem).attr("d",o+s);$(C).remove();svgedit.path.path.matrix&&svgedit.path.recalcRotatedPath();svgedit.path.path.init();La.toEditMode(svgedit.path.path.elem);svgedit.path.path.selectPt();return false}}else{if(!$.contains(a,Zb(o))){console.log("Clicked outside canvas");return false}w=m.pathSegList.numberOfItems;v=m.pathSegList.getItem(w-1);C=v.x;v=v.y;if(o.shiftKey){o=Na(C,v,B,l);B=o.x;l=o.y}o=s.pathSegList.getItem(1);o=o.pathSegType===4?m.createSVGPathSegLinetoAbs(Kb(B), -Kb(l)):m.createSVGPathSegCurvetoCubicAbs(Kb(B),Kb(l),o.x1/q,o.y1/q,o.x2/q,o.y2/q);m.pathSegList.appendItem(o);B*=q;l*=q;s.setAttribute("d",["M",B,l,B,l].join(" "));s=w;if(b)s+=svgedit.path.path.segs.length;svgedit.path.addPointGrip(s,B,l)}}else{d_attr="M"+B+","+l+" ";m=ma({element:"path",curStyles:true,attr:{d:d_attr,id:ya(),opacity:N.opacity/2}});s.setAttribute("d",["M",mouse_x,mouse_y,mouse_x,mouse_y].join(" "));s=b?svgedit.path.path.segs.length:0;svgedit.path.addPointGrip(s,mouse_x,mouse_y)}}else if(svgedit.path.path){svgedit.path.path.storeD(); -C=o.target.id;if(C.substr(0,14)=="pathpointgrip_"){l=svgedit.path.path.cur_pt=parseInt(C.substr(14));svgedit.path.path.dragging=[s,B];w=svgedit.path.path.segs[l];if(o.shiftKey)w.selected?svgedit.path.path.removePtFromSelection(l):svgedit.path.path.addPtsToSelection(l);else{if(svgedit.path.path.selected_pts.length<=1||!w.selected)svgedit.path.path.clearSelection();svgedit.path.path.addPtsToSelection(l)}}else if(C.indexOf("ctrlpointgrip_")==0){svgedit.path.path.dragging=[s,B];o=C.split("_")[1].split("c"); -l=o[0]-0;svgedit.path.path.selectPt(l,o[1]-0)}if(!svgedit.path.path.dragging){if(za==null)za=Ha.getRubberBandBox();la(za,{x:s*q,y:B*q,width:0,height:0,display:"inline"},100)}}},mouseMove:function(o,l,s){A=true;if(Ia==="path"){if(m){var B=m.pathSegList,w=B.numberOfItems-1;if(d){var v=svgedit.path.addCtrlGrip("1c1"),C=svgedit.path.addCtrlGrip("0c2");v.setAttribute("cx",l);v.setAttribute("cy",s);v.setAttribute("display","inline");v=d[0];var F=d[1];B.getItem(w);var J=v+(v-l/q),K=F+(F-s/q);if(!o.altKey){C.setAttribute("cx", -J*q);C.setAttribute("cy",K*q);C.setAttribute("display","inline")}C=svgedit.path.getCtrlLine(1);var P=svgedit.path.getCtrlLine(2);la(C,{x1:l,y1:s,x2:v,y2:F,display:"inline"});o.altKey||la(P,{x1:J*q,y1:K*q,x2:v,y2:F,display:"inline"});if(w===0)n=[l,s];else{B=B.getItem(w-1);l=B.x;s=B.y;if(B.pathSegType===6){l+=l-B.x2;s+=s-B.y2}else if(n){l=n[0]/q;s=n[1]/q}svgedit.path.replacePathSeg(6,w,[v,F,l,s,J,K],m)}}else if(v=ja("path_stretch_line")){w=B.getItem(w);if(w.pathSegType===6)svgedit.path.replacePathSeg(6, -1,[l,s,(w.x+(w.x-w.x2))*q,(w.y+(w.y-w.y2))*q,l,s],v);else n?svgedit.path.replacePathSeg(6,1,[l,s,n[0],n[1],l,s],v):svgedit.path.replacePathSeg(4,1,[l,s],v)}}}else if(svgedit.path.path.dragging){v=svgedit.path.getPointFromGrip({x:svgedit.path.path.dragging[0],y:svgedit.path.path.dragging[1]},svgedit.path.path);F=svgedit.path.getPointFromGrip({x:l,y:s},svgedit.path.path);w=F.x-v.x;v=F.y-v.y;svgedit.path.path.dragging=[l,s];svgedit.path.path.dragctrl?svgedit.path.path.moveCtrl(w,v):svgedit.path.path.movePts(w, -v)}else{svgedit.path.path.selected_pts=[];svgedit.path.path.eachSeg(function(){if(this.next||this.prev){var ca=za.getBBox(),fa=svgedit.path.getGripPt(this);ca=svgedit.math.rectsIntersect(ca,{x:fa.x,y:fa.y,width:0,height:0});this.select(ca);ca&&svgedit.path.path.selected_pts.push(this.index)}})}},mouseUp:function(o,l){if(Ia==="path"){d=null;if(!m){l=ja(ua());Ja=false;n=null}return{keep:true,element:l}}if(svgedit.path.path.dragging){var s=svgedit.path.path.cur_pt;svgedit.path.path.dragging=false;svgedit.path.path.dragctrl= -false;svgedit.path.path.update();A&&svgedit.path.path.endChanges("Move path point(s)");!o.shiftKey&&!A&&svgedit.path.path.selectPt(s)}else if(za&&za.getAttribute("display")!="none"){za.setAttribute("display","none");za.getAttribute("width")<=2&&za.getAttribute("height")<=2&&La.toSelectMode(o.target)}else La.toSelectMode(o.target);A=false},toEditMode:function(o){svgedit.path.path=svgedit.path.getPath_(o);Ia="pathedit";Ta();svgedit.path.path.show(true).update();svgedit.path.path.oldbbox=svgedit.utilities.getBBox(svgedit.path.path.elem); -b=false},toSelectMode:function(o){var l=o==svgedit.path.path.elem;Ia="select";svgedit.path.path.show(false);c=false;Ta();svgedit.path.path.matrix&&svgedit.path.recalcRotatedPath();if(l){aa("selected",[o]);eb([o],true)}},addSubPath:function(o){if(o){Ia="path";b=true}else{La.clear(true);La.toEditMode(svgedit.path.path.elem)}},select:function(o){if(c===o){La.toEditMode(o);Ia="pathedit"}else c=o},reorient:function(){var o=I[0];if(o)if(ra(o)!=0){var l=new Ga("Reorient path"),s={d:o.getAttribute("d"),transform:o.getAttribute("transform")}; -l.addSubCommand(new Qa(o,s));Ta();this.resetOrientation(o);Ca(l);svgedit.path.getPath_(o).show(false).matrix=null;this.clear();eb([o],true);aa("changed",I)}},clear:function(){c=null;if(m){var o=ja(ua());$(ja("path_stretch_line")).remove();$(o).remove();$(ja("pathpointgrip_container")).find("*").attr("display","none");m=n=null;Ja=false}else Ia=="pathedit"&&this.toSelectMode();svgedit.path.path&&svgedit.path.path.init().show(false)},resetOrientation:function(o){if(o==null||o.nodeName!="path")return false; -var l=ia(o),s=ga(l).matrix;l.clear();o.removeAttribute("transform");l=o.pathSegList;for(var B=l.numberOfItems,w=0;w<B;++w){var v=l.getItem(w),C=v.pathSegType;if(C!=1){var F=[];$.each(["",1,2],function(J,K){var P=v["x"+K],ca=v["y"+K];if(P!==undefined&&ca!==undefined){P=ka(P,ca,s);F.splice(F.length,0,P.x,P.y)}});svgedit.path.replacePathSeg(C,w,F,o)}}h(o,s)},zoomChange:function(){Ia=="pathedit"&&svgedit.path.path.update()},getNodePoint:function(){var o=svgedit.path.path.segs[svgedit.path.path.selected_pts.length? -svgedit.path.path.selected_pts[0]:1];return{x:o.item.x,y:o.item.y,type:o.type}},linkControlPoints:function(o){svgedit.path.setLinkControlPoints(o)},clonePathNode:function(){svgedit.path.path.storeD();for(var o=svgedit.path.path.selected_pts,l=o.length,s=[];l--;){var B=o[l];svgedit.path.path.addSeg(B);s.push(B+l);s.push(B+l+1)}svgedit.path.path.init().addPtsToSelection(s);svgedit.path.path.endChanges("Clone path node(s)")},opencloseSubPath:function(){var o=svgedit.path.path.selected_pts;if(o.length=== -1){var l=svgedit.path.path.elem,s=l.pathSegList,B=o[0],w=null,v=null;svgedit.path.path.eachSeg(function(K){if(this.type===2&&K<=B)v=this.item;if(K<=B)return true;if(this.type===2){w=K;return false}else if(this.type===1)return w=false});if(w==null)w=svgedit.path.path.segs.length-1;if(w!==false){var C=l.createSVGPathSegLinetoAbs(v.x,v.y),F=l.createSVGPathSegClosePath();if(w==svgedit.path.path.segs.length-1){s.appendItem(C);s.appendItem(F)}else{svgedit.path.insertItemBefore(l,F,w);svgedit.path.insertItemBefore(l, -C,w)}svgedit.path.path.init().selectPt(w+1)}else if(svgedit.path.path.segs[B].mate){s.removeItem(B);s.removeItem(B);svgedit.path.path.init().selectPt(B-1)}else{for(o=0;o<s.numberOfItems;o++){var J=s.getItem(o);if(J.pathSegType===2)C=o;else if(o===B)s.removeItem(C);else if(J.pathSegType===1&&B<o){F=o-1;s.removeItem(o);break}}for(o=B-C-1;o--;)svgedit.path.insertItemBefore(l,s.getItem(C),F);l=s.getItem(C);svgedit.path.replacePathSeg(2,C,[l.x,l.y]);o=B;svgedit.path.path.init().selectPt(0)}}},deletePathNode:function(){if(La.canDeleteNodes){svgedit.path.path.storeD(); -for(var o=svgedit.path.path.selected_pts,l=o.length;l--;)svgedit.path.path.deleteSeg(o[l]);var s=function(){var B=svgedit.path.path.elem.pathSegList,w=B.numberOfItems,v=function(J,K){for(;K--;)B.removeItem(J)};if(w<=1)return true;for(;w--;){var C=B.getItem(w);if(C.pathSegType===1){C=B.getItem(w-1);var F=B.getItem(w-2);if(C.pathSegType===2){v(w-1,2);s();break}else if(F.pathSegType===2){v(w-2,3);s();break}}else if(C.pathSegType===2)if(w>0){C=B.getItem(w-1).pathSegType;if(C===2){v(w-1,1);s();break}else if(C=== -1&&B.numberOfItems-1===w){v(w,1);s();break}}}return false};s();if(svgedit.path.path.elem.pathSegList.numberOfItems<=1){La.toSelectMode(svgedit.path.path.elem);e.deleteSelectedElements()}else{svgedit.path.path.init();svgedit.path.path.clearSelection();if(window.opera){o=$(svgedit.path.path.elem);o.attr("d",o.attr("d"))}svgedit.path.path.endChanges("Delete path node(s)")}}},smoothPolylineIntoPath:function(o){var l=o.points,s=l.numberOfItems;if(s>=4){var B=l.getItem(0),w=null;o=[];o.push(["M",B.x,",", -B.y," C"].join(""));for(var v=1;v<=s-4;v+=3){var C=l.getItem(v),F=l.getItem(v+1),J=l.getItem(v+2);if(w)if((B=svgedit.path.smoothControlPoints(w,C,B))&&B.length==2){C=o[o.length-1].split(",");C[2]=B[0].x;C[3]=B[0].y;o[o.length-1]=C.join(",");C=B[1]}o.push([C.x,C.y,F.x,F.y,J.x,J.y].join(","));B=J;w=F}for(o.push("L");v<s;++v){F=l.getItem(v);o.push([F.x,F.y].join(","))}o=o.join(" ");o=ma({element:"path",curStyles:true,attr:{id:ua(),d:o,fill:"none"}})}return o},setSegType:function(o){svgedit.path.path.setSegType(o)}, -moveNode:function(o,l){var s=svgedit.path.path.selected_pts;if(s.length){svgedit.path.path.storeD();s=svgedit.path.path.segs[s[0]];var B={x:0,y:0};B[o]=l-s.item[o];s.move(B.x,B.y);svgedit.path.path.endChanges("Move path point")}},fixEnd:function(o){for(var l=o.pathSegList,s=l.numberOfItems,B,w=0;w<s;++w){var v=l.getItem(w);if(v.pathSegType===2)B=v;if(v.pathSegType===1){v=l.getItem(w-1);if(v.x!=B.x||v.y!=B.y){l=o.createSVGPathSegLinetoAbs(B.x,B.y);svgedit.path.insertItemBefore(o,l,w);La.fixEnd(o); -break}}}svgedit.browser.isWebkit()&&o.setAttribute("d",La.convertPath(o))},convertPath:function(o,l){for(var s=o.pathSegList,B=s.numberOfItems,w=0,v=0,C="",F=null,J=0;J<B;++J){var K=s.getItem(J),P=K.x||0,ca=K.y||0,fa=K.x1||0,R=K.y1||0,W=K.x2||0,Y=K.y2||0,na=K.pathSegType,Xa=wb[na]["to"+(l?"Lower":"Upper")+"Case"](),qb=function(Hb,yb,Gb){yb=yb?" "+yb.join(" "):"";Gb=Gb?" "+svgedit.units.shortFloat(Gb):"";$.each(Hb,function(ac,jc){Hb[ac]=svgedit.units.shortFloat(jc)});C+=Xa+Hb.join(" ")+yb+Gb};switch(na){case 1:C+= -"z";break;case 12:P-=w;case 13:if(l){w+=P;Xa="l"}else{P+=w;w=P;Xa="L"}qb([[P,v]]);break;case 14:ca-=v;case 15:if(l){v+=ca;Xa="l"}else{ca+=v;v=ca;Xa="L"}qb([[w,ca]]);break;case 2:case 4:case 18:P-=w;ca-=v;case 5:case 3:if(F&&s.getItem(J-1).pathSegType===1&&!l){w=F[0];v=F[1]}case 19:if(l){w+=P;v+=ca}else{P+=w;ca+=v;w=P;v=ca}if(na===3)F=[w,v];qb([[P,ca]]);break;case 6:P-=w;fa-=w;W-=w;ca-=v;R-=v;Y-=v;case 7:if(l){w+=P;v+=ca}else{P+=w;fa+=w;W+=w;ca+=v;R+=v;Y+=v;w=P;v=ca}qb([[fa,R],[W,Y],[P,ca]]);break; -case 8:P-=w;fa-=w;ca-=v;R-=v;case 9:if(l){w+=P;v+=ca}else{P+=w;fa+=w;ca+=v;R+=v;w=P;v=ca}qb([[fa,R],[P,ca]]);break;case 10:P-=w;ca-=v;case 11:if(l){w+=P;v+=ca}else{P+=w;ca+=v;w=P;v=ca}qb([[K.r1,K.r2]],[K.angle,K.largeArcFlag?1:0,K.sweepFlag?1:0],[P,ca]);break;case 16:P-=w;W-=w;ca-=v;Y-=v;case 17:if(l){w+=P;v+=ca}else{P+=w;W+=w;ca+=v;Y+=v;w=P;v=ca}qb([[W,Y],[P,ca]])}}return C}}}(),fc=this.removeUnusedDefElems=function(){var b=p.getElementsByTagNameNS(i,"defs");if(!b||!b.length)return 0;for(var c=[], -d=0,n=["fill","stroke","filter","marker-start","marker-mid","marker-end"],m=n.length,A=p.getElementsByTagNameNS(i,"*"),o=A.length,l=0;l<o;l++){for(var s=A[l],B=0;B<m;B++){var w=Ra(s.getAttribute(n[B]));w&&c.push(w.substr(1))}(s=U(s))&&s.indexOf("#")===0&&c.push(s.substr(1))}b=$(b).find("linearGradient, radialGradient, filter, marker, svg, symbol");defelem_ids=[];for(l=b.length;l--;){n=b[l];m=n.id;if(c.indexOf(m)<0){Jb[m]=n;n.parentNode.removeChild(n);d++}}return d};this.svgCanvasToString=function(){for(;fc()> -0;);La.clear(true);$.each(p.childNodes,function(d,n){d&&n.nodeType===8&&n.data.indexOf("Created with")>=0&&p.insertBefore(n,p.firstChild)});if(M){$b();Ib([M])}var b=[];$(p).find("g:data(gsvg)").each(function(){for(var d=this.attributes,n=d.length,m=0;m<n;m++)if(d[m].nodeName=="id"||d[m].nodeName=="style")n--;if(n<=0){d=this.firstChild;b.push(d);$(this).replaceWith(d)}});var c=this.svgToString(p,0);b.length&&$(b).each(function(){pa(this)});return c};this.svgToString=function(b,c){var d=[],n=svgedit.utilities.toXml, -m=u.baseUnit,A=RegExp("^-?[\\d\\.]+"+m+"$");if(b){T(b);var o=b.attributes,l,s,B=b.childNodes;for(s=0;s<c;s++)d.push(" ");d.push("<");d.push(b.nodeName);if(b.id==="svgcontent"){s=Ub();if(m!=="px"){s.w=svgedit.units.convertUnit(s.w,m)+m;s.h=svgedit.units.convertUnit(s.h,m)+m}d.push(' width="'+s.w+'" height="'+s.h+'" xmlns="'+i+'"');var w={};$(b).find("*").andSelf().each(function(){$.each(this.attributes,function(J,K){var P=K.namespaceURI;if(P&&!w[P]&&wa[P]!=="xmlns"&&wa[P]!=="xml"){w[P]=true;d.push(" xmlns:"+ -wa[P]+'="'+P+'"')}})});s=o.length;for(m=["width","height","xmlns","x","y","viewBox","id","overflow"];s--;){l=o.item(s);var v=n(l.nodeValue);if(l.nodeName.indexOf("xmlns:")!==0)if(v!=""&&m.indexOf(l.localName)==-1)if(!l.namespaceURI||wa[l.namespaceURI]){d.push(" ");d.push(l.nodeName);d.push('="');d.push(v);d.push('"')}}}else{if(b.nodeName==="defs"&&!b.firstChild)return;var C=["-moz-math-font-style","_moz-math-font-style"];for(s=o.length-1;s>=0;s--){l=o.item(s);v=n(l.nodeValue);if(!(C.indexOf(l.localName)>= -0))if(v!="")if(v.indexOf("pointer-events")!==0)if(!(l.localName==="class"&&v.indexOf("se_")===0)){d.push(" ");if(l.localName==="d")v=La.convertPath(b,true);if(isNaN(v)){if(A.test(v))v=svgedit.units.shortFloat(v)+m}else v=svgedit.units.shortFloat(v);if(Ua.apply&&b.nodeName==="image"&&l.localName==="href"&&Ua.images&&Ua.images==="embed"){var F=Va[v];if(F)v=F}if(!l.namespaceURI||l.namespaceURI==i||wa[l.namespaceURI]){d.push(l.nodeName);d.push('="');d.push(v);d.push('"')}}}}if(b.hasChildNodes()){d.push(">"); -c++;o=false;for(s=0;s<B.length;s++){m=B.item(s);switch(m.nodeType){case 1:d.push("\n");d.push(this.svgToString(B.item(s),c));break;case 3:m=m.nodeValue.replace(/^\s+|\s+$/g,"");if(m!=""){o=true;d.push(n(m)+"")}break;case 4:d.push("\n");d.push(Array(c+1).join(" "));d.push("<![CDATA[");d.push(m.nodeValue);d.push("]]\>");break;case 8:d.push("\n");d.push(Array(c+1).join(" "));d.push("<!--");d.push(m.data);d.push("--\>")}}c--;if(!o){d.push("\n");for(s=0;s<c;s++)d.push(" ")}d.push("</");d.push(b.nodeName); -d.push(">")}else d.push("/>")}return d.join("")};this.embedImage=function(b,c){$(new Image).load(function(){var d=document.createElement("canvas");d.width=this.width;d.height=this.height;d.getContext("2d").drawImage(this,0,0);try{var n=";svgedit_url="+encodeURIComponent(b);n=d.toDataURL().replace(";base64",n+";base64");Va[b]=n}catch(m){Va[b]=false}ub=b;c&&c(Va[b])}).attr("src",b)};this.setGoodImage=function(b){ub=b};this.open=function(){};this.save=function(b){Ta();b&&$.extend(Ua,b);Ua.apply=true; -b=this.svgCanvasToString();aa("saved",b)};this.rasterExport=function(){Ta();var b=[],c={feGaussianBlur:zb.exportNoBlur,foreignObject:zb.exportNoforeignObject,"[stroke-dasharray]":zb.exportNoDashArray},d=$(p);if(!("font"in $("<canvas>")[0].getContext("2d")))c.text=zb.exportNoText;$.each(c,function(n,m){d.find(n).length&&b.push(m)});c=this.svgCanvasToString();aa("exported",{svg:c,issues:b})};this.getSvgString=function(){Ua.apply=false;return this.svgCanvasToString()};this.randomizeIds=function(){arguments.length> -0&&arguments[0]==false?svgedit.draw.randomizeIds(false,D()):svgedit.draw.randomizeIds(true,D())};var bc=this.uniquifyElems=function(b){var c={},d=["filter","linearGradient","pattern","radialGradient","symbol","textPath","use"];svgedit.utilities.walkTree(b,function(l){if(l.nodeType==1){if(l.id){l.id in c||(c[l.id]={elem:null,attrs:[],hrefs:[]});c[l.id].elem=l}$.each(Pb,function(B,w){var v=l.getAttributeNode(w);if(v){var C=svgedit.utilities.getUrlFromAttr(v.value);if(C=C?C.substr(1):null){C in c||(c[C]= -{elem:null,attrs:[],hrefs:[]});c[C].attrs.push(v)}}});var s=svgedit.utilities.getHref(l);if(s&&d.indexOf(l.nodeName)>=0)if(s=s.substr(1)){s in c||(c[s]={elem:null,attrs:[],hrefs:[]});c[s].hrefs.push(l)}}});for(var n in c)if(n){var m=c[n].elem;if(m){b=ya();m.id=b;m=c[n].attrs;for(var A=m.length;A--;){var o=m[A];o.ownerElement.setAttribute(o.name,"url(#"+b+")")}m=c[n].hrefs;for(A=m.length;A--;)svgedit.utilities.setHref(m[A],"#"+b)}}},Tb=this.setUseData=function(b){var c=$(b);if(b.tagName!=="use")c= -c.find("use");c.each(function(){var d=U(this).substr(1);if(d=ja(d)){$(this).data("ref",d);if(d.tagName=="symbol"||d.tagName=="svg")$(this).data("symbol",d).data("ref",d)}})},gc=this.convertGradients=function(b){var c=$(b).find("linearGradient, radialGradient");if(!c.length&&svgedit.browser.isWebkit())c=$(b).find("*").filter(function(){return this.tagName.indexOf("Gradient")>=0});c.each(function(){if($(this).attr("gradientUnits")==="userSpaceOnUse"){var d=$(p).find('[fill="url(#'+this.id+')"],[stroke="url(#'+ -this.id+')"]');if(d.length)if(d=svgedit.utilities.getBBox(d[0]))if(this.tagName==="linearGradient"){var n=$(this).attr(["x1","y1","x2","y2"]),m=this.gradientTransform.baseVal;if(m&&m.numberOfItems>0){var A=ga(m).matrix;m=ka(n.x1,n.y1,A);A=ka(n.x2,n.y2,A);n.x1=m.x;n.y1=m.y;n.x2=A.x;n.y2=A.y;this.removeAttribute("gradientTransform")}$(this).attr({x1:(n.x1-d.x)/d.width,y1:(n.y1-d.y)/d.height,x2:(n.x2-d.x)/d.width,y2:(n.y2-d.y)/d.height});this.removeAttribute("gradientUnits")}}})},kc=this.convertToGroup= -function(b){b||(b=I[0]);var c=$(b),d=new Ga,n;if(c.data("gsvg")){d=$(b.firstChild).attr(["x","y"]);$(b.firstChild.firstChild).unwrap();$(b).removeData("gsvg");n=ia(b);var m=g.createSVGTransform();m.setTranslate(d.x,d.y);n.appendItem(m);nb(b);aa("selected",[b])}else if(c.data("symbol")){b=c.data("symbol");n=c.attr("transform");m=c.attr(["x","y"]);var A=b.getAttribute("viewBox");if(A){A=A.split(" ");m.x-=+A[0];m.y-=+A[1]}n+=" translate("+(m.x||0)+","+(m.y||0)+")";m=c.prev();d.addSubCommand(new Oa(c[0], -c[0].nextSibling,c[0].parentNode));c.remove();A=$(p).find("use:data(symbol)").length;c=f.createElementNS(i,"g");for(var o=b.childNodes,l=0;l<o.length;l++)c.appendChild(o[l].cloneNode(true));if(svgedit.browser.isGecko()){o=$(ib()).children("linearGradient,radialGradient,pattern").clone();$(c).append(o)}n&&c.setAttribute("transform",n);n=b.parentNode;bc(c);svgedit.browser.isGecko()&&$(ib()).append($(c).find("linearGradient,radialGradient,pattern"));c.id=ya();m.after(c);if(n){if(!A){m=b.nextSibling; -n.removeChild(b);d.addSubCommand(new Oa(b,m,n))}d.addSubCommand(new Fa(c))}Tb(c);svgedit.browser.isGecko()?gc(ib()):gc(c);svgedit.utilities.walkTreePost(c,function(s){try{nb(s)}catch(B){console.log(B)}});$(c).find("a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use").each(function(){if(!this.id)this.id=ya()});Ib([c]);(b=ec(c,true))&&d.addSubCommand(b);Ca(d)}else console.log("Unexpected element to ungroup:",b)};this.setSvgString=function(b){try{var c=svgedit.utilities.text2xml(b); -this.prepareSvg(c);var d=new Ga("Change Source"),n=p.nextSibling,m=g.removeChild(p);d.addSubCommand(new Oa(m,n,g));p=f.adoptNode?f.adoptNode(c.documentElement):f.importNode(c.documentElement,true);g.appendChild(p);var A=$(p);e.current_drawing_=new svgedit.draw.Drawing(p,z);var o=D().getNonce();o?aa("setnonce",o):aa("unsetnonce");A.find("image").each(function(){var F=this;Yb(F);var J=U(this);if(J.indexOf("data:")===0){var K=J.match(/svgedit_url=(.*?);/);if(K){var P=decodeURIComponent(K[1]);$(new Image).load(function(){F.setAttributeNS("http://www.w3.org/1999/xlink", -"xlink:href",P)}).attr("src",P)}}e.embedImage(J)});A.find("svg").each(function(){if(!$(this).closest("defs").length){bc(this);var F=this.parentNode;if(F.childNodes.length===1&&F.nodeName==="g"){$(F).data("gsvg",this);F.id=F.id||ya()}else pa(this)}});svgedit.browser.isGecko()&&A.find("linearGradient, radialGradient, pattern").appendTo(ib());Tb(A);gc(A[0]);svgedit.utilities.walkTreePost(p,function(F){try{nb(F)}catch(J){console.log(J)}});var l={id:"svgcontent",overflow:u.show_outside_canvas?"visible": -"hidden"},s=false;if(A.attr("viewBox")){var B=A.attr("viewBox").split(" ");l.width=B[2];l.height=B[3]}else $.each(["width","height"],function(F,J){var K=A.attr(J);K||(K="100%");if((K+"").substr(-1)==="%")s=true;else l[J]=ha(J,K)});Vb();A.children().find("a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use").each(function(){if(!this.id)this.id=ya()});if(s){var w=getStrokedBBox();l.width=w.width+w.x;l.height=w.height+w.y}if(l.width<=0)l.width=100;if(l.height<=0)l.height= -100;A.attr(l);this.contentW=l.width;this.contentH=l.height;d.addSubCommand(new Fa(p));var v=A.attr(["width","height"]);d.addSubCommand(new Qa(g,v));q=1;svgedit.transformlist.resetListMap();Ta();svgedit.path.clearData();g.appendChild(Ha.selectorParentGroup);Ca(d);aa("changed",[p])}catch(C){console.log(C);return false}return true};this.importSvgString=function(b){try{var c=svgedit.utilities.encode64(b.length+b).substr(0,32),d=false;if(Cb[c])if($(Cb[c].symbol).parents("#svgroot").length)d=true;var n= -new Ga("Import SVG");if(d)var m=Cb[c].symbol,A=Cb[c].xform;else{var o=svgedit.utilities.text2xml(b);this.prepareSvg(o);var l;l=f.adoptNode?f.adoptNode(o.documentElement):f.importNode(o.documentElement,true);bc(l);var s=ha("width",l.getAttribute("width")),B=ha("height",l.getAttribute("height")),w=l.getAttribute("viewBox"),v=w?w.split(" "):[0,0,s,B];for(b=0;b<4;++b)v[b]=+v[b];p.getAttribute("width");var C=+p.getAttribute("height");A=B>s?"scale("+C/3/v[3]+")":"scale("+C/3/v[2]+")";A="translate(0) "+ -A+" translate(0)";m=f.createElementNS(i,"symbol");var F=ib();for(svgedit.browser.isGecko()&&$(l).find("linearGradient, radialGradient, pattern").appendTo(F);l.firstChild;)m.appendChild(l.firstChild);var J=l.attributes;for(l=0;l<J.length;l++){var K=J[l];m.setAttribute(K.nodeName,K.nodeValue)}m.id=ya();Cb[c]={symbol:m,xform:A};ib().appendChild(m);n.addSubCommand(new Fa(m))}var P=f.createElementNS(i,"use");P.id=ya();Z(P,"#"+m.id);(M||D().getCurrentLayer()).appendChild(P);n.addSubCommand(new Fa(P));Ta(); -P.setAttribute("transform",A);nb(P);$(P).data("symbol",m).data("ref",m);eb([P]);Ca(n);aa("changed",[p])}catch(ca){console.log(ca);return false}return true};var Vb=e.identifyLayers=function(){$b();D().identifyLayers()};this.createLayer=function(b){var c=new Ga("Create Layer");b=D().createLayer(b);c.addSubCommand(new Fa(b));Ca(c);Ta();aa("changed",[b])};this.cloneLayer=function(b){var c=new Ga("Duplicate Layer"),d=f.createElementNS(i,"g"),n=f.createElementNS(i,"title");n.textContent=b;d.appendChild(n); -n=D().getCurrentLayer();$(n).after(d);n=n.childNodes;for(var m=0;m<n.length;m++){var A=n[m];A.localName!="title"&&d.appendChild(V(A))}Ta();Vb();c.addSubCommand(new Fa(d));Ca(c);e.setCurrentLayer(b);aa("changed",[d])};this.deleteCurrentLayer=function(){var b=D().getCurrentLayer(),c=b.nextSibling,d=b.parentNode;if(b=D().deleteCurrentLayer()){var n=new Ga("Delete Layer");n.addSubCommand(new Oa(b,c,d));Ca(n);Ta();aa("changed",[d]);return true}return false};this.setCurrentLayer=function(b){(b=D().setCurrentLayer(svgedit.utilities.toXml(b)))&& -Ta();return b};this.renameCurrentLayer=function(b){var c=D();if(c.current_layer){var d=c.current_layer;if(!e.setCurrentLayer(b)){for(var n=new Ga("Rename Layer"),m=0;m<c.getNumLayers();++m)if(c.all_layers[m][1]==d)break;var A=c.getLayerName(m);c.all_layers[m][0]=svgedit.utilities.toXml(b);var o=d.childNodes.length;for(m=0;m<o;++m){var l=d.childNodes.item(m);if(l&&l.tagName=="title"){for(;l.firstChild;)l.removeChild(l.firstChild);l.textContent=b;n.addSubCommand(new Qa(l,{"#text":A}));Ca(n);aa("changed", -[d]);return true}}}c.current_layer=d}return false};this.setCurrentLayerPosition=function(b){var c=D();if(c.current_layer&&b>=0&&b<c.getNumLayers()){for(var d=0;d<c.getNumLayers();++d)if(c.all_layers[d][1]==c.current_layer)break;if(d==c.getNumLayers())return false;if(d!=b){var n=null,m=c.current_layer.nextSibling;if(b>d){if(b<c.getNumLayers()-1)n=c.all_layers[b+1][1]}else n=c.all_layers[b][1];p.insertBefore(c.current_layer,n);Ca(new Ma(c.current_layer,m,p));Vb();e.setCurrentLayer(c.getLayerName(b)); -return true}}return false};this.setLayerVisibility=function(b,c){var d=D(),n=d.getLayerVisibility(b),m=d.setLayerVisibility(b,c);if(m)Ca(new Qa(m,{display:n?"inline":"none"},"Layer Visibility"));else return false;if(m==d.getCurrentLayer()){Ta();La.clear()}return true};this.moveSelectedToLayer=function(b){for(var c=null,d=D(),n=0;n<d.getNumLayers();++n)if(d.getLayerName(n)==b){c=d.all_layers[n][1];break}if(!c)return false;b=new Ga("Move Elements to Layer");d=I;for(n=d.length;n--;){var m=d[n];if(m){var A= -m.nextSibling,o=m.parentNode;c.appendChild(m);b.addSubCommand(new Ma(m,A,o))}}Ca(b);return true};this.mergeLayer=function(b){var c=new Ga("Merge Layer"),d=D(),n=$(d.current_layer).prev()[0];if(n){for(c.addSubCommand(new Oa(d.current_layer,d.current_layer.nextSibling,p));d.current_layer.firstChild;){var m=d.current_layer.firstChild;if(m.localName=="title"){c.addSubCommand(new Oa(m,m.nextSibling,d.current_layer));d.current_layer.removeChild(m)}else{var A=m.nextSibling;n.appendChild(m);c.addSubCommand(new Ma(m, -A,d.current_layer))}}p.removeChild(d.current_layer);if(!b){Ta();Vb();aa("changed",[p]);Ca(c)}d.current_layer=n;return c}};this.mergeAllLayers=function(){var b=new Ga("Merge all Layers"),c=D();for(c.current_layer=c.all_layers[c.getNumLayers()-1][1];$(p).children("g").length>1;)b.addSubCommand(e.mergeLayer(true));Ta();Vb();aa("changed",[p]);Ca(b)};var $b=this.leaveContext=function(){var b=Bb.length;if(b){for(var c=0;c<b;c++){var d=Bb[c],n=gb(d,"orig_opac");n!==1?d.setAttribute("opacity",n):d.removeAttribute("opacity"); -d.setAttribute("style","pointer-events: inherit")}Bb=[];Ta(true);aa("contextset",null)}M=null},mc=this.setContext=function(b){$b();if(typeof b==="string")b=ja(b);M=b;$(b).parentsUntil("#svgcontent").andSelf().siblings().each(function(){var c=this.getAttribute("opacity")||1;gb(this,"orig_opac",c);this.setAttribute("opacity",c*0.33);this.setAttribute("style","pointer-events: none");Bb.push(this)});Ta();aa("contextset",M)};this.clear=function(){La.clear();Ta();e.clearSvgContentElement();e.current_drawing_= -new svgedit.draw.Drawing(p);e.createLayer("Layer 1");e.undoMgr.resetUndoStack();Ha.initGroup();za=Ha.getRubberBandBox();aa("cleared")};this.linkControlPoints=La.linkControlPoints;this.getContentElem=function(){return p};this.getRootElem=function(){return g};this.getSelectedElems=function(){return I};var Ub=this.getResolution=function(){var b=p.getAttribute("width")/q,c=p.getAttribute("height")/q;return{w:b,h:c,zoom:q}};this.getZoom=function(){return q};this.getVersion=function(){return"svgcanvas.js ($Rev: 2082 $)"}; -this.setUiStrings=function(b){$.extend(zb,b.notification)};this.setConfig=function(b){$.extend(u,b)};this.getTitle=function(b){if(b=b||I[0]){b=$(b).data("gsvg")||$(b).data("symbol")||b;b=b.childNodes;for(var c=0;c<b.length;c++)if(b[c].nodeName=="title")return b[c].textContent;return""}};this.setGroupTitle=function(b){var c=I[0];c=$(c).data("gsvg")||c;var d=$(c).children("title"),n=new Ga("Set Label");if(b.length)if(d.length){d=d[0];n.addSubCommand(new Qa(d,{"#text":d.textContent}));d.textContent= -b}else{d=f.createElementNS(i,"title");d.textContent=b;$(c).prepend(d);n.addSubCommand(new Fa(d))}else{n.addSubCommand(new Oa(d[0],d.nextSibling,c));d.remove()}Ca(n)};this.getDocumentTitle=function(){return e.getTitle(p)};this.setDocumentTitle=function(b){for(var c=p.childNodes,d=false,n="",m=new Ga("Change Image Title"),A=0;A<c.length;A++)if(c[A].nodeName=="title"){d=c[A];n=d.textContent;break}if(!d){d=f.createElementNS(i,"title");p.insertBefore(d,p.firstChild)}if(b.length)d.textContent=b;else d.parentNode.removeChild(d); -m.addSubCommand(new Qa(d,{"#text":n}));Ca(m)};this.getEditorNS=function(b){b&&p.setAttribute("xmlns:se","http://svg-edit.googlecode.com");return"http://svg-edit.googlecode.com"};this.setResolution=function(b,c){var d=Ub(),n=d.w;d=d.h;var m;if(b=="fit"){var A=getStrokedBBox();if(A){m=new Ga("Fit Canvas to Content");var o=Lb();eb(o);var l=[],s=[];$.each(o,function(){l.push(A.x*-1);s.push(A.y*-1)});o=e.moveSelectedElements(l,s,true);m.addSubCommand(o);Ta();b=Math.round(A.width);c=Math.round(A.height)}else return false}if(b!= -n||c!=d){o=g.suspendRedraw(1E3);m||(m=new Ga("Change Image Dimensions"));b=ha("width",b);c=ha("height",c);p.setAttribute("width",b);p.setAttribute("height",c);this.contentW=b;this.contentH=c;m.addSubCommand(new Qa(p,{width:n,height:d}));p.setAttribute("viewBox",[0,0,b/q,c/q].join(" "));m.addSubCommand(new Qa(p,{viewBox:["0 0",n,d].join(" ")}));Ca(m);g.unsuspendRedraw(o);aa("changed",[p])}return true};this.getOffset=function(){return $(p).attr(["x","y"])};this.setBBoxZoom=function(b,c,d){var n=0.85, -m=function(A){if(!A)return false;var o=Math.min(Math.round(c/A.width*100*n)/100,Math.round(d/A.height*100*n)/100);e.setZoom(o);return{zoom:o,bbox:A}};if(typeof b=="object"){b=b;if(b.width==0||b.height==0){e.setZoom(b.zoom?b.zoom:q*b.factor);return{zoom:q,bbox:b}}return m(b)}switch(b){case "selection":if(!I[0])return;b=$.map(I,function(A){if(A)return A});b=getStrokedBBox(b);break;case "canvas":b=Ub();n=0.95;b={width:b.w,height:b.h,x:0,y:0};break;case "content":b=getStrokedBBox();break;case "layer":b= -getStrokedBBox(Lb(D().getCurrentLayer()));break;default:return}return m(b)};this.setZoom=function(b){var c=Ub();p.setAttribute("viewBox","0 0 "+c.w/b+" "+c.h/b);q=b;$.each(I,function(d,n){n&&Ha.requestSelector(n).resize()});La.zoomChange();pb("zoomChanged",b)};this.getMode=function(){return Ia};this.setMode=function(b){La.clear(true);fb.clear();$("#workarea").attr("class",b);cb=I[0]&&I[0].nodeName=="text"?ab:N;Ia=b};this.getColor=function(b){return cb[b]};this.setColor=function(b,c,d){N[b]=c;cb[b+ -"_paint"]={type:"solidColor"};for(var n=[],m=I.length;m--;){var A=I[m];if(A)if(A.tagName=="g")svgedit.utilities.walkTree(A,function(o){o.nodeName!="g"&&n.push(o)});else if(b=="fill")A.tagName!="polyline"&&A.tagName!="line"&&n.push(A);else n.push(A)}if(n.length>0)if(d)Nb(b,c,n);else{jb(b,c,n);aa("changed",n)}};var ib=function(){var b=p.getElementsByTagNameNS(i,"defs");if(b.length>0)b=b[0];else{b=f.createElementNS(i,"defs");p.firstChild?p.insertBefore(b,p.firstChild.nextSibling):p.appendChild(b)}return b}, -hc=this.setGradient=function(b){if(!(!cb[b+"_paint"]||cb[b+"_paint"].type=="solidColor")){var c=e[b+"Grad"],d=cc(c),n=ib();if(d)c=d;else{c=n.appendChild(f.importNode(c,true));c.id=ya()}e.setColor(b,"url(#"+c.id+")")}},cc=function(b){var c=ib();c=$(c).find("linearGradient, radialGradient");for(var d=c.length,n=["r","cx","cy","fx","fy"];d--;){var m=c[d];if(b.tagName=="linearGradient"){if(b.getAttribute("x1")!=m.getAttribute("x1")||b.getAttribute("y1")!=m.getAttribute("y1")||b.getAttribute("x2")!=m.getAttribute("x2")|| -b.getAttribute("y2")!=m.getAttribute("y2"))continue}else{var A=$(b).attr(n),o=$(m).attr(n),l=false;$.each(n,function(F,J){if(A[J]!=o[J])l=true});if(l)continue}var s=b.getElementsByTagNameNS(i,"stop"),B=m.getElementsByTagNameNS(i,"stop");if(s.length==B.length){for(var w=s.length;w--;){var v=s[w],C=B[w];if(v.getAttribute("offset")!=C.getAttribute("offset")||v.getAttribute("stop-opacity")!=C.getAttribute("stop-opacity")||v.getAttribute("stop-color")!=C.getAttribute("stop-color"))break}if(w==-1)return m}}return null}; -this.setPaint=function(b,c){var d=new $.jGraduate.Paint(c);this.setPaintOpacity(b,d.alpha/100,true);cb[b+"_paint"]=d;switch(d.type){case "solidColor":if(d.solidColor!="none")this.setColor(b,"#"+d.solidColor);else{this.setColor(b,"none");document.querySelector(b=="fill"?"#fill_color rect":"#stroke_color rect").setAttribute("fill","transparent")}break;case "linearGradient":case "radialGradient":e[b+"Grad"]=d[d.type];hc(b)}};this.getStrokeWidth=function(){return cb.stroke_width};this.setStrokeWidth= -function(b){if(b==0&&["line","path"].indexOf(Ia)>=0)e.setStrokeWidth(1);else{cb.stroke_width=b;for(var c=[],d=I.length;d--;){var n=I[d];if(n)n.tagName=="g"?svgedit.utilities.walkTree(n,function(m){m.nodeName!="g"&&c.push(m)}):c.push(n)}if(c.length>0){jb("stroke-width",b,c);aa("changed",I)}}};this.setStrokeAttr=function(b,c){N[b.replace("-","_")]=c;for(var d=[],n=I.length;n--;){var m=I[n];if(m)m.tagName=="g"?svgedit.utilities.walkTree(m,function(A){A.nodeName!="g"&&d.push(A)}):d.push(m)}if(d.length> -0){jb(b,c,d);aa("changed",I)}};this.getStyle=function(){return N};this.getOpacity=function(){return N.opacity};this.setOpacity=function(b){N.opacity=b;jb("opacity",b)};this.getFillOpacity=function(){return N.fill_opacity};this.getStrokeOpacity=function(){return N.stroke_opacity};this.setPaintOpacity=function(b,c,d){N[b+"_opacity"]=c;d?Nb(b+"-opacity",c):jb(b+"-opacity",c)};this.getBlur=function(b){var c=0;if(b)if(b.getAttribute("filter"))if(b=ja(b.id+"_blur"))c=b.firstChild.getAttribute("stdDeviation"); -return c};(function(){function b(){var m=e.undoMgr.finishUndoableChange();c.addSubCommand(m);Ca(c);d=c=null}var c=null,d=null,n=false;e.setBlurNoUndo=function(m){if(d)if(m===0){Nb("filter","");n=true}else{var A=I[0];n&&Nb("filter","url(#"+A.id+"_blur)");if(svgedit.browser.isWebkit()){A.removeAttribute("filter");A.setAttribute("filter","url(#"+A.id+"_blur)")}Nb("stdDeviation",m,[d.firstChild]);e.setBlurOffsets(d,m)}else e.setBlur(m)};e.setBlurOffsets=function(m,A){if(A>3)la(m,{x:"-50%",y:"-50%",width:"200%", -height:"200%"},100);else if(!svgedit.browser.isWebkit()){m.removeAttribute("x");m.removeAttribute("y");m.removeAttribute("width");m.removeAttribute("height")}};e.setBlur=function(m,A){if(c)b();else{var o=I[0],l=o.id;d=ja(l+"_blur");m-=0;var s=new Ga;if(d){if(m===0)d=null}else{var B=ma({element:"feGaussianBlur",attr:{"in":"SourceGraphic",stdDeviation:m}});d=ma({element:"filter",attr:{id:l+"_blur"}});d.appendChild(B);ib().appendChild(d);s.addSubCommand(new Fa(d))}B={filter:o.getAttribute("filter")}; -if(m===0){o.removeAttribute("filter");s.addSubCommand(new Qa(o,B))}else{jb("filter","url(#"+l+"_blur)");s.addSubCommand(new Qa(o,B));e.setBlurOffsets(d,m);c=s;e.undoMgr.beginUndoableChange("stdDeviation",[d?d.firstChild:null]);if(A){e.setBlurNoUndo(m);b()}}}}})();this.getBold=function(){var b=I[0];if(b!=null&&b.tagName=="text"&&I[1]==null)return b.getAttribute("font-weight")=="bold";return false};this.setBold=function(b){var c=I[0];if(c!=null&&c.tagName=="text"&&I[1]==null)jb("font-weight",b?"bold": -"normal");I[0].textContent||fb.setCursor()};this.getItalic=function(){var b=I[0];if(b!=null&&b.tagName=="text"&&I[1]==null)return b.getAttribute("font-style")=="italic";return false};this.setItalic=function(b){var c=I[0];if(c!=null&&c.tagName=="text"&&I[1]==null)jb("font-style",b?"italic":"normal");I[0].textContent||fb.setCursor()};this.getFontFamily=function(){return ab.font_family};this.setFontFamily=function(b){ab.font_family=b;jb("font-family",b);I[0]&&!I[0].textContent&&fb.setCursor()};this.setFontColor= -function(b){ab.fill=b;jb("fill",b)};this.getFontSize=function(){return ab.fill};this.getFontSize=function(){return ab.font_size};this.setFontSize=function(b){ab.font_size=b;jb("font-size",b);I[0].textContent||fb.setCursor()};this.getText=function(){var b=I[0];if(b==null)return"";return b.textContent};this.setTextContent=function(b){jb("#text",b);fb.init(b);fb.setCursor()};this.setImageURL=function(b){var c=I[0];if(c){var d=$(c).attr(["width","height"]);d=!d.width||!d.height;var n=U(c);if(n!==b)d= -true;else if(!d)return;var m=new Ga("Change Image URL");Z(c,b);m.addSubCommand(new Qa(c,{"#href":n}));d?$(new Image).load(function(){var A=$(c).attr(["width","height"]);$(c).attr({width:this.width,height:this.height});Ha.requestSelector(c).resize();m.addSubCommand(new Qa(c,A));Ca(m);aa("changed",[c])}).attr("src",b):Ca(m)}};this.setLinkURL=function(b){var c=I[0];if(c){if(c.tagName!=="a"){c=$(c).parents("a");if(c.length)c=c[0];else return}var d=U(c);if(d!==b){var n=new Ga("Change Link URL");Z(c,b); -n.addSubCommand(new Qa(c,{"#href":d}));Ca(n)}}};this.setRectRadius=function(b){var c=I[0];if(c!=null&&c.tagName=="rect"){var d=c.getAttribute("rx");if(d!=b){c.setAttribute("rx",b);c.setAttribute("ry",b);Ca(new Qa(c,{rx:d,ry:d},"Radius"));aa("changed",[c])}}};this.makeHyperlink=function(b){e.groupSelectedElements("a",b)};this.removeHyperlink=function(){e.ungroupSelectedElement()};this.setSegType=function(b){La.setSegType(b)};this.convertToPath=function(b,c){if(b==null)$.each(I,function(fa,R){R&&e.convertToPath(R)}); -else{if(!c)var d=new Ga("Convert element to Path");var n=c?{}:{fill:N.fill,"fill-opacity":N.fill_opacity,stroke:N.stroke,"stroke-width":N.stroke_width,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,opacity:N.opacity,visibility:"hidden"};$.each(["marker-start","marker-end","marker-mid","filter","clip-path"],function(){if(b.getAttribute(this))n[this]=b.getAttribute(this)});var m=ma({element:"path",attr:n}), -A=b.getAttribute("transform");A&&m.setAttribute("transform",A);var o=b.id,l=b.parentNode;b.nextSibling?l.insertBefore(m,b):l.appendChild(m);var s="",B=function(fa){$.each(fa,function(R,W){var Y=W[1];s+=W[0];for(var na=0;na<Y.length;na+=2)s+=Y[na]+","+Y[na+1]+" "})},w=1.81;switch(b.tagName){case "ellipse":case "circle":var v=$(b).attr(["rx","ry","cx","cy"]),C=v.cx,F=v.cy,J=v.rx;v=v.ry;if(b.tagName=="circle")J=v=$(b).attr("r");B([["M",[C-J,F]],["C",[C-J,F-v/w,C-J/w,F-v,C,F-v]],["C",[C+J/w,F-v,C+J,F- -v/w,C+J,F]],["C",[C+J,F+v/w,C+J/w,F+v,C,F+v]],["C",[C-J/w,F+v,C-J,F+v/w,C-J,F]],["Z",[]]]);break;case "path":s=b.getAttribute("d");break;case "line":v=$(b).attr(["x1","y1","x2","y2"]);s="M"+v.x1+","+v.y1+"L"+v.x2+","+v.y2;break;case "polyline":case "polygon":s="M"+b.getAttribute("points");break;case "rect":v=$(b).attr(["rx","ry"]);J=v.rx;v=v.ry;var K=b.getBBox();C=K.x;F=K.y;var P=K.width;K=K.height;w=4-w;!J&&!v?B([["M",[C,F]],["L",[C+P,F]],["L",[C+P,F+K]],["L",[C,F+K]],["L",[C,F]],["Z",[]]]):B([["M", -[C,F+v]],["C",[C,F+v/w,C+J/w,F,C+J,F]],["L",[C+P-J,F]],["C",[C+P-J/w,F,C+P,F+v/w,C+P,F+v]],["L",[C+P,F+K-v]],["C",[C+P,F+K-v/w,C+P-J/w,F+K,C+P-J,F+K]],["L",[C+J,F+K]],["C",[C+J/w,F+K,C,F+K-v/w,C,F+K-v]],["L",[C,F+v]],["Z",[]]]);break;default:m.parentNode.removeChild(m)}s&&m.setAttribute("d",s);if(c){La.resetOrientation(m);d=false;try{d=m.getBBox()}catch(ca){}m.parentNode.removeChild(m);return d}else{if(A){A=ia(m);qa(A)&&La.resetOrientation(m)}d.addSubCommand(new Oa(b,b.nextSibling,l));d.addSubCommand(new Fa(m)); -Ta();b.parentNode.removeChild(b);m.setAttribute("id",o);m.removeAttribute("visibility");eb([m],true);Ca(d)}}};var Nb=function(b,c,d){var n=g.suspendRedraw(1E3);Ia=="pathedit"&&La.moveNode(b,c);d=d||I;for(var m=d.length,A=["g","polyline","path"];m--;){var o=d[m];if(o!=null){Ia==="textedit"&&b!=="#text"&&o.textContent.length&&fb.toSelectMode(o);if((b==="x"||b==="y")&&A.indexOf(o.tagName)>=0){var l=getStrokedBBox([o]);e.moveSelectedElements((b==="x"?c-l.x:0)*q,(b==="y"?c-l.y:0)*q,true)}else{l=b==="#text"? -o.textContent:o.getAttribute(b);if(l==null)l="";if(l!==String(c)){if(b=="#text"){svgedit.utilities.getBBox(o);o.textContent=c;if(/rotate/.test(o.getAttribute("transform")))o=Eb(o)}else b=="#href"?Z(o,c):o.setAttribute(b,c);if(svgedit.browser.isGecko()&&o.nodeName==="text"&&/rotate/.test(o.getAttribute("transform")))if((c+"").indexOf("url")===0||["font-size","font-family","x","y"].indexOf(b)>=0&&o.textContent)o=Eb(o);I.indexOf(o)>=0&&setTimeout(function(){o.parentNode&&Ha.requestSelector(o).resize()}, -0);l=ra(o);if(l!=0&&b!="transform")for(var s=ia(o),B=s.numberOfItems;B--;)if(s.getItem(B).type==4){s.removeItem(B);var w=svgedit.utilities.getBBox(o),v=ka(w.x+w.width/2,w.y+w.height/2,ga(s).matrix);w=v.x;v=v.y;var C=g.createSVGTransform();C.setRotate(l,w,v);s.insertItemBefore(C,B);break}}}}}g.unsuspendRedraw(n)},jb=this.changeSelectedAttribute=function(b,c,d){d=d||I;e.undoMgr.beginUndoableChange(b,d);Nb(b,c,d);b=e.undoMgr.finishUndoableChange();b.isEmpty()||Ca(b)};this.deleteSelectedElements=function(){for(var b= -new Ga("Delete Elements"),c=I.length,d=[],n=0;n<c;++n){var m=I[n];if(m==null)break;var A=m.parentNode,o=m;Ha.releaseSelector(o);svgedit.path.removePath_(o.id);if(A.tagName==="a"&&A.childNodes.length===1){o=A;A=A.parentNode}var l=o.nextSibling;o=A.removeChild(o);d.push(m);I[n]=null;b.addSubCommand(new Oa(o,l,A))}b.isEmpty()||Ca(b);aa("changed",d);Ta()};this.cutSelectedElements=function(){for(var b=new Ga("Cut Elements"),c=I.length,d=[],n=0;n<c;++n){var m=I[n];if(m==null)break;var A=m.parentNode,o= -m;Ha.releaseSelector(o);svgedit.path.removePath_(o.id);var l=o.nextSibling;o=A.removeChild(o);d.push(m);I[n]=null;b.addSubCommand(new Oa(o,l,A))}b.isEmpty()||Ca(b);aa("changed",d);Ta();e.clipBoard=d};this.copySelectedElements=function(){e.clipBoard=$.merge([],I)};this.pasteElements=function(b,c,d){var n=e.clipBoard,m=n.length;if(m){for(var A=[],o=new Ga("Paste elements");m--;){var l=n[m];if(l){var s=V(l);if(!ja(l.id))s.id=l.id;A.push(s);(M||D().getCurrentLayer()).appendChild(s);o.addSubCommand(new Fa(s))}}Ib(A); -if(b!="in_place"){if(xb==null){xb.x=0;xb.y=0}var B,w;if(b){if(b==="point"){B=c;w=d}}else{B=xb.x;w=xb.y}b=getStrokedBBox(A);var v=B-(b.x+b.width/2),C=w-(b.y+b.height/2),F=[],J=[];$.each(A,function(){F.push(v);J.push(C)});B=e.moveSelectedElements(F,J,false);o.addSubCommand(B)}Ca(o);aa("changed",A)}};this.groupSelectedElements=function(b){b||(b="g");var c="";switch(b){case "a":c="Make hyperlink";var d="";if(arguments.length>1)d=arguments[1];break;default:b="g";c="Group Elements"}c=new Ga(c);var n=ma({element:b, -attr:{id:ya()}});b==="a"&&Z(n,d);c.addSubCommand(new Fa(n));for(d=I.length;d--;){var m=I[d];if(m!=null){if(m.parentNode.tagName==="a"&&m.parentNode.childNodes.length===1)m=m.parentNode;var A=m.nextSibling,o=m.parentNode;n.appendChild(m);c.addSubCommand(new Ma(m,A,o))}}c.isEmpty()||Ca(c);Ib([n],true)};var ec=this.pushGroupProperties=function(b,c){var d=b.childNodes,n=d.length,m=b.getAttribute("transform"),A=ia(b),o=ga(A).matrix,l=new Ga("Push group properties"),s=0,B=ra(b),w=$(b).attr(["filter","opacity"]), -v,C;for(s=0;s<n;s++){var F=d[s];if(F.nodeType===1){if(w.opacity!==null&&w.opacity!==1){F.getAttribute("opacity");var J=Math.round((F.getAttribute("opacity")||1)*w.opacity*100)/100;jb("opacity",J,[F])}if(w.filter){var K=J=this.getBlur(F);C||(C=this.getBlur(b));if(J)J=C-0+(J-0);else if(J===0)J=C;if(K)v=Sa(F.getAttribute("filter"));else if(v){v=V(v);ib().appendChild(v)}else v=Sa(w.filter);v.id=F.id+"_"+(v.firstChild.tagName==="feGaussianBlur"?"blur":"filter");jb("filter","url(#"+v.id+")",[F]);if(J){jb("stdDeviation", -J,[v.firstChild]);e.setBlurOffsets(v,J)}}J=ia(F);if(~F.tagName.indexOf("Gradient"))J=null;if(J)if(F.tagName!=="defs")if(A.numberOfItems){if(B&&A.numberOfItems==1){var P=A.getItem(0).matrix,ca=g.createSVGMatrix();if(K=ra(F))ca=J.getItem(0).matrix;var fa=svgedit.utilities.getBBox(F),R=ga(J).matrix,W=ka(fa.x+fa.width/2,fa.y+fa.height/2,R);fa=B+K;R=g.createSVGTransform();R.setRotate(fa,W.x,W.y);P=X(P,ca,R.matrix.inverse());K&&J.removeItem(0);if(fa)J.numberOfItems?J.insertItemBefore(R,0):J.appendItem(R); -if(P.e||P.f){K=g.createSVGTransform();K.setTranslate(P.e,P.f);J.numberOfItems?J.insertItemBefore(K,0):J.appendItem(K)}}else{K=F.getAttribute("transform");P={};P.transform=K?K:"";K=g.createSVGTransform();P=ga(J).matrix;ca=P.inverse();P=X(ca,o,P);K.setMatrix(P);J.appendItem(K)}(F=nb(F))&&l.addSubCommand(F)}}}if(m){P={};P.transform=m;b.setAttribute("transform","");b.removeAttribute("transform");l.addSubCommand(new Qa(b,P))}if(c&&!l.isEmpty())return l};this.ungroupSelectedElement=function(){var b=I[0]; -if($(b).data("gsvg")||$(b).data("symbol"))kc(b);else if(b.tagName==="use"){var c=ja(U(b).substr(1));$(b).data("symbol",c).data("ref",c);kc(b)}else{c=$(b).parents("a");if(c.length)b=c[0];if(b.tagName==="g"||b.tagName==="a"){c=new Ga("Ungroup Elements");var d=ec(b,true);d&&c.addSubCommand(d);d=b.parentNode;for(var n=b.nextSibling,m=Array(b.childNodes.length),A=0;b.firstChild;){var o=b.firstChild,l=o.nextSibling,s=o.parentNode;if(o.tagName==="title"){c.addSubCommand(new Oa(o,o.nextSibling,s));s.removeChild(o)}else{m[A++]= -o=d.insertBefore(o,n);c.addSubCommand(new Ma(o,l,s))}}Ta();n=b.nextSibling;b=d.removeChild(b);c.addSubCommand(new Oa(b,n,d));c.isEmpty()||Ca(c);eb(m)}}};this.moveToTopSelectedElement=function(){var b=I[0];if(b!=null){b=b;var c=b.parentNode,d=b.nextSibling;b=b.parentNode.appendChild(b);if(d!=b.nextSibling){Ca(new Ma(b,d,c,"top"));aa("changed",[b])}}};this.moveToBottomSelectedElement=function(){var b=I[0];if(b!=null){b=b;var c=b.parentNode,d=b.nextSibling,n=b.parentNode.firstChild;if(n.tagName=="title")n= -n.nextSibling;if(n.tagName=="defs")n=n.nextSibling;b=b.parentNode.insertBefore(b,n);if(d!=b.nextSibling){Ca(new Ma(b,d,c,"bottom"));aa("changed",[b])}}};this.moveUpDownSelected=function(b){var c=I[0];if(c){vb=[];var d,n,m=$(Rb(getStrokedBBox([c]))).toArray();b=="Down"&&m.reverse();$.each(m,function(){if(n){d=this;return false}else if(this==c)n=true});if(d){m=c.parentNode;var A=c.nextSibling;$(d)[b=="Down"?"before":"after"](c);if(A!=c.nextSibling){Ca(new Ma(c,A,m,"Move "+b));aa("changed",[c])}}}}; -this.moveSelectedElements=function(b,c,d){if(b.constructor!=Array){b/=q;c/=q}d=d||true;for(var n=new Ga("position"),m=I.length;m--;){var A=I[m];if(A!=null){var o=g.createSVGTransform(),l=ia(A);b.constructor==Array?o.setTranslate(b[m],c[m]):o.setTranslate(b,c);l.numberOfItems?l.insertItemBefore(o,0):l.appendItem(o);(o=nb(A))&&n.addSubCommand(o);Ha.requestSelector(A).resize()}}if(!n.isEmpty()){d&&Ca(n);aa("changed",I);return n}};this.cloneSelectedElements=function(b,c){for(var d=new Ga("Clone Elements"), -n=I.length,m=0;m<n;++m){var A=I[m];if(A==null)break}n=I.slice(0,m);this.clearSelection(true);for(m=n.length;m--;){A=n[m]=V(n[m]);(M||D().getCurrentLayer()).appendChild(A);d.addSubCommand(new Fa(A))}if(!d.isEmpty()){eb(n.reverse());this.moveSelectedElements(b,c,false);Ca(d)}};this.alignSelectedElements=function(b,c){var d=[],n=Number.MAX_VALUE,m=Number.MIN_VALUE,A=Number.MAX_VALUE,o=Number.MIN_VALUE,l=Number.MIN_VALUE,s=Number.MIN_VALUE,B=I.length;if(B){for(var w=0;w<B;++w){if(I[w]==null)break;d[w]= -getStrokedBBox([I[w]]);switch(c){case "smallest":if((b=="l"||b=="c"||b=="r")&&(l==Number.MIN_VALUE||l>d[w].width)||(b=="t"||b=="m"||b=="b")&&(s==Number.MIN_VALUE||s>d[w].height)){n=d[w].x;A=d[w].y;m=d[w].x+d[w].width;o=d[w].y+d[w].height;l=d[w].width;s=d[w].height}break;case "largest":if((b=="l"||b=="c"||b=="r")&&(l==Number.MIN_VALUE||l<d[w].width)||(b=="t"||b=="m"||b=="b")&&(s==Number.MIN_VALUE||s<d[w].height)){n=d[w].x;A=d[w].y;m=d[w].x+d[w].width;o=d[w].y+d[w].height;l=d[w].width;s=d[w].height}break; -default:if(d[w].x<n)n=d[w].x;if(d[w].y<A)A=d[w].y;if(d[w].x+d[w].width>m)m=d[w].x+d[w].width;if(d[w].y+d[w].height>o)o=d[w].y+d[w].height}}if(c=="page"){A=n=0;m=e.contentW;o=e.contentH}l=Array(B);s=Array(B);for(w=0;w<B;++w){if(I[w]==null)break;var v=d[w];l[w]=0;s[w]=0;switch(b){case "l":l[w]=n-v.x;break;case "c":l[w]=(n+m)/2-(v.x+v.width/2);break;case "r":l[w]=m-(v.x+v.width);break;case "t":s[w]=A-v.y;break;case "m":s[w]=(A+o)/2-(v.y+v.height/2);break;case "b":s[w]=o-(v.y+v.height)}}this.moveSelectedElements(l, -s)}};this.contentW=Ub().w;this.contentH=Ub().h;this.updateCanvas=function(b,c){g.setAttribute("width",b);g.setAttribute("height",c);var d=$("#canvasBackground")[0],n=p.getAttribute("x"),m=p.getAttribute("y"),A=b/2-this.contentW*q/2,o=c/2-this.contentH*q/2;la(p,{width:this.contentW*q,height:this.contentH*q,x:A,y:o,viewBox:"0 0 "+this.contentW+" "+this.contentH});la(d,{width:p.getAttribute("width"),height:p.getAttribute("height"),x:A,y:o});(d=ja("background_image"))&&la(d,{width:"100%",height:"100%"}); -Ha.selectorParentGroup.setAttribute("transform","translate("+A+","+o+")");return{x:A,y:o,old_x:n,old_y:m,d_x:A-n,d_y:o-m}};this.setBackground=function(b,c){var d=ja("canvasBackground"),n=$(d).find("rect")[0],m=ja("background_image");n.setAttribute("fill",b);if(c){if(!m){m=f.createElementNS(i,"image");la(m,{id:"background_image",width:"100%",height:"100%",preserveAspectRatio:"xMinYMin",style:"pointer-events:none"})}Z(m,c);d.appendChild(m)}else m&&m.parentNode.removeChild(m)};this.cycleElement=function(b){var c= -I[0],d=false,n=Lb(M||D().getCurrentLayer());if(n.length){if(c==null){b=b?n.length-1:0;d=n[b]}else for(var m=n.length;m--;)if(n[m]==c){b=b?m-1:m+1;if(b>=n.length)b=0;else if(b<0)b=n.length-1;d=n[b];break}Ib([d],true);aa("selected",I)}};this.clear();this.getPrivateMethods=function(){return{addCommandToHistory:Ca,setGradient:hc,addSvgElementFromJson:ma,assignAttributes:la,BatchCommand:Ga,call:aa,ChangeElementCommand:Qa,copyElem:V,ffClone:Eb,findDefs:ib,findDuplicateGradient:cc,getElem:ja,getId:ua,getIntersectionList:Rb, -getMouseTarget:Zb,getNextId:ya,getPathBBox:ea,getUrlFromAttr:Ra,hasMatrixTransform:qa,identifyLayers:Vb,InsertElementCommand:Fa,isIdentity:svgedit.math.isIdentity,logMatrix:tb,matrixMultiply:X,MoveElementCommand:Ma,preventClickDefault:Yb,recalculateAllSelectedDimensions:Ab,recalculateDimensions:nb,remapElement:Fb,RemoveElementCommand:Oa,removeUnusedDefElems:fc,round:Kb,runExtensions:pb,sanitizeSvg:Da,SVGEditTransformList:svgedit.transformlist.SVGTransformList,toString:toString,transformBox:svgedit.math.transformBox, -transformListToTransform:ga,transformPoint:ka,walkTree:svgedit.utilities.walkTree}}};(function(){document.addEventListener("touchstart",touchHandler,true);document.addEventListener("touchmove",touchHandler,true);document.addEventListener("touchend",touchHandler,true);document.addEventListener("touchcancel",touchHandler,true);if(!window.svgEditor)window.svgEditor=function(a){function H(D,q){var M=h.setSvgString(D)!==false;q=q||a.noop;M?q(true):a.alert(g.notification.errorLoadingSVG,function(){q(false)})}var h,i={},u=false,E={lang:"en",iconsize:"m",bkgd_color:"FFF",bkgd_url:"",img_save:"embed"}, -e={},f={canvas_expansion:1.2,dimensions:[640,480],initFill:{color:"fff",opacity:1},initStroke:{width:1.5,color:"000",opacity:1},initOpacity:1,imgPath:"images/",langPath:"locale/",extPath:"extensions/",jGraduatePath:"jgraduate/images/",extensions:["ext-markers.js","ext-eyedropper.js","ext-shapes.js","ext-grid.js"],initTool:"select",wireframe:false,colorPickerCSS:false,gridSnapping:false,gridColor:"#000",baseUnit:"px",snappingStep:10,showRulers:true,show_outside_canvas:false},g=i.uiStrings={common:{ok:"OK", -cancel:"Cancel",key_up:"Up",key_down:"Down",key_backspace:"Backspace",key_del:"Del"},layers:{layer:"Layer"},notification:{invalidAttrValGiven:"Invalid value given",noContentToFitTo:"No content to fit to",dupeLayerName:"There is already a layer named that!",enterUniqueLayerName:"Please enter a unique layer name",enterNewLayerName:"Please enter the new layer name",layerHasThatName:"Layer already has that name",QmoveElemsToLayer:'Move selected elements to layer "%s"?',QwantToClear:"Do you want to clear the drawing?\nThis will also erase your undo history!", -QwantToOpen:"Do you want to open a new file?\nThis will also erase your undo history!",QerrorsRevertToSource:"There were parsing errors in your SVG source.\nRevert back to original SVG source?",QignoreSourceChanges:"Ignore changes made to SVG source?",featNotSupported:"Feature not supported",enterNewImgURL:"Enter the new image URL",defsFailOnSave:"NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",loadingImage:"Loading image, please wait...", -saveFromBrowser:'Select "Save As..." in your browser to save this image as a %s file.',noteTheseIssues:"Also note the following issues: ",unsavedChanges:"There are unsaved changes.",enterNewLinkURL:"Enter the new hyperlink URL",errorLoadingSVG:"Error: Unable to load SVG data",URLloadFail:"Unable to load from URL",retrieving:'Retrieving "%s" ...'}};e={};var p={};i.curConfig=f;i.tool_scale=1;a.pref=function(D,q){if(q)e[D]=q;D="svg-edit-"+D;var M=location.hostname,ba=M&&M.indexOf(".")>=0,N=q!=undefined, -I=false;try{if(window.localStorage)I=localStorage}catch(ma){}try{if(window.globalStorage&&ba)I=globalStorage[M]}catch(ia){}if(I)if(N)I.setItem(D,q);else{if(I.getItem(D))return I.getItem(D)+""}else if(window.widget)if(N)widget.setPreferenceForKey(q,D);else return widget.preferenceForKey(D);else if(N){M=new Date;M.setTime(M.getTime()+31536E6);q=encodeURIComponent(q);document.cookie=D+"="+q+"; expires="+M.toUTCString()}else return(M=document.cookie.match(RegExp(D+"=([^;]+)")))?decodeURIComponent(M[1]): -""};i.setConfig=function(D){a.each(D,function(q,M){q in E&&a.pref(q,M)});a.extend(true,f,D);if(D.extensions)f.extensions=D.extensions};i.setCustomHandlers=function(D){i.ready(function(){if(D.open){a('#tool_open > input[type="file"]').remove();a("#tool_open").show();h.open=D.open}if(D.save){i.show_save_warning=false;h.bind("saved",D.save)}D.pngsave&&h.bind("exported",D.pngsave);p=D})};i.randomizeIds=function(){h.randomizeIds(arguments)};i.init=function(){function D(k,t){var G=k.id,L=G.split("_"),O= -L[0];L=L[1];t&&h.setStrokeAttr("stroke-"+O,L);ab();F("#cur_"+O,G,20);a(k).addClass("current").siblings().removeClass("current")}function q(k,t){a.pref("bkgd_color",k);a.pref("bkgd_url",t);h.setBackground(k,t)}function M(){var k=h.getHref(T);k=k.indexOf("data:")===0?"":k;a.prompt(g.notification.enterNewImgURL,k,function(t){t&&ub(t)})}function ba(){if(h.deleteCurrentLayer()){Ua();rb();a("#layerlist tr.layer").removeClass("layersel");a("#layerlist tr.layer:first").addClass("layersel")}}function N(){var k= -h.getCurrentDrawing().getCurrentLayerName()+" copy";a.prompt(g.notification.enterUniqueLayerName,k,function(t){if(t)if(h.getCurrentDrawing().hasLayer(t))a.alert(g.notification.dupeLayerName);else{h.cloneLayer(t);Ua();rb()}})}function I(k){var t=a("#layerlist tr.layersel").index(),G=h.getCurrentDrawing().getNumLayers();if(t>0||t<G-1){t+=k;h.setCurrentLayerPosition(G-t-1);rb()}}function ma(k,t){var G=document.getElementById("ruler_x_cursor"),L=document.getElementById("ruler_y_cursor"),O=document.getElementById("workarea"), -S=document.getElementById("title_show");a("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers",function(Wb){Wb.stopPropagation();G.style.left=Wb.pageX-66+O.scrollLeft+"px";L.style.top=Wb.pageY-48+O.scrollTop+"px";Wb=Wb.target.getAttribute("title");typeof Wb!="undefined"&&Wb&&S.innerHTML(Wb)});t||(t=h.getZoom());k||(k=a("#svgcanvas"));for(var da=h.getContentElem(),oa=svgedit.units.getTypeMap()[f.baseUnit],xa=0;xa<2;xa++){var Ba=xa===0,sa=Ba?"x":"y",Ya=Ba?"width":"height",Za=da.getAttribute(sa)- -0;sa=a("#ruler_"+sa+" canvas:first");$hcanv=sa.clone();sa.replaceWith($hcanv);var Q=$hcanv[0];var ob=sa=k[Ya]()*2;Q.parentNode.style[Ya]=ob+"px";var $a=0,Ka,Ea=Q.getContext("2d");Ea.fillStyle="rgb(200,0,0)";Ea.fillRect(0,0,Q.width,Q.height);$hcanv.siblings().remove();if(sa>=3E4){var Pa=parseInt(sa/3E4)+1;Ka=Array(Pa);Ka[0]=Ea;for(var ta=1;ta<Pa;ta++){Q[Ya]=3E4;var bb=Q.cloneNode(true);Q.parentNode.appendChild(bb);Ka[ta]=bb.getContext("2d")}bb[Ya]=sa%3E4;sa=3E4}Q[Ya]=sa;Ya=oa*t;var hb=50/Ya;Q=1;for(ta= -0;ta<ic.length;ta++){Q=Pa=ic[ta];if(hb<=Pa)break}hb=Q*Ya;Ea.font="normal 9px 'Lucida Grande', sans-serif";Ea.fillStyle="#777";for(var sb=Za/Ya%Q*Ya,Xb=sb-hb;sb<ob;sb+=hb){Xb+=hb;ta=Math.round(sb)+0.5;if(Ba){Ea.moveTo(ta,15);Ea.lineTo(ta,0)}else{Ea.moveTo(15,ta);Ea.lineTo(0,ta)}Pa=(Xb-Za)/Ya;if(Q>=1)ta=Math.round(Pa);else{ta=(Q+"").split(".")[1].length;ta=Pa.toFixed(ta)-0}if(ta!==0&&ta!==1E3&&ta%1E3===0)ta=ta/1E3+"K";if(Ba){Ea.fillText(ta,sb+2,8);Ea.fillStyle="#777"}else{Pa=(ta+"").split("");for(ta= -0;ta<Pa.length;ta++){Ea.fillText(Pa[ta],1,sb+9+ta*9);Ea.fillStyle="#777"}}Pa=hb/10;for(ta=1;ta<10;ta++){var Db=Math.round(sb+Pa*ta)+0.5;if(Ka&&Db>sa){$a++;Ea.stroke();if($a>=Ka.length){ta=10;sb=ob;continue}Ea=Ka[$a];sb-=3E4;Db=Math.round(sb+Pa*ta)+0.5}var pc=ta%2?12:10;if(Ba){Ea.moveTo(Db,15);Ea.lineTo(Db,pc)}else{Ea.moveTo(15,Db);Ea.lineTo(pc,Db)}}}Ea.strokeStyle="#666";Ea.stroke()}}(function(){var k=window.opener;if(k)try{var t=k.document.createEvent("Event");t.initEvent("svgEditorReady",true,true); -k.document.documentElement.dispatchEvent(t)}catch(G){}})();(function(){var k=a.deparam.querystring(true);if(!a.isEmptyObject(k)){if(k.dimensions)k.dimensions=k.dimensions.split(",");if(k.extensions)k.extensions=k.extensions.split(",");if(k.bkgd_color)k.bkgd_color="#"+k.bkgd_color;svgEditor.setConfig(k);var t=k.source,G=a.param.querystring();if(!t)if(G.indexOf("source=data:")>=0)t=G.match(/source=(data:[^&]*)/)[1];if(t)if(t.indexOf("data:")===0){t=t.replace(/ /g,"+");i.loadFromDataURI(t)}else i.loadFromString(t); -else if(G.indexOf("paramurl=")!==-1)svgEditor.loadFromURL(G.substr(9));else k.url&&svgEditor.loadFromURL(k.url)}})();var ia=function(){a.each(f.extensions,function(){var t=this;a.getScript(f.extPath+t,function(G){if(!G){G=document.createElement("script");G.src=f.extPath+t;document.querySelector("head").appendChild(G)}})});var k=[];a("#lang_select option").each(function(){k.push(this.value)});i.putLocale(null,k)};document.location.protocol==="file:"?setTimeout(ia,100):ia();a.svgIcons(f.imgPath+"svg_edit_icons.svg", -{w:24,h:24,id_match:false,no_img:!svgedit.browser.isWebkit(),fallback_path:f.imgPath,fallback:{new_image:"clear.png",save:"save.png",open:"open.png",source:"source.png",docprops:"document-properties.png",wireframe:"wireframe.png",undo:"undo.png",redo:"redo.png",select:"select.png",select_node:"select_node.png",pencil:"fhpath.png",pen:"line.png",square:"square.png",rect:"rect.png",fh_rect:"freehand-square.png",circle:"circle.png",ellipse:"ellipse.png",fh_ellipse:"freehand-circle.png",path:"path.png", -text:"text.png",image:"image.png",zoom:"zoom.png",clone:"clone.png",node_clone:"node_clone.png","delete":"delete.png",node_delete:"node_delete.png",move_top:"move_top.png",move_bottom:"move_bottom.png",to_path:"to_path.png",link_controls:"link_controls.png",reorient:"reorient.png",align_left:"align-left.png",align_center:"align-center",align_right:"align-right",align_top:"align-top",align_middle:"align-middle",align_bottom:"align-bottom",go_up:"go-up.png",go_down:"go-down.png",ok:"save.png",cancel:"cancel.png", -arrow_right:"flyouth.png",arrow_down:"dropdown.gif"},placement:{"#tool_docprops > div":"docprops","#tool_select":"select","#tool_fhpath":"pencil","#tool_line":"pen","#tool_rect,#tools_rect_show":"rect","#tool_square":"square","#tool_fhrect":"fh_rect","#tool_ellipse,#tools_ellipse_show":"ellipse","#tool_circle":"circle","#tool_fhellipse":"fh_ellipse","#tool_path":"path","#tool_text,#layer_rename":"text","#tool_image":"image","#tool_zoom":"zoom","#tool_node_clone":"node_clone","#tool_node_delete":"node_delete", -"#tool_add_subpath":"add_subpath","#tool_openclose_path":"open_path","#tool_node_link":"link_controls","#tool_alignleft, #tool_posleft":"align_left","#tool_aligncenter, #tool_poscenter":"align_center","#tool_alignright, #tool_posright":"align_right","#tool_aligntop, #tool_postop":"align_top","#tool_alignmiddle, #tool_posmiddle":"align_middle","#tool_alignbottom, #tool_posbottom":"align_bottom","#cur_position":"align","#linecap_butt,#cur_linecap":"linecap_butt","#linecap_round":"linecap_round","#linecap_square":"linecap_square", -"#linejoin_miter,#cur_linejoin":"linejoin_miter","#linejoin_round":"linejoin_round","#linejoin_bevel":"linejoin_bevel","#url_notice":"warning","#layer_up":"go_up","#layer_down":"go_down","#layer_moreopts":"context_menu","#layerlist td.layervis":"eye","#tool_source_save,#tool_docprops_save,#tool_prefs_save":"ok","#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel":"cancel","#rwidthLabel, #iwidthLabel":"width","#rheightLabel, #iheightLabel":"height","#angleLabel":"angle","#linkLabel,#tool_make_link,#tool_make_link_multi":"globe_link", -"#zoomLabel":"zoom","#blurLabel":"blur",".flyout_arrow_horiz":"arrow_right","#palette .palette_item:first, #fill_bg, #stroke_bg":"no_color"},resize:{"#logo .svg_icon":32,".flyout_arrow_horiz .svg_icon":5,".layer_button .svg_icon, #layerlist td.layervis .svg_icon":14,"#main_button .dropdown .svg_icon":9,"#fill_bg .svg_icon, #stroke_bg .svg_icon":24,".palette_item:first .svg_icon":16,".toolbar_button button .svg_icon":16,".stroke_tool div div .svg_icon":20,"#tools_bottom label .svg_icon":18,"#zoom_dropdown .svg_icon":7}, -callback:function(){a(".toolbar_button button > svg, .toolbar_button button > img").each(function(){a(this).parent().prepend(this)});var k=a("#tools_left");if(k.length!=0){k.offset();k.outerHeight()}a(".tools_flyout").each(function(){var t=a("#"+this.id+"_show"),G=t.attr("data-curopt");if(!t.children("svg, img").length){G=a(G).children().clone();if(G.length){G[0].removeAttribute("style");t.append(G)}}});svgEditor.runCallbacks();setTimeout(function(){a(".flyout_arrow_horiz:empty").each(function(){a(this).append(a.getSvgIcon("arrow_right").width(5).height(5))})}, -1)}});i.canvas=h=new a.SvgCanvas(document.getElementById("svgcanvas"),f);i.show_save_warning=false;ia=navigator.platform.indexOf("Mac")>=0;var ka=navigator.userAgent.indexOf("AppleWebKit")>=0,X=ia?"meta+":"ctrl+",qa=h.pathActions,ga=h.undoMgr,Na=svgedit.utilities,va=f.imgPath+"placeholder.svg",ha=a("#workarea"),Ra=a("#cmenu_canvas");a("#cmenu_layers");var U=null,Z=1,ea="toolbars",ra="",ja={fill:null,stroke:null};(function(){a("#dialog_container").draggable({cancel:"#dialog_content, #dialog_buttons *", -containment:"window"});var k=a("#dialog_box"),t=a("#dialog_buttons"),G=function(L,O,S,da){a("#dialog_content").html("<p>"+O.replace(/\n/g,"</p><p>")+"</p>").toggleClass("prompt",L=="prompt");t.empty();var oa=a('<input type="button" value="'+g.common.ok+'">').appendTo(t);L!="alert"&&a('<input type="button" value="'+g.common.cancel+'">').appendTo(t).click(function(){k.hide();S(false)});if(L=="prompt"){var xa=a('<input type="text">').prependTo(t);xa.val(da||"");xa.bind("keydown","return",function(){oa.click()})}L== -"process"&&oa.hide();k.show();oa.click(function(){k.hide();var Ba=L=="prompt"?xa.val():true;S&&S(Ba)}).focus();L=="prompt"&&xa.focus()};a.alert=function(L,O){G("alert",L,O)};a.confirm=function(L,O){G("confirm",L,O)};a.process_cancel=function(L,O){G("process",L,O)};a.prompt=function(L,O,S){G("prompt",L,S,O)}})();var la=function(){var k=a(".tool_button_current");if(k.length&&k[0].id!=="tool_select"){k.removeClass("tool_button_current").addClass("tool_button");a("#tool_select").addClass("tool_button_current").removeClass("tool_button"); -a("#styleoverrides").text("#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}")}h.setMode("select")},T=null,wa=false,Da=false,Ma=false,Fa=false,Oa="",Qa=a("title:first").text(),Ga=function(k,t,G){h.getResolution();a("#svgcanvas").position();if(t=h.setBBoxZoom(t,ha.width()-15,ha.height()-15)){k=t.zoom;t=t.bbox;if(k<0.0010)Ia({value:0.1});else{a("#zoom").val(k*100);G?Ob():Ob(false,{x:t.x*k+t.width*k/2,y:t.y*k+t.height*k/2});h.getMode()=="zoom"&&t.width&&la();m()}}};a("#cur_context_panel").delegate("a", -"click",function(){var k=a(this);k.attr("data-root")?h.leaveContext():h.setContext(k.text());return false});var Ca={},Ha=function(k){a.each(k,function(t,G){var L=a(t).children(),O=t+"_show",S=a(O),da=false;L.addClass("tool_button").unbind("click mousedown mouseup").each(function(Ba){var sa=G[Ba];Ca[sa.sel]=sa.fn;if(sa.isDefault)da=Ba;Ba=function(Ya){var Za=sa;if(Ya.type==="keydown"){var Q=a(Za.parent+"_show").hasClass("tool_button_current"),ob=a(Za.parent+"_show").attr("data-curopt");a.each(k[sa.parent], -function(Ka,Ea){if(Ea.sel==ob)Za=!Ya.shiftKey||!Q?Ea:k[sa.parent][Ka+1]||k[sa.parent][0]})}if(a(this).hasClass("disabled"))return false;db(O)&&Za.fn();var $a=Za.icon?a.getSvgIcon(Za.icon,true):a(Za.sel).children().eq(0).clone();$a[0].setAttribute("width",S.width());$a[0].setAttribute("height",S.height());S.children(":not(.flyout_arrow_horiz)").remove();S.append($a).attr("data-curopt",Za.sel)};a(this).mouseup(Ba);sa.key&&a(document).bind("keydown",sa.key[0]+" shift+"+sa.key[0],Ba)});if(da)S.attr("data-curopt", -G[da].sel);else S.attr("data-curopt")||S.attr("data-curopt",G[0].sel);var oa,xa=a(O).position();a(t).css({left:xa.left+34,top:xa.top+77});S.mousedown(function(Ba){a("#tools_shapelib").is(":visible")&&db(O,false);if(S.hasClass("disabled"))return false;var sa=a(t),Ya=xa.left+34,Za=sa.width()*-1,Q=sa.data("shown_popop")?200:0;oa=setTimeout(function(){S.data("isLibrary")?sa.css("left",Ya).show():sa.css("left",Za).show().animate({left:Ya},150);sa.data("shown_popop",true)},Q);Ba.preventDefault()}).mouseup(function(){clearTimeout(oa); -var Ba=a(this).attr("data-curopt");if(S.data("isLibrary")&&a(O.replace("_show","")).is(":visible"))db(O,true);else db(O)&&Ba in Ca&&Ca[Ba]()})});Pb()},Aa=function(k,t){return a("<div>",{"class":"tools_flyout",id:k}).appendTo("#svg_editor").append(t)},zb=function(){a(".tools_flyout").each(function(){var k=a("#"+this.id+"_show"),t=k.offset();k=k.outerWidth();a(this).css({left:(t.left+k)*Z,top:t.top})})},Pb=function(){a(".tools_flyout").each(function(){var k=a("#"+this.id+"_show");if(!k.data("isLibrary")){var t= -[];a(this).children().each(function(){t.push(this.title)});k[0].title=t.join(" / ")}})},gb,mb=function(k,t,G){var L=null;if(k.indexOf("url(#")===0){k=(k=h.getRefElem(k))?k.cloneNode(true):a("#"+G+"_color defs *")[0];L={alpha:t};L[k.tagName]=k}else L=k.indexOf("#")===0?{alpha:t,solidColor:k.substr(1)}:{alpha:t,solidColor:"none"};return new a.jGraduate.Paint(L)},Va=h.getResolution();if(f.baseUnit!=="px"){Va.w=svgedit.units.convertUnit(Va.w)+f.baseUnit;Va.h=svgedit.units.convertUnit(Va.h)+f.baseUnit}a(".canvas_width").val(Va.w); -a(".canvas_height").val(Va.h);a("#docprops_button").on("click",function(){o()});var ub=i.setImageURL=function(k){k||(k=va);h.setImageURL(k);a("#image_url").val(k);if(k.indexOf("data:")===0){a("#image_url").hide();a("#change_image_url").show()}else{h.embedImage(k,function(t){t?a("#url_notice").hide():a("#url_notice").show();va=k});a("#image_url").show();a("#change_image_url").hide()}},Bb=function(k){var t=Math.min(Math.max(12+k.value.length*6,50),300);a(k).width(t)},Ua=function(){var k=T;if(k!=null&& -!k.parentNode)k=null;var t=h.getCurrentDrawing().getCurrentLayerName(),G=h.getMode(),L=f.baseUnit!=="px"?f.baseUnit:null,O=G=="pathedit",S=a("#cmenu_canvas li");a("#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\t\t\t\t\t#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel").hide();a(".menu_item","#edit_menu").addClass("disabled");a(".menu_item","#object_menu").addClass("disabled");!k&&!wa&&a("#canvas_panel").show(); -if(k!=null){var da=k.nodeName,oa=h.getRotationAngle(k);a("#angle").val(Math.round(oa));oa=h.getBlur(k);a("#blur").val(oa);a("#blur_slider").slider("option","value",oa);h.addedNew&&da==="image"&&h.getHref(k).indexOf("data:")!==0&&M();if(!O&&G!="pathedit"){a("#selected_panel").show();a(".action_selected").removeClass("disabled");if(["line","circle","ellipse"].indexOf(da)>=0)a("#xy_panel").hide();else{var xa,Ba;if(["g","polyline","path"].indexOf(da)>=0){if(G=h.getStrokedBBox([k])){xa=G.x;Ba=G.y}}else{xa= -k.getAttribute("x");Ba=k.getAttribute("y")}if(L){xa=svgedit.units.convertUnit(xa);Ba=svgedit.units.convertUnit(Ba)}a("#selected_x").val(xa||0);a("#selected_y").val(Ba||0);a("#xy_panel").show()}["image","text","path","g","use"].indexOf(da)==-1&&a(".action_path_convert_selected").removeClass("disabled");da==="path"&&a(".action_path_selected").removeClass("disabled")}else{t=qa.getNodePoint();a("#tool_add_subpath").removeClass("push_button_pressed").addClass("tool_button");a("#tool_node_delete").toggleClass("disabled", -!qa.canDeleteNodes);F("#tool_openclose_path",qa.closed_subpath?"open_path":"close_path");if(t){O=a("#seg_type");if(L){t.x=svgedit.units.convertUnit(t.x);t.y=svgedit.units.convertUnit(t.y)}a("#path_node_x").val(t.x);a("#path_node_y").val(t.y);t.type?O.val(t.type).removeAttr("disabled"):O.val(4).attr("disabled","disabled")}return}L={g:[],a:[],rect:["rx","width","height"],image:["width","height"],circle:["cx","cy","r"],ellipse:["cx","cy","rx","ry"],line:["x1","y1","x2","y2"],text:[],use:[]};var sa=k.tagName; -a(k).data("gsvg")&&a("#g_panel").show();sa=="path"&&a("#path_panel").show();if(L[sa]){L=L[sa];a("#"+sa+"_panel").show();a.each(L,function(Ya,Za){var Q=k.getAttribute(Za);if(f.baseUnit!=="px"&&k[Za])Q=svgedit.units.convertUnit(k[Za].baseVal.value);a("#"+sa+"_"+Za).val(Q||0)});if(sa=="text"){a("#text_panel").css("display","inline");h.getItalic()?a("#tool_italic").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_italic").removeClass("push_button_pressed").addClass("tool_button");h.getBold()? -a("#tool_bold").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_bold").removeClass("push_button_pressed").addClass("tool_button");a("#font_family").val(k.getAttribute("font-family"));a("#font_size").val(k.getAttribute("font-size"));a("#text").val(k.textContent);h.addedNew&&setTimeout(function(){a("#text").focus().select()},100)}else if(sa=="image")ub(h.getHref(k));else if(sa==="g"||sa==="use"){a("#container_panel").show();a(".action_group_selected").removeClass("disabled");L=h.getTitle(); -da=a("#g_title")[0];da.value=L;Bb(da);sa=="use"?da.setAttribute("disabled","disabled"):da.removeAttribute("disabled")}}S[(sa==="g"?"en":"dis")+"ableContextMenuItems"]("#ungroup");S[(sa==="g"||!wa?"dis":"en")+"ableContextMenuItems"]("#group")}else if(wa){a("#multiselected_panel").show();a(".action_multi_selected").removeClass("disabled");S.enableContextMenuItems("#group").disableContextMenuItems("#ungroup")}else S.disableContextMenuItems("#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back"); -ga.getUndoStackSize()>0?a("#tool_undo").removeClass("disabled"):a("#tool_undo").addClass("disabled");ga.getRedoStackSize()>0?a("#tool_redo").removeClass("disabled"):a("#tool_redo").addClass("disabled");h.addedNew=false;if(k&&!O||wa){a("#selLayerNames").removeAttr("disabled").val(t);Ra.enableContextMenuItems("#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back")}else a("#selLayerNames").attr("disabled","disabled")};a("#text").focus(function(){});a("#text").blur(function(){});h.bind("selected", -function(k,t){var G=h.getMode();G==="select"&&la();G=G=="pathedit";T=t.length==1||t[1]==null?t[0]:null;wa=t.length>=2&&t[1]!=null;if(T!=null)if(!G){if(T!=null)switch(T.tagName){case "use":case "image":case "foreignObject":break;case "g":case "a":for(var L=null,O=T.getElementsByTagName("*"),S=0,da=O.length;S<da;S++){var oa=O[S].getAttribute("stroke-width");if(S===0)L=oa;else if(L!==oa)L=null}a("#stroke_width").val(L===null?"":L);ja.fill.update(true);ja.stroke.update(true);break;default:ja.fill.update(true); -ja.stroke.update(true);a("#stroke_width").val(T.getAttribute("stroke-width")||1);a("#stroke_style").val(T.getAttribute("stroke-dasharray")||"none");L=T.getAttribute("stroke-linejoin")||"miter";a("#linejoin_"+L).length!=0&&D(a("#linejoin_"+L)[0]);L=T.getAttribute("stroke-linecap")||"butt";a("#linecap_"+L).length!=0&&D(a("#linecap_"+L)[0])}if(T!=null){L=(T.getAttribute("opacity")||1)*100;a("#group_opacity").val(L);a("#opac_slider").slider("option","value",L);a("#elem_id").val(T.id)}ac()}a("#path_node_panel").toggle(G); -a("#tools_bottom_2,#tools_bottom_3").toggle(!G);if(G){a(".tool_button_current").removeClass("tool_button_current").addClass("tool_button");a("#tool_select").addClass("tool_button_current").removeClass("tool_button");F("#tool_select","select_node");wa=false;if(t.length)T=t[0]}else F("#tool_select","select");Ua();h.runExtensions("selectedChanged",{elems:t,selectedElement:T,multiselected:wa})});h.bind("transition",function(k,t){var G=h.getMode(),L=t[0];if(L){wa=t.length>=2&&t[1]!=null;if(!wa)switch(G){case "rotate":G= -h.getRotationAngle(L);a("#angle").val(Math.round(G));a("#tool_reorient").toggleClass("disabled",G==0)}h.runExtensions("elementTransition",{elems:t})}});h.bind("changed",function(k,t){var G=h.getMode();G==="select"&&la();for(var L=0;L<t.length;++L){var O=t[L];if(O&&O.tagName==="svg"){rb();Ob()}else if(O&&T&&T.parentNode==null)T=O}i.show_save_warning=true;Ua();if(T&&G==="select"){ja.fill.update();ja.stroke.update()}h.runExtensions("elementChanged",{elems:t})});h.bind("saved",function(k,t){i.show_save_warning= -false;t='<?xml version="1.0"?>\n'+t;var G=navigator.userAgent;if(~G.indexOf("Chrome")&&a.browser.version>=533||~G.indexOf("MSIE"))A(0,true);else{var L=k.open("data:image/svg+xml;base64,"+Na.encode64(t)),O=a.pref("save_notice_done");if(O!=="all"){var S=g.notification.saveFromBrowser.replace("%s","SVG");if(G.indexOf("Gecko/")!==-1)if(t.indexOf("<defs")!==-1){S+="\n\n"+g.notification.defsFailOnSave;a.pref("save_notice_done","all");O="all"}else a.pref("save_notice_done","part");else a.pref("save_notice_done", -"all");O!=="part"&&L.alert(S)}}});h.bind("exported",function(k,t){var G=t.issues;a("#export_canvas").length||a("<canvas>",{id:"export_canvas"}).hide().appendTo("body");var L=a("#export_canvas")[0];L.width=h.contentW;L.height=h.contentH;canvg(L,t.svg,{renderCallback:function(){var O=L.toDataURL("image/png");U.location.href=O;if(a.pref("export_notice_done")!=="all"){O=g.notification.saveFromBrowser.replace("%s","PNG");if(G.length)O+="\n\n"+g.notification.noteTheseIssues+"\n \u2022 "+G.join("\n \u2022 "); -a.pref("export_notice_done","all");U.alert(O)}}})});h.bind("zoomed",Ga);h.bind("contextset",function(k,t){var G="";if(t){var L="";G='<a href="#" data-root="y">'+h.getCurrentDrawing().getCurrentLayerName()+"</a>";a(t).parentsUntil("#svgcontent > g").andSelf().each(function(){if(this.id){L+=" > "+this.id;G+=this!==t?' > <a href="#">'+this.id+"</a>":" > "+this.id}});Oa=L}else Oa=null;a("#cur_context_panel").toggle(!!t).html(G);w()});h.bind("extension_added",function(k,t){function G(){if(gb){clearTimeout(gb); -gb=null}O||(gb=setTimeout(function(){O=true;P(e.iconsize)},50))}var L=false,O=false,S=true,da=function(){if(t.callback&&!L&&S){L=true;t.callback()}},oa=[];t.context_tools&&a.each(t.context_tools,function(Za,Q){var ob=Q.container_id?' id="'+Q.container_id+'"':"",$a=a("#"+Q.panel);$a.length||($a=a("<div>",{id:Q.panel}).appendTo("#tools_top"));switch(Q.type){case "tool_button":var Ka='<div class="tool_button">'+Q.id+"</div>",Ea=a(Ka).appendTo($a);Q.events&&a.each(Q.events,function(bb,hb){a(Ea).bind(bb, -hb)});break;case "select":Ka="<label"+ob+'><select id="'+Q.id+'">';a.each(Q.options,function(bb,hb){Ka+='<option value="'+bb+'"'+(bb==Q.defval?" selected":"")+">"+hb+"</option>"});Ka+="</select></label>";var Pa=a(Ka).appendTo($a).find("select");a.each(Q.events,function(bb,hb){a(Pa).bind(bb,hb)});break;case "button-select":Ka='<div id="'+Q.id+'" class="dropdown toolset" title="'+Q.title+'"><div id="cur_'+Q.id+'" class="icon_label"></div><button></button></div>';ob=a('<ul id="'+Q.id+'_opts"></ul>').appendTo("#option_lists"); -Q.colnum&&ob.addClass("optcols"+Q.colnum);a(Ka).appendTo($a).children();oa.push({elem:"#"+Q.id,list:"#"+Q.id+"_opts",title:Q.title,callback:Q.events.change,cur:"#cur_"+Q.id});break;case "input":Ka="<label"+ob+'><span id="'+Q.id+'_label">'+Q.label+':</span><input id="'+Q.id+'" title="'+Q.title+'" size="'+(Q.size||"4")+'" value="'+(Q.defval||"")+'" type="text"/></label>';var ta=a(Ka).appendTo($a).find("input");Q.spindata&&ta.SpinButton(Q.spindata);Q.events&&a.each(Q.events,function(bb,hb){ta.bind(bb, -hb)})}});if(t.buttons){var xa={},Ba={},sa=t.svgicons,Ya={};a.each(t.buttons,function(Za,Q){for(var ob,$a=Q.id,Ka=Za;a("#"+$a).length;)$a=Q.id+"_"+ ++Ka;if(sa){xa[$a]=Q.icon;Ka=Q.svgicon?Q.svgicon:Q.id;if(Q.type=="app_menu")Ba["#"+$a+" > div"]=Ka;else Ba["#"+$a]=Ka}else ob=Q.type=="menu"?"":a('<img src="'+Q.icon+'">');var Ea,Pa;switch(Q.type){case "mode_flyout":case "mode":Ea="tool_button";if(Q.cls)Ea+=" "+Q.cls;Pa="#tools_left";break;case "context":Ea="tool_button";Pa="#"+Q.panel;a(Pa).length||a("<div>", -{id:Q.panel}).appendTo("#tools_top");break;case "menu":Ea="menu_item tool_button";Pa="#"+(Q.after||Q.panel);break;case "app_menu":Ea="";Pa=Q.parent||"#main_menu ul";a(Pa).length||a("<div>",{id:Q.panel}).appendTo("#tools_top")}var ta=a(Q.list||Q.type=="app_menu"?"<li/>":"<div/>").attr("id",$a).attr("title",Q.title).addClass(Ea);if(!Q.includeWith&&!Q.list){if("position"in Q)a(Pa).children().eq(Q.position).before(ta);else Q.type!="menu"||!Q.after?ta.appendTo(Pa):a(Pa).after(ta);if(Q.type=="mode_flyout"){Ka= -a(ta);Ea=Ka.parent();if(!Ka.parent().hasClass("tools_flyout")){var bb=Ka[0].id.replace("tool_","tools_"),hb=Ka.clone().attr("id",bb+"_show").append(a("<div>",{"class":"flyout_arrow_horiz"}));Ka.before(hb);Ea=Aa(bb,Ka);Ea.data("isLibrary",true);hb.data("isLibrary",true)}Ba["#"+bb+"_show"]=Q.id;$a=Ya["#"+Ea[0].id]=[{sel:"#"+$a,fn:Q.events.click,icon:Q.id,isDefault:true},sb]}else if(Q.type=="app_menu"||Q.type=="menu")ta.append(Q.title)}else if(Q.list){ta.addClass("push_button");a("#"+Q.list+"_opts").append(ta); -if(Q.isDefault){a("#cur_"+Q.list).append(ta.children().clone());Ka=Q.svgicon?Q.svgicon:Q.id;Ba["#cur_"+Q.list]=Ka}}else if(Q.includeWith){Pa=Q.includeWith;Ka=a(Pa.button);Ea=Ka.parent();if(!Ka.parent().hasClass("tools_flyout")){bb=Ka[0].id.replace("tool_","tools_");hb=Ka.clone().attr("id",bb+"_show").append(a("<div>",{"class":"flyout_arrow_horiz"}));Ka.before(hb);Ea=Aa(bb,Ka)}var sb=nc.getButtonData(Pa.button);if(Pa.isDefault)Ba["#"+bb+"_show"]=Q.id;$a=Ya["#"+Ea[0].id]=[{sel:"#"+$a,fn:Q.events.click, -icon:Q.id,key:Q.key,isDefault:Q.includeWith?Q.includeWith.isDefault:0},sb];bb="position"in Pa?Pa.position:"last";sb=Ea.children().length;if(!isNaN(bb)&&bb>=0&&bb<sb)Ea.children().eq(bb).before(ta);else{Ea.append(ta);$a.reverse()}}sa||ta.append(ob);Q.list||a.each(Q.events,function(Xb,Db){if(Xb=="click")if(Q.type=="mode"){Q.includeWith?ta.bind(Xb,Db):ta.bind(Xb,function(){db(ta)&&Db()});if(Q.key){a(document).bind("keydown",Q.key,Db);Q.title&&ta.attr("title",Q.title+" ["+Q.key+"]")}}else ta.bind(Xb, -Db);else ta.bind(Xb,Db)});Ha(Ya)});a.each(oa,function(){lb(this.elem,this.list,this.callback,{seticon:true})});if(sa)S=false;a.svgIcons(sa,{w:24,h:24,id_match:false,no_img:!ka,fallback:xa,placement:Ba,callback:function(){e.iconsize&&e.iconsize!="m"&&G();S=true;da()}})}da()});h.textActions.setInputElem(a("#text")[0]);var Ja='<div class="palette_item" data-rgb="#none"></div>';a.each(["#000000","#3f3f3f","#7f7f7f","#bfbfbf","#ffffff","#ff0000","#ff7f00","#ffff00","#7fff00","#00ff00","#00ff7f","#00ffff", -"#007fff","#0000ff","#7f00ff","#ff00ff","#ff007f","#7f0000","#7f3f00","#7f7f00","#3f7f00","#007f00","#007f3f","#007f7f","#003f7f","#00007f","#3f007f","#7f007f","#7f003f","#ffaaaa","#ffd4aa","#ffffaa","#d4ffaa","#aaffaa","#aaffd4","#aaffff","#aad4ff","#aaaaff","#d4aaff","#ffaaff","#ffaad4"],function(k,t){Ja+='<div class="palette_item" style="background-color: '+t+';" data-rgb="'+t+'"></div>'});a("#palette").append(Ja);Ja="";a.each(["#FFF","#888","#000"],function(){Ja+='<div class="color_block" style="background-color:'+ -this+';"></div>'});a("#bg_blocks").append(Ja);var Wa=a("#bg_blocks div");Wa.each(function(){a(this).click(function(){Wa.removeClass("cur_background");a(this).addClass("cur_background")})});if(a.pref("bkgd_color"))q(a.pref("bkgd_color"),a.pref("bkgd_url"));else a.pref("bkgd_url")&&q(E.bkgd_color,a.pref("bkgd_url"));if(a.pref("img_save")){e.img_save=a.pref("img_save");a("#image_save_opts input").val([e.img_save])}var Ia=function(k){var t=k.value/100;if(t<0.0010)k.value=0.1;else{k=h.getZoom();Ga(window, -{width:0,height:0,x:(ha[0].scrollLeft+ha.width()/2)/k,y:(ha[0].scrollTop+ha.height()/2)/k,zoom:t},true)}},kb=function(k,t){if(t==null)t=k.value;a("#group_opacity").val(t);if(!k||!k.handle)a("#opac_slider").slider("option","value",t);h.setOpacity(t/100)},Cb=function(k,t,G){if(t==null)t=k.value;a("#blur").val(t);var L=false;if(!k||!k.handle){a("#blur_slider").slider("option","value",t);L=true}G?h.setBlurNoUndo(t):h.setBlur(t,L)},ab=function(){window.opera&&a("<p/>").hide().appendTo("body").remove()}; -a("#stroke_style").change(function(){h.setStrokeAttr("stroke-dasharray",a(this).val());ab()});a("#stroke_linejoin").change(function(){h.setStrokeAttr("stroke-linejoin",a(this).val());ab()});a("select").change(function(){a(this).blur()});var cb=false;a("#selLayerNames").change(function(){var k=this.options[this.selectedIndex].value,t=g.notification.QmoveElemsToLayer.replace("%s",k),G=function(L){if(L){cb=true;h.moveSelectedToLayer(k);h.clearSelection();rb()}};if(k)cb?G(true):a.confirm(t,G)});a("#font_family").change(function(){h.setFontFamily(this.value)}); -a("#seg_type").change(function(){h.setSegType(a(this).val())});a("#text").keyup(function(){h.setTextContent(this.value)});a("#image_url").change(function(){ub(this.value)});a("#link_url").change(function(){this.value.length?h.setLinkURL(this.value):h.removeHyperlink()});a("#g_title").change(function(){h.setGroupTitle(this.value)});a(".attr_changer").change(function(){var k=this.getAttribute("data-attr"),t=this.value;if(svgedit.units.isValidUnit(k,t,T))this.blur();else{a.alert(g.notification.invalidAttrValGiven); -this.value=T.getAttribute(k);return false}if(k!=="id")if(isNaN(t))t=h.convertToNum(k,t);else if(f.baseUnit!=="px"){var G=svgedit.units.getTypeMap();if(T[k]||h.getMode()==="pathedit"||k==="x"||k==="y")t*=G[f.baseUnit]}if(k==="id"){k=T;h.clearSelection();k.id=t;h.addToSelection([k],true)}else h.changeSelectedAttribute(k,t);this.blur()});a("#palette").mouseover(function(){var k=a('<input type="hidden">');a(this).append(k);k.focus().remove()});a(".palette_item").mousedown(function(){var k=a("#tool_stroke").hasClass("active"), -t=k?"stroke":"fill",G=a(this).attr("data-rgb"),L=null;console.log(G);if(G==="transparent"||G==="initial"||G==="#none"){G="none";L=new a.jGraduate.Paint}else L=new a.jGraduate.Paint({alpha:100,solidColor:G.substr(1)});ja[t].setPaint(L);if(k){h.setColor("stroke",G);G!="none"&&h.getStrokeOpacity()!=1&&h.setPaintOpacity("stroke",1)}else{h.setColor("fill",G);G!="none"&&h.getFillOpacity()!=1&&h.setPaintOpacity("fill",1)}ac()}).bind("contextmenu",function(k){k.preventDefault()});a("#toggle_stroke_tools").toggle(function(){a(".stroke_tool").css("display", -"table-cell");a(this).addClass("expanded");na()},function(){a(".stroke_tool").css("display","none");a(this).removeClass("expanded");na()});var db=function(k,t){if(a(k).hasClass("disabled"))return false;if(a(k).parent().hasClass("tools_flyout"))return true;var G=G||"normal";t||a(".tools_flyout").fadeOut(G);a("#styleoverrides").text("");a(".tool_button_current").removeClass("tool_button_current").addClass("tool_button");a(k).addClass("tool_button_current").removeClass("tool_button");return true};(function(){var k= -null,t=null,G=ha[0],L=false,O=false;a("#svgcanvas").bind("mousemove mouseup",function(S){if(L!==false){G.scrollLeft-=S.clientX-k;G.scrollTop-=S.clientY-t;k=S.clientX;t=S.clientY;if(S.type==="mouseup")L=false;return false}}).mousedown(function(S){if(S.button===1||O===true){L=true;k=S.clientX;t=S.clientY;return false}});a(window).mouseup(function(){L=false});a(document).bind("keydown","space",function(S){h.spaceKey=O=true;S.preventDefault()}).bind("keyup","space",function(S){S.preventDefault();h.spaceKey= -O=false}).bind("keydown","alt",function(){h.getMode()==="zoom"&&ha.addClass("out")}).bind("keyup","alt",function(){h.getMode()==="zoom"&&ha.removeClass("out")})})();var za=a(".menu"),vb=function(k){k.target.style.background="#fff";setTimeout(function(){k.target.style.background="#ddd"},50);setTimeout(function(){k.target.style.background="#fff"},150);setTimeout(function(){k.target.style.background="#ddd"},200);setTimeout(function(){k.target.style.background=""},200);setTimeout(function(){a("#menu_bar").removeClass("active")}, -220);return false};a(".menu_item").live("click",function(k){vb(k)});a("svg, body").on("click",function(k){if(!a(k.target).hasClass("menu_title")&&a("#menu_bar").hasClass("active"))if(!a(k.target).hasClass("disabled")&&a(k.target).hasClass("menu_item"))vb(k);else{a("#menu_bar").removeClass("active");a(".tools_flyout").hide();a("input").blur()}});a(".menu_title").on("click",function(){a("#menu_bar").toggleClass("active")});a(".menu_title").on("mouseover",function(){za.removeClass("open");a(this).parent().addClass("open")}); -i.addDropDown=function(k,t,G){if(a(k).length!=0){var L=a(k).find("button"),O=a(k).find("ul").attr("id",a(k)[0].id+"-list");G||a("#option_lists").append(O);var S=false;G&&a(k).addClass("dropup");O.find("li").bind("mouseup",t);a(window).mouseup(function(){if(!S){L.removeClass("down");O.hide()}S=false});L.bind("mousedown",function(){if(L.hasClass("down")){L.removeClass("down");O.hide()}else{L.addClass("down");if(!G){var da=a(k).offset();O.css({top:da.top,left:da.left-110})}O.show();S=true}}).hover(function(){S= -true}).mouseout(function(){S=false})}};var lb=function(k,t,G,L){var O=a(k);t=a(t);var S=false,da=L.dropUp;da&&a(k).addClass("dropup");t.find("li").bind("mouseup",function(){if(L.seticon){F("#cur_"+O[0].id,a(this).children());a(this).addClass("current").siblings().removeClass("current")}G.apply(this,arguments)});a(window).mouseup(function(){if(!S){O.removeClass("down");t.hide();t.css({top:0,left:0})}S=false});t.height();a(k).bind("mousedown",function(){var oa=a(k).offset();if(da){oa.top-=t.height(); -oa.left+=8}else oa.top+=a(k).height();a(t).offset(oa);if(O.hasClass("down")){O.removeClass("down");t.hide();t.css({top:0,left:0})}else{O.addClass("down");t.show();S=true;return false}}).hover(function(){S=true}).mouseout(function(){S=false});L.multiclick&&t.mousedown(function(){S=true})};i.addDropDown("#font_family_dropdown",function(){a(this).text();a("#font_family").val(a(this).text()).change()});i.addDropDown("#opacity_dropdown",function(){if(!a(this).find("div").length){var k=parseInt(a(this).text().split("%")[0]); -kb(false,k)}},false);a("#opac_slider").slider({start:function(){a("#opacity_dropdown li:not(.special)").hide()},stop:function(){a("#opacity_dropdown li").show();a(window).mouseup()},slide:function(k,t){kb(t)}});i.addDropDown("#blur_dropdown",a.noop);var xb=false;a("#blur_slider").slider({max:10,step:0.1,stop:function(k,t){xb=false;Cb(t);a("#blur_dropdown li").show();a(window).mouseup()},start:function(){xb=true},slide:function(k,t){Cb(t,null,xb)}});i.addDropDown("#zoom_dropdown",function(){var k= -a(this),t=k.attr("data-val");t?Ga(window,t):Ia({value:parseInt(k.text())})},true);lb("#stroke_linecap","#linecap_opts",function(){D(this,true)},{dropUp:true});lb("#stroke_linejoin","#linejoin_opts",function(){D(this,true)},{dropUp:true});a("div","#position_opts").each(function(){this.addEventListener("mouseup",function(){var k=this.id.replace("tool_pos","").charAt(0);h.alignSelectedElements(k,"page")})});(function(){var k,t=function(){a(k).blur()};a("#svg_editor").find("button, select, input:not(#text)").focus(function(){k= -this;ea="toolbars";ha.mousedown(t)}).blur(function(){ea="canvas";ha.unbind("mousedown",t);h.getMode()=="textedit"&&a("#text").focus()})})();var Jb=function(){if(db("#tool_select")){h.setMode("select");a("#styleoverrides").text("#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}")}},pb=function(){db("#tool_fhpath")&&h.setMode("fhpath")},Kb=function(){db("#tool_line")&&h.setMode("line")},Rb=function(){db("#tool_rect")&&h.setMode("rect")},Lb=function(){db("#tool_ellipse")&& -h.setMode("ellipse")},Sb=function(){db("#tool_image")&&h.setMode("image")},pa=function(){db("#tool_zoom")&&h.setMode("zoom")},V=function(){if(db("#tool_zoom")){c();la()}},ua=function(){db("#tool_text")&&h.setMode("text")},ya=function(){db("#tool_path")&&h.setMode("path")},aa=function(){if(T!=null||wa)h.deleteSelectedElements()},Sa=function(){if(T!=null||wa)h.cutSelectedElements()},Eb=function(){if(T!=null||wa)h.copySelectedElements()},Ab=function(){var k=h.getZoom(),t=(ha[0].scrollLeft+ha.width()/ -2)/k-h.contentW;k=(ha[0].scrollTop+ha.height()/2)/k-h.contentH;h.pasteElements("point",t,k)},wb=function(){T!=null&&h.moveToTopSelectedElement()},tb=function(){T!=null&&h.moveToBottomSelectedElement()},Fb=function(){T!=null&&h.moveUpDownSelected("Up")},Qb=function(){T!=null&&h.moveUpDownSelected("Down")},nb=function(){T!=null&&h.convertToPath()},Mb=function(){T!=null&&qa.reorient()},Ta=function(){if(T!=null||wa)a.prompt(g.notification.enterNewLinkURL,"http://",function(k){k&&h.makeHyperlink(k)})}, -eb=function(k,t){if(T!=null||wa){if(f.gridSnapping){var G=h.getZoom()*f.snappingStep;k*=G;t*=G}h.moveSelectedElements(k,t)}},Ib=function(){var k=!a("#tool_node_link").hasClass("push_button_pressed");k?a("#tool_node_link").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_node_link").removeClass("push_button_pressed").addClass("tool_button");qa.linkControlPoints(k)},Zb=function(){qa.getNodePoint()&&qa.clonePathNode()},Yb=function(){qa.getNodePoint()&&qa.deletePathNode()},fb=function(){var k= -a("#tool_add_subpath"),t=!k.hasClass("push_button_pressed");t?k.addClass("push_button_pressed").removeClass("tool_button"):k.removeClass("push_button_pressed").addClass("tool_button");qa.addSubPath(t)},La=function(){qa.opencloseSubPath()},fc=function(){h.cycleElement(1)},bc=function(){h.cycleElement(0)},Tb=function(k,t){if(!(T==null||wa)){k||(t*=-1);var G=a("#angle").val()*1+t;h.setRotationAngle(G);Ua()}},gc=function(){var k=f.dimensions;a.confirm(g.notification.QwantToClear,function(t){if(t){la(); -h.clear();h.setResolution(k[0],k[1]);Ob(true);c();rb();Ua();ja.fill.prep();ja.stroke.prep();h.runExtensions("onNewDocument")}})},kc=function(){h.setBold(!h.getBold());Ua();return false},Vb=function(){h.setItalic(!h.getItalic());Ua();return false},$b=function(){if(!p.pngsave){var k=g.notification.loadingImage;U=window.open("data:text/html;charset=utf-8,<title>"+k+"

      "+k+"

      ")}window.canvg?h.rasterExport():a.getScript("canvg/rgbcolor.js",function(){a.getScript("canvg/canvg.js",function(){h.rasterExport()})})}, -mc=function(){h.open()},Ub=function(){},ib=function(k){var t=k.prev();t.css("background","#09f");setTimeout(function(){t.css("background","")},200)},hc=function(){if(ga.getUndoStackSize()>0){window.event.type==="keydown"&&ib(a("#edit_menu"));ga.undo();rb()}},cc=function(){if(ga.getRedoStackSize()>0){window.event.type==="keydown"&&ib(a("#edit_menu"));ga.redo();rb()}},Nb=function(){if(wa)h.groupSelectedElements();else T&&h.ungroupSelectedElement()},jb=function(){window.event.type==="keydown"&&ib(a("#edit_menu")); -h.cloneSelectedElements(20,20)},ec=function(){var k=this.id.replace("tool_align","").charAt(0);h.alignSelectedElements(k,a("#align_relative_to").val())},b=function(){var k=document.querySelector("#tool_stroke rect"),t=document.querySelector("#tool_fill rect"),G=t.getAttribute("fill"),L=k.getAttribute("fill");k=parseFloat(k.getAttribute("stroke-opacity"));if(isNaN(k))k=100;t=parseFloat(t.getAttribute("fill-opacity"));if(isNaN(t))t=100;L=mb(L,k,"stroke");G=mb(G,t,"fill");ja.fill.setPaint(L,true);ja.stroke.setPaint(G, -true)},c=function(k){var t=h.getResolution();k=k?t.zoom*k:1;a("#zoom").val(k*100);h.setZoom(k);m();Ob(true)},d=function(){!a("#tool_wireframe").hasClass("push_button_pressed")?a("#tool_wireframe").addClass("push_button_pressed"):a("#tool_wireframe").removeClass("push_button_pressed");ha.toggleClass("wireframe");if(!jc){var k=a("#wireframe_rules");k.length?k.empty():a('').appendTo("head");m()}},n=function(){if(a("#tool_rulers").hasClass("push_button_pressed")){a("#tool_rulers").removeClass("push_button_pressed"); -a("#show_rulers").attr("checked",false);f.showRulers=false}else{a("#tool_rulers").addClass("push_button_pressed");a("#show_rulers").attr("checked",true);f.showRulers=true}a("#rulers").toggle(!!f.showRulers)},m=function(){if(!jc){var k="#workarea.wireframe #svgcontent * { stroke-width: "+1/h.getZoom()+"px; }";a("#wireframe_rules").text(ha.hasClass("wireframe")?k:"")}},A=function(k,t){if(!Da){Da=true;a("#save_output_btns").toggle(!!t);a("#tool_source_back").toggle(!t);var G=ra=h.getSvgString();a("#svg_source_textarea").val(G); -a("#svg_source_editor").fadeIn();s();a("#svg_source_textarea").focus()}},o=function(){if(!Ma){Ma=true;a("#image_save_opts input").val([e.img_save]);var k=h.getResolution();if(f.baseUnit!=="px"){k.w=svgedit.units.convertUnit(k.w)+f.baseUnit;k.h=svgedit.units.convertUnit(k.h)+f.baseUnit}a(".canvas_width").val(k.w);a(".canvas_height").val(k.h);a("#canvas_title").val(h.getDocumentTitle());a("#svg_docprops").show()}},l=function(){if(!Fa){Fa=true;var k=a("#bg_blocks div"),t=a.pref("bkgd_color"),G=a.pref("bkgd_url"); -k.each(function(){var L=a(this),O=L.css("background-color")==t;L.toggleClass("cur_background",O);O&&a("#canvas_bg_url").removeClass("cur_background")});t||k.eq(0).addClass("cur_background");G&&a("#canvas_bg_url").val(G);a("grid_snapping_step").attr("value",f.snappingStep);f.gridSnapping==true?a("#grid_snapping_on").attr("checked","checked"):a("#grid_snapping_on").removeAttr("checked");a("#svg_prefs").show()}},s=function(){var k=a("#svg_source_container").height()-50;a("#svg_source_textarea").css("height", -k)},B=function(){if(Da){var k=function(){h.clearSelection();fa();c();rb();w();ja.fill.prep();ja.stroke.prep()};h.setSvgString(a("#svg_source_textarea").val())?k():a.confirm(g.notification.QerrorsRevertToSource,function(t){if(!t)return false;k()});la()}},w=function(k){k=k||h.getDocumentTitle();k=Qa+(k?": "+k:"");a("title:first").text(k)},v=function(){var k=a("#canvas_width"),t=k.val(),G=a("#canvas_height"),L=G.val();if(t!="fit"&&!svgedit.units.isValidUnit("width",t)){a.alert(g.notification.invalidAttrValGiven); -k.parent().addClass("error");return false}k.parent().removeClass("error");if(L!="fit"&&!svgedit.units.isValidUnit("height",L)){a.alert(g.notification.invalidAttrValGiven);G.parent().addClass("error");return false}G.parent().removeClass("error");if(!h.setResolution(t,L)){a.alert(g.notification.noContentToFitTo);return false}e.img_save=a("#image_save_opts :checked").val();a.pref("img_save",e.img_save);Ob();R()},C=function(){var k=a("#bg_blocks div.cur_background").css("background-color")||"#FFF";q(k, -a("#canvas_bg_url").val());k=a("#lang_select").val();k!=e.lang&&i.putLocale(k);P(a("#iconsize").val());f.gridSnapping=a("#grid_snapping_on")[0].checked;f.snappingStep=a("#grid_snapping_step").val();f.showRulers=a("#show_rulers")[0].checked;a("#rulers").toggle(f.showRulers);f.showRulers&&ma();f.baseUnit=a("#base_unit").val();h.setConfig(f);Ob();W()},F=i.setIcon=function(k,t){var G=typeof t==="string"?a.getSvgIcon(t,true):t.clone();G?a(k).empty().append(G):console.log("NOTE: Icon image missing: "+t)}, -J;J=function(){var k=/^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/,t=document.getElementsByTagName("script")[0],G;for(G in t.style)if(k.test(G))return G.match(k)[0];if("WebkitOpacity"in t.style)return"Webkit";if("KhtmlOpacity"in t.style)return"Khtml";return""}();var K=function(k,t){J.toLowerCase();var G=["top","left","bottom","right"];k.each(function(){for(var L=a(this),O=L.outerWidth()*(t-1),S=L.outerHeight()*(t-1),da=0;da<4;da++){var oa=G[da],xa=L.data("orig_margin-"+oa);if(xa==null){xa=parseInt(L.css("margin-"+ -oa));L.data("orig_margin-"+oa,xa)}xa=xa*t;if(oa==="right")xa+=O;else if(oa==="bottom")xa+=S;L.css("margin-"+oa,xa)}})},P=i.setIconSize=function(k,t){if(!(k==e.size&&!t)){console.log("size",k);var G=a("#tools_top .toolset, #editor_panel > *, #history_panel > *,\t\t\t\t#main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\t\t\t\t#g_panel > *, #tool_font_size > *, .tools_flyout"),L=1;L=typeof k=="number"?k:{s:0.75,m:1,l:1.25,xl:1.5}[k];i.tool_scale=Z=L;zb();var O=G.parents(":hidden"); -O.css("visibility","hidden").show();K(G,L);O.css("visibility","visible").hide();a.pref("iconsize",k);a("#iconsize").val(k);O={"#tools_top":{left:50,height:72},"#tools_left":{width:31,top:74},"div#workarea":{left:38,top:74}};G=a("#tool_size_rules");if(G.length)G.empty();else G=a('').appendTo("head");if(k!="m"){var S="";a.each(O,function(da,oa){da="#svg_editor "+da.replace(/,/g,", #svg_editor");S+=da+"{";a.each(oa,function(xa,Ba){if(typeof Ba==="number")var sa=Ba* -L+"px";else if(Ba[k]||Ba.all)sa=Ba[k]||Ba.all;S+=xa+":"+sa+";"});S+="}"});O="-"+J.toLowerCase()+"-";S+="#tools_top .toolset, #editor_panel > *, #history_panel > *,\t\t\t\t#main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\t\t\t\t#g_panel > *, #tool_font_size > *, .tools_flyout{"+O+"transform: scale("+L+");} #svg_editor div.toolset .toolset {"+O+"transform: scale(1); margin: 1px !important;} #svg_editor .ui-slider {"+O+"transform: scale("+1/L+");}";G.text(S)}zb()}},ca=function(){a("#dialog_box").hide(); -if(!Da&&!Ma&&!Fa)Oa&&h.leaveContext();else{if(Da)ra!==a("#svg_source_textarea").val()?a.confirm(g.notification.QignoreSourceChanges,function(k){k&&fa()}):fa();else if(Ma)R();else Fa&&W();na()}},fa=function(){a("#svg_source_editor").hide();Da=false;a("#svg_source_textarea").blur()},R=function(){a("#svg_docprops").hide();a("#canvas_width,#canvas_height").removeAttr("disabled");a("#resolution")[0].selectedIndex=0;a("#image_save_opts input").val([e.img_save]);Ma=false},W=function(){a("#svg_prefs").hide(); -Fa=false},Y={width:a(window).width(),height:a(window).height()},na=a.noop,Xa;svgedit.browser.isIE()&&function(){na=function(){if(ha[0].scrollLeft===0&&ha[0].scrollTop===0){ha[0].scrollLeft=Xa.left;ha[0].scrollTop=Xa.top}};Xa={left:ha[0].scrollLeft,top:ha[0].scrollTop};a(window).resize(na);svgEditor.ready(function(){setTimeout(function(){na()},500)});ha.scroll(function(){Xa={left:ha[0].scrollLeft,top:ha[0].scrollTop}})}();a(window).resize(function(){Da&&s();a.each(Y,function(k,t){var G=a(window)[k](); -ha[0]["scroll"+(k==="width"?"Left":"Top")]-=(G-t)/2;Y[k]=G})});(function(){ha.scroll(function(){if(a("#ruler_x").length!=0)a("#ruler_x")[0].scrollLeft=ha[0].scrollLeft;if(a("#ruler_y").length!=0)a("#ruler_y")[0].scrollTop=ha[0].scrollTop})})();a("#url_notice").click(function(){a.alert(this.title)});a("#change_image_url").click(M);(function(){var k=["clear","open","save","source","delete","delete_multi","paste","clone","clone_multi","move_top","move_bottom"],t="";a.each(k,function(G,L){t+="#tool_"+ -L+(G==k.length-1?",":"")});a(t).mousedown(function(){a(this).addClass("tool_button_current")}).bind("mousedown mouseout",function(){a(this).removeClass("tool_button_current")});a("#tool_undo, #tool_redo").mousedown(function(){a(this).hasClass("disabled")||a(this).addClass("tool_button_current")}).bind("mousedown mouseout",function(){a(this).removeClass("tool_button_current")})})();if(ia&&!window.opera){ia=["tool_clear","tool_save","tool_source","tool_undo","tool_redo","tool_clone"];for(Va=ia.length;Va--;){var qb= -document.getElementById(ia[Va]);if(qb!=null){var Hb=qb.title,yb=Hb.indexOf("Ctrl+");qb.title=[Hb.substr(0,yb),"Cmd+",Hb.substr(yb+5)].join("")}}}var Gb=function(k){var t=k.attr("id")=="stroke_color"?"stroke":"fill",G=ja[t].paint,L=t=="stroke"?"Pick a Stroke Paint and Opacity":"Pick a Fill Paint and Opacity";k=k.position();a("#color_picker").draggable({cancel:".jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker",containment:"window"}).css(f.colorPickerCSS||{left:k.left,bottom:50-k.top}).jGraduate({paint:G, -window:{pickerTitle:L},images:{clientPath:f.jGraduatePath},newstop:"inverse"},function(O){G=new a.jGraduate.Paint(O);ja[t].setPaint(G);h.setPaint(t,G);a("#color_picker").hide()},function(){a("#color_picker").hide()})},ac=function(){var k=h.getColor("fill")=="none",t=h.getColor("stroke")=="none",G=["#tool_fhpath","#tool_line"],L=["#tools_rect .tool_button","#tools_ellipse .tool_button","#tool_text","#tool_path"];if(t)for(var O in G){var S=G[O];a(S).hasClass("tool_button_current")&&Jb();a(S).addClass("disabled")}else for(O in G){S= -G[O];a(S).removeClass("disabled")}if(t&&k)for(O in L){S=L[O];a(S).hasClass("tool_button_current")&&Jb();a(S).addClass("disabled")}else for(O in L){S=L[O];a(S).removeClass("disabled")}h.runExtensions("toolButtonStateUpdate",{nofill:k,nostroke:t});a(".tools_flyout").each(function(){var da=a("#"+this.id+"_show"),oa=false;a(this).children().each(function(){a(this).hasClass("disabled")||(oa=true)});da.toggleClass("disabled",!oa)});ab()};ia=function(k,t){var G=f[t==="fill"?"initFill":"initStroke"],L=(new DOMParser).parseFromString('\t\t\t\t\t',"text/xml").documentElement;L=a(k)[0].appendChild(document.importNode(L,true));L.setAttribute("width",24.5);this.rect=L.firstChild;this.defs=L.getElementsByTagName("defs")[0];this.grad=this.defs.firstChild;this.paint=new a.jGraduate.Paint({solidColor:G.color});this.type=t;this.setPaint=function(O,S){this.paint=O;var da="none",oa=O.type,xa=O.alpha/100;switch(oa){case "solidColor":da="#"+O[oa];break;case "linearGradient":case "radialGradient":this.defs.removeChild(this.grad); -this.grad=this.defs.appendChild(O[oa]);da="url(#"+(this.grad.id="gradbox_"+this.type)+")"}this.rect.setAttribute("fill",da);this.rect.setAttribute("opacity",xa);if(S){h.setColor(this.type,da,true);h.setPaintOpacity(this.type,xa,true)}};this.update=function(O){if(T){var S=this.type;switch(T.tagName){case "use":case "image":case "foreignObject":return;case "g":case "a":for(var da=null,oa=T.getElementsByTagName("*"),xa=0,Ba=oa.length;xa300)k=300-G;else if(G+k<2)k=2-G;if(k!=0){dc-=k;G=a("#layerpanel");ha.css("right",parseInt(ha.css("right"))+k);t.css("width",parseInt(t.css("width"))+k);G.css("width",parseInt(G.css("width"))+k);t=a("#ruler_x");t.css("right",parseInt(t.css("right"))+k)}}};a("#sidepanel_handle").mousedown(function(k){dc=k.pageX;a(window).mousemove(qc); -oc=false;setTimeout(function(){oc=true},20)}).mouseup(function(){lc||rc();dc=-1;lc=false});a(window).mouseup(function(){dc=-1;lc=false;a("#svg_editor").unbind("mousemove",qc)});var rc=function(k){var t=parseInt(a("#sidepanels").css("width"));k=(t>2||k?2:150)-t;t=a("#sidepanels");var G=a("#layerpanel"),L=a("#ruler_x");ha.css("right",parseInt(ha.css("right"))+k);t.css("width",parseInt(t.css("width"))+k);G.css("width",parseInt(G.css("width"))+k);L.css("right",parseInt(L.css("right"))+k)},sc=function(k){for(var t= -Array(h.getCurrentDrawing().getNumLayers()),G=0;G'+S+"":''+S+"";k.append(da);t.append('")}if(O!==undefined){O.clone();a("td.layervis",k).append(O.clone());a.resizeSvgIcons({"td.layervis .svg_icon":14})}a("#layerlist td.layername").mouseup(function(oa){a("#layerlist tr.layer").removeClass("layersel"); -a(this.parentNode).addClass("layersel");h.setCurrentLayer(this.textContent);oa.preventDefault()}).mouseover(function(){a(this).css({"font-style":"italic",color:"blue"});sc(this.textContent)}).mouseout(function(){a(this).css({"font-style":"normal",color:"black"});sc()});a("#layerlist td.layervis").click(function(){var oa=a(this.parentNode).prevAll().length;oa=a("#layerlist tr.layer:eq("+oa+") td.layername").text();var xa=a(this).hasClass("layerinvis");h.setLayerVisibility(oa,xa);xa?a(this).removeClass("layerinvis"): -a(this).addClass("layerinvis")});for(t=5-a("#layerlist tr.layer").size();t-- >0;)k.append('_')};rb();a(window).bind("load resize",function(){ha.css("line-height",ha.height()+"px")});a("#resolution").change(function(){var k=a("#canvas_width,#canvas_height");if(this.selectedIndex)if(this.value=="content")k.val("fit").attr("disabled","disabled");else{var t=this.value.split("x");a("#canvas_width").val(t[0]);a("#canvas_height").val(t[1]);k.removeAttr("disabled")}else a("#canvas_width").val()== -"fit"&&k.removeAttr("disabled").val(100)});a("input,select").attr("autocomplete","off");var nc=function(){var k=[{sel:"#tool_select",fn:Jb,evt:"click",key:["V",true]},{sel:"#tool_fhpath",fn:pb,evt:"click",key:["Q",true]},{sel:"#tool_line",fn:Kb,evt:"click",key:["L",true]},{sel:"#tool_rect",fn:Rb,evt:"click",key:["R",true],icon:"rect"},{sel:"#tool_ellipse",fn:Lb,evt:"mouseup",key:["C",true],icon:"ellipse"},{sel:"#tool_path",fn:ya,evt:"click",key:["P",true]},{sel:"#tool_text",fn:ua,evt:"click",key:["T", -true]},{sel:"#tool_image",fn:Sb,evt:"mouseup"},{sel:"#tool_zoom",fn:pa,evt:"mouseup",key:["Z",true]},{sel:"#tool_clear",fn:gc,evt:"mouseup",key:[X+"N",true]},{sel:"#tool_save",fn:function(){Da?B():h.save({images:e.img_save,round_digits:6})},evt:"mouseup",key:[X+"S",true]},{sel:"#tool_export",fn:$b,evt:"mouseup"},{sel:"#tool_open",fn:mc,evt:"mouseup"},{sel:"#tool_import",fn:Ub,evt:"mouseup"},{sel:"#tool_source",fn:A,evt:"click",key:[X+"U",true]},{sel:"#tool_wireframe",fn:d,evt:"click"},{sel:"#tool_rulers", -fn:n,evt:"click"},{sel:"#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel",fn:ca,evt:"click",key:["esc",false,false],hidekey:true},{sel:"#tool_source_save",fn:B,evt:"click"},{sel:"#tool_docprops_save",fn:v,evt:"click"},{sel:"#tool_docprops",fn:o,evt:"mouseup"},{sel:"#tool_prefs_save",fn:C,evt:"click"},{sel:"#tool_prefs_option",fn:function(){l();return false},evt:"mouseup"},{sel:"#tool_delete,#tool_delete_multi",fn:aa,evt:"click",key:["del/backspace",true]},{sel:"#tool_reorient", -fn:Mb,evt:"click"},{sel:"#tool_node_link",fn:Ib,evt:"click"},{sel:"#tool_node_clone",fn:Zb,evt:"click"},{sel:"#tool_node_delete",fn:Yb,evt:"click"},{sel:"#tool_openclose_path",fn:La,evt:"click"},{sel:"#tool_add_subpath",fn:fb,evt:"click"},{sel:"#tool_move_top",fn:wb,evt:"click",key:X+"shift+up"},{sel:"#tool_move_bottom",fn:tb,evt:"click",key:X+"shift+down"},{sel:"#tool_move_up",fn:Fb,evt:"click",key:[X+"up",true]},{sel:"#tool_move_down",fn:Qb,evt:"click",key:[X+"down",true]},{sel:"#tool_topath",fn:nb, -evt:"click"},{sel:"#tool_make_link,#tool_make_link_multi",fn:Ta,evt:"click"},{sel:"#tool_undo",fn:hc,evt:"click",key:[X+"Z",true]},{sel:"#tool_redo",fn:cc,evt:"click",key:["Y",true]},{sel:"#tool_clone,#tool_clone_multi",fn:jb,evt:"click",key:[X+"D",true]},{sel:"#tool_group",fn:Nb,evt:"click",key:[X+"G",true]},{sel:"#tool_ungroup",fn:Nb,evt:"click",key:X+"shift+G"},{sel:"#tool_unlink_use",fn:Nb,evt:"click"},{sel:"[id^=tool_align]",fn:ec,evt:"click"},{sel:"#tool_switch",fn:b,evt:"click",key:["X",true]}, -{sel:"#tool_bold",fn:kc,evt:"mousedown",key:[X+"B",true]},{sel:"#tool_italic",fn:Vb,evt:"mousedown",key:[X+"I",true]},{sel:"#copy_save_done",fn:ca,evt:"click"},{key:"ctrl+left",fn:function(){Tb(0,1)}},{key:"ctrl+right",fn:function(){Tb(1,1)}},{key:"ctrl+shift+left",fn:function(){Tb(0,5)}},{key:"ctrl+shift+right",fn:function(){Tb(1,5)}},{key:"shift+O",fn:bc},{key:"shift+P",fn:fc},{key:[X+"+",true],fn:function(){c(2)}},{key:[X+"-",true],fn:function(){c(0.5)}},{key:["up",true],fn:function(){eb(0,-1)}}, -{key:["down",true],fn:function(){eb(0,1)}},{key:["left",true],fn:function(){eb(-1,0)}},{key:["right",true],fn:function(){eb(1,0)}},{key:"shift+up",fn:function(){eb(0,-10)}},{key:"shift+down",fn:function(){eb(0,10)}},{key:"shift+left",fn:function(){eb(-10,0)}},{key:"shift+right",fn:function(){eb(10,0)}},{key:["alt+up",true],fn:function(){h.cloneSelectedElements(0,-1)}},{key:["alt+down",true],fn:function(){h.cloneSelectedElements(0,1)}},{key:["alt+left",true],fn:function(){h.cloneSelectedElements(-1, -0)}},{key:["alt+right",true],fn:function(){h.cloneSelectedElements(1,0)}},{key:["alt+shift+up",true],fn:function(){h.cloneSelectedElements(0,-10)}},{key:["alt+shift+down",true],fn:function(){h.cloneSelectedElements(0,10)}},{key:["alt+shift+left",true],fn:function(){h.cloneSelectedElements(-10,0)}},{key:["alt+shift+right",true],fn:function(){h.cloneSelectedElements(10,0)}},{key:X+"A",fn:function(){h.selectAllInCurrentLayer()}},{key:X+"z",fn:hc},{key:X+"shift+z",fn:cc},{key:X+"y",fn:cc},{key:X+"x", -fn:Sa},{key:X+"c",fn:Eb},{key:X+"v",fn:Ab}],t={"4/Shift+4":"#tools_rect_show","5/Shift+5":"#tools_ellipse_show"};return{setAll:function(){var G={};a.each(k,function(L,O){if(O.sel){var S=a(O.sel);if(S.length==0)return true;if(O.evt){if(svgedit.browser.isTouch()&&O.evt==="click")O.evt="mousedown";S[O.evt](O.fn)}if(O.parent&&a(O.parent+"_show").length!=0){var da=a(O.parent);da.length||(da=Aa(O.parent.substr(1)));da.append(S);a.isArray(G[O.parent])||(G[O.parent]=[]);G[O.parent].push(O)}}if(O.key){var oa= -O.fn,xa=false;if(a.isArray(O.key)){da=O.key[0];if(O.key.length>1)xa=O.key[1]}else da=O.key;da+="";svgedit.browser.isMac&&da.indexOf("+")!=-1&&da.split("+")[0]=="ctrl"&&da.replace("ctrl","cmd");a.each(da.split("/"),function(sa,Ya){a(document).bind("keydown",Ya,function(Za){oa();xa&&Za.preventDefault();return false})});if(O.sel&&!O.hidekey&&S.attr("title")){var Ba=S.attr("title").split("[")[0]+" ("+da+")";t[da]=O.sel;S.parents("#main_menu").length||S.attr("title",Ba)}}});Ha(G);a(".attr_changer, #image_url").bind("keydown", -"return",function(L){a(this).change();L.preventDefault()});a(window).bind("keydown","tab",function(L){if(ea==="canvas"){L.preventDefault();fc()}}).bind("keydown","shift+tab",function(L){if(ea==="canvas"){L.preventDefault();bc()}});a("#tool_zoom").dblclick(V)},setTitles:function(){a.each(t,function(G,L){var O=a(L).parents("#main_menu").length;a(L).each(function(){var S=O?a(this).text().split(" [")[0]:this.title.split(" [")[0],da="";a.each(G.split("/"),function(oa,xa){var Ba=xa.split("+"),sa="";if(Ba.length> -1){sa=Ba[0]+"+";xa=Ba[1]}da+=(oa?"/":"")+sa+(g["key_"+xa]||xa)});if(O)this.lastChild.textContent=S+" ["+da+"]";else this.title=S+" ["+da+"]"})})},getButtonData:function(G){var L;a.each(k,function(O,S){if(S.sel===G)L=S});return L}}}();nc.setAll();i.ready(function(){var k=f.initTool,t=a("#tools_left, #svg_editor .tools_flyout"),G=t.find("#tool_"+k);k=t.find("#"+k);(G.length?G:k.length?k:a("#tool_select")).click().mouseup();f.wireframe&&a("#tool_wireframe").click();f.showlayers&&rc();a("#rulers").toggle(!!f.showRulers); -if(f.showRulers)a("#show_rulers")[0].checked=true;if(f.gridSnapping)a("#grid_snapping_on")[0].checked=true;f.baseUnit&&a("#base_unit").val(f.baseUnit);f.snappingStep&&a("#grid_snapping_step").val(f.snappingStep)});a("#rect_rx").SpinButton({min:0,max:1E3,step:1,callback:function(k){h.setRectRadius(k.value)}});a("#stroke_width").SpinButton({min:0,max:99,step:1,smallStep:0.1,callback:function(k){var t=k.value;if(t==0&&T&&["line","polyline"].indexOf(T.nodeName)>=0)t=k.value=1;h.setStrokeWidth(t)}});a("#angle").SpinButton({min:-180, -max:180,step:5,callback:function(k){h.setRotationAngle(k.value);a("#tool_reorient").toggleClass("disabled",k.value==0)}});a("#font_size").SpinButton({step:1,min:0.0010,stepfunc:function(k,t){var G=k.value-0,L=G+t,O=L>=G;if(t===0)return G;return G>=24?O?Math.round(G*1.1):Math.round(G/1.1):G<=1?O?G*2:G/2:L},callback:function(k){h.setFontSize(k.value)}});a("#group_opacity").SpinButton({step:5,min:0,max:100,callback:kb});a("#blur").SpinButton({step:0.1,min:0,max:10,callback:Cb});a("#zoom").SpinButton({min:0.0010, -max:1E4,step:50,stepfunc:function(k,t){var G=k.value-0;if(G===0)return 100;var L=G+t;if(t===0)return G;return G>=100?L:L>=G?G*2:G/2},callback:Ia}).val(h.getZoom()*100);a("#workarea").contextMenu({menu:"cmenu_canvas",inSpeed:0},function(k){switch(k){case "delete":aa();break;case "cut":Sa();break;case "copy":Eb();break;case "paste":h.pasteElements();break;case "paste_in_place":h.pasteElements("in_place");break;case "group":h.groupSelectedElements();break;case "ungroup":h.ungroupSelectedElement();break; -case "move_front":wb();break;case "move_up":T!=null&&h.moveUpDownSelected("Up");break;case "move_down":T!=null&&h.moveUpDownSelected("Down");break;case "move_back":tb();break;default:svgedit.contextmenu&&svgedit.contextmenu.hasCustomHandler(k)&&svgedit.contextmenu.getCustomHandler(k).call()}h.clipBoard.length&&Ra.enableContextMenuItems("#paste,#paste_in_place")});ia=function(k){switch(k){case "dupe":N();break;case "delete":ba();break;case "merge_down":if(a("#layerlist tr.layersel").index()!=h.getCurrentDrawing().getNumLayers()- -1){h.mergeLayer();Ua();rb()}break;case "merge_all":h.mergeAllLayers();Ua();rb()}};a("#layerlist").contextMenu({menu:"cmenu_layers",inSpeed:0},ia);a("#layer_moreopts").contextMenu({menu:"cmenu_layers",inSpeed:0,allowLeft:true},ia);a(".contextMenu li").mousedown(function(k){k.preventDefault()});a("#cmenu_canvas li").disableContextMenu();Ra.enableContextMenuItems("#delete,#cut,#copy");window.onbeforeunload=function(){if(ga.getUndoStackSize()===0)i.show_save_warning=false;if(!f.no_save_warning&&i.show_save_warning)return g.notification.unsavedChanges}; -i.openPrep=function(k){a("#main_menu").hide();ga.getUndoStackSize()===0?k(true):a.confirm(g.notification.QwantToOpen,k)};if(window.FileReader){ia=a('').change(function(){var k=this;i.openPrep(function(t){if(t){h.clear();if(k.files.length==1){t=new FileReader;t.onloadend=function(G){H(G.target.result);Ob()};t.readAsText(k.files[0])}}})});a("#tool_open").show().prepend(ia);ia=a('').change(function(){a("#main_menu").hide();if(this.files.length==1){var k=new FileReader; -k.onloadend=function(t){h.importSvgString(t.target.result,true);Ob()};k.readAsText(this.files[0])}});a("#tool_import").show().prepend(ia)}var Ob=i.updateCanvas=function(k,t){var G=ha.width(),L=ha.height(),O=G,S=L,da=h.getZoom(),oa=a("#svgcanvas"),xa={x:ha[0].scrollLeft+O/2,y:ha[0].scrollTop+S/2},Ba=f.canvas_expansion;G=Math.max(O,h.contentW*da*Ba);L=Math.max(S,h.contentH*da*Ba);G==O&&L==S?ha.css("overflow","hidden"):ha.css("overflow","scroll");Ba=oa.height()/2;var sa=oa.width()/2;oa.width(G).height(L); -var Ya=L/2,Za=G/2,Q=h.updateCanvas(G,L),ob=Za/sa;G=G/2-O/2;L=L/2-S/2;if(t){t.x+=Q.x;t.y+=Q.y}else t={x:Za+(xa.x-sa)*ob,y:Ya+(xa.y-Ba)*ob};if(k)if(h.contentW>ha.width()){ha[0].scrollLeft=Q.x-10;ha[0].scrollTop=Q.y-10}else{ha[0].scrollLeft=G;ha[0].scrollTop=L}else{ha[0].scrollLeft=t.x-O/2;ha[0].scrollTop=t.y-S/2}if(f.showRulers){ma(oa,da);ha.scroll()}},ic=[];for(Va=0.1;Va<1E5;Va*=10){ic.push(1*Va);ic.push(2*Va);ic.push(5*Va)}Ob(true);try{var tc=function(k){if(window.JSON&&JSON.stringify)return JSON.stringify(k); -var t=arguments.callee;if(typeof k=="boolean"||typeof k=="number")return k+"";else if(typeof k=="string")return'"'+k.replace(/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,function(O){return"\\u"+("0000"+O.charCodeAt(0).toString(16)).slice(-4)})+'"';else if(k.length){for(var G=0;G");var h=H.shortcut||"";$("#cmenu_canvas").append("
    • "+H.label+""+h+"
    • ")}});svgedit.contextmenu.resetCustomMenus=function(){a.contextMenuExtensions= -{}};svgedit.contextmenu.add=function(H){if(H&&H.id&&H.label&&H.action&&typeof H.action=="function")if(H.id in a.contextMenuExtensions)console.error('Cannot add extension "'+H.id+'", an extension by that name already exists"');else{console.log("Registed contextmenu item: {id:"+H.id+", label:"+H.label+"}");a.contextMenuExtensions[H.id]=H}else console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function")};svgedit.contextmenu.hasCustomHandler= -function(H){return a.contextMenuExtensions[H]&&true};svgedit.contextmenu.getCustomHandler=function(H){return a.contextMenuExtensions[H].action}})();var svgEditor=function(a,H){function h(u,E,e){var f=a("#svg_editor").parent(),g;for(g in E){var p=E[g];p||console.log(g);if(e)g="#"+g;if(f.find(g).length){var z=f.find(g)[0];switch(u){case "content":for(var D=0;D elements. Each element should contain the markup of an SVG -icon. The element has an ID that should -correspond with the ID of the HTML element used on the page that should contain -or optionally be replaced by the icon. Additionally, one empty element should be -added at the end with id "svg_eof". - -2. Optionally create fallback raster images for each SVG icon. - -3. Include the jQuery and the SVG Icon Loader scripts on your page. - -4. Run $.svgIcons() when the document is ready: - -$.svgIcons( file [string], options [object literal]); - -File is the location of a local SVG or SVGz file. - -All options are optional and can include: - -- 'w (number)': The icon widths - -- 'h (number)': The icon heights - -- 'fallback (object literal)': List of raster images with each - key being the SVG icon ID to replace, and the value the image file name. - -- 'fallback_path (string)': The path to use for all images - listed under "fallback" - -- 'replace (boolean)': If set to true, HTML elements will be replaced by, - rather than include the SVG icon. - -- 'placement (object literal)': List with selectors for keys and SVG icon ids - as values. This provides a custom method of adding icons. - -- 'resize (object literal)': List with selectors for keys and numbers - as values. This allows an easy way to resize specific icons. - -- 'callback (function)': A function to call when all icons have been loaded. - Includes an object literal as its argument with as keys all icon IDs and the - icon as a jQuery object as its value. - -- 'id_match (boolean)': Automatically attempt to match SVG icon ids with - corresponding HTML id (default: true) - -- 'no_img (boolean)': Prevent attempting to convert the icon into an - element (may be faster, help for browser consistency) - -- 'svgz (boolean)': Indicate that the file is an SVGZ file, and thus not to - parse as XML. SVGZ files add compression benefits, but getting data from - them fails in Firefox 2 and older. - -5. To access an icon at a later point without using the callback, use this: - $.getSvgIcon(id (string)); - -This will return the icon (as jQuery object) with a given ID. - -6. To resize icons at a later point without using the callback, use this: - $.resizeSvgIcons(resizeOptions) (use the same way as the "resize" parameter) - - -Example usage #1: - -$(function() { - $.svgIcons('my_icon_set.svg'); // The SVG file that contains all icons - // No options have been set, so all icons will automatically be inserted - // into HTML elements that match the same IDs. -}); - -Example usage #2: - -$(function() { - $.svgIcons('my_icon_set.svg', { // The SVG file that contains all icons - callback: function(icons) { // Custom callback function that sets click - // events for each icon - $.each(icons, function(id, icon) { - icon.click(function() { - alert('You clicked on the icon with id ' + id); - }); - }); - } - }); //The SVG file that contains all icons -}); - -Example usage #3: - -$(function() { - $.svgIcons('my_icon_set.svgz', { // The SVGZ file that contains all icons - w: 32, // All icons will be 32px wide - h: 32, // All icons will be 32px high - fallback_path: 'icons/', // All fallback files can be found here - fallback: { - '#open_icon': 'open.png', // The "open.png" will be appended to the - // HTML element with ID "open_icon" - '#close_icon': 'close.png', - '#save_icon': 'save.png' - }, - placement: {'.open_icon','open'}, // The "open" icon will be added - // to all elements with class "open_icon" - resize: function() { - '#save_icon .svg_icon': 64 // The "save" icon will be resized to 64 x 64px - }, - - callback: function(icons) { // Sets background color for "close" icon - icons['close'].css('background','red'); - }, - - svgz: true // Indicates that an SVGZ file is being used - - }) -}); - -*/ - - -(function($) { - var svg_icons = {}, fixIDs; - - $.svgIcons = function(file, opts) { - var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - icon_w = opts.w?opts.w : 24, - icon_h = opts.h?opts.h : 24, - elems, svgdoc, testImg, - icons_made = false, data_loaded = false, load_attempts = 0, - ua = navigator.userAgent, isOpera = !!window.opera, isSafari = (ua.indexOf('Safari/') > -1 && ua.indexOf('Chrome/')==-1), - data_pre = 'data:image/svg+xml;charset=utf-8;base64,'; - - if(opts.svgz) { - var data_el = $('').appendTo('body').hide(); - try { - svgdoc = data_el[0].contentDocument; - data_el.load(getIcons); - getIcons(0, true); // Opera will not run "load" event if file is already cached - } catch(err1) { - useFallback(); - } - } else { - var parser = new DOMParser(); - $.ajax({ - url: file, - dataType: 'string', - success: function(data) { - if(!data) { - $(useFallback); - return; - } - svgdoc = parser.parseFromString(data, "text/xml"); - $(function() { - getIcons('ajax'); - }); - }, - error: function(err) { - // TODO: Fix Opera widget icon bug - if(window.opera) { - $(function() { - useFallback(); - }); - } else { - if(err.responseText) { - svgdoc = parser.parseFromString(err.responseText, "text/xml"); - - if(!svgdoc.childNodes.length) { - $(useFallback); - } - $(function() { - getIcons('ajax'); - }); - } else { - $(useFallback); - } - } - } - }); - } - - function getIcons(evt, no_wait) { - if(evt !== 'ajax') { - if(data_loaded) return; - // Webkit sometimes says svgdoc is undefined, other times - // it fails to load all nodes. Thus we must make sure the "eof" - // element is loaded. - svgdoc = data_el[0].contentDocument; // Needed again for Webkit - var isReady = (svgdoc && svgdoc.getElementById('svg_eof')); - if(!isReady && !(no_wait && isReady)) { - load_attempts++; - if(load_attempts < 50) { - setTimeout(getIcons, 20); - } else { - useFallback(); - data_loaded = true; - } - return; - } - data_loaded = true; - } - - elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent'); - - if(!opts.no_img) { - var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; - - testImg = $(new Image()).attr({ - src: testSrc, - width: 0, - height: 0 - }).appendTo('body') - .load(function () { - // Safari 4 crashes, Opera and Chrome don't - makeIcons(true); - }).error(function () { - makeIcons(); - }); - } else { - setTimeout(function() { - if(!icons_made) makeIcons(); - },500); - } - } - - var setIcon = function(target, icon, id, setID) { - if(isOpera) icon.css('visibility','hidden'); - if(opts.replace) { - if(setID) icon.attr('id',id); - var cl = target.attr('class'); - if(cl) icon.attr('class','svg_icon '+cl); - target.replaceWith(icon); - } else { - - target.append(icon); - } - if(isOpera) { - setTimeout(function() { - icon.removeAttr('style'); - },1); - } - } - - var addIcon = function(icon, id) { - if(opts.id_match === undefined || opts.id_match !== false) { - setIcon(holder, icon, id, true); - } - svg_icons[id] = icon; - } - - function makeIcons(toImage, fallback) { - if(icons_made) return; - if(opts.no_img) toImage = false; - var holder; - - if(toImage) { - var temp_holder = $(document.createElement('div')); - temp_holder.hide().appendTo('body'); - } - if(fallback) { - var path = opts.fallback_path?opts.fallback_path:''; - $.each(fallback, function(id, imgsrc) { - holder = $('#' + id); - var icon = $(new Image()) - .attr({ - 'class':'svg_icon', - src: path + imgsrc, - 'width': icon_w, - 'height': icon_h, - 'alt': 'icon' - }); - - addIcon(icon, id); - }); - } else { - var len = elems.length; - for(var i = 0; i < len; i++) { - var elem = elems[i]; - var id = elem.id; - if(id === 'svg_eof') break; - holder = $('#' + id); - var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; - var svgroot = document.createElementNS(svgns, "svg"); - svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' ')); - // Make flexible by converting width/height to viewBox - var w = svg.getAttribute('width'); - var h = svg.getAttribute('height'); - svg.removeAttribute('width'); - svg.removeAttribute('height'); - - var vb = svg.getAttribute('viewBox'); - if(!vb) { - svg.setAttribute('viewBox', [0,0,w,h].join(' ')); - } - - // Not using jQuery to be a bit faster - svgroot.setAttribute('xmlns', svgns); - svgroot.setAttribute('width', icon_w); - svgroot.setAttribute('height', icon_h); - svgroot.setAttribute("xmlns:xlink", xlinkns); - svgroot.setAttribute("class", 'svg_icon'); - - // Without cloning, Firefox will make another GET request. - // With cloning, causes issue in Opera/Win/Non-EN - if(!isOpera) svg = svg.cloneNode(true); - - svgroot.appendChild(svg); - - if(toImage) { - // Without cloning, Safari will crash - // With cloning, causes issue in Opera/Win/Non-EN - var svgcontent = isOpera?svgroot:svgroot.cloneNode(true); - temp_holder.empty().append(svgroot); - var str = data_pre + encode64(temp_holder.html()); - var icon = $(new Image()) - .attr({'class':'svg_icon', src:str}); - } else { - var icon = fixIDs($(svgroot), i); - } - addIcon(icon, id); - } - - } - - if(opts.placement) { - $.each(opts.placement, function(sel, id) { - if(!svg_icons[id]) return; - $(sel).each(function(i) { - var copy = svg_icons[id].clone(); - if(i > 0 && !toImage) copy = fixIDs(copy, i, true); - setIcon($(this), copy, id); - }) - }); - } - if(!fallback) { - if(toImage) temp_holder.remove(); - if(data_el) data_el.remove(); - if(testImg) testImg.remove(); - } - if(opts.resize) $.resizeSvgIcons(opts.resize); - icons_made = true; - - if(opts.callback) opts.callback(svg_icons); - } - - fixIDs = function(svg_el, svg_num, force) { - var defs = svg_el.find('defs'); - if(!defs.length) return svg_el; - - if(isOpera) { - var id_elems = defs.find('*').filter(function() { - return !!this.id; - }); - } else { - var id_elems = defs.find('[id]'); - } - - var all_elems = svg_el[0].getElementsByTagName('*'), len = all_elems.length; - - id_elems.each(function(i) { - var id = this.id; - var no_dupes = ($(svgdoc).find('#' + id).length <= 1); - if(isOpera) no_dupes = false; // Opera didn't clone svg_el, so not reliable - // if(!force && no_dupes) return; - var new_id = 'x' + id + svg_num + i; - this.id = new_id; - - var old_val = 'url(#' + id + ')'; - var new_val = 'url(#' + new_id + ')'; - - // Selector method, possibly faster but fails in Opera / jQuery 1.4.3 -// svg_el.find('[fill="url(#' + id + ')"]').each(function() { -// this.setAttribute('fill', 'url(#' + new_id + ')'); -// }).end().find('[stroke="url(#' + id + ')"]').each(function() { -// this.setAttribute('stroke', 'url(#' + new_id + ')'); -// }).end().find('use').each(function() { -// if(this.getAttribute('xlink:href') == '#' + id) { -// this.setAttributeNS(xlinkns,'href','#' + new_id); -// } -// }).end().find('[filter="url(#' + id + ')"]').each(function() { -// this.setAttribute('filter', 'url(#' + new_id + ')'); -// }); - - for(var i = 0; i < len; i++) { - var elem = all_elems[i]; - if(elem.getAttribute('fill') === old_val) { - elem.setAttribute('fill', new_val); - } - if(elem.getAttribute('stroke') === old_val) { - elem.setAttribute('stroke', new_val); - } - if(elem.getAttribute('filter') === old_val) { - elem.setAttribute('filter', new_val); - } - } - }); - return svg_el; - } - - function useFallback() { - if(file.indexOf('.svgz') != -1) { - var reg_file = file.replace('.svgz','.svg'); - if(window.console) { - console.log('.svgz failed, trying with .svg'); - } - $.svgIcons(reg_file, opts); - } else if(opts.fallback) { - makeIcons(false, opts.fallback); - } - } - - function encode64(input) { - // base64 strings are 4/3 larger than the original string - if(window.btoa) return window.btoa(input); - var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0, p = 0; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = _keyStr.charAt(enc1); - output[p++] = _keyStr.charAt(enc2); - output[p++] = _keyStr.charAt(enc3); - output[p++] = _keyStr.charAt(enc4); - } while (i < input.length); - - return output.join(''); - } - } - - $.getSvgIcon = function(id, uniqueClone) { - var icon = svg_icons[id]; - if(uniqueClone && icon) { - icon = fixIDs(icon, 0, true).clone(true); - } - return icon; - } - - $.resizeSvgIcons = function(obj) { - // FF2 and older don't detect .svg_icon, so we change it detect svg elems instead - var change_sel = !$('.svg_icon:first').length; - $.each(obj, function(sel, size) { - var arr = $.isArray(size); - var w = arr?size[0]:size, - h = arr?size[1]:size; - if(change_sel) { - sel = sel.replace(/\.svg_icon/g,'svg'); - } - $(sel).each(function() { - this.setAttribute('width', w); - this.setAttribute('height', h); - if(window.opera && window.widget) { - this.parentNode.style.width = w + 'px'; - this.parentNode.style.height = h + 'px'; - } - }); - }); - } - -})(jQuery); \ No newline at end of file diff --git a/build/firefox/content/editor/svgtransformlist.js b/build/firefox/content/editor/svgtransformlist.js deleted file mode 100644 index 5c291ca..0000000 --- a/build/firefox/content/editor/svgtransformlist.js +++ /dev/null @@ -1,291 +0,0 @@ -/** - * SVGTransformList - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) browser.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.transformlist) { - svgedit.transformlist = {}; -} - -var svgroot = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - -// Helper function. -function transformToString(xform) { - var m = xform.matrix, - text = ""; - switch(xform.type) { - case 1: // MATRIX - text = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - break; - case 2: // TRANSLATE - text = "translate(" + m.e + "," + m.f + ")"; - break; - case 3: // SCALE - if (m.a == m.d) text = "scale(" + m.a + ")"; - else text = "scale(" + m.a + "," + m.d + ")"; - break; - case 4: // ROTATE - var cx = 0, cy = 0; - // this prevents divide by zero - if (xform.angle != 0) { - var K = 1 - m.a; - cy = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b ); - cx = ( m.e - m.b * cy ) / K; - } - text = "rotate(" + xform.angle + " " + cx + "," + cy + ")"; - break; - } - return text; -}; - - -/** - * Map of SVGTransformList objects. - */ -var listMap_ = {}; - - -// ************************************************************************************** -// SVGTransformList implementation for Webkit -// These methods do not currently raise any exceptions. -// These methods also do not check that transforms are being inserted. This is basically -// implementing as much of SVGTransformList that we need to get the job done. -// -// interface SVGEditTransformList { -// attribute unsigned long numberOfItems; -// void clear ( ) -// SVGTransform initialize ( in SVGTransform newItem ) -// SVGTransform getItem ( in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform insertItemBefore ( in SVGTransform newItem, in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform replaceItem ( in SVGTransform newItem, in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform removeItem ( in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform appendItem ( in SVGTransform newItem ) -// NOT IMPLEMENTED: SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix ); -// NOT IMPLEMENTED: SVGTransform consolidate ( ); -// } -// ************************************************************************************** -svgedit.transformlist.SVGTransformList = function(elem) { - this._elem = elem || null; - this._xforms = []; - // TODO: how do we capture the undo-ability in the changed transform list? - this._update = function() { - var tstr = ""; - var concatMatrix = svgroot.createSVGMatrix(); - for (var i = 0; i < this.numberOfItems; ++i) { - var xform = this._list.getItem(i); - tstr += transformToString(xform) + " "; - } - this._elem.setAttribute("transform", tstr); - }; - this._list = this; - this._init = function() { - // Transform attribute parser - var str = this._elem.getAttribute("transform"); - if(!str) return; - - // TODO: Add skew support in future - var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; - var arr = []; - var m = true; - while(m) { - m = str.match(re); - str = str.replace(re,''); - if(m && m[1]) { - var x = m[1]; - var bits = x.split(/\s*\(/); - var name = bits[0]; - var val_bits = bits[1].match(/\s*(.*?)\s*\)/); - val_bits[1] = val_bits[1].replace(/(\d)-/g, "$1 -"); - var val_arr = val_bits[1].split(/[, ]+/); - var letters = 'abcdef'.split(''); - var mtx = svgroot.createSVGMatrix(); - $.each(val_arr, function(i, item) { - val_arr[i] = parseFloat(item); - if(name == 'matrix') { - mtx[letters[i]] = val_arr[i]; - } - }); - var xform = svgroot.createSVGTransform(); - var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1); - var values = name=='matrix'?[mtx]:val_arr; - - if (name == 'scale' && values.length == 1) { - values.push(values[0]); - } else if (name == 'translate' && values.length == 1) { - values.push(0); - } else if (name == 'rotate' && values.length == 1) { - values.push(0); - values.push(0); - } - xform[fname].apply(xform, values); - this._list.appendItem(xform); - } - } - }; - this._removeFromOtherLists = function(item) { - if (item) { - // Check if this transform is already in a transformlist, and - // remove it if so. - var found = false; - for (var id in listMap_) { - var tl = listMap_[id]; - for (var i = 0, len = tl._xforms.length; i < len; ++i) { - if(tl._xforms[i] == item) { - found = true; - tl.removeItem(i); - break; - } - } - if (found) { - break; - } - } - } - }; - - this.numberOfItems = 0; - this.clear = function() { - this.numberOfItems = 0; - this._xforms = []; - }; - - this.initialize = function(newItem) { - this.numberOfItems = 1; - this._removeFromOtherLists(newItem); - this._xforms = [newItem]; - }; - - this.getItem = function(index) { - if (index < this.numberOfItems && index >= 0) { - return this._xforms[index]; - } - throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR - }; - - this.insertItemBefore = function(newItem, index) { - var retValue = null; - if (index >= 0) { - if (index < this.numberOfItems) { - this._removeFromOtherLists(newItem); - var newxforms = new Array(this.numberOfItems + 1); - // TODO: use array copying and slicing - for ( var i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - newxforms[i] = newItem; - for ( var j = i+1; i < this.numberOfItems; ++j, ++i) { - newxforms[j] = this._xforms[i]; - } - this.numberOfItems++; - this._xforms = newxforms; - retValue = newItem; - this._list._update(); - } - else { - retValue = this._list.appendItem(newItem); - } - } - return retValue; - }; - - this.replaceItem = function(newItem, index) { - var retValue = null; - if (index < this.numberOfItems && index >= 0) { - this._removeFromOtherLists(newItem); - this._xforms[index] = newItem; - retValue = newItem; - this._list._update(); - } - return retValue; - }; - - this.removeItem = function(index) { - if (index < this.numberOfItems && index >= 0) { - var retValue = this._xforms[index]; - var newxforms = new Array(this.numberOfItems - 1); - for (var i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - for (var j = i; j < this.numberOfItems-1; ++j, ++i) { - newxforms[j] = this._xforms[i+1]; - } - this.numberOfItems--; - this._xforms = newxforms; - this._list._update(); - return retValue; - } else { - throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR - } - }; - - this.appendItem = function(newItem) { - this._removeFromOtherLists(newItem); - this._xforms.push(newItem); - this.numberOfItems++; - this._list._update(); - return newItem; - }; -}; - - -svgedit.transformlist.resetListMap = function() { - listMap_ = {}; -}; - -/** - * Removes transforms of the given element from the map. - * Parameters: - * elem - a DOM Element - */ -svgedit.transformlist.removeElementFromListMap = function(elem) { - if (elem.id && listMap_[elem.id]) { - delete listMap_[elem.id]; - } -}; - -// Function: getTransformList -// Returns an object that behaves like a SVGTransformList for the given DOM element -// -// Parameters: -// elem - DOM element to get a transformlist from -svgedit.transformlist.getTransformList = function(elem) { - if (!svgedit.browser.supportsNativeTransformLists()) { - var id = elem.id; - if(!id) { - // Get unique ID for temporary element - id = 'temp'; - } - var t = listMap_[id]; - if (!t || id == 'temp') { - listMap_[id] = new svgedit.transformlist.SVGTransformList(elem); - listMap_[id]._init(); - t = listMap_[id]; - } - return t; - } - else if (elem.transform) { - return elem.transform.baseVal; - } - else if (elem.gradientTransform) { - return elem.gradientTransform.baseVal; - } - else if (elem.patternTransform) { - return elem.patternTransform.baseVal; - } - - return null; -}; - - -})(); \ No newline at end of file diff --git a/build/firefox/content/editor/svgutils.js b/build/firefox/content/editor/svgutils.js deleted file mode 100644 index a3a6b49..0000000 --- a/build/firefox/content/editor/svgutils.js +++ /dev/null @@ -1,648 +0,0 @@ -/** - * Package: svgedit.utilities - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.utilities) { - svgedit.utilities = {}; -} - -// Constants - -// String used to encode base64. -var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -var SVGNS = 'http://www.w3.org/2000/svg'; -var XLINKNS = 'http://www.w3.org/1999/xlink'; -var XMLNS = "http://www.w3.org/XML/1998/namespace"; - -// Much faster than running getBBox() every time -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); -//var hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath'; - -var editorContext_ = null; -var domdoc_ = null; -var domcontainer_ = null; -var svgroot_ = null; - -svgedit.utilities.init = function(editorContext) { - editorContext_ = editorContext; - domdoc_ = editorContext.getDOMDocument(); - domcontainer_ = editorContext.getDOMContainer(); - svgroot_ = editorContext.getSVGRoot(); -}; - -// Function: svgedit.utilities.toXml -// Converts characters in a string to XML-friendly entities. -// -// Example: "&" becomes "&" -// -// Parameters: -// str - The string to be converted -// -// Returns: -// The converted string -svgedit.utilities.toXml = function(str) { - return $('

      ').text(str).html(); -}; - -// Function: svgedit.utilities.fromXml -// Converts XML entities in a string to single characters. -// Example: "&" becomes "&" -// -// Parameters: -// str - The string to be converted -// -// Returns: -// The converted string -svgedit.utilities.fromXml = function(str) { - return $('

      ').html(str).text(); -}; - -// This code was written by Tyler Akins and has been placed in the -// public domain. It would be nice if you left this header intact. -// Base64 code from Tyler Akins -- http://rumkin.com - -// schiller: Removed string concatenation in favour of Array.join() optimization, -// also precalculate the size of the array needed. - -// Function: svgedit.utilities.encode64 -// Converts a string to base64 -svgedit.utilities.encode64 = function(input) { - // base64 strings are 4/3 larger than the original string -// input = svgedit.utilities.encodeUTF8(input); // convert non-ASCII characters - input = svgedit.utilities.convertToXMLReferences(input); - if(window.btoa) return window.btoa(input); // Use native if available - var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0, p = 0; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = KEYSTR.charAt(enc1); - output[p++] = KEYSTR.charAt(enc2); - output[p++] = KEYSTR.charAt(enc3); - output[p++] = KEYSTR.charAt(enc4); - } while (i < input.length); - - return output.join(''); -}; - -// Function: svgedit.utilities.decode64 -// Converts a string from base64 -svgedit.utilities.decode64 = function(input) { - if(window.atob) return window.atob(input); - var output = ""; - var chr1, chr2, chr3 = ""; - var enc1, enc2, enc3, enc4 = ""; - var i = 0; - - // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - do { - enc1 = KEYSTR.indexOf(input.charAt(i++)); - enc2 = KEYSTR.indexOf(input.charAt(i++)); - enc3 = KEYSTR.indexOf(input.charAt(i++)); - enc4 = KEYSTR.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - chr1 = chr2 = chr3 = ""; - enc1 = enc2 = enc3 = enc4 = ""; - - } while (i < input.length); - return unescape(output); -}; - -// Currently not being used, so commented out for now -// based on http://phpjs.org/functions/utf8_encode:577 -// codedread:does not seem to work with webkit-based browsers on OSX -// "encodeUTF8": function(input) { -// //return unescape(encodeURIComponent(input)); //may or may not work -// var output = ''; -// for (var n = 0; n < input.length; n++){ -// var c = input.charCodeAt(n); -// if (c < 128) { -// output += input[n]; -// } -// else if (c > 127) { -// if (c < 2048){ -// output += String.fromCharCode((c >> 6) | 192); -// } -// else { -// output += String.fromCharCode((c >> 12) | 224) + String.fromCharCode((c >> 6) & 63 | 128); -// } -// output += String.fromCharCode((c & 63) | 128); -// } -// } -// return output; -// }, - -// Function: svgedit.utilities.convertToXMLReferences -// Converts a string to use XML references -svgedit.utilities.convertToXMLReferences = function(input) { - var output = ''; - for (var n = 0; n < input.length; n++){ - var c = input.charCodeAt(n); - if (c < 128) { - output += input[n]; - } else if(c > 127) { - output += ("&#" + c + ";"); - } - } - return output; -}; - -// Function: svgedit.utilities.text2xml -// Cross-browser compatible method of converting a string to an XML tree -// found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f -svgedit.utilities.text2xml = function(sXML) { - if(sXML.indexOf('= 0) { - sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns'); - } - - var out; - try{ - var dXML = (window.DOMParser)?new DOMParser():new ActiveXObject("Microsoft.XMLDOM"); - dXML.async = false; - } catch(e){ - throw new Error("XML Parser could not be instantiated"); - }; - try{ - if(dXML.loadXML) out = (dXML.loadXML(sXML))?dXML:false; - else out = dXML.parseFromString(sXML, "text/xml"); - } - catch(e){ throw new Error("Error parsing XML string"); }; - return out; -}; - -// Function: svgedit.utilities.bboxToObj -// Converts a SVGRect into an object. -// -// Parameters: -// bbox - a SVGRect -// -// Returns: -// An object with properties names x, y, width, height. -svgedit.utilities.bboxToObj = function(bbox) { - return { - x: bbox.x, - y: bbox.y, - width: bbox.width, - height: bbox.height - } -}; - -// Function: svgedit.utilities.walkTree -// Walks the tree and executes the callback on each element in a top-down fashion -// -// Parameters: -// elem - DOM element to traverse -// cbFn - Callback function to run on each element -svgedit.utilities.walkTree = function(elem, cbFn){ - if (elem && elem.nodeType == 1) { - cbFn(elem); - var i = elem.childNodes.length; - while (i--) { - svgedit.utilities.walkTree(elem.childNodes.item(i), cbFn); - } - } -}; - -// Function: svgedit.utilities.walkTreePost -// Walks the tree and executes the callback on each element in a depth-first fashion -// TODO: FIXME: Shouldn't this be calling walkTreePost? -// -// Parameters: -// elem - DOM element to traverse -// cbFn - Callback function to run on each element -svgedit.utilities.walkTreePost = function(elem, cbFn) { - if (elem && elem.nodeType == 1) { - var i = elem.childNodes.length; - while (i--) { - svgedit.utilities.walkTree(elem.childNodes.item(i), cbFn); - } - cbFn(elem); - } -}; - -// Function: svgedit.utilities.getUrlFromAttr -// Extracts the URL from the url(...) syntax of some attributes. -// Three variants: -// * -// * -// * -// -// Parameters: -// attrVal - The attribute value as a string -// -// Returns: -// String with just the URL, like someFile.svg#foo -svgedit.utilities.getUrlFromAttr = function(attrVal) { - if (attrVal) { - // url("#somegrad") - if (attrVal.indexOf('url("') === 0) { - return attrVal.substring(5,attrVal.indexOf('"',6)); - } - // url('#somegrad') - else if (attrVal.indexOf("url('") === 0) { - return attrVal.substring(5,attrVal.indexOf("'",6)); - } - else if (attrVal.indexOf("url(") === 0) { - return attrVal.substring(4,attrVal.indexOf(')')); - } - } - return null; -}; - -// Function: svgedit.utilities.getHref -// Returns the given element's xlink:href value -svgedit.utilities.getHref = function(elem) { - return elem.getAttributeNS(XLINKNS, "href"); -} - -// Function: svgedit.utilities.setHref -// Sets the given element's xlink:href value -svgedit.utilities.setHref = function(elem, val) { - elem.setAttributeNS(XLINKNS, "xlink:href", val); -} - -// Function: findDefs -// Parameters: -// svgElement - The element. -// -// Returns: -// The document's element, create it first if necessary -svgedit.utilities.findDefs = function(svgElement) { - var svgElement = editorContext_.getSVGContent().documentElement; - var defs = svgElement.getElementsByTagNameNS(SVGNS, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - // first child is a comment, so call nextSibling - defs = svgElement.insertBefore( svgElement.ownerDocument.createElementNS(SVGNS, "defs" ), svgElement.firstChild.nextSibling); - } - return defs; -}; - -// TODO(codedread): Consider moving the next to functions to bbox.js - -// Function: svgedit.utilities.getPathBBox -// Get correct BBox for a path in Webkit -// Converted from code found here: -// http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html -// -// Parameters: -// path - The path DOM element to get the BBox for -// -// Returns: -// A BBox-like object -svgedit.utilities.getPathBBox = function(path) { - var seglist = path.pathSegList; - var tot = seglist.numberOfItems; - - var bounds = [[], []]; - var start = seglist.getItem(0); - var P0 = [start.x, start.y]; - - for(var i=0; i < tot; i++) { - var seg = seglist.getItem(i); - - if(typeof seg.x == 'undefined') continue; - - // Add actual points to limits - bounds[0].push(P0[0]); - bounds[1].push(P0[1]); - - if(seg.x1) { - var P1 = [seg.x1, seg.y1], - P2 = [seg.x2, seg.y2], - P3 = [seg.x, seg.y]; - - for(var j=0; j < 2; j++) { - - var calc = function(t) { - return Math.pow(1-t,3) * P0[j] - + 3 * Math.pow(1-t,2) * t * P1[j] - + 3 * (1-t) * Math.pow(t,2) * P2[j] - + Math.pow(t,3) * P3[j]; - }; - - var b = 6 * P0[j] - 12 * P1[j] + 6 * P2[j]; - var a = -3 * P0[j] + 9 * P1[j] - 9 * P2[j] + 3 * P3[j]; - var c = 3 * P1[j] - 3 * P0[j]; - - if(a == 0) { - if(b == 0) { - continue; - } - var t = -c / b; - if(0 < t && t < 1) { - bounds[j].push(calc(t)); - } - continue; - } - - var b2ac = Math.pow(b,2) - 4 * c * a; - if(b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac))/(2 * a); - if(0 < t1 && t1 < 1) bounds[j].push(calc(t1)); - var t2 = (-b - Math.sqrt(b2ac))/(2 * a); - if(0 < t2 && t2 < 1) bounds[j].push(calc(t2)); - } - P0 = P3; - } else { - bounds[0].push(seg.x); - bounds[1].push(seg.y); - } - } - - var x = Math.min.apply(null, bounds[0]); - var w = Math.max.apply(null, bounds[0]) - x; - var y = Math.min.apply(null, bounds[1]); - var h = Math.max.apply(null, bounds[1]) - y; - return { - 'x': x, - 'y': y, - 'width': w, - 'height': h - }; -}; - -// Function: groupBBFix -// Get the given/selected element's bounding box object, checking for -// horizontal/vertical lines (see issue 717) -// Note that performance is currently terrible, so some way to improve would -// be great. -// -// Parameters: -// selected - Container or DOM element -function groupBBFix(selected) { - if(svgedit.browser.supportsHVLineContainerBBox()) { - try { return selected.getBBox();} catch(e){} - } - var ref = $.data(selected, 'ref'); - var matched = null; - - if(ref) { - var copy = $(ref).children().clone().attr('visibility', 'hidden'); - $(svgroot_).append(copy); - matched = copy.filter('line, path'); - } else { - matched = $(selected).find('line, path'); - } - - var issue = false; - if(matched.length) { - matched.each(function() { - var bb = this.getBBox(); - if(!bb.width || !bb.height) { - issue = true; - } - }); - if(issue) { - var elems = ref ? copy : $(selected).children(); - ret = getStrokedBBox(elems); - } else { - ret = selected.getBBox(); - } - } else { - ret = selected.getBBox(); - } - if(ref) { - copy.remove(); - } - return ret; -} - -// Function: svgedit.utilities.getBBox -// Get the given/selected element's bounding box object, convert it to be more -// usable when necessary -// -// Parameters: -// elem - Optional DOM element to get the BBox for -svgedit.utilities.getBBox = function(elem) { - var selected = elem || editorContext_.geSelectedElements()[0]; - if (elem.nodeType != 1) return null; - var ret = null; - var elname = selected.nodeName; - - switch ( elname ) { - case 'text': - if(selected.textContent === '') { - selected.textContent = 'a'; // Some character needed for the selector to use. - ret = selected.getBBox(); - selected.textContent = ''; - } else { - try { ret = selected.getBBox();} catch(e){} - } - break; - case 'path': - if(!svgedit.browser.supportsPathBBox()) { - ret = svgedit.utilities.getPathBBox(selected); - } else { - try { ret = selected.getBBox();} catch(e){} - } - break; - case 'g': - case 'a': - ret = groupBBFix(selected); - break; - default: - - if(elname === 'use') { - ret = groupBBFix(selected, true); - } - - if(elname === 'use') { - if(!ret) ret = selected.getBBox(); - if(!svgedit.browser.isWebkit()) { - var bb = {}; - bb.width = ret.width; - bb.height = ret.height; - bb.x = ret.x + parseFloat(selected.getAttribute('x')||0); - bb.y = ret.y + parseFloat(selected.getAttribute('y')||0); - ret = bb; - } - } else if(~visElems_arr.indexOf(elname)) { - try { ret = selected.getBBox();} - 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; - } - } - } - } - - if(ret) { - ret = svgedit.utilities.bboxToObj(ret); - } - - // get the bounding box from the DOM (which is in that element's coordinate system) - return ret; -}; - -// Function: svgedit.utilities.getRotationAngle -// Get the rotation angle of the given/selected DOM element -// -// Parameters: -// elem - Optional DOM element to get the angle for -// to_rad - Boolean that when true returns the value in radians rather than degrees -// -// Returns: -// Float with the angle in degrees or radians -svgedit.utilities.getRotationAngle = function(elem, to_rad) { - var selected = elem || editorContext_.getSelectedElements()[0]; - // find the rotation transform (if any) and set it - var tlist = svgedit.transformlist.getTransformList(selected); - if(!tlist) return 0; // elements have no tlist - var N = tlist.numberOfItems; - for (var i = 0; i < N; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - return to_rad ? xform.angle * Math.PI / 180.0 : xform.angle; - } - } - return 0.0; -}; - -// Function: getElem -// Get a DOM element by ID within the SVG root element. -// -// Parameters: -// id - String with the element's new ID -if (svgedit.browser.supportsSelectors()) { - svgedit.utilities.getElem = function(id) { - // querySelector lookup - return svgroot_.querySelector('#'+id); - }; -} else if (svgedit.browser.supportsXpath()) { - svgedit.utilities.getElem = function(id) { - // xpath lookup - return domdoc_.evaluate( - 'svg:svg[@id="svgroot"]//svg:*[@id="'+id+'"]', - domcontainer_, - function() { return "http://www.w3.org/2000/svg"; }, - 9, - null).singleNodeValue; - }; -} else { - svgedit.utilities.getElem = function(id) { - // jQuery lookup: twice as slow as xpath in FF - return $(svgroot_).find('[id=' + id + ']')[0]; - }; -} - -// Function: assignAttributes -// Assigns multiple attributes to an element. -// -// Parameters: -// node - DOM element to apply new attribute values to -// attrs - Object with attribute keys/values -// suspendLength - Optional integer of milliseconds to suspend redraw -// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr -svgedit.utilities.assignAttributes = function(node, attrs, suspendLength, unitCheck) { - if(!suspendLength) suspendLength = 0; - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!svgedit.browser.isOpera()) svgroot_.suspendRedraw(suspendLength); - - for (var i in attrs) { - var ns = (i.substr(0,4) === "xml:" ? XMLNS : - i.substr(0,6) === "xlink:" ? XLINKNS : null); - - if(ns) { - node.setAttributeNS(ns, i, attrs[i]); - } else if(!unitCheck) { - node.setAttribute(i, attrs[i]); - } else { - svgedit.units.setUnitAttr(node, i, attrs[i]); - } - - } - - if (!svgedit.browser.isOpera()) svgroot_.unsuspendRedraw(handle); -}; - -// Function: cleanupElement -// Remove unneeded (default) attributes, makes resulting SVG smaller -// -// Parameters: -// element - DOM element to clean up -svgedit.utilities.cleanupElement = function(element) { - var handle = svgroot_.suspendRedraw(60); - var defaults = { - 'fill-opacity':1, - 'stop-opacity':1, - 'opacity':1, - 'stroke':'none', - 'stroke-dasharray':'none', - 'stroke-linejoin':'miter', - 'stroke-linecap':'butt', - 'stroke-opacity':1, - 'stroke-width':1, - 'rx':0, - 'ry':0 - } - - for(var attr in defaults) { - var val = defaults[attr]; - if(element.getAttribute(attr) == val) { - element.removeAttribute(attr); - } - } - - svgroot_.unsuspendRedraw(handle); -}; - - -})(); diff --git a/build/firefox/content/editor/touch.js b/build/firefox/content/editor/touch.js deleted file mode 100644 index 7db1544..0000000 --- a/build/firefox/content/editor/touch.js +++ /dev/null @@ -1,28 +0,0 @@ -function touchHandler(event) -{ - - var touches = event.changedTouches, - first = touches[0], - type = ""; - switch(event.type) - { - case "touchstart": type="mousedown"; break; - case "touchmove": type="mousemove"; break; - case "touchend": type="mouseup"; break; - default: return; - } - - //initMouseEvent(type, canBubble, cancelable, view, clickCount, - // screenX, screenY, clientX, clientY, ctrlKey, - // altKey, shiftKey, metaKey, button, relatedTarget); - - var simulatedEvent = document.createEvent("MouseEvent"); - simulatedEvent.initMouseEvent(type, true, true, window, 1, - first.screenX, first.screenY, - first.clientX, first.clientY, false, - false, false, false, 0/*left*/, null); - if(touches.length < 2) { - first.target.dispatchEvent(simulatedEvent); - event.preventDefault(); - } -} diff --git a/build/firefox/content/editor/units.js b/build/firefox/content/editor/units.js deleted file mode 100644 index f2b30e7..0000000 --- a/build/firefox/content/editor/units.js +++ /dev/null @@ -1,281 +0,0 @@ -/** - * Package: svgedit.units - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.units) { - svgedit.units = {}; -} - -var w_attrs = ['x', 'x1', 'cx', 'rx', 'width']; -var h_attrs = ['y', 'y1', 'cy', 'ry', 'height']; -var unit_attrs = $.merge(['r','radius'], w_attrs); - -var unitNumMap = { - '%': 2, - 'em': 3, - 'ex': 4, - 'px': 5, - 'cm': 6, - 'mm': 7, - 'in': 8, - 'pt': 9, - 'pc': 10 -}; - -$.merge(unit_attrs, h_attrs); - -// Container of elements. -var elementContainer_; - -/** - * Stores mapping of unit type to user coordinates. - */ -var typeMap_ = {px: 1}; - -/** - * ElementContainer interface - * - * function getBaseUnit() - returns a string of the base unit type of the container ("em") - * function getElement() - returns an element in the container given an id - * function getHeight() - returns the container's height - * function getWidth() - returns the container's width - * function getRoundDigits() - returns the number of digits number should be rounded to - */ - -/** - * Function: svgedit.units.init() - * Initializes this module. - * - * Parameters: - * elementContainer - an object implementing the ElementContainer interface. - */ -svgedit.units.init = function(elementContainer) { - elementContainer_ = elementContainer; - - var svgns = 'http://www.w3.org/2000/svg'; - - // Get correct em/ex values by creating a temporary SVG. - var svg = document.createElementNS(svgns, 'svg'); - document.body.appendChild(svg); - var rect = document.createElementNS(svgns,'rect'); - rect.setAttribute('width',"1em"); - rect.setAttribute('height',"1ex"); - rect.setAttribute('x',"1in"); - svg.appendChild(rect); - var bb = rect.getBBox(); - document.body.removeChild(svg); - - var inch = bb.x; - typeMap_['em'] = bb.width; - typeMap_['ex'] = bb.height; - typeMap_['in'] = inch; - typeMap_['cm'] = inch / 2.54; - typeMap_['mm'] = inch / 25.4; - typeMap_['pt'] = inch / 72; - typeMap_['pc'] = inch / 6; - typeMap_['%'] = 0; -}; - -// Group: Unit conversion functions - -// Function: svgedit.units.getTypeMap -// Returns the unit object with values for each unit -svgedit.units.getTypeMap = function() { - return typeMap_; -}; - -// Function: svgedit.units.shortFloat -// Rounds a given value to a float with number of digits defined in save_options -// -// Parameters: -// val - The value as a String, Number or Array of two numbers to be rounded -// -// Returns: -// If a string/number was given, returns a Float. If an array, return a string -// with comma-seperated floats -svgedit.units.shortFloat = function(val) { - var digits = elementContainer_.getRoundDigits(); - if(!isNaN(val)) { - // Note that + converts to Number - return +((+val).toFixed(digits)); - } else if($.isArray(val)) { - return svgedit.units.shortFloat(val[0]) + ',' + svgedit.units.shortFloat(val[1]); - } - return parseFloat(val).toFixed(digits) - 0; -}; - -// Function: svgedit.units.convertUnit -// Converts the number to given unit or baseUnit -svgedit.units.convertUnit = function(val, unit) { - unit = unit || elementContainer_.getBaseUnit(); -// baseVal.convertToSpecifiedUnits(unitNumMap[unit]); -// var val = baseVal.valueInSpecifiedUnits; -// baseVal.convertToSpecifiedUnits(1); - return svgedit.unit.shortFloat(val / typeMap_[unit]); -}; - -// Function: svgedit.units.setUnitAttr -// Sets an element's attribute based on the unit in its current value. -// -// Parameters: -// elem - DOM element to be changed -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to convert -svgedit.units.setUnitAttr = function(elem, attr, val) { - if(!isNaN(val)) { - // New value is a number, so check currently used unit - var old_val = elem.getAttribute(attr); - - // Enable this for alternate mode -// if(old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) { -// // Old value was a number, so get unit, then convert -// var unit; -// if(old_val.substr(-1) === '%') { -// var res = getResolution(); -// unit = '%'; -// val *= 100; -// if(w_attrs.indexOf(attr) >= 0) { -// val = val / res.w; -// } else if(h_attrs.indexOf(attr) >= 0) { -// val = val / res.h; -// } else { -// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2); -// } -// } else { -// if(elementContainer_.getBaseUnit() !== 'px') { -// unit = elementContainer_.getBaseUnit(); -// } else { -// unit = old_val.substr(-2); -// } -// val = val / typeMap_[unit]; -// } -// -// val += unit; -// } - } - elem.setAttribute(attr, val); -}; - -var attrsToConvert = { - "line": ['x1', 'x2', 'y1', 'y2'], - "circle": ['cx', 'cy', 'r'], - "ellipse": ['cx', 'cy', 'rx', 'ry'], - "foreignObject": ['x', 'y', 'width', 'height'], - "rect": ['x', 'y', 'width', 'height'], - "image": ['x', 'y', 'width', 'height'], - "use": ['x', 'y', 'width', 'height'], - "text": ['x', 'y'] -}; - -// Function: svgedit.units.convertAttrs -// Converts all applicable attributes to the configured baseUnit -// -// Parameters: -// element - a DOM element whose attributes should be converted -svgedit.units.convertAttrs = function(element) { - var elName = element.tagName; - var unit = elementContainer_.getBaseUnit(); - var attrs = attrsToConvert[elName]; - if(!attrs) return; - var len = attrs.length - for(var i = 0; i < len; i++) { - var attr = attrs[i]; - var cur = element.getAttribute(attr); - if(cur) { - if(!isNaN(cur)) { - element.setAttribute(attr, (cur / typeMap_[unit]) + unit); - } else { - // Convert existing? - } - } - } -}; - -// Function: svgedit.units.convertToNum -// Converts given values to numbers. Attributes must be supplied in -// case a percentage is given -// -// Parameters: -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to convert -svgedit.units.convertToNum = function(attr, val) { - // Return a number if that's what it already is - if(!isNaN(val)) return val-0; - - if(val.substr(-1) === '%') { - // Deal with percentage, depends on attribute - var num = val.substr(0, val.length-1)/100; - var width = elementContainer_.getWidth(); - var height = elementContainer_.getHeight(); - - if(w_attrs.indexOf(attr) >= 0) { - return num * width; - } else if(h_attrs.indexOf(attr) >= 0) { - return num * height; - } else { - return num * Math.sqrt((width*width) + (height*height))/Math.sqrt(2); - } - } else { - var unit = val.substr(-2); - var num = val.substr(0, val.length-2); - // Note that this multiplication turns the string into a number - return num * typeMap_[unit]; - } -}; - -// Function: svgedit.units.isValidUnit -// Check if an attribute's value is in a valid format -// -// Parameters: -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to check -svgedit.units.isValidUnit = function(attr, val, selectedElement) { - var valid = false; - if(unit_attrs.indexOf(attr) >= 0) { - // True if it's just a number - if(!isNaN(val)) { - valid = true; - } else { - // Not a number, check if it has a valid unit - val = val.toLowerCase(); - $.each(typeMap_, function(unit) { - if(valid) return; - var re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - if(re.test(val)) valid = true; - }); - } - } else if (attr == "id") { - // if we're trying to change the id, make sure it's not already present in the doc - // and the id value is valid. - - var result = false; - // because getElem() can throw an exception in the case of an invalid id - // (according to http://www.w3.org/TR/xml-id/ IDs must be a NCName) - // we wrap it in an exception and only return true if the ID was valid and - // not already present - try { - var elem = elementContainer_.getElement(val); - result = (elem == null || elem === selectedElement); - } catch(e) {} - return result; - } else { - valid = true; - } - - return valid; -}; - - -})(); \ No newline at end of file diff --git a/build/firefox/content/svg-edit-overlay.css b/build/firefox/content/svg-edit-overlay.css deleted file mode 100644 index 4b7e9b5..0000000 --- a/build/firefox/content/svg-edit-overlay.css +++ /dev/null @@ -1,21 +0,0 @@ -#svg-edit-statusbar-button { - list-style-image: url("chrome://svg-edit/content/editor/images/logo.png"); - display: -moz-box; - /*-moz-image-region: rect(16px, 16px, 32px, 0px);*/ - padding-left: 0px; - padding-right: 0px; - width: 16px; - height: 16px; - -} - -#svg-edit-statusbar-button[state="active"] { - list-style-image: url("chrome://svg-edit/content/editor/images/logo.png"); - -moz-image-region: rect(32px, 16px, 48px, 0px); -} - -#svg-edit-statusbar-button[state="error"] { - list-style-image: url("chrome://svg-edit/content/editor/images/logo.png"); - -moz-image-region: rect(0px, 16px, 16px, 0px); -} - diff --git a/build/firefox/content/svg-edit-overlay.js b/build/firefox/content/svg-edit-overlay.js deleted file mode 100644 index 8d1600d..0000000 --- a/build/firefox/content/svg-edit-overlay.js +++ /dev/null @@ -1,4 +0,0 @@ -function start_svg_edit() { - var url = "chrome://svg-edit/content/editor/svg-editor.html"; - window.openDialog(url, "SVG Editor", "width=1024,height=700,menubar=no,toolbar=no"); -} diff --git a/build/firefox/content/svg-edit-overlay.xul b/build/firefox/content/svg-edit-overlay.xul deleted file mode 100644 index 08fdd88..0000000 --- a/build/firefox/content/svg-edit-overlay.xul +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/build/firefox/handlers.js b/build/firefox/handlers.js deleted file mode 100644 index 1b20811..0000000 --- a/build/firefox/handlers.js +++ /dev/null @@ -1,55 +0,0 @@ -// Note: This JavaScript file must be included as the last script on the main HTML editor page to override the open/save handlers -$(function() { - if(!window.Components) return; - - function moz_file_picker(readflag) { - var fp = window.Components.classes["@mozilla.org/filepicker;1"]. - createInstance(Components.interfaces.nsIFilePicker); - if(readflag) - fp.init(window, "Pick a SVG file", fp.modeOpen); - else - fp.init(window, "Pick a SVG file", fp.modeSave); - fp.defaultExtension = "*.svg"; - fp.show(); - return fp.file; - } - - svgCanvas.setCustomHandlers({ - 'open':function() { - try { - netscape.security.PrivilegeManager. - enablePrivilege("UniversalXPConnect"); - var file = moz_file_picker(true); - if(!file) - return(null); - - var inputStream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream); - inputStream.init(file, 0x01, 00004, null); - var sInputStream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream); - sInputStream.init(inputStream); - svgCanvas.setSvgString(sInputStream. - read(sInputStream.available())); - } catch(e) { - console.log("Exception while attempting to load" + e); - } - }, - 'save':function(svg, str) { - try { - var file = moz_file_picker(false); - if(!file) - return; - - if (!file.exists()) - file.create(0, 0664); - - var out = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream); - out.init(file, 0x20 | 0x02, 00004,null); - out.write(str, str.length); - out.flush(); - out.close(); - } catch(e) { - alert(e); - } - } - }); -}); diff --git a/build/firefox/install.rdf b/build/firefox/install.rdf deleted file mode 100644 index 781b80a..0000000 --- a/build/firefox/install.rdf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - svg-edit@googlegroups.com - 2.6 - 2 - - - {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 1.5 - 4.* - - - SVG-edit - - diff --git a/build/opera/config.xml b/build/opera/config.xml deleted file mode 100644 index 797aafb..0000000 --- a/build/opera/config.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - SVG Edit - - A simple SVG Editor. - - 800 - 600 - editor/images/logo.svg - - SVG Edit - 2010-09 - - - - - diff --git a/build/opera/editor/browser-not-supported.html b/build/opera/editor/browser-not-supported.html deleted file mode 100644 index 3010fcf..0000000 --- a/build/opera/editor/browser-not-supported.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - -Browser does not support SVG | SVG-edit - - - -

      -SVG-edit logo
      -

      Sorry, but your browser does not support SVG. Below is a list of alternate browsers and versions that support SVG and SVG-edit (from caniuse.com).

      -

      Try the latest version of Firefox, Google Chrome, Safari, Opera or Internet Explorer.

      -

      If you are unable to install one of these and must use an old version of Internet Explorer, you can install the Google Chrome Frame plugin.

      - - - -
      - - - diff --git a/build/opera/editor/browser.js b/build/opera/editor/browser.js deleted file mode 100644 index edfba7b..0000000 --- a/build/opera/editor/browser.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Package: svgedit.browser - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Alexis Deveria - */ - -// Dependencies: -// 1) jQuery (for $.alert()) - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.browser) { - svgedit.browser = {}; -} -var supportsSvg_ = (function() { - return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect; -})(); -svgedit.browser.supportsSvg = function() { return supportsSvg_; } -if(!svgedit.browser.supportsSvg()) { - window.location = "browser-not-supported.html"; -} -else{ - -var svgns = 'http://www.w3.org/2000/svg'; -var userAgent = navigator.userAgent; -var svg = document.createElementNS(svgns, 'svg'); - -// Note: Browser sniffing should only be used if no other detection method is possible -var isOpera_ = !!window.opera; -var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0; -var isGecko_ = userAgent.indexOf('Gecko/') >= 0; -var isIE_ = userAgent.indexOf('MSIE') >= 0; -var isChrome_ = userAgent.indexOf('Chrome/') >= 0; -var isWindows_ = userAgent.indexOf('Windows') >= 0; -var isMac_ = userAgent.indexOf('Macintosh') >= 0; -var isTouch_ = 'ontouchstart' in window; - -var supportsSelectors_ = (function() { - return !!svg.querySelector; -})(); - -var supportsXpath_ = (function() { - return !!document.evaluate; -})(); - -// segList functions (for FF1.5 and 2.0) -var supportsPathReplaceItem_ = (function() { - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.replaceItem(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -var supportsPathInsertItemBefore_ = (function() { - var path = document.createElementNS(svgns,'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.insertItemBefore(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -// text character positioning (for IE9) -var supportsGoodTextCharPos_ = (function() { - var retValue = false; - var svgroot = document.createElementNS(svgns, 'svg'); - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgroot); - svgcontent.setAttribute('x', 5); - svgroot.appendChild(svgcontent); - var text = document.createElementNS(svgns,'text'); - text.textContent = 'a'; - svgcontent.appendChild(text); - var pos = text.getStartPositionOfChar(0).x; - document.documentElement.removeChild(svgroot); - return (pos === 0); -})(); - -var supportsPathBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 C0,0 10,10 10,0'); - svgcontent.appendChild(path); - var bbox = path.getBBox(); - document.documentElement.removeChild(svgcontent); - return (bbox.height > 4 && bbox.height < 5); -})(); - -// Support for correct bbox sizing on groups with horizontal/vertical lines -var supportsHVLineContainerBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,0'); - var path2 = document.createElementNS(svgns, 'path'); - path2.setAttribute('d','M5,0 15,0'); - var g = document.createElementNS(svgns, 'g'); - g.appendChild(path); - g.appendChild(path2); - svgcontent.appendChild(g); - var bbox = g.getBBox(); - document.documentElement.removeChild(svgcontent); - // Webkit gives 0, FF gives 10, Opera (correctly) gives 15 - return (bbox.width == 15); -})(); - -var supportsEditableText_ = (function() { - // TODO: Find better way to check support for this - return isOpera_; -})(); - -var supportsGoodDecimals_ = (function() { - // Correct decimals on clone attributes (Opera < 10.5/win/non-en) - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('x',.1); - var crect = rect.cloneNode(false); - var retValue = (crect.getAttribute('x').indexOf(',') == -1); - if(!retValue) { - $.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\ - Please upgrade to the latest version in which the problems have been fixed."); - } - return retValue; -})(); - -var supportsNonScalingStroke_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('style','vector-effect:non-scaling-stroke'); - return rect.style.vectorEffect === 'non-scaling-stroke'; -})(); - -var supportsNativeSVGTransformLists_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - var rxform = rect.transform.baseVal; - - var t1 = svg.createSVGTransform(); - rxform.appendItem(t1); - return rxform.getItem(0) == t1; -})(); - -// Public API - -svgedit.browser.isOpera = function() { return isOpera_; } -svgedit.browser.isWebkit = function() { return isWebkit_; } -svgedit.browser.isGecko = function() { return isGecko_; } -svgedit.browser.isIE = function() { return isIE_; } -svgedit.browser.isChrome = function() { return isChrome_; } -svgedit.browser.isWindows = function() { return isWindows_; } -svgedit.browser.isMac = function() { return isMac_; } -svgedit.browser.isTouch = function() { return isTouch_; } - -svgedit.browser.supportsSelectors = function() { return supportsSelectors_; } -svgedit.browser.supportsXpath = function() { return supportsXpath_; } - -svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; } -svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; } -svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; } -svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; } -svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; } -svgedit.browser.supportsEditableText = function() { return supportsEditableText_; } -svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; } -svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; } -svgedit.browser.supportsNativeTransformLists = function() { return supportsNativeSVGTransformLists_; } - -} - -})(); diff --git a/build/opera/editor/canvg/canvg.js b/build/opera/editor/canvg/canvg.js deleted file mode 100644 index 7b24a38..0000000 --- a/build/opera/editor/canvg/canvg.js +++ /dev/null @@ -1,2620 +0,0 @@ -/* - * canvg.js - Javascript SVG parser and renderer on Canvas - * MIT Licensed - * Gabe Lerner (gabelerner@gmail.com) - * http://code.google.com/p/canvg/ - * - * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ - */ -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(!Array.prototype.indexOf){ - Array.prototype.indexOf = function(obj){ - for(var i=0; i ignore mouse events - // ignoreAnimation: true => ignore animations - // ignoreDimensions: true => does not try to resize canvas - // ignoreClear: true => does not clear canvas - // offsetX: int => draws at a x offset - // offsetY: int => draws at a y offset - // scaleWidth: int => scales horizontally to width - // scaleHeight: int => scales vertically to height - // renderCallback: function => will call the function after the first render is completed - // forceRedraw: function => will call the function on every frame, if it returns true, will redraw - this.canvg = function (target, s, opts) { - // no parameters - if (target == null && s == null && opts == null) { - var svgTags = document.getElementsByTagName('svg'); - for (var i=0; i]*>/, ''); - var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); - xmlDoc.async = 'false'; - xmlDoc.loadXML(xml); - return xmlDoc; - } - } - - svg.Property = function(name, value) { - this.name = name; - this.value = value; - - this.hasValue = function() { - return (this.value != null && this.value !== ''); - } - - // return the numerical value of the property - this.numValue = function() { - if (!this.hasValue()) return 0; - - var n = parseFloat(this.value); - if ((this.value + '').match(/%$/)) { - n = n / 100.0; - } - return n; - } - - this.valueOrDefault = function(def) { - if (this.hasValue()) return this.value; - return def; - } - - this.numValueOrDefault = function(def) { - if (this.hasValue()) return this.numValue(); - return def; - } - - /* EXTENSIONS */ - var that = this; - - // color extensions - this.Color = { - // augment the current color value with the opacity - addOpacity: function(opacity) { - var newValue = that.value; - if (opacity != null && opacity != '') { - var color = new RGBColor(that.value); - if (color.ok) { - newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')'; - } - } - return new svg.Property(that.name, newValue); - } - } - - // definition extensions - this.Definition = { - // get the definition from the definitions table - getDefinition: function() { - var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2'); - return svg.Definitions[name]; - }, - - isUrl: function() { - return that.value.indexOf('url(') == 0 - }, - - getFillStyle: function(e) { - var def = this.getDefinition(); - - // gradient - if (def != null && def.createGradient) { - return def.createGradient(svg.ctx, e); - } - - // pattern - if (def != null && def.createPattern) { - return def.createPattern(svg.ctx, e); - } - - return null; - } - } - - // length extensions - this.Length = { - DPI: function(viewPort) { - return 96.0; // TODO: compute? - }, - - EM: function(viewPort) { - var em = 12; - - var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); - if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort); - - return em; - }, - - // get the length as pixels - toPixels: function(viewPort) { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/em$/)) return that.numValue() * this.EM(viewPort); - if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0; - if (s.match(/px$/)) return that.numValue(); - if (s.match(/pt$/)) return that.numValue() * 1.25; - if (s.match(/pc$/)) return that.numValue() * 15; - if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54; - if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4; - if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort); - if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort); - return that.numValue(); - } - } - - // time extensions - this.Time = { - // get the time as milliseconds - toMilliseconds: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/s$/)) return that.numValue() * 1000; - if (s.match(/ms$/)) return that.numValue(); - return that.numValue(); - } - } - - // angle extensions - this.Angle = { - // get the angle as radians - toRadians: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0); - if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0); - if (s.match(/rad$/)) return that.numValue(); - return that.numValue() * (Math.PI / 180.0); - } - } - } - - // fonts - svg.Font = new (function() { - this.Styles = ['normal','italic','oblique','inherit']; - this.Variants = ['normal','small-caps','inherit']; - this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit']; - - this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { - var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); - return { - fontFamily: fontFamily || f.fontFamily, - fontSize: fontSize || f.fontSize, - fontStyle: fontStyle || f.fontStyle, - fontWeight: fontWeight || f.fontWeight, - fontVariant: fontVariant || f.fontVariant, - toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } - } - } - - var that = this; - this.Parse = function(s) { - var f = {}; - var d = svg.trim(svg.compressSpaces(s || '')).split(' '); - var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } - var ff = ''; - for (var i=0; i this.x2) this.x2 = x; - } - - if (y != null) { - if (isNaN(this.y1) || isNaN(this.y2)) { - this.y1 = y; - this.y2 = y; - } - if (y < this.y1) this.y1 = y; - if (y > this.y2) this.y2 = y; - } - } - this.addX = function(x) { this.addPoint(x, null); } - this.addY = function(y) { this.addPoint(null, y); } - - this.addBoundingBox = function(bb) { - this.addPoint(bb.x1, bb.y1); - this.addPoint(bb.x2, bb.y2); - } - - this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { - var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) - var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) - this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); - } - - this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { - // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; - this.addPoint(p0[0], p0[1]); - this.addPoint(p3[0], p3[1]); - - for (i=0; i<=1; i++) { - var f = function(t) { - return Math.pow(1-t, 3) * p0[i] - + 3 * Math.pow(1-t, 2) * t * p1[i] - + 3 * (1-t) * Math.pow(t, 2) * p2[i] - + Math.pow(t, 3) * p3[i]; - } - - var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; - var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; - var c = 3 * p1[i] - 3 * p0[i]; - - if (a == 0) { - if (b == 0) continue; - var t = -c / b; - if (0 < t && t < 1) { - if (i == 0) this.addX(f(t)); - if (i == 1) this.addY(f(t)); - } - continue; - } - - var b2ac = Math.pow(b, 2) - 4 * c * a; - if (b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); - if (0 < t1 && t1 < 1) { - if (i == 0) this.addX(f(t1)); - if (i == 1) this.addY(f(t1)); - } - var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); - if (0 < t2 && t2 < 1) { - if (i == 0) this.addX(f(t2)); - if (i == 1) this.addY(f(t2)); - } - } - } - - this.isPointInBox = function(x, y) { - return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); - } - - this.addPoint(x1, y1); - this.addPoint(x2, y2); - } - - // transforms - svg.Transform = function(v) { - var that = this; - this.Type = {} - - // translate - this.Type.translate = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.translate(this.p.x || 0.0, this.p.y || 0.0); - } - this.applyToPoint = function(p) { - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - } - } - - // rotate - this.Type.rotate = function(s) { - var a = svg.ToNumberArray(s); - this.angle = new svg.Property('angle', a[0]); - this.cx = a[1] || 0; - this.cy = a[2] || 0; - this.apply = function(ctx) { - ctx.translate(this.cx, this.cy); - ctx.rotate(this.angle.Angle.toRadians()); - ctx.translate(-this.cx, -this.cy); - } - this.applyToPoint = function(p) { - var a = this.angle.Angle.toRadians(); - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); - p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); - } - } - - this.Type.scale = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); - } - this.applyToPoint = function(p) { - p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); - } - } - - this.Type.matrix = function(s) { - this.m = svg.ToNumberArray(s); - this.apply = function(ctx) { - ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); - } - this.applyToPoint = function(p) { - p.applyTransform(this.m); - } - } - - this.Type.SkewBase = function(s) { - this.base = that.Type.matrix; - this.base(s); - this.angle = new svg.Property('angle', s); - } - this.Type.SkewBase.prototype = new this.Type.matrix; - - this.Type.skewX = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0]; - } - this.Type.skewX.prototype = new this.Type.SkewBase; - - this.Type.skewY = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0]; - } - this.Type.skewY.prototype = new this.Type.SkewBase; - - this.transforms = []; - - this.apply = function(ctx) { - for (var i=0; i= this.tokens.length - 1; - } - - this.isCommandOrEnd = function() { - if (this.isEnd()) return true; - return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; - } - - this.isRelativeCommand = function() { - return this.command == this.command.toLowerCase(); - } - - this.getToken = function() { - this.i = this.i + 1; - return this.tokens[this.i]; - } - - this.getScalar = function() { - return parseFloat(this.getToken()); - } - - this.nextCommand = function() { - this.previousCommand = this.command; - this.command = this.getToken(); - } - - this.getPoint = function() { - var p = new svg.Point(this.getScalar(), this.getScalar()); - return this.makeAbsolute(p); - } - - this.getAsControlPoint = function() { - var p = this.getPoint(); - this.control = p; - return p; - } - - this.getAsCurrentPoint = function() { - var p = this.getPoint(); - this.current = p; - return p; - } - - this.getReflectedControlPoint = function() { - if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') { - return this.current; - } - - // reflect point - var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); - return p; - } - - this.makeAbsolute = function(p) { - if (this.isRelativeCommand()) { - p.x = this.current.x + p.x; - p.y = this.current.y + p.y; - } - return p; - } - - this.addMarker = function(p, from, priorTo) { - // if the last angle isn't filled in because we didn't have this point yet ... - if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) { - this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo); - } - this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); - } - - this.addMarkerAngle = function(p, a) { - this.points.push(p); - this.angles.push(a); - } - - this.getMarkerPoints = function() { return this.points; } - this.getMarkerAngles = function() { - for (var i=0; i 1) { - rx *= Math.sqrt(l); - ry *= Math.sqrt(l); - } - // cx', cy' - var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( - ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / - (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) - ); - if (isNaN(s)) s = 0; - var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); - // cx, cy - var centp = new svg.Point( - (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, - (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y - ); - // vector magnitude - var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } - // ratio between two vectors - var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } - // angle between two vectors - var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } - // initial angle - var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); - // angle delta - var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; - var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; - var ad = a(u, v); - if (r(u,v) <= -1) ad = Math.PI; - if (r(u,v) >= 1) ad = 0; - - if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI; - if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI; - - // for markers - var halfWay = new svg.Point( - centp.x - rx * Math.cos((a1 + ad) / 2), - centp.y - ry * Math.sin((a1 + ad) / 2) - ); - pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - - bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better - if (ctx != null) { - var r = rx > ry ? rx : ry; - var sx = rx > ry ? 1 : rx / ry; - var sy = rx > ry ? ry / rx : 1; - - ctx.translate(centp.x, centp.y); - ctx.rotate(xAxisRotation); - ctx.scale(sx, sy); - ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); - ctx.scale(1/sx, 1/sy); - ctx.rotate(-xAxisRotation); - ctx.translate(-centp.x, -centp.y); - } - } - break; - case 'Z': - if (ctx != null) ctx.closePath(); - pp.current = pp.start; - } - } - - return bb; - } - - this.getMarkers = function() { - var points = this.PathParser.getMarkerPoints(); - var angles = this.PathParser.getMarkerAngles(); - - var markers = []; - for (var i=0; i this.maxDuration) { - // loop for indefinitely repeating animations - if (this.attribute('repeatCount').value == 'indefinite') { - this.duration = 0.0 - } - else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { - this.removed = true; - this.getProperty().value = this.initialValue; - return true; - } - else { - return false; // no updates made - } - } - this.duration = this.duration + delta; - - // if we're past the begin time - var updated = false; - if (this.begin < this.duration) { - var newValue = this.calcValue(); // tween - - if (this.attribute('type').hasValue()) { - // for transform, etc. - var type = this.attribute('type').value; - newValue = type + '(' + newValue + ')'; - } - - this.getProperty().value = newValue; - updated = true; - } - - return updated; - } - - // fraction of duration we've covered - this.progress = function() { - return ((this.duration - this.begin) / (this.maxDuration - this.begin)); - } - } - svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; - - // animate element - svg.Element.animate = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = this.attribute('from').numValue(); - var to = this.attribute('to').numValue(); - - // tween value linearly - return from + (to - from) * this.progress(); - }; - } - svg.Element.animate.prototype = new svg.Element.AnimateBase; - - // animate color element - svg.Element.animateColor = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = new RGBColor(this.attribute('from').value); - var to = new RGBColor(this.attribute('to').value); - - if (from.ok && to.ok) { - // tween color linearly - var r = from.r + (to.r - from.r) * this.progress(); - var g = from.g + (to.g - from.g) * this.progress(); - var b = from.b + (to.b - from.b) * this.progress(); - return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; - } - return this.attribute('from').value; - }; - } - svg.Element.animateColor.prototype = new svg.Element.AnimateBase; - - // animate transform element - svg.Element.animateTransform = function(node) { - this.base = svg.Element.animate; - this.base(node); - } - svg.Element.animateTransform.prototype = new svg.Element.animate; - - // font element - svg.Element.font = function(node) { - this.base = svg.Element.ElementBase; - this.base(node); - - this.horizAdvX = this.attribute('horiz-adv-x').numValue(); - - this.isRTL = false; - this.isArabic = false; - this.fontFace = null; - this.missingGlyph = null; - this.glyphs = []; - for (var i=0; i0 && text[i-1]!=' ' && i0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial'; - if (typeof(font.glyphs[c]) != 'undefined') { - glyph = font.glyphs[c][arabicForm]; - if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c]; - } - } - else { - glyph = font.glyphs[c]; - } - if (glyph == null) glyph = font.missingGlyph; - return glyph; - } - - this.renderChildren = function(ctx) { - var customFont = this.parent.style('font-family').Definition.getDefinition(); - if (customFont != null) { - var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); - var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle); - var text = this.getText(); - if (customFont.isRTL) text = text.split("").reverse().join(""); - - var dx = svg.ToNumberArray(this.parent.attribute('dx').value); - for (var i=0; i 0 ? node.childNodes[0].nodeValue : // element - node.text; - this.getText = function() { - return this.text; - } - } - svg.Element.tspan.prototype = new svg.Element.TextElementBase; - - // tref - svg.Element.tref = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.getText = function() { - var element = this.attribute('xlink:href').Definition.getDefinition(); - if (element != null) return element.children[0].getText(); - } - } - svg.Element.tref.prototype = new svg.Element.TextElementBase; - - // a element - svg.Element.a = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.hasText = true; - for (var i=0; i 1 ? node.childNodes[1].nodeValue : ''); - css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments - css = svg.compressSpaces(css); // replace whitespace - var cssDefs = css.split('}'); - for (var i=0; i 0) { - var urlStart = srcs[s].indexOf('url'); - var urlEnd = srcs[s].indexOf(')', urlStart); - var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6); - var doc = svg.parseXml(svg.ajax(url)); - var fonts = doc.getElementsByTagName('font'); - for (var f=0; f - * @link http://www.phpied.com/rgb-color-parser-in-javascript/ - * @license Use it if you like it - */ -function RGBColor(color_string) -{ - this.ok = false; - - // strip any leading # - if (color_string.charAt(0) == '#') { // remove # if any - color_string = color_string.substr(1,6); - } - - color_string = color_string.replace(/ /g,''); - color_string = color_string.toLowerCase(); - - // before getting into regexps, try simple matches - // and overwrite the input - var simple_colors = { - aliceblue: 'f0f8ff', - antiquewhite: 'faebd7', - aqua: '00ffff', - aquamarine: '7fffd4', - azure: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '000000', - blanchedalmond: 'ffebcd', - blue: '0000ff', - blueviolet: '8a2be2', - brown: 'a52a2a', - burlywood: 'deb887', - cadetblue: '5f9ea0', - chartreuse: '7fff00', - chocolate: 'd2691e', - coral: 'ff7f50', - cornflowerblue: '6495ed', - cornsilk: 'fff8dc', - crimson: 'dc143c', - cyan: '00ffff', - darkblue: '00008b', - darkcyan: '008b8b', - darkgoldenrod: 'b8860b', - darkgray: 'a9a9a9', - darkgreen: '006400', - darkkhaki: 'bdb76b', - darkmagenta: '8b008b', - darkolivegreen: '556b2f', - darkorange: 'ff8c00', - darkorchid: '9932cc', - darkred: '8b0000', - darksalmon: 'e9967a', - darkseagreen: '8fbc8f', - darkslateblue: '483d8b', - darkslategray: '2f4f4f', - darkturquoise: '00ced1', - darkviolet: '9400d3', - deeppink: 'ff1493', - deepskyblue: '00bfff', - dimgray: '696969', - dodgerblue: '1e90ff', - feldspar: 'd19275', - firebrick: 'b22222', - floralwhite: 'fffaf0', - forestgreen: '228b22', - fuchsia: 'ff00ff', - gainsboro: 'dcdcdc', - ghostwhite: 'f8f8ff', - gold: 'ffd700', - goldenrod: 'daa520', - gray: '808080', - green: '008000', - greenyellow: 'adff2f', - honeydew: 'f0fff0', - hotpink: 'ff69b4', - indianred : 'cd5c5c', - indigo : '4b0082', - ivory: 'fffff0', - khaki: 'f0e68c', - lavender: 'e6e6fa', - lavenderblush: 'fff0f5', - lawngreen: '7cfc00', - lemonchiffon: 'fffacd', - lightblue: 'add8e6', - lightcoral: 'f08080', - lightcyan: 'e0ffff', - lightgoldenrodyellow: 'fafad2', - lightgrey: 'd3d3d3', - lightgreen: '90ee90', - lightpink: 'ffb6c1', - lightsalmon: 'ffa07a', - lightseagreen: '20b2aa', - lightskyblue: '87cefa', - lightslateblue: '8470ff', - lightslategray: '778899', - lightsteelblue: 'b0c4de', - lightyellow: 'ffffe0', - lime: '00ff00', - limegreen: '32cd32', - linen: 'faf0e6', - magenta: 'ff00ff', - maroon: '800000', - mediumaquamarine: '66cdaa', - mediumblue: '0000cd', - mediumorchid: 'ba55d3', - mediumpurple: '9370d8', - mediumseagreen: '3cb371', - mediumslateblue: '7b68ee', - mediumspringgreen: '00fa9a', - mediumturquoise: '48d1cc', - mediumvioletred: 'c71585', - midnightblue: '191970', - mintcream: 'f5fffa', - mistyrose: 'ffe4e1', - moccasin: 'ffe4b5', - navajowhite: 'ffdead', - navy: '000080', - oldlace: 'fdf5e6', - olive: '808000', - olivedrab: '6b8e23', - orange: 'ffa500', - orangered: 'ff4500', - orchid: 'da70d6', - palegoldenrod: 'eee8aa', - palegreen: '98fb98', - paleturquoise: 'afeeee', - palevioletred: 'd87093', - papayawhip: 'ffefd5', - peachpuff: 'ffdab9', - peru: 'cd853f', - pink: 'ffc0cb', - plum: 'dda0dd', - powderblue: 'b0e0e6', - purple: '800080', - red: 'ff0000', - rosybrown: 'bc8f8f', - royalblue: '4169e1', - saddlebrown: '8b4513', - salmon: 'fa8072', - sandybrown: 'f4a460', - seagreen: '2e8b57', - seashell: 'fff5ee', - sienna: 'a0522d', - silver: 'c0c0c0', - skyblue: '87ceeb', - slateblue: '6a5acd', - slategray: '708090', - snow: 'fffafa', - springgreen: '00ff7f', - steelblue: '4682b4', - tan: 'd2b48c', - teal: '008080', - thistle: 'd8bfd8', - tomato: 'ff6347', - turquoise: '40e0d0', - violet: 'ee82ee', - violetred: 'd02090', - wheat: 'f5deb3', - white: 'ffffff', - whitesmoke: 'f5f5f5', - yellow: 'ffff00', - yellowgreen: '9acd32' - }; - for (var key in simple_colors) { - if (color_string == key) { - color_string = simple_colors[key]; - } - } - // emd of simple type-in colors - - // array of color definition objects - var color_defs = [ - { - re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, - example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], - process: function (bits){ - return [ - parseInt(bits[1]), - parseInt(bits[2]), - parseInt(bits[3]) - ]; - } - }, - { - re: /^(\w{2})(\w{2})(\w{2})$/, - example: ['#00ff00', '336699'], - process: function (bits){ - return [ - parseInt(bits[1], 16), - parseInt(bits[2], 16), - parseInt(bits[3], 16) - ]; - } - }, - { - re: /^(\w{1})(\w{1})(\w{1})$/, - example: ['#fb0', 'f0f'], - process: function (bits){ - return [ - parseInt(bits[1] + bits[1], 16), - parseInt(bits[2] + bits[2], 16), - parseInt(bits[3] + bits[3], 16) - ]; - } - } - ]; - - // search through the definitions to find a match - for (var i = 0; i < color_defs.length; i++) { - var re = color_defs[i].re; - var processor = color_defs[i].process; - var bits = re.exec(color_string); - if (bits) { - channels = processor(bits); - this.r = channels[0]; - this.g = channels[1]; - this.b = channels[2]; - this.ok = true; - } - - } - - // validate/cleanup values - this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); - this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); - this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); - - // some getters - this.toRGB = function () { - return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; - } - this.toHex = function () { - var r = this.r.toString(16); - var g = this.g.toString(16); - var b = this.b.toString(16); - if (r.length == 1) r = '0' + r; - if (g.length == 1) g = '0' + g; - if (b.length == 1) b = '0' + b; - return '#' + r + g + b; - } - - // help - this.getHelpXML = function () { - - var examples = new Array(); - // add regexps - for (var i = 0; i < color_defs.length; i++) { - var example = color_defs[i].example; - for (var j = 0; j < example.length; j++) { - examples[examples.length] = example[j]; - } - } - // add type-in colors - for (var sc in simple_colors) { - examples[examples.length] = sc; - } - - var xml = document.createElement('ul'); - xml.setAttribute('id', 'rgbcolor-examples'); - for (var i = 0; i < examples.length; i++) { - try { - var list_item = document.createElement('li'); - var list_color = new RGBColor(examples[i]); - var example_div = document.createElement('div'); - example_div.style.cssText = - 'margin: 3px; ' - + 'border: 1px solid black; ' - + 'background:' + list_color.toHex() + '; ' - + 'color:' + list_color.toHex() - ; - example_div.appendChild(document.createTextNode('test')); - var list_item_value = document.createTextNode( - ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() - ); - list_item.appendChild(example_div); - list_item.appendChild(list_item_value); - xml.appendChild(list_item); - - } catch(e){} - } - return xml; - - } - -} diff --git a/build/opera/editor/contextmenu.js b/build/opera/editor/contextmenu.js deleted file mode 100644 index afa4318..0000000 --- a/build/opera/editor/contextmenu.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Package: svgedit.contextmenu - * - * Licensed under the Apache License, Version 2 - * - * Author: Adam Bender - */ -// Dependencies: -// 1) jQuery (for dom injection of context menus)\ - -var svgedit = svgedit || {}; -(function() { - var self = this; - if (!svgedit.contextmenu) { - svgedit.contextmenu = {}; - } - self.contextMenuExtensions = {} - var addContextMenuItem = function(menuItem) { - // menuItem: {id, label, shortcut, action} - if (!menuItemIsValid(menuItem)) { - console - .error("Menu items must be defined and have at least properties: id, label, action, where action must be a function"); - return; - } - if (menuItem.id in self.contextMenuExtensions) { - console.error('Cannot add extension "' + menuItem.id - + '", an extension by that name already exists"'); - return; - } - // Register menuItem action, see below for deferred menu dom injection - console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}"); - self.contextMenuExtensions[menuItem.id] = menuItem; - //TODO: Need to consider how to handle custom enable/disable behavior - } - var hasCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey] && true; - } - var getCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey].action; - } - var injectExtendedContextMenuItemIntoDom = function(menuItem) { - if (Object.keys(self.contextMenuExtensions).length == 0) { - // all menuItems appear at the bottom of the menu in their own container. - // if this is the first extension menu we need to add the separator. - $("#cmenu_canvas").append("
    • "); - } - var shortcut = menuItem.shortcut || ""; - $("#cmenu_canvas").append("
    • " - + menuItem.label + "" - + shortcut + "
    • "); - } - - var menuItemIsValid = function(menuItem) { - return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function'; - } - - // Defer injection to wait out initial menu processing. This probably goes away once all context - // menu behavior is brought here. - svgEditor.ready(function() { - for (menuItem in contextMenuExtensions) { - injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]); - } - }); - svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {}} - svgedit.contextmenu.add = addContextMenuItem; - svgedit.contextmenu.hasCustomHandler = hasCustomHandler; - svgedit.contextmenu.getCustomHandler = getCustomHandler; -})(); diff --git a/build/opera/editor/contextmenu/jquery.contextMenu.js b/build/opera/editor/contextmenu/jquery.contextMenu.js deleted file mode 100755 index 009d6cd..0000000 --- a/build/opera/editor/contextmenu/jquery.contextMenu.js +++ /dev/null @@ -1,203 +0,0 @@ -// jQuery Context Menu Plugin -// -// Version 1.01 -// -// Cory S.N. LaViska -// A Beautiful Site (http://abeautifulsite.net/) -// Modified by Alexis Deveria -// -// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/ -// -// Terms of Use -// -// This plugin is dual-licensed under the GNU General Public License -// and the MIT License and is copyright A Beautiful Site, LLC. -// -if(jQuery)( function() { - var win = $(window); - var doc = $(document); - - $.extend($.fn, { - - contextMenu: function(o, callback) { - // Defaults - if( o.menu == undefined ) return false; - if( o.inSpeed == undefined ) o.inSpeed = 150; - if( o.outSpeed == undefined ) o.outSpeed = 75; - // 0 needs to be -1 for expected results (no fade) - if( o.inSpeed == 0 ) o.inSpeed = -1; - if( o.outSpeed == 0 ) o.outSpeed = -1; - // Loop each context menu - $(this).each( function() { - var el = $(this); - var offset = $(el).offset(); - - var menu = $('#' + o.menu); - - // Add contextMenu class - menu.addClass('contextMenu'); - // Simulate a true right click - $(this).bind( "mousedown", function(e) { - var evt = e; - $(this).mouseup( function(e) { - var srcElement = $(this); - srcElement.unbind('mouseup'); - $(".contextMenu").hide(); - if( evt.button === 2 || o.allowLeft || (evt.ctrlKey && svgedit.browser.isMac()) ) { - e.stopPropagation(); - - // Get this context menu - - if( el.hasClass('disabled') ) return false; - - // Detect mouse position - var d = {}, x = e.pageX, y = e.pageY; - - var x_off = win.width() - menu.width(), - y_off = win.height() - menu.height(); - - if(x > x_off - 15) x = x_off-15; - if(y > y_off - 30) y = y_off-30; // 30 is needed to prevent scrollbars in FF - - // Show the menu - doc.unbind('click'); - menu.css({ top: y, left: x }).fadeIn(o.inSpeed); - // Hover events - menu.find('A').mouseover( function() { - menu.find('LI.hover').removeClass('hover'); - $(this).parent().addClass('hover'); - }).mouseout( function() { - menu.find('LI.hover').removeClass('hover'); - }); - - // Keyboard - doc.keypress( function(e) { - switch( e.keyCode ) { - case 38: // up - if( !menu.find('LI.hover').length ) { - menu.find('LI:last').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:last').addClass('hover'); - } - break; - case 40: // down - if( menu.find('LI.hover').length == 0 ) { - menu.find('LI:first').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:first').addClass('hover'); - } - break; - case 13: // enter - menu.find('LI.hover A').trigger('click'); - break; - case 27: // esc - doc.trigger('click'); - break - } - }); - - // When items are selected - menu.find('A').unbind('mouseup'); - menu.find('LI:not(.disabled) A').mouseup( function() { - doc.unbind('click').unbind('keypress'); - $(".contextMenu").hide(); - // Callback - if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); - return false; - }); - - // Hide bindings - setTimeout( function() { // Delay for Mozilla - doc.click( function() { - doc.unbind('click').unbind('keypress'); - menu.fadeOut(o.outSpeed); - return false; - }); - }, 0); - } - }); - }); - - // Disable text selection - if( $.browser.mozilla ) { - $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); - } else if( $.browser.msie ) { - $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); - } else { - $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); - } - // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) - $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); - - }); - return $(this); - }, - - // Disable context menu items on the fly - disableContextMenuItems: function(o) { - if( o == undefined ) { - // Disable all - $(this).find('LI').addClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Enable context menu items on the fly - enableContextMenuItems: function(o) { - if( o == undefined ) { - // Enable all - $(this).find('LI.disabled').removeClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Disable context menu(s) - disableContextMenu: function() { - $(this).each( function() { - $(this).addClass('disabled'); - }); - return( $(this) ); - }, - - // Enable context menu(s) - enableContextMenu: function() { - $(this).each( function() { - $(this).removeClass('disabled'); - }); - return( $(this) ); - }, - - // Destroy context menu(s) - destroyContextMenu: function() { - // Destroy specified context menus - $(this).each( function() { - // Disable action - $(this).unbind('mousedown').unbind('mouseup'); - }); - return( $(this) ); - } - - }); -})(jQuery); \ No newline at end of file diff --git a/build/opera/editor/draginput.js b/build/opera/editor/draginput.js deleted file mode 100644 index 0c172b1..0000000 --- a/build/opera/editor/draginput.js +++ /dev/null @@ -1,47 +0,0 @@ -;(function($) { - - var methods = { - - init : function(options) { - - return this.each(function() { - - var settings = { - }; - - if(options) { - $.extend(settings, options); - } - - var plugin = this; - var $plugin = $(this); - - $plugin.settings = settings; - - this.privateMethod = function() { - } - - $plugin.data("example", {}); - - // Plug-in code here... - }); - - }, - - publicFunction : function() { - } - }; - - $.fn.example = function(method) { - if(methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } - else if(typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } - else { - $.error("Method " + method + " does not exist on jQuery.example"); - } - }; - -})(jQuery); \ No newline at end of file diff --git a/build/opera/editor/draw.js b/build/opera/editor/draw.js deleted file mode 100644 index 8db3138..0000000 --- a/build/opera/editor/draw.js +++ /dev/null @@ -1,528 +0,0 @@ -/** - * Package: svgedit.draw - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2011 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgutils.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.draw) { - svgedit.draw = {}; -} - -var svg_ns = "http://www.w3.org/2000/svg"; -var se_ns = "http://svg-edit.googlecode.com"; -var xmlns_ns = "http://www.w3.org/2000/xmlns/"; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); - -var RandomizeModes = { - LET_DOCUMENT_DECIDE: 0, - ALWAYS_RANDOMIZE: 1, - NEVER_RANDOMIZE: 2 -}; -var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE; - -/** - * This class encapsulates the concept of a layer in the drawing - * @param name {String} Layer name - * @param child {SVGGElement} Layer SVG group. - */ -svgedit.draw.Layer = function(name, group) { - this.name_ = name; - this.group_ = group; -}; - -svgedit.draw.Layer.prototype.getName = function() { - return this.name_; -}; - -svgedit.draw.Layer.prototype.getGroup = function() { - return this.group_; -}; - - -// Called to ensure that drawings will or will not have randomized ids. -// The current_drawing will have its nonce set if it doesn't already. -// -// Params: -// enableRandomization - flag indicating if documents should have randomized ids -svgedit.draw.randomizeIds = function(enableRandomization, current_drawing) { - randomize_ids = enableRandomization == false ? - RandomizeModes.NEVER_RANDOMIZE : - RandomizeModes.ALWAYS_RANDOMIZE; - - if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !current_drawing.getNonce()) { - current_drawing.setNonce(Math.floor(Math.random() * 100001)); - } else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && current_drawing.getNonce()) { - current_drawing.clearNonce(); - } -}; - -/** - * This class encapsulates the concept of a SVG-edit drawing - * - * @param svgElem {SVGSVGElement} The SVG DOM Element that this JS object - * encapsulates. If the svgElem has a se:nonce attribute on it, then - * IDs will use the nonce as they are generated. - * @param opt_idPrefix {String} The ID prefix to use. Defaults to "svg_" - * if not specified. - */ -svgedit.draw.Drawing = function(svgElem, opt_idPrefix) { - if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI || - svgElem.tagName != 'svg' || svgElem.namespaceURI != svg_ns) { - throw "Error: svgedit.draw.Drawing instance initialized without a element"; - } - - /** - * The SVG DOM Element that represents this drawing. - * @type {SVGSVGElement} - */ - this.svgElem_ = svgElem; - - /** - * The latest object number used in this drawing. - * @type {number} - */ - this.obj_num = 0; - - /** - * The prefix to prepend to each element id in the drawing. - * @type {String} - */ - this.idPrefix = opt_idPrefix || "svg_"; - - /** - * An array of released element ids to immediately reuse. - * @type {Array.} - */ - this.releasedNums = []; - - /** - * The z-ordered array of tuples containing layer names and elements. - * The first layer is the one at the bottom of the rendering. - * TODO: Turn this into an Array. - * @type {Array.>} - */ - this.all_layers = []; - - /** - * The current layer being used. - * TODO: Make this a {Layer}. - * @type {SVGGElement} - */ - this.current_layer = null; - - /** - * The nonce to use to uniquely identify elements across drawings. - * @type {!String} - */ - this.nonce_ = ""; - var n = this.svgElem_.getAttributeNS(se_ns, 'nonce'); - // If already set in the DOM, use the nonce throughout the document - // else, if randomizeIds(true) has been called, create and set the nonce. - if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) { - this.nonce_ = n; - } else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) { - this.setNonce(Math.floor(Math.random() * 100001)); - } -}; - -svgedit.draw.Drawing.prototype.getElem_ = function(id) { - if(this.svgElem_.querySelector) { - // querySelector lookup - return this.svgElem_.querySelector('#'+id); - } else { - // jQuery lookup: twice as slow as xpath in FF - return $(this.svgElem_).find('[id=' + id + ']')[0]; - } -}; - -svgedit.draw.Drawing.prototype.getSvgElem = function() { - return this.svgElem_; -}; - -svgedit.draw.Drawing.prototype.getNonce = function() { - return this.nonce_; -}; - -svgedit.draw.Drawing.prototype.setNonce = function(n) { - this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns); - this.svgElem_.setAttributeNS(se_ns, 'se:nonce', n); - this.nonce_ = n; -}; - -svgedit.draw.Drawing.prototype.clearNonce = function() { - // We deliberately leave any se:nonce attributes alone, - // we just don't use it to randomize ids. - this.nonce_ = ""; -}; - -/** - * Returns the latest object id as a string. - * @return {String} The latest object Id. - */ -svgedit.draw.Drawing.prototype.getId = function() { - return this.nonce_ ? - this.idPrefix + this.nonce_ +'_' + this.obj_num : - this.idPrefix + this.obj_num; -}; - -/** - * Returns the next object Id as a string. - * @return {String} The next object Id to use. - */ -svgedit.draw.Drawing.prototype.getNextId = function() { - var oldObjNum = this.obj_num; - var restoreOldObjNum = false; - - // If there are any released numbers in the release stack, - // use the last one instead of the next obj_num. - // We need to temporarily use obj_num as that is what getId() depends on. - if (this.releasedNums.length > 0) { - this.obj_num = this.releasedNums.pop(); - restoreOldObjNum = true; - } else { - // If we are not using a released id, then increment the obj_num. - this.obj_num++; - } - - // Ensure the ID does not exist. - var id = this.getId(); - while (this.getElem_(id)) { - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - restoreOldObjNum = false; - } - this.obj_num++; - id = this.getId(); - } - // Restore the old object number if required. - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - } - return id; -}; - -// Function: svgedit.draw.Drawing.releaseId -// Releases the object Id, letting it be used as the next id in getNextId(). -// This method DOES NOT remove any elements from the DOM, it is expected -// that client code will do this. -// -// Parameters: -// id - The id to release. -// -// Returns: -// True if the id was valid to be released, false otherwise. -svgedit.draw.Drawing.prototype.releaseId = function(id) { - // confirm if this is a valid id for this Document, else return false - var front = this.idPrefix + (this.nonce_ ? this.nonce_ +'_' : ''); - if (typeof id != typeof '' || id.indexOf(front) != 0) { - return false; - } - // extract the obj_num of this id - var num = parseInt(id.substr(front.length)); - - // if we didn't get a positive number or we already released this number - // then return false. - if (typeof num != typeof 1 || num <= 0 || this.releasedNums.indexOf(num) != -1) { - return false; - } - - // push the released number into the released queue - this.releasedNums.push(num); - - return true; -}; - -// Function: svgedit.draw.Drawing.getNumLayers -// Returns the number of layers in the current drawing. -// -// Returns: -// The number of layers in the current drawing. -svgedit.draw.Drawing.prototype.getNumLayers = function() { - return this.all_layers.length; -}; - -// Function: svgedit.draw.Drawing.hasLayer -// Check if layer with given name already exists -svgedit.draw.Drawing.prototype.hasLayer = function(name) { - for(var i = 0; i < this.getNumLayers(); i++) { - if(this.all_layers[i][0] == name) return true; - } - return false; -}; - - -// Function: svgedit.draw.Drawing.getLayerName -// Returns the name of the ith layer. If the index is out of range, an empty string is returned. -// -// Parameters: -// i - the zero-based index of the layer you are querying. -// -// Returns: -// The name of the ith layer -svgedit.draw.Drawing.prototype.getLayerName = function(i) { - if (i >= 0 && i < this.getNumLayers()) { - return this.all_layers[i][0]; - } - return ""; -}; - -// Function: svgedit.draw.Drawing.getCurrentLayer -// Returns: -// The SVGGElement representing the current layer. -svgedit.draw.Drawing.prototype.getCurrentLayer = function() { - return this.current_layer; -}; - -// Function: getCurrentLayerName -// Returns the name of the currently selected layer. If an error occurs, an empty string -// is returned. -// -// Returns: -// The name of the currently active layer. -svgedit.draw.Drawing.prototype.getCurrentLayerName = function() { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.all_layers[i][1] == this.current_layer) { - return this.getLayerName(i); - } - } - return ""; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (name == this.getLayerName(i)) { - if (this.current_layer != this.all_layers[i][1]) { - this.current_layer.setAttribute("style", "pointer-events:none"); - this.current_layer = this.all_layers[i][1]; - this.current_layer.setAttribute("style", "pointer-events:all"); - } - return true; - } - } - return false; -}; - - -// Function: svgedit.draw.Drawing.deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -// Returns: -// The SVGGElement of the layer removed or null. -svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() { - if (this.current_layer && this.getNumLayers() > 1) { - // actually delete from the DOM and return it - var parent = this.current_layer.parentNode; - var nextSibling = this.current_layer.nextSibling; - var oldLayerGroup = parent.removeChild(this.current_layer); - this.identifyLayers(); - return oldLayerGroup; - } - return null; -}; - -// Function: svgedit.draw.Drawing.identifyLayers -// Updates layer system and sets the current layer to the -// top-most layer (last child of this drawing). -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 a_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] ); - a_layer = child; - svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); - a_layer.setAttribute("style", "pointer-events:none"); - } - // if group did not have a name, it is an orphan - else { - orphans.push(child); - } - } - // if child has is "visible" (i.e. not a or element), then it is an orphan - else if(~visElems_arr.indexOf(child.nodeName)) { - 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; - a_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = newname; - a_layer.appendChild(layer_title); - for (var j = 0; j < orphans.length; ++j) { - a_layer.appendChild(orphans[j]); - } - this.svgElem_.appendChild(a_layer); - this.all_layers.push( [newname, a_layer] ); - } - svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style","pointer-events:inherit");}); - this.current_layer = a_layer; - this.current_layer.setAttribute("style","pointer-events:all"); -}; - -// Function: svgedit.draw.Drawing.createLayer -// Creates a new top-level layer in the drawing with the given name and -// sets the current layer to it. -// -// Parameters: -// name - The given name -// -// Returns: -// The SVGGElement of the new layer, which is also the current layer -// of this drawing. -svgedit.draw.Drawing.prototype.createLayer = function(name) { - var svgdoc = this.svgElem_.ownerDocument; - var new_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - this.svgElem_.appendChild(new_layer); - this.identifyLayers(); - return new_layer; -}; - -// Function: svgedit.draw.Drawing.getLayerVisibility -// Returns whether the layer is visible. If the layer name is not valid, then this function -// returns false. -// -// Parameters: -// layername - the name of the layer which you want to query. -// -// Returns: -// The visibility state of the layer, or false if the layer name was invalid. -svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) { - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return false; - return (layer.getAttribute('display') != 'none'); -}; - -// Function: svgedit.draw.Drawing.setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// The SVGGElement representing the layer if the layername was valid, otherwise null. -svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) { - if (typeof bVisible != typeof true) { - return null; - } - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return null; - - var oldDisplay = layer.getAttribute("display"); - if (!oldDisplay) oldDisplay = "inline"; - layer.setAttribute("display", bVisible ? "inline" : "none"); - return layer; -}; - - -// Function: svgedit.draw.Drawing.getLayerOpacity -// Returns the opacity of the given layer. If the input name is not a layer, null is returned. -// -// Parameters: -// layername - name of the layer on which to get the opacity -// -// Returns: -// The opacity value of the given layer. This will be a value between 0.0 and 1.0, or null -// if layername is not a valid layer -svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - var opacity = g.getAttribute('opacity'); - if (!opacity) { - opacity = '1.0'; - } - return parseFloat(opacity); - } - } - return null; -}; - -// Function: svgedit.draw.Drawing.setLayerOpacity -// Sets the opacity of the given layer. If the input name is not a layer, nothing happens. -// If opacity is not a value between 0.0 and 1.0, then nothing happens. -// -// Parameters: -// layername - name of the layer on which to set the opacity -// opacity - a float value in the range 0.0-1.0 -svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) { - if (typeof opacity != typeof 1.0 || opacity < 0.0 || opacity > 1.0) { - return; - } - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - g.setAttribute("opacity", opacity); - break; - } - } -}; - -})(); diff --git a/build/opera/editor/embedapi.html b/build/opera/editor/embedapi.html deleted file mode 100644 index 3db0364..0000000 --- a/build/opera/editor/embedapi.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - -
      - - - - diff --git a/build/opera/editor/embedapi.js b/build/opera/editor/embedapi.js deleted file mode 100644 index 8debfd6..0000000 --- a/build/opera/editor/embedapi.js +++ /dev/null @@ -1,173 +0,0 @@ -/* -function embedded_svg_edit(frame){ - //initialize communication - this.frame = frame; - this.stack = []; //callback stack - - var editapi = this; - - window.addEventListener("message", function(e){ - if(e.data.substr(0,5) == "ERROR"){ - editapi.stack.splice(0,1)[0](e.data,"error") - }else{ - editapi.stack.splice(0,1)[0](e.data) - } - }, false) -} - -embedded_svg_edit.prototype.call = function(code, callback){ - this.stack.push(callback); - this.frame.contentWindow.postMessage(code,"*"); -} - -embedded_svg_edit.prototype.getSvgString = function(callback){ - this.call("svgCanvas.getSvgString()",callback) -} - -embedded_svg_edit.prototype.setSvgString = function(svg){ - this.call("svgCanvas.setSvgString('"+svg.replace(/'/g, "\\'")+"')"); -} -*/ - - -/* -Embedded SVG-edit API - -General usage: -- Have an iframe somewhere pointing to a version of svg-edit > r1000 -- Initialize the magic with: -var svgCanvas = new embedded_svg_edit(window.frames['svgedit']); -- Pass functions in this format: -svgCanvas.setSvgString("string") -- Or if a callback is needed: -svgCanvas.setSvgString("string")(function(data, error){ - if(error){ - //there was an error - }else{ - //handle data - } -}) - -Everything is done with the same API as the real svg-edit, -and all documentation is unchanged. The only difference is -when handling returns, the callback notation is used instead. - -var blah = new embedded_svg_edit(window.frames['svgedit']); -blah.clearSelection("woot","blah",1337,[1,2,3,4,5,"moo"],-42,{a: "tree",b:6, c: 9})(function(){console.log("GET DATA",arguments)}) -*/ - -function embedded_svg_edit(frame){ - //initialize communication - this.frame = frame; - //this.stack = [] //callback stack - this.callbacks = {}; //successor to stack - this.encode = embedded_svg_edit.encode; - //List of functions extracted with this: - //Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html - - //for(var i=0,q=[],f = document.querySelectorAll("div.CFunction h3.CTitle a");i - - - - Layer 1 - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/opera/editor/extensions/ext-arrows.js b/build/opera/editor/extensions/ext-arrows.js deleted file mode 100644 index 4bb5cd2..0000000 --- a/build/opera/editor/extensions/ext-arrows.js +++ /dev/null @@ -1,298 +0,0 @@ -/* - * ext-arrows.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - - -svgEditor.addExtension("Arrows", function(S) { - var svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomize_ids = S.randomize_ids, - selElems; - - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); - - var lang_list = { - "en":[ - {"id": "arrow_none", "textContent": "No arrow" } - ], - "fr":[ - {"id": "arrow_none", "textContent": "Sans flèche" } - ] - }; - - var prefix = 'se_arrow_'; - if (randomize_ids) { - var arrowprefix = prefix + nonce + '_'; - } else { - var arrowprefix = prefix; - } - - var pathdata = { - fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, - bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} - } - - function setArrowNonce(window, n) { - randomize_ids = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function unsetArrowNonce(window) { - randomize_ids = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if(!str) return null; - var m = str.match(/\(\#(.*)\)/); - if(!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } - - function showPanel(on) { - $('#arrow_panel').toggle(on); - - if(on) { - var el = selElems[0]; - var end = el.getAttribute("marker-end"); - var start = el.getAttribute("marker-start"); - var mid = el.getAttribute("marker-mid"); - var val; - - if(end && start) { - val = "both"; - } else if(end) { - val = "end"; - } else if(start) { - val = "start"; - } else if(mid) { - val = "mid"; - if(mid.indexOf("bk") != -1) { - val = "mid_bk"; - } - } - - if(!start && !mid && !end) { - val = "none"; - } - - $("#arrow_list").val(val); - } - } - - function resetMarker() { - var el = selElems[0]; - el.removeAttribute("marker-start"); - el.removeAttribute("marker-mid"); - el.removeAttribute("marker-end"); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var marker = S.getElem(id); - - var data = pathdata[dir]; - - if(type == "mid") { - data.refx = 5; - } - - if(!marker) { - marker = addElem({ - "element": "marker", - "attr": { - "viewBox": "0 0 10 10", - "id": id, - "refY": 5, - "markerUnits": "strokeWidth", - "markerWidth": 5, - "markerHeight": 5, - "orient": "auto", - "style": "pointer-events:none" // Currently needed for Opera - } - }); - var arrow = addElem({ - "element": "path", - "attr": { - "d": data.d, - "fill": "#000000" - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - var type = this.value; - resetMarker(); - - if(type == "none") { - return; - } - - // Set marker on element - var dir = "fw"; - if(type == "mid_bk") { - type = "mid"; - dir = "bk"; - } else if(type == "both") { - addMarker("bk", type); - svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); - type = "end"; - dir = "fw"; - } else if (type == "start") { - dir = "bk"; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); - S.call("changed", selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - - var mtypes = ['start','mid','end']; - var defs = S.findDefs(); - - $.each(mtypes, function(i, type) { - var marker = getLinked(elem, 'marker-'+type); - if(!marker) return; - - var cur_color = $(marker).children().attr('fill'); - var cur_d = $(marker).children().attr('d'); - var new_marker = null; - if(cur_color === color) return; - - var all_markers = $(defs).find('marker'); - // Different color, check if already made - all_markers.each(function() { - var attrs = $(this).children().attr(['fill', 'd']); - if(attrs.fill === color && attrs.d === cur_d) { - // Found another marker with this color and this path - new_marker = this; - } - }); - - if(!new_marker) { - // Create a new marker with this color - var last_id = marker.id; - var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; - - new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); - - $(new_marker).children().attr('fill', color); - } - - $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function() { - var elem = this; - $.each(mtypes, function(j, mtype) { - if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { - return remove = false; - } - }); - if(!remove) return false; - }); - - // Not found, so can safely remove - if(remove) { - $(marker).remove(); - } - - }); - - } - - return { - name: "Arrows", - context_tools: [{ - type: "select", - panel: "arrow_panel", - title: "Select arrow type", - id: "arrow_list", - options: { - none: "No arrow", - end: "---->", - start: "<----", - both: "<--->", - mid: "-->--", - mid_bk: "--<--" - }, - defval: "none", - events: { - change: setArrow - } - }], - callback: function() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function(lang) { - return { - data: lang_list[lang] - }; - }, - selectedChanged: function(opts) { - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - var marker_elems = ['line','path','polyline','polygon']; - - while(i--) { - var elem = selElems[i]; - if(elem && $.inArray(elem.tagName, marker_elems) != -1) { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function(opts) { - var elem = opts.elems[0]; - if(elem && ( - elem.getAttribute("marker-start") || - elem.getAttribute("marker-mid") || - elem.getAttribute("marker-end") - )) { - // var start = elem.getAttribute("marker-start"); - // var mid = elem.getAttribute("marker-mid"); - // var end = elem.getAttribute("marker-end"); - // Has marker, so see if it should match color - colorChanged(elem); - } - - } - }; -}); diff --git a/build/opera/editor/extensions/ext-closepath.js b/build/opera/editor/extensions/ext-closepath.js deleted file mode 100644 index bf8e72c..0000000 --- a/build/opera/editor/extensions/ext-closepath.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ext-closepath.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * - */ - -// This extension adds a simple button to the contextual panel for paths -// The button toggles whether the path is open or closed -svgEditor.addExtension("ClosePath", function(S) { - var selElems, - updateButton = function(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) updateButton(path); - } - }, - - toggleClosed = function() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if(seglist.getItem(last).pathSegType == 1) { - seglist.removeItem(last); - } - else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; - - return { - name: "ClosePath", - svgicons: "extensions/closepath_icons.svg", - buttons: [{ - id: "tool_openpath", - type: "context", - panel: "closepath_panel", - title: "Open path", - events: { - 'click': function() { - toggleClosed(); - } - } - }, - { - id: "tool_closepath", - type: "context", - panel: "closepath_panel", - title: "Close path", - events: { - 'click': function() { - toggleClosed(); - } - } - }], - callback: function() { - $('#closepath_panel').hide(); - }, - selectedChanged: function(opts) { - selElems = opts.elems; - var i = selElems.length; - - while(i--) { - var elem = selElems[i]; - if(elem && elem.tagName == 'path') { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; -}); diff --git a/build/opera/editor/extensions/ext-connector.js b/build/opera/editor/extensions/ext-connector.js deleted file mode 100644 index 3498c7f..0000000 --- a/build/opera/editor/extensions/ext-connector.js +++ /dev/null @@ -1,587 +0,0 @@ -/* - * ext-connector.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - -svgEditor.addExtension("Connector", function(S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = svgEditor.curConfig, - started = false, - start_x, - start_y, - cur_line, - start_elem, - end_elem, - connections = [], - conn_sel = ".se_connector", - se_ns, -// connect_str = "-SE_CONNECT-", - selElems = []; - - elData = $.data; - - var lang_list = { - "en":[ - {"id": "mode_connect", "title": "Connect two objects" } - ], - "fr":[ - {"id": "mode_connect", "title": "Connecter deux objets"} - ] - }; - - function getOffset(side, line) { - var give_offset = !!line.getAttribute('marker-' + side); -// var give_offset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return give_offset ? size : 0; - } - - function showPanel(on) { - var conn_rules = $('#connector_rules'); - if(!conn_rules.length) { - conn_rules = $(' -
      - -
      - - -
      -
      -

      Layers

      -
      -
      -
      -
      -
      -
      -
      -
      - - - - - - -
      Layer 1
      - Move elements to: - -
      -
      L a y e r s
      -
      - - - - - -
      - -
      - -
      -

      Canvas

      - - -
      - -
      - -
      -

      Rectangle

      -
      - - -
      - -
      - -
      -

      Path

      -
      - -
      -

      Image

      -
      - - -
      -
      - - -
      -
      - -
      -
      - - -
      -
      - -
      -
      - -
      -

      Ellipse

      -
      - - -
      -
      - - -
      -
      - -
      -

      Line

      -
      - - -
      -
      - - -
      -
      - -
      -

      Text

      - -
      - - - - -
      - -
      -
      B
      -
      i
      -
      - - - - - -
      - - -
      - - - - -
      - -
      - -
      - -
      -

      Group

      -
      - - -
      - -
      - -
      -

      Path

      -
      - -
      - - - - -
      -
      -
      -
      -
      - - -
      - - - - - - - - -

      Stroke

      -
      - -
      - - - - - - -

      Align

      -
      - -
      -
      -

      Position

      - - -
      -
      - - -
      -

      Multiple Elements

      - - - - - - -
      -

      Align

      - -
      - -
      - -
      - -
      -
      - -
      - - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      -
      -
      - -
      -
      -
      -
      -
      - -
      - -
      -
      -
      -
      -
      - -
      -
      -
      -
      -
      -
      -
      -
      -
      -
      - -
      - - -
      - -
      - -
      - -
      - -
      -
      -
      -
      - - - - - -
      - - - -
      -
      -
      -
      -

      Copy the contents of this box into a text editor, then save the file with a .svg extension.

      - -
      -
      - -
      -
      - - -
      -
      -
      - - -
      -
      -
      - -
      - Canvas Dimensions - - - - - - -
      -
      - - -
      -
      -
      - -
      -
      -
      - -
      - Editor Preferences - - - - - - - - - - - - - - - - - -
      -
      - - -
      -
      -
      - -
      -
      -
      -
      -
      -
      -
      - - - - - - - - - diff --git a/build/opera/editor/svg-editor.js b/build/opera/editor/svg-editor.js deleted file mode 100644 index 861b40a..0000000 --- a/build/opera/editor/svg-editor.js +++ /dev/null @@ -1,4892 +0,0 @@ -/* - * svg-editor.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Narendra Sisodiya - * - */ - -// Dependencies: -// 1) units.js -// 2) browser.js -// 3) svgcanvas.js - -(function() { - - document.addEventListener("touchstart", touchHandler, true); - document.addEventListener("touchmove", touchHandler, true); - document.addEventListener("touchend", touchHandler, true); - document.addEventListener("touchcancel", touchHandler, true); - if(!window.svgEditor) window.svgEditor = function($) { - var svgCanvas; - var Editor = {}; - var is_ready = false; - - var defaultPrefs = { - lang:'en', - iconsize:'m', - bkgd_color:'FFF', - bkgd_url:'', - img_save:'embed' - }, - curPrefs = {}, - - // Note: Difference between Prefs and Config is that Prefs can be - // changed in the UI and are stored in the browser, config can not - - curConfig = { - canvas_expansion: 1.2, - dimensions: [640,480], - initFill: { - color: 'fff', // solid red - opacity: 1 - }, - initStroke: { - width: 1.5, - color: '000', // solid black - opacity: 1 - }, - initOpacity: 1, - imgPath: 'images/', - langPath: 'locale/', - extPath: 'extensions/', - jGraduatePath: 'jgraduate/images/', - extensions: ['ext-markers.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-grid.js'], - initTool: 'select', - wireframe: false, - colorPickerCSS: false, - gridSnapping: false, - gridColor: "#000", - baseUnit: 'px', - snappingStep: 10, - showRulers: true, - show_outside_canvas: false - }, - uiStrings = Editor.uiStrings = { - common: { - "ok":"OK", - "cancel":"Cancel", - "key_up":"Up", - "key_down":"Down", - "key_backspace":"Backspace", - "key_del":"Del" - - }, - // This is needed if the locale is English, since the locale strings are not read in that instance. - layers: { - "layer":"Layer" - }, - notification: { - "invalidAttrValGiven":"Invalid value given", - "noContentToFitTo":"No content to fit to", - "dupeLayerName":"There is already a layer named that!", - "enterUniqueLayerName":"Please enter a unique layer name", - "enterNewLayerName":"Please enter the new layer name", - "layerHasThatName":"Layer already has that name", - "QmoveElemsToLayer":"Move selected elements to layer \"%s\"?", - "QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!", - "QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!", - "QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?", - "QignoreSourceChanges":"Ignore changes made to SVG source?", - "featNotSupported":"Feature not supported", - "enterNewImgURL":"Enter the new image URL", - "defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.", - "loadingImage":"Loading image, please wait...", - "saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.", - "noteTheseIssues": "Also note the following issues: ", - "unsavedChanges": "There are unsaved changes.", - "enterNewLinkURL": "Enter the new hyperlink URL", - "errorLoadingSVG": "Error: Unable to load SVG data", - "URLloadFail": "Unable to load from URL", - "retrieving": 'Retrieving "%s" ...' - } - }; - - var curPrefs = {}; //$.extend({}, defaultPrefs); - - var customHandlers = {}; - - Editor.curConfig = curConfig; - - Editor.tool_scale = 1; - -// window.ontouchmove = function(e) { -// e.stopPropagation(); -// }; -// -// $(document).bind("touchmove", function(evt) { -// if (evt.target.tagName.toLowerCase() !== "path" && evt.target.tagName.toLowerCase() !== "a") { -// return evt.preventDefault(); -// } -// }); - - // Store and retrieve preferences - $.pref = function(key, val) { - if(val) curPrefs[key] = val; - key = 'svg-edit-'+key; - var host = location.hostname, - onweb = host && host.indexOf('.') >= 0, - store = (val != undefined), - storage = false; - // Some FF versions throw security errors here - try { - if(window.localStorage) { // && onweb removed so Webkit works locally - storage = localStorage; - } - } catch(e) {} - try { - if(window.globalStorage && onweb) { - storage = globalStorage[host]; - } - } catch(e) {} - - if(storage) { - if(store) storage.setItem(key, val); - else if (storage.getItem(key)) return storage.getItem(key) + ''; // Convert to string for FF (.value fails in Webkit) - } else if(window.widget) { - if(store) widget.setPreferenceForKey(val, key); - else return widget.preferenceForKey(key); - } else { - if(store) { - var d = new Date(); - d.setTime(d.getTime() + 31536000000); - val = encodeURIComponent(val); - document.cookie = key+'='+val+'; expires='+d.toUTCString(); - } else { - var result = document.cookie.match(new RegExp(key + "=([^;]+)")); - return result?decodeURIComponent(result[1]):''; - } - } - } - - Editor.setConfig = function(opts) { - $.each(opts, function(key, val) { - // Only allow prefs defined in defaultPrefs - if(key in defaultPrefs) { - $.pref(key, val); - } - }); - $.extend(true, curConfig, opts); - if(opts.extensions) { - curConfig.extensions = opts.extensions; - } - - } - - // Extension mechanisms must call setCustomHandlers with two functions: opts.open and opts.save - // opts.open's responsibilities are: - // - invoke a file chooser dialog in 'open' mode - // - let user pick a SVG file - // - calls setCanvas.setSvgString() with the string contents of that file - // opts.save's responsibilities are: - // - accept the string contents of the current document - // - invoke a file chooser dialog in 'save' mode - // - save the file to location chosen by the user - Editor.setCustomHandlers = function(opts) { - Editor.ready(function() { - if(opts.open) { - $('#tool_open > input[type="file"]').remove(); - $('#tool_open').show(); - svgCanvas.open = opts.open; - } - if(opts.save) { - Editor.show_save_warning = false; - svgCanvas.bind("saved", opts.save); - } - if(opts.pngsave) { - svgCanvas.bind("exported", opts.pngsave); - } - customHandlers = opts; - }); - } - - Editor.randomizeIds = function() { - svgCanvas.randomizeIds(arguments) - } - - Editor.init = function() { - // For external openers - (function() { - // let the opener know SVG Edit is ready - var w = window.opener; - if (w) { - try { - var svgEditorReadyEvent = w.document.createEvent("Event"); - svgEditorReadyEvent.initEvent("svgEditorReady", true, true); - w.document.documentElement.dispatchEvent(svgEditorReadyEvent); - } - catch(e) {} - } - })(); - - (function() { - // Load config/data from URL if given - var urldata = $.deparam.querystring(true); - if(!$.isEmptyObject(urldata)) { - if(urldata.dimensions) { - urldata.dimensions = urldata.dimensions.split(','); - } - - if(urldata.extensions) { - urldata.extensions = urldata.extensions.split(','); - } - - if(urldata.bkgd_color) { - urldata.bkgd_color = '#' + urldata.bkgd_color; - } - - svgEditor.setConfig(urldata); - - var src = urldata.source; - var qstr = $.param.querystring(); - - if(!src) { // urldata.source may have been null if it ended with '=' - if(qstr.indexOf('source=data:') >= 0) { - src = qstr.match(/source=(data:[^&]*)/)[1]; - } - } - - if(src) { - if(src.indexOf("data:") === 0) { - // plusses get replaced by spaces, so re-insert - src = src.replace(/ /g, "+"); - Editor.loadFromDataURI(src); - } else { - Editor.loadFromString(src); - } - } else if(qstr.indexOf('paramurl=') !== -1) { - // Get paramater URL (use full length of remaining location.href) - svgEditor.loadFromURL(qstr.substr(9)); - } else if(urldata.url) { - svgEditor.loadFromURL(urldata.url); - } - } - })(); - - var extFunc = function() { - $.each(curConfig.extensions, function() { - 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); - } - }); - }); - - var good_langs = []; - - $('#lang_select option').each(function() { - good_langs.push(this.value); - }); - - // var lang = ('lang' in curPrefs) ? curPrefs.lang : null; - Editor.putLocale(null, good_langs); - } - - // Load extensions - // Bit of a hack to run extensions in local Opera/IE9 - if(document.location.protocol === 'file:') { - setTimeout(extFunc, 100); - } else { - extFunc(); - } - $.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { - w:24, h:24, - id_match: false, - no_img: !svgedit.browser.isWebkit(), // Opera & Firefox 4 gives odd behavior w/images - fallback_path: curConfig.imgPath, - fallback:{ - 'new_image':'clear.png', - 'save':'save.png', - 'open':'open.png', - 'source':'source.png', - 'docprops':'document-properties.png', - 'wireframe':'wireframe.png', - - 'undo':'undo.png', - 'redo':'redo.png', - - 'select':'select.png', - 'select_node':'select_node.png', - 'pencil':'fhpath.png', - 'pen':'line.png', - 'square':'square.png', - 'rect':'rect.png', - 'fh_rect':'freehand-square.png', - 'circle':'circle.png', - 'ellipse':'ellipse.png', - 'fh_ellipse':'freehand-circle.png', - 'path':'path.png', - 'text':'text.png', - 'image':'image.png', - 'zoom':'zoom.png', - - 'clone':'clone.png', - 'node_clone':'node_clone.png', - 'delete':'delete.png', - 'node_delete':'node_delete.png', - //'group':'shape_group.png', - //'ungroup':'shape_ungroup.png', - 'move_top':'move_top.png', - 'move_bottom':'move_bottom.png', - 'to_path':'to_path.png', - 'link_controls':'link_controls.png', - 'reorient':'reorient.png', - - 'align_left':'align-left.png', - 'align_center':'align-center', - 'align_right':'align-right', - 'align_top':'align-top', - 'align_middle':'align-middle', - 'align_bottom':'align-bottom', - - 'go_up':'go-up.png', - 'go_down':'go-down.png', - - 'ok':'save.png', - 'cancel':'cancel.png', - - 'arrow_right':'flyouth.png', - 'arrow_down':'dropdown.gif' - }, - placement: { - '#tool_docprops > div':'docprops', - - '#tool_select':'select', - '#tool_fhpath':'pencil', - '#tool_line':'pen', - '#tool_rect,#tools_rect_show':'rect', - '#tool_square':'square', - '#tool_fhrect':'fh_rect', - '#tool_ellipse,#tools_ellipse_show':'ellipse', - '#tool_circle':'circle', - '#tool_fhellipse':'fh_ellipse', - '#tool_path':'path', - '#tool_text,#layer_rename':'text', - '#tool_image':'image', - '#tool_zoom':'zoom', - - '#tool_node_clone':'node_clone', - '#tool_node_delete':'node_delete', - '#tool_add_subpath':'add_subpath', - '#tool_openclose_path':'open_path', - '#tool_node_link':'link_controls', - //'#tool_group':'group', - //'#tool_ungroup':'ungroup', - //'#tool_unlink_use':'unlink_use', - - '#tool_alignleft, #tool_posleft':'align_left', - '#tool_aligncenter, #tool_poscenter':'align_center', - '#tool_alignright, #tool_posright':'align_right', - '#tool_aligntop, #tool_postop':'align_top', - '#tool_alignmiddle, #tool_posmiddle':'align_middle', - '#tool_alignbottom, #tool_posbottom':'align_bottom', - '#cur_position':'align', - - '#linecap_butt,#cur_linecap':'linecap_butt', - '#linecap_round':'linecap_round', - '#linecap_square':'linecap_square', - - '#linejoin_miter,#cur_linejoin':'linejoin_miter', - '#linejoin_round':'linejoin_round', - '#linejoin_bevel':'linejoin_bevel', - - '#url_notice':'warning', - - '#layer_up':'go_up', - '#layer_down':'go_down', - '#layer_moreopts':'context_menu', - '#layerlist td.layervis':'eye', - - '#tool_source_save,#tool_docprops_save,#tool_prefs_save':'ok', - '#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel':'cancel', - - '#rwidthLabel, #iwidthLabel':'width', - '#rheightLabel, #iheightLabel':'height', - //'#cornerRadiusLabel span':'c_radius', - '#angleLabel':'angle', - '#linkLabel,#tool_make_link,#tool_make_link_multi':'globe_link', - '#zoomLabel':'zoom', - //'#tool_fill label': 'fill', - //'#tool_stroke .icon_label': 'stroke', - //'#group_opacityLabel': 'opacity', - '#blurLabel': 'blur', - //'#font_sizeLabel': 'fontsize', - - '.flyout_arrow_horiz':'arrow_right', - //'.dropdown button, #main_button .dropdown':'arrow_down', - '#palette .palette_item:first, #fill_bg, #stroke_bg':'no_color' - }, - resize: { - '#logo .svg_icon': 32, - '.flyout_arrow_horiz .svg_icon': 5, - '.layer_button .svg_icon, #layerlist td.layervis .svg_icon': 14, - //'.dropdown button .svg_icon': 7, - '#main_button .dropdown .svg_icon': 9, - '#fill_bg .svg_icon, #stroke_bg .svg_icon': 24, - '.palette_item:first .svg_icon': 16, - '.toolbar_button button .svg_icon':16, - '.stroke_tool div div .svg_icon': 20, - '#tools_bottom label .svg_icon': 18, - '#zoom_dropdown .svg_icon': 7 - }, - callback: function(icons) { - $('.toolbar_button button > svg, .toolbar_button button > img').each(function() { - $(this).parent().prepend(this); - }); - - var tleft = $('#tools_left'); - if (tleft.length != 0) { - var min_height = tleft.offset().top + tleft.outerHeight(); - } - - // Look for any missing flyout icons from plugins - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var sel = shower.attr('data-curopt'); - // Check if there's an icon here - if(!shower.children('svg, img').length) { - var clone = $(sel).children().clone(); - if(clone.length) { - clone[0].removeAttribute('style'); //Needed for Opera - shower.append(clone); - } - } - }); - - svgEditor.runCallbacks(); - - setTimeout(function() { - $('.flyout_arrow_horiz:empty').each(function() { - $(this).append($.getSvgIcon('arrow_right').width(5).height(5)); - }); - }, 1); - } - }); - - Editor.canvas = svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), curConfig); - Editor.show_save_warning = false; - var palette = ["#000000", "#3f3f3f", "#7f7f7f", "#bfbfbf", "#ffffff", - "#ff0000", "#ff7f00", "#ffff00", "#7fff00", - "#00ff00", "#00ff7f", "#00ffff", "#007fff", - "#0000ff", "#7f00ff", "#ff00ff", "#ff007f", - "#7f0000", "#7f3f00", "#7f7f00", "#3f7f00", - "#007f00", "#007f3f", "#007f7f", "#003f7f", - "#00007f", "#3f007f", "#7f007f", "#7f003f", - "#ffaaaa", "#ffd4aa", "#ffffaa", "#d4ffaa", - "#aaffaa", "#aaffd4", "#aaffff", "#aad4ff", - "#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4" - ], - isMac = (navigator.platform.indexOf("Mac") >= 0), - isWebkit = (navigator.userAgent.indexOf("AppleWebKit") >= 0), - modKey = (isMac ? "meta+" : "ctrl+"), // ⌘ - path = svgCanvas.pathActions, - undoMgr = svgCanvas.undoMgr, - Utils = svgedit.utilities, - default_img_url = curConfig.imgPath + "placeholder.svg", - workarea = $("#workarea"), - canv_menu = $("#cmenu_canvas"), - layer_menu = $("#cmenu_layers"), - exportWindow = null, - tool_scale = 1, - zoomInIcon = 'crosshair', - zoomOutIcon = 'crosshair', - ui_context = 'toolbars', - orig_source = '', - paintBox = {fill: null, stroke:null}; - - // This sets up alternative dialog boxes. They mostly work the same way as - // their UI counterparts, expect instead of returning the result, a callback - // needs to be included that returns the result as its first parameter. - // In the future we may want to add additional types of dialog boxes, since - // they should be easy to handle this way. - (function() { - $('#dialog_container').draggable({cancel:'#dialog_content, #dialog_buttons *', containment: 'window'}); - var box = $('#dialog_box'), btn_holder = $('#dialog_buttons'); - - var dbox = function(type, msg, callback, defText) { - $('#dialog_content').html('

      '+msg.replace(/\n/g,'

      ')+'

      ') - .toggleClass('prompt',(type=='prompt')); - btn_holder.empty(); - - var ok = $('').appendTo(btn_holder); - - if(type != 'alert') { - $('') - .appendTo(btn_holder) - .click(function() { box.hide();callback(false)}); - } - - if(type == 'prompt') { - var input = $('').prependTo(btn_holder); - input.val(defText || ''); - input.bind('keydown', 'return', function() {ok.click();}); - } - - if(type == 'process') { - ok.hide(); - } - - box.show(); - - ok.click(function() { - box.hide(); - var resp = (type == 'prompt')?input.val():true; - if(callback) callback(resp); - }).focus(); - - if(type == 'prompt') input.focus(); - } - - $.alert = function(msg, cb) { dbox('alert', msg, cb);}; - $.confirm = function(msg, cb) { dbox('confirm', msg, cb);}; - $.process_cancel = function(msg, cb) { dbox('process', msg, cb);}; - $.prompt = function(msg, txt, cb) { dbox('prompt', msg, cb, txt);}; - }()); - - var setSelectMode = function() { - var curr = $('.tool_button_current'); - if(curr.length && curr[0].id !== 'tool_select') { - curr.removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}'); - } - svgCanvas.setMode('select'); - }; - - var togglePathEditMode = function(editmode, elems) { - $('#path_node_panel').toggle(editmode); - $('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); - if(editmode) { - // Change select icon - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - setIcon('#tool_select', 'select_node'); - multiselected = false; - if(elems.length) { - selectedElement = elems[0]; - } - } else { - setIcon('#tool_select', 'select'); - } - } - - // used to make the flyouts stay on the screen longer the very first time - var flyoutspeed = 1250; - var textBeingEntered = false; - var selectedElement = null; - var multiselected = false; - var editingsource = false; - var docprops = false; - var preferences = false; - var cur_context = ''; - var orig_title = $('title:first').text(); - - var saveHandler = function(window,svg) { - Editor.show_save_warning = false; - - // 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; - - // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable - - var ua = navigator.userAgent; - - // Chrome 5 (and 6?) don't allow saving, show source instead ( http://code.google.com/p/chromium/issues/detail?id=46735 ) - // IE9 doesn't allow standalone Data URLs ( https://connect.microsoft.com/IE/feedback/details/542600/data-uri-images-fail-when-loaded-by-themselves ) - if((~ua.indexOf('Chrome') && $.browser.version >= 533) || ~ua.indexOf('MSIE')) { - showSourceEditor(0,true); - return; - } - var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg)); - - // Alert will only appear the first time saved OR the first time the bug is encountered - var done = $.pref('save_notice_done'); - if(done !== "all") { - - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'SVG'); - - // Check if FF and has - if(ua.indexOf('Gecko/') !== -1) { - if(svg.indexOf('', {id: 'export_canvas'}).hide().appendTo('body'); - } - var c = $('#export_canvas')[0]; - - c.width = svgCanvas.contentW; - c.height = svgCanvas.contentH; - canvg(c, data.svg, {renderCallback: function() { - var datauri = c.toDataURL('image/png'); - exportWindow.location.href = datauri; - var done = $.pref('export_notice_done'); - if(done !== "all") { - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'PNG'); - - // Check if there's issues - if(issues.length) { - var pre = "\n \u2022 "; - note += ("\n\n" + uiStrings.notification.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 - var selectedChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") setSelectMode(); - var is_node = (mode == "pathedit"); - // if elems[1] is present, then we have more than one element - selectedElement = (elems.length == 1 || elems[1] == null ? elems[0] : null); - multiselected = (elems.length >= 2 && elems[1] != null); - if (selectedElement != null) { - // unless we're already in always set the mode of the editor to select because - // upon creation of a text element the editor is switched into - // select mode and this event fires - we need our UI to be in sync - - if (!is_node) { - updateToolbar(); - } - - } // if (elem != null) - // Deal with pathedit mode - togglePathEditMode(is_node, elems); - updateContextPanel(); - svgCanvas.runExtensions("selectedChanged", { - elems: elems, - selectedElement: selectedElement, - multiselected: multiselected - }); - }; - - // Call when part of element is in process of changing, generally - // on mousemove actions like rotate, move, etc. - var elementTransition = function(window,elems) { - var mode = svgCanvas.getMode(); - var elem = elems[0]; - - if(!elem) return; - - multiselected = (elems.length >= 2 && elems[1] != null); - // Only updating fields for single elements for now - if(!multiselected) { - switch ( mode ) { - case "rotate": - var ang = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(ang)); - $('#tool_reorient').toggleClass('disabled', ang == 0); - break; - - // TODO: Update values that change on move/resize, etc -// case "select": -// case "resize": -// break; - } - } - svgCanvas.runExtensions("elementTransition", { - elems: elems - }); - }; - - // called when any element has changed - var elementChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") { - setSelectMode(); - } - - for (var i = 0; i < elems.length; ++i) { - var elem = elems[i]; - - // if the element changed was the svg, then it could be a resolution change - if (elem && elem.tagName === "svg") { - populateLayers(); - updateCanvas(); - } - // 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) { // This was added in r1430, but not sure why - selectedElement = elem; - } - } - - Editor.show_save_warning = true; - - // we update the contextual panel with potentially new - // positional/sizing information (we DON'T want to update the - // toolbar here as that creates an infinite loop) - // also this updates the history buttons - - // we tell it to skip focusing the text control if the - // text element was previously in focus - updateContextPanel(); - - // In the event a gradient was flipped: - if(selectedElement && mode === "select") { - paintBox.fill.update(); - paintBox.stroke.update(); - } - - svgCanvas.runExtensions("elementChanged", { - elems: elems - }); - }; - - var zoomChanged = function(window, bbox, autoCenter) { - var scrbar = 15, - res = svgCanvas.getResolution(), - w_area = workarea, - canvas_pos = $('#svgcanvas').position(); - var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); - if(!z_info) return; - var zoomlevel = z_info.zoom, - bb = z_info.bbox; - - if(zoomlevel < .001) { - changeZoom({value: .1}); - return; - } - -// $('#zoom').val(Math.round(zoomlevel*100)); - $('#zoom').val(zoomlevel*100); - - if(autoCenter) { - updateCanvas(); - } else { - updateCanvas(false, {x: bb.x * zoomlevel + (bb.width * zoomlevel)/2, y: bb.y * zoomlevel + (bb.height * zoomlevel)/2}); - } - - if(svgCanvas.getMode() == 'zoom' && bb.width) { - // Go to select if a zoom box was drawn - setSelectMode(); - } - - zoomDone(); - } - - $('#cur_context_panel').delegate('a', 'click', function() { - var link = $(this); - if(link.attr('data-root')) { - svgCanvas.leaveContext(); - } else { - svgCanvas.setContext(link.text()); - } - return false; - }); - - var contextChanged = function(win, context) { - - var link_str = ''; - if(context) { - var str = ''; - link_str = '' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + ''; - - $(context).parentsUntil('#svgcontent > g').andSelf().each(function() { - if(this.id) { - str += ' > ' + this.id; - if(this !== context) { - link_str += ' > ' + this.id + ''; - } else { - link_str += ' > ' + this.id; - } - } - }); - - cur_context = str; - } else { - cur_context = null; - } - $('#cur_context_panel').toggle(!!context).html(link_str); - - - updateTitle(); - } - - // Makes sure the current selected paint is available to work with - var prepPaints = function() { - paintBox.fill.prep(); - paintBox.stroke.prep(); - } - - var flyout_funcs = {}; - - var setupFlyouts = function(holders) { - $.each(holders, function(hold_sel, btn_opts) { - var buttons = $(hold_sel).children(); - var show_sel = hold_sel + '_show'; - var shower = $(show_sel); - var def = false; - buttons.addClass('tool_button') - .unbind('click mousedown mouseup') // may not be necessary - .each(function(i) { - // Get this buttons options - var opts = btn_opts[i]; - - // Remember the function that goes with this ID - flyout_funcs[opts.sel] = opts.fn; - - if(opts.isDefault) def = i; - - // Clicking the icon in flyout should set this set's icon - var func = function(event) { - var options = opts; - //find the currently selected tool if comes from keystroke - if (event.type === "keydown") { - var flyoutIsSelected = $(options.parent + "_show").hasClass('tool_button_current'); - var currentOperation = $(options.parent + "_show").attr("data-curopt"); - $.each(holders[opts.parent], function(i, tool){ - if (tool.sel == currentOperation) { - if(!event.shiftKey || !flyoutIsSelected) { - options = tool; - } - else { - options = holders[opts.parent][i+1] || holders[opts.parent][0]; - } - } - }); - } - if($(this).hasClass('disabled')) return false; - if (toolButtonClick(show_sel)) { - options.fn(); - } - if(options.icon) { - var icon = $.getSvgIcon(options.icon, true); - } else { - var icon = $(options.sel).children().eq(0).clone(); - } - - icon[0].setAttribute('width',shower.width()); - icon[0].setAttribute('height',shower.height()); - shower.children(':not(.flyout_arrow_horiz)').remove(); - shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode - } - - $(this).mouseup(func); - - if(opts.key) { - $(document).bind('keydown', opts.key[0] + " shift+" + opts.key[0], func); - } - }); - - if(def) { - shower.attr('data-curopt', btn_opts[def].sel); - } else if(!shower.attr('data-curopt')) { - // Set first as default - shower.attr('data-curopt', btn_opts[0].sel); - } - - var timer; - - var pos = $(show_sel).position(); - $(hold_sel).css({'left': pos.left+34, 'top': pos.top+77}); - - // Clicking the "show" icon should set the current mode - shower.mousedown(function(evt) { - if ($('#tools_shapelib').is(":visible")) toolButtonClick(show_sel, false); - if(shower.hasClass('disabled')) return false; - var holder = $(hold_sel); - var l = pos.left+34; - var w = holder.width()*-1; - var time = holder.data('shown_popop')?200:0; - timer = setTimeout(function() { - // Show corresponding menu - if(!shower.data('isLibrary')) { - holder.css('left', w).show().animate({ - left: l - },150); - } else { - holder.css('left', l).show(); - } - holder.data('shown_popop',true); - },time); - evt.preventDefault(); - }).mouseup(function(evt) { - clearTimeout(timer); - var opt = $(this).attr('data-curopt'); - // Is library and popped up, so do nothing - if(shower.data('isLibrary') && $(show_sel.replace('_show','')).is(':visible')) { - toolButtonClick(show_sel, true); - return; - } - if (toolButtonClick(show_sel) && (opt in flyout_funcs)) { - flyout_funcs[opt](); - } - }); - - // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();}); - }); - - setFlyoutTitles(); - } - - var makeFlyoutHolder = function(id, child) { - var div = $('
      ',{ - 'class': 'tools_flyout', - id: id - }).appendTo('#svg_editor').append(child); - - return div; - } - - var setFlyoutPositions = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var pos = shower.offset(); - var w = shower.outerWidth(); - $(this).css({left: (pos.left + w)*tool_scale, top: pos.top}); - }); - } - - var setFlyoutTitles = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - if(shower.data('isLibrary')) return; - - var tooltips = []; - $(this).children().each(function() { - tooltips.push(this.title); - }); - 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 && cb_ready) { - cb_called = true; - ext.callback(); - } - } - - var btn_selects = []; - - if(ext.context_tools) { - $.each(ext.context_tools, function(i, tool) { - // Add select tool - var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):""; - - var panel = $('#' + tool.panel); - - // create the panel if it doesn't exist - if(!panel.length) - panel = $('
      ', {id: tool.panel}).appendTo("#tools_top"); - - // TODO: Allow support for other types, or adding to existing tool - switch (tool.type) { - case 'tool_button': - var html = '
      ' + tool.id + '
      '; - var div = $(html).appendTo(panel); - if (tool.events) { - $.each(tool.events, function(evt, func) { - $(div).bind(evt, func); - }); - } - break; - case 'select': - var html = '' - + '"; - // Creates the tool, hides & adds it, returns the select element - var sel = $(html).appendTo(panel).find('select'); - - $.each(tool.events, function(evt, func) { - $(sel).bind(evt, func); - }); - break; - case 'button-select': - var html = ''; - - var list = $('
        ').appendTo('#option_lists'); - - if(tool.colnum) { - list.addClass('optcols' + tool.colnum); - } - - // Creates the tool, hides & adds it, returns the select element - var dropdown = $(html).appendTo(panel).children(); - - btn_selects.push({ - elem: ('#' + tool.id), - list: ('#' + tool.id + '_opts'), - title: tool.title, - callback: tool.events.change, - cur: ('#cur_' + tool.id) - }); - - break; - case 'input': - var html = '' - + '' - + tool.label + ':' - + '' - - // Creates the tool, hides & adds it, returns the select element - - // Add to given tool.panel - var inp = $(html).appendTo(panel).find('input'); - - if(tool.spindata) { - inp.SpinButton(tool.spindata); - } - - if(tool.events) { - $.each(tool.events, function(evt, func) { - inp.bind(evt, func); - }); - } - break; - - default: - break; - } - }); - } - - if(ext.buttons) { - var fallback_obj = {}, - placement_obj = {}, - svgicons = ext.svgicons; - var holders = {}; - - - // Add buttons given by extension - $.each(ext.buttons, function(i, btn) { - var icon; - var id = btn.id; - var num = i; - - // Give button a unique ID - while($('#'+id).length) { - id = btn.id + '_' + (++num); - } - - if(!svgicons) { - icon = (btn.type == "menu") ? "" : $(''); - } else { - fallback_obj[id] = btn.icon; - var svgicon = btn.svgicon?btn.svgicon:btn.id; - if(btn.type == 'app_menu') { - placement_obj['#' + id + ' > div'] = svgicon; - } else { - placement_obj['#' + id] = svgicon; - } - } - - var cls, parent; - - - - // Set button up according to its type - switch ( btn.type ) { - case 'mode_flyout': - case 'mode': - cls = 'tool_button'; - if(btn.cls) { - cls += " " + btn.cls; - } - parent = "#tools_left"; - break; - case 'context': - cls = 'tool_button'; - parent = "#" + btn.panel; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
        ', {id: btn.panel}).appendTo("#tools_top"); - break; - case 'menu': - cls = 'menu_item tool_button'; - parent = "#" + (btn.after || btn.panel); - break; - case 'app_menu': - cls = ''; - parent = btn.parent || '#main_menu ul'; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
        ', {id: btn.panel}).appendTo("#tools_top"); - break; - } - - var button = $((btn.list || btn.type == 'app_menu')?'
      • ':'
        ') - .attr("id", id) - .attr("title", btn.title) - .addClass(cls); - if(!btn.includeWith && !btn.list) { - if("position" in btn) { - $(parent).children().eq(btn.position).before(button); - } else { - if (btn.type != "menu" || !btn.after) button.appendTo(parent); - else $(parent).after(button); - } - - if(btn.type =='mode_flyout') { - // Add to flyout menu / make flyout menu - // var opts = btn.includeWith; - // // opts.button, default, position - var ref_btn = $(button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
        ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - flyout_holder.data('isLibrary', true); - show_btn.data('isLibrary', true); - } - - - - // var ref_data = Actions.getButtonData(opts.button); - - placement_obj['#' + tls_id + '_show'] = btn.id; - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, -// key: btn.key, - isDefault: true - }, ref_data]; - - } else if(btn.type == 'app_menu' || btn.type == 'menu') { - button.append(btn.title); - } - - } else if(btn.list) { - // Add button to list - button.addClass('push_button'); - $('#' + btn.list + '_opts').append(button); - if(btn.isDefault) { - $('#cur_' + btn.list).append(button.children().clone()); - var svgicon = btn.svgicon?btn.svgicon:btn.id; - placement_obj['#cur_' + btn.list] = svgicon; - } - } else if(btn.includeWith) { - // Add to flyout menu / make flyout menu - var opts = btn.includeWith; - // opts.button, default, position - var ref_btn = $(opts.button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
        ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - } - - var ref_data = Actions.getButtonData(opts.button); - - if(opts.isDefault) { - placement_obj['#' + tls_id + '_show'] = btn.id; - } - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, - key: btn.key, - isDefault: btn.includeWith?btn.includeWith.isDefault:0 - }, ref_data]; - - // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} - - var pos = ("position" in opts)?opts.position:'last'; - var len = flyout_holder.children().length; - - // Add at given position or end - if(!isNaN(pos) && pos >= 0 && pos < len) { - flyout_holder.children().eq(pos).before(button); - } else { - flyout_holder.append(button); - cur_h.reverse(); - } - } - - if(!svgicons) { - button.append(icon); - } - - if(!btn.list) { - // Add given events to button - $.each(btn.events, function(name, func) { - if(name == "click") { - if(btn.type == 'mode') { - if(btn.includeWith) { - button.bind(name, func); - } else { - button.bind(name, function() { - if(toolButtonClick(button)) { - func(); - } - }); - } - if(btn.key) { - $(document).bind('keydown', btn.key, func); - if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']'); - } - } else { - button.bind(name, func); - } - } else { - button.bind(name, func); - } - }); - } - setupFlyouts(holders); - }); - - $.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, - id_match: false, - no_img: (!isWebkit), - fallback: fallback_obj, - placement: placement_obj, - callback: function(icons) { - // Non-ideal hack to make the icon match the current size - if(curPrefs.iconsize && curPrefs.iconsize != 'm') { - prepResize(); - } - cb_ready = true; // Ready for callback - runCallback(); - } - - }); - } - - runCallback(); - }; - - var getPaint = function(color, opac, type) { - // update the editor's fill paint - var opts = null; - if (color.indexOf("url(#") === 0) { - var refElem = svgCanvas.getRefElem(color); - if(refElem) { - refElem = refElem.cloneNode(true); - } else { - refElem = $("#" + type + "_color defs *")[0]; - } - - opts = { alpha: opac }; - opts[refElem.tagName] = refElem; - } - else if (color.indexOf("#") === 0) { - opts = { - alpha: opac, - solidColor: color.substr(1) - }; - } - else { - opts = { - alpha: opac, - solidColor: 'none' - }; - } - return new $.jGraduate.Paint(opts); - }; - - // set the canvas properties at init - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#docprops_button').on("click", function(){showDocProperties()}); - - // 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) { - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - break; - case 'g': - case 'a': - // Look for common styles - - var gWidth = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var swidth = childs[i].getAttribute("stroke-width"); - - if(i === 0) { - gWidth = swidth; - } else if(gWidth !== swidth) { - gWidth = null; - } - } - - $('#stroke_width').val(gWidth === null ? "" : gWidth); - - paintBox.fill.update(true); - paintBox.stroke.update(true); - - - break; - default: - paintBox.fill.update(true); - paintBox.stroke.update(true); - - $('#stroke_width').val(selectedElement.getAttribute("stroke-width") || 1); - $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none"); - - var attr = selectedElement.getAttribute("stroke-linejoin") || 'miter'; - - if ($('#linejoin_' + attr).length != 0) - setStrokeOpt($('#linejoin_' + attr)[0]); - - attr = selectedElement.getAttribute("stroke-linecap") || 'butt'; - - if ($('#linecap_' + attr).length != 0) - setStrokeOpt($('#linecap_' + attr)[0]); - } - - } - - // All elements including image and group have opacity - if(selectedElement != null) { - var opac_perc = ((selectedElement.getAttribute("opacity")||1.0)*100); - $('#group_opacity').val(opac_perc); - $('#opac_slider').slider('option', 'value', opac_perc); - $('#elem_id').val(selectedElement.id); - } - - updateToolButtonState(); - }; - - var setImageURL = Editor.setImageURL = function(url) { - if(!url) url = default_img_url; - - svgCanvas.setImageURL(url); - $('#image_url').val(url); - - if(url.indexOf('data:') === 0) { - // data URI found - $('#image_url').hide(); - $('#change_image_url').show(); - } else { - // regular URL - - svgCanvas.embedImage(url, function(datauri) { - if(!datauri) { - // Couldn't embed, so show warning - $('#url_notice').show(); - } else { - $('#url_notice').hide(); - } - default_img_url = url; - }); - $('#image_url').show(); - $('#change_image_url').hide(); - } - } - - 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; - // If element has just been deleted, consider it null - if(elem != null && !elem.parentNode) elem = null; - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var currentMode = svgCanvas.getMode(); - var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; - - var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false; - var menu_items = $('#cmenu_canvas li'); - $('#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\ - #ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel').hide(); - $('.menu_item', '#edit_menu').addClass('disabled'); - $('.menu_item', '#object_menu').addClass('disabled'); - if (!elem && !multiselected) $("#canvas_panel").show(); - if (elem != null) { - var elname = elem.nodeName; - var angle = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(angle)); - - var blurval = svgCanvas.getBlur(elem); - $('#blur').val(blurval); - $('#blur_slider').slider('option', 'value', blurval); - - if(svgCanvas.addedNew) { - if(elname === 'image') { - // Prompt for URL if not a data URL - if(svgCanvas.getHref(elem).indexOf('data:') !== 0) { - promptImgURL(); - } - } /*else if(elname == 'text') { - // TODO: Do something here for new text - }*/ - } - - if(!is_node && currentMode != 'pathedit') { - $('#selected_panel').show(); - $('.action_selected').removeClass('disabled'); - // Elements in this array already have coord fields - if(['line', 'circle', 'ellipse'].indexOf(elname) >= 0) { - $('#xy_panel').hide(); - } else { - var x,y; - - // Get BBox vals for g, polyline and path - if(['g', 'polyline', 'path'].indexOf(elname) >= 0) { - var bb = svgCanvas.getStrokedBBox([elem]); - if(bb) { - x = bb.x; - y = bb.y; - } - } else { - x = elem.getAttribute('x'); - y = elem.getAttribute('y'); - } - - if(unit) { - x = svgedit.units.convertUnit(x); - y = svgedit.units.convertUnit(y); - } - - $('#selected_x').val(x || 0); - $('#selected_y').val(y || 0); - $('#xy_panel').show(); - } - - // Elements in this array cannot be converted to a path - var no_path = ['image', 'text', 'path', 'g', 'use'].indexOf(elname) == -1; - if (no_path) $('.action_path_convert_selected').removeClass('disabled'); - if (elname === "path") $('.action_path_selected').removeClass('disabled'); - } else { - var point = path.getNodePoint(); - $('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); - $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); - - // Show open/close button based on selected point - setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); - - if(point) { - var seg_type = $('#seg_type'); - if(unit) { - point.x = svgedit.units.convertUnit(point.x); - point.y = svgedit.units.convertUnit(point.y); - } - $('#path_node_x').val(point.x); - $('#path_node_y').val(point.y); - if(point.type) { - seg_type.val(point.type).removeAttr('disabled'); - } else { - seg_type.val(4).attr('disabled','disabled'); - } - } - return; - } - - // update contextual tools here - var panels = { - g: [], - a: [], - rect: ['rx','width','height'], - image: ['width','height'], - circle: ['cx','cy','r'], - ellipse: ['cx','cy','rx','ry'], - line: ['x1','y1','x2','y2'], - text: [], - 'use': [] - }; - - var el_name = elem.tagName; - - if($(elem).data('gsvg')) { - $('#g_panel').show(); - } - - if (el_name == "path") { - $('#path_panel').show(); - } - -// var link_href = null; -// if (el_name === 'a') { -// link_href = svgCanvas.getHref(elem); -// $('#g_panel').show(); -// } -// -// if(elem.parentNode.tagName === 'a') { -// if(!$(elem).siblings().length) { -// $('#a_panel').show(); -// link_href = svgCanvas.getHref(elem.parentNode); -// } -// } -// -// // Hide/show the make_link buttons -// $('#tool_make_link, #tool_make_link').toggle(!link_href); -// -// if(link_href) { -// $('#link_url').val(link_href); -// } - - if(panels[el_name]) { - var cur_panel = panels[el_name]; - $('#' + el_name + '_panel').show(); - - $.each(cur_panel, function(i, item) { - var attrVal = elem.getAttribute(item); - if(curConfig.baseUnit !== 'px' && elem[item]) { - var bv = elem[item].baseVal.value; - attrVal = svgedit.units.convertUnit(bv); - } - - $('#' + el_name + '_' + item).val(attrVal || 0); - }); - if(el_name == 'text') { - $('#text_panel').css("display", "inline"); - if (svgCanvas.getItalic()) { - $('#tool_italic').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_italic').removeClass('push_button_pressed').addClass('tool_button'); - } - if (svgCanvas.getBold()) { - $('#tool_bold').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_bold').removeClass('push_button_pressed').addClass('tool_button'); - } - $('#font_family').val(elem.getAttribute("font-family")); - $('#font_size').val(elem.getAttribute("font-size")); - $('#text').val(elem.textContent); - if (svgCanvas.addedNew) { - // Timeout needed for IE9 - setTimeout(function() { - $('#text').focus().select(); - },100); - } - } // text - else if(el_name == 'image') { - setImageURL(svgCanvas.getHref(elem)); - } // image - else if(el_name === 'g' || el_name === 'use') { - $('#container_panel').show(); - $('.action_group_selected').removeClass('disabled'); - 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); - } - } - } - menu_items[(el_name === 'g' ? 'en':'dis') + 'ableContextMenuItems']('#ungroup'); - menu_items[((el_name === 'g' || !multiselected) ? 'dis':'en') + 'ableContextMenuItems']('#group'); - } // if (elem != null) - else if (multiselected) { - $('#multiselected_panel').show(); - $('.action_multi_selected').removeClass('disabled'); - menu_items - .enableContextMenuItems('#group') - .disableContextMenuItems('#ungroup'); - } else { - menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); - } - - // update history buttons - if (undoMgr.getUndoStackSize() > 0) { - $('#tool_undo').removeClass( 'disabled'); - } - else { - $('#tool_undo').addClass( 'disabled'); - } - if (undoMgr.getRedoStackSize() > 0) { - $('#tool_redo').removeClass( 'disabled'); - } - else { - $('#tool_redo').addClass( 'disabled'); - } - - svgCanvas.addedNew = false; - - if ( (elem && !is_node) || multiselected) { - // update the selected elements' layer - $('#selLayerNames').removeAttr('disabled').val(currentLayerName); - - // Enable regular menu options - canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); - } - else { - $('#selLayerNames').attr('disabled', 'disabled'); - } - }; - - $('#text').focus( function(){ textBeingEntered = true; } ); - $('#text').blur( function(){ textBeingEntered = false; } ); - - // bind the selected event to our function that handles updates to the UI - svgCanvas.bind("selected", selectedChanged); - svgCanvas.bind("transition", elementTransition); - svgCanvas.bind("changed", elementChanged); - svgCanvas.bind("saved", saveHandler); - svgCanvas.bind("exported", exportHandler); - svgCanvas.bind("zoomed", zoomChanged); - svgCanvas.bind("contextset", contextChanged); - svgCanvas.bind("extension_added", extAdded); - svgCanvas.textActions.setInputElem($("#text")[0]); - - var str = '
        ' - $.each(palette, function(i,item){ - str += '
        '; - }); - $('#palette').append(str); - - // Set up editor background functionality - // TODO add checkerboard as "pattern" - var color_blocks = ['#FFF','#888','#000']; // ,'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP%2F%2F%2F9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG%2Bgq4jM3IFLJgpswNly%2FXkcBpIiVaInlLJr9FZWAQA7)']; - var str = ''; - $.each(color_blocks, function() { - str += '
        '; - }); - $('#bg_blocks').append(str); - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - blocks.each(function() { - var blk = $(this); - blk.click(function() { - blocks.removeClass(cur_bg); - $(this).addClass(cur_bg); - }); - }); - - if($.pref('bkgd_color')) { - setBackground($.pref('bkgd_color'), $.pref('bkgd_url')); - } else if($.pref('bkgd_url')) { - // No color set, only URL - setBackground(defaultPrefs.bkgd_color, $.pref('bkgd_url')); - } - - if($.pref('img_save')) { - curPrefs.img_save = $.pref('img_save'); - $('#image_save_opts input').val([curPrefs.img_save]); - } - - var changeRectRadius = function(ctl) { - svgCanvas.setRectRadius(ctl.value); - } - - var changeFontSize = function(ctl) { - svgCanvas.setFontSize(ctl.value); - } - - var changeStrokeWidth = function(ctl) { - var val = ctl.value; - if(val == 0 && selectedElement && ['line', 'polyline'].indexOf(selectedElement.nodeName) >= 0) { - val = ctl.value = 1; - } - svgCanvas.setStrokeWidth(val); - } - - var changeRotationAngle = function(ctl) { - svgCanvas.setRotationAngle(ctl.value); - $('#tool_reorient').toggleClass('disabled', ctl.value == 0); - } - var changeZoom = function(ctl) { - var zoomlevel = ctl.value / 100; - if(zoomlevel < .001) { - ctl.value = .1; - return; - } - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - - zoomChanged(window, { - width: 0, - height: 0, - // center pt of scroll position - x: (w_area[0].scrollLeft + w_area.width()/2)/zoom, - y: (w_area[0].scrollTop + w_area.height()/2)/zoom, - zoom: zoomlevel - }, true); - } - - var changeOpacity = function(ctl, val) { - if(val == null) val = ctl.value; - $('#group_opacity').val(val); - if(!ctl || !ctl.handle) { - $('#opac_slider').slider('option', 'value', val); - } - svgCanvas.setOpacity(val/100); - } - - var changeBlur = function(ctl, val, noUndo) { - if(val == null) val = ctl.value; - $('#blur').val(val); - var complete = false; - if(!ctl || !ctl.handle) { - $('#blur_slider').slider('option', 'value', val); - complete = true; - } - if(noUndo) { - svgCanvas.setBlurNoUndo(val); - } else { - svgCanvas.setBlur(val, complete); - } - } - - var operaRepaint = function() { - // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change - if(!window.opera) return; - $('

        ').hide().appendTo('body').remove(); - } - - $('#stroke_style').change(function(){ - svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val()); - operaRepaint(); - }); - - $('#stroke_linejoin').change(function(){ - svgCanvas.setStrokeAttr('stroke-linejoin', $(this).val()); - operaRepaint(); - }); - - - // Lose focus for select elements when changed (Allows keyboard shortcuts to work better) - $('select').change(function(){$(this).blur();}); - - // fired when user wants to move elements to another layer - var promptMoveLayerOnce = false; - $('#selLayerNames').change(function(){ - var destLayer = this.options[this.selectedIndex].value; - var confirm_str = uiStrings.notification.QmoveElemsToLayer.replace('%s',destLayer); - var moveToLayer = function(ok) { - if(!ok) return; - promptMoveLayerOnce = true; - svgCanvas.moveSelectedToLayer(destLayer); - svgCanvas.clearSelection(); - populateLayers(); - } - if (destLayer) { - if(promptMoveLayerOnce) { - moveToLayer(true); - } else { - $.confirm(confirm_str, moveToLayer); - } - } - }); - - $('#font_family').change(function() { - svgCanvas.setFontFamily(this.value); - }); - - $('#seg_type').change(function() { - svgCanvas.setSegType($(this).val()); - }); - - $('#text').keyup(function(){ - svgCanvas.setTextContent(this.value); - }); - - $('#image_url').change(function(){ - setImageURL(this.value); - }); - - $('#link_url').change(function() { - if(this.value.length) { - svgCanvas.setLinkURL(this.value); - } else { - svgCanvas.removeHyperlink(); - } - }); - - $('#g_title').change(function() { - svgCanvas.setGroupTitle(this.value); - }); - - $('.attr_changer').change(function() { - var attr = this.getAttribute("data-attr"); - var val = this.value; - var valid = svgedit.units.isValidUnit(attr, val, selectedElement); - if(!valid) { - $.alert(uiStrings.notification.invalidAttrValGiven); - this.value = selectedElement.getAttribute(attr); - return false; - } - else{ - this.blur() - } - - if (attr !== "id") { - if (isNaN(val)) { - val = svgCanvas.convertToNum(attr, val); - } else if(curConfig.baseUnit !== 'px') { - // Convert unitless value to one with given unit - - var unitData = svgedit.units.getTypeMap(); - - if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") { - val *= unitData[curConfig.baseUnit]; - } - } - } - - // if the user is changing the id, then de-select the element first - // change the ID, then re-select it with the new ID - if (attr === "id") { - var elem = selectedElement; - svgCanvas.clearSelection(); - elem.id = val; - svgCanvas.addToSelection([elem],true); - } - else { - svgCanvas.changeSelectedAttribute(attr, val); - } - this.blur(); - }); - - // Prevent selection of elements when shift-clicking - $('#palette').mouseover(function() { - var inp = $(''); - $(this).append(inp); - inp.focus().remove(); - }); - - $('.palette_item').mousedown(function(evt){ - var isStroke = $('#tool_stroke').hasClass('active'); - var picker = isStroke ? "stroke" : "fill"; - var color = $(this).attr('data-rgb'); - var paint = null; - - // Webkit-based browsers returned 'initial' here for no stroke - console.log(color); - if (color === 'transparent' || color === 'initial' || color === '#none') { - color = 'none'; - paint = new $.jGraduate.Paint(); - } - else { - paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)}); - } - - paintBox[picker].setPaint(paint); - - if (isStroke) { - svgCanvas.setColor('stroke', color); - if (color != 'none' && svgCanvas.getStrokeOpacity() != 1) { - svgCanvas.setPaintOpacity('stroke', 1.0); - } - } else { - svgCanvas.setColor('fill', color); - if (color != 'none' && svgCanvas.getFillOpacity() != 1) { - svgCanvas.setPaintOpacity('fill', 1.0); - } - } - updateToolButtonState(); - }).bind('contextmenu', function(e) {e.preventDefault()}); - - $("#toggle_stroke_tools").toggle(function() { - $(".stroke_tool").css('display','table-cell'); - $(this).addClass('expanded'); - resetScrollPos(); - }, function() { - $(".stroke_tool").css('display','none'); - $(this).removeClass('expanded'); - resetScrollPos(); - }); - - // This is a common function used when a tool has been clicked (chosen) - // It does several common things: - // - removes the tool_button_current class from whatever tool currently has it - // - hides any flyouts - // - adds the tool_button_current class to the button passed in - var toolButtonClick = function(button, noHiding) { - if ($(button).hasClass('disabled')) return false; - if($(button).parent().hasClass('tools_flyout')) return true; - var fadeFlyouts = fadeFlyouts || 'normal'; - if(!noHiding) { - $('.tools_flyout').fadeOut(fadeFlyouts); - } - $('#styleoverrides').text(''); - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $(button).addClass('tool_button_current').removeClass('tool_button'); - return true; - }; - - (function() { - var last_x = null, last_y = null, w_area = workarea[0], - panning = false, keypan = false; - - $('#svgcanvas').bind('mousemove mouseup', function(evt) { - if(panning === false) return; - - w_area.scrollLeft -= (evt.clientX - last_x); - w_area.scrollTop -= (evt.clientY - last_y); - - last_x = evt.clientX; - last_y = evt.clientY; - - if(evt.type === 'mouseup') panning = false; - return false; - }).mousedown(function(evt) { - if(evt.button === 1 || keypan === true) { - panning = true; - last_x = evt.clientX; - last_y = evt.clientY; - return false; - } - }); - - $(window).mouseup(function() { - panning = false; - }); - - $(document).bind('keydown', 'space', function(evt) { - svgCanvas.spaceKey = keypan = true; - evt.preventDefault(); - }).bind('keyup', 'space', function(evt) { - evt.preventDefault(); - svgCanvas.spaceKey = keypan = false; - }).bind('keydown', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.addClass('out'); - } - }).bind('keyup', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.removeClass('out'); - } - }) - }()); - - - function setStrokeOpt(opt, changeElem) { - var id = opt.id; - var bits = id.split('_'); - var pre = bits[0]; - var val = bits[1]; - - if(changeElem) { - svgCanvas.setStrokeAttr('stroke-' + pre, val); - } - operaRepaint(); - setIcon('#cur_' + pre , id, 20); - $(opt).addClass('current').siblings().removeClass('current'); - } - - //menu handling - var menus = $('.menu'); - var blinker = function(e) { - e.target.style.background = "#fff"; - setTimeout(function(){e.target.style.background = "#ddd";}, 50); - setTimeout(function(){e.target.style.background = "#fff";}, 150); - setTimeout(function(){e.target.style.background = "#ddd";}, 200); - setTimeout(function(){e.target.style.background = "";}, 200); - setTimeout(function(){$('#menu_bar').removeClass('active')}, 220); - return false; - } - var closer = function(e){ - if (!$(e.target).hasClass("menu_title") && $('#menu_bar').hasClass("active")) { - if(!$(e.target).hasClass("disabled") && $(e.target).hasClass("menu_item")) { - blinker(e); - return; - } - $('#menu_bar').removeClass('active') - $('.tools_flyout').hide(); - $('input').blur(); - } - } - $('.menu_item').live('click', function(e){blinker(e)}); - $("svg, body").on('click', function(e){closer(e)}); - $('.menu_title').on('click', function() {$("#menu_bar").toggleClass('active');}); - $('.menu_title').on('mouseover', function() { - menus.removeClass('open'); - $(this).parent().addClass('open'); - }); - - // Made public for UI customization. - // TODO: Group UI functions into a public svgEditor.ui interface. - Editor.addDropDown = function(elem, callback, dropUp) { - if ($(elem).length == 0) return; // Quit if called on non-existant element - var button = $(elem).find('button'); - - var list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list'); - - if(!dropUp) { - // Move list to place where it can overflow container - $('#option_lists').append(list); - } - - var on_button = false; - if(dropUp) { - $(elem).addClass('dropup'); - } - - list.find('li').bind('mouseup', callback); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - } - on_button = false; - }); - - button.bind('mousedown',function() { - if (!button.hasClass('down')) { - button.addClass('down'); - - if(!dropUp) { - var pos = $(elem).offset(); - // position slider - list.css({ - top: pos.top, - left: pos.left - 110 - }); - } - list.show(); - - on_button = true; - } else { - button.removeClass('down'); - list.hide(); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - } - - // TODO: Combine this with addDropDown or find other way to optimize - var addAltDropDown = function(elem, list, callback, opts) { - var button = $(elem); - var list = $(list); - var on_button = false; - var dropUp = opts.dropUp; - if(dropUp) { - $(elem).addClass('dropup'); - } - list.find('li').bind('mouseup', function() { - if(opts.seticon) { - setIcon('#cur_' + button[0].id , $(this).children()); - $(this).addClass('current').siblings().removeClass('current'); - } - callback.apply(this, arguments); - - }); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - list.css({top:0, left:0}); - } - on_button = false; - }); - - var height = list.height(); - $(elem).bind('mousedown',function() { - var off = $(elem).offset(); - if(dropUp) { - off.top -= list.height(); - off.left += 8; - } else { - off.top += $(elem).height(); - } - $(list).offset(off); - - if (!button.hasClass('down')) { - button.addClass('down'); - list.show(); - on_button = true; - return false; - } else { - button.removeClass('down'); - // CSS position must be reset for Webkit - list.hide(); - list.css({top:0, left:0}); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - - if(opts.multiclick) { - list.mousedown(function() { - on_button = true; - }); - } - } - - Editor.addDropDown('#font_family_dropdown', function() { - var fam = $(this).text(); - $('#font_family').val($(this).text()).change(); - }); - - Editor.addDropDown('#opacity_dropdown', function() { - if($(this).find('div').length) return; - var perc = parseInt($(this).text().split('%')[0]); - changeOpacity(false, perc); - }, false); - - // For slider usage, see: http://jqueryui.com/demos/slider/ - $("#opac_slider").slider({ - start: function() { - $('#opacity_dropdown li:not(.special)').hide(); - }, - stop: function() { - $('#opacity_dropdown li').show(); - $(window).mouseup(); - }, - slide: function(evt, ui){ - changeOpacity(ui); - } - }); - - Editor.addDropDown('#blur_dropdown', $.noop); - - var slideStart = false; - - $("#blur_slider").slider({ - max: 10, - step: .1, - stop: function(evt, ui) { - slideStart = false; - changeBlur(ui); - $('#blur_dropdown li').show(); - $(window).mouseup(); - }, - start: function() { - slideStart = true; - }, - slide: function(evt, ui){ - changeBlur(ui, null, slideStart); - } - }); - - - Editor.addDropDown('#zoom_dropdown', function() { - var item = $(this); - var val = item.attr('data-val'); - if(val) { - zoomChanged(window, val); - } else { - changeZoom({value:parseInt(item.text())}); - } - }, true); - - addAltDropDown('#stroke_linecap', '#linecap_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - addAltDropDown('#stroke_linejoin', '#linejoin_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - $('div', '#position_opts').each(function(){ - this.addEventListener("mouseup", function(){ - var letter = this.id.replace('tool_pos','').charAt(0); - svgCanvas.alignSelectedElements(letter, 'page'); - }) - }); - - /* - - When a flyout icon is selected - (if flyout) { - - Change the icon - - Make pressing the button run its stuff - } - - Run its stuff - - When its shortcut key is pressed - - If not current in list, do as above - , else: - - Just run its stuff - - */ - - // Unfocus text input when workarea is mousedowned. - (function() { - var inp; - var unfocus = function() { - $(inp).blur(); - } - - $('#svg_editor').find('button, select, input:not(#text)').focus(function() { - inp = this; - ui_context = 'toolbars'; - workarea.mousedown(unfocus); - }).blur(function() { - ui_context = 'canvas'; - workarea.unbind('mousedown', unfocus); - // Go back to selecting text if in textedit mode - if(svgCanvas.getMode() == 'textedit') { - $('#text').focus(); - } - }); - - }()); - - var clickSelect = function() { - if (toolButtonClick('#tool_select')) { - svgCanvas.setMode('select'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}'); - } - }; - - var clickFHPath = function() { - if (toolButtonClick('#tool_fhpath')) { - svgCanvas.setMode('fhpath'); - } - }; - - var clickLine = function() { - if (toolButtonClick('#tool_line')) { - svgCanvas.setMode('line'); - } - }; - - var clickSquare = function(){ - if (toolButtonClick('#tool_square')) { - svgCanvas.setMode('square'); - } - }; - - var clickRect = function(){ - if (toolButtonClick('#tool_rect')) { - svgCanvas.setMode('rect'); - } - }; - - var clickFHRect = function(){ - if (toolButtonClick('#tool_fhrect')) { - svgCanvas.setMode('fhrect'); - } - }; - - var clickCircle = function(){ - if (toolButtonClick('#tool_circle')) { - svgCanvas.setMode('circle'); - } - }; - - var clickEllipse = function(){ - if (toolButtonClick('#tool_ellipse')) { - svgCanvas.setMode('ellipse'); - } - }; - - var clickFHEllipse = function(){ - if (toolButtonClick('#tool_fhellipse')) { - svgCanvas.setMode('fhellipse'); - } - }; - - var clickImage = function(){ - if (toolButtonClick('#tool_image')) { - svgCanvas.setMode('image'); - } - }; - - var clickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - svgCanvas.setMode('zoom'); - } - }; - - var dblclickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - zoomImage(); - setSelectMode(); - } - }; - - var clickText = function(){ - if (toolButtonClick('#tool_text')) { - svgCanvas.setMode('text'); - } - }; - - var clickPath = function(){ - if (toolButtonClick('#tool_path')) { - svgCanvas.setMode('path'); - } - }; - - // Delete is a contextual tool that only appears in the ribbon if - // an element has been selected - var deleteSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.deleteSelectedElements(); - } - }; - - var cutSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.cutSelectedElements(); - } - }; - - var copySelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.copySelectedElements(); - } - }; - - var pasteInCenter = function() { - var zoom = svgCanvas.getZoom(); - - var x = (workarea[0].scrollLeft + workarea.width()/2)/zoom - svgCanvas.contentW; - var y = (workarea[0].scrollTop + workarea.height()/2)/zoom - svgCanvas.contentH; - svgCanvas.pasteElements('point', x, y); - } - - var moveToTopSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToTopSelectedElement(); - } - }; - - var moveToBottomSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToBottomSelectedElement(); - } - }; - - var moveUpSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Up"); - } - }; - - var moveDownSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Down"); - } - }; - - var moveUpDownSelected = function(dir) { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected(dir); - } - }; - - var convertToPath = function() { - if (selectedElement != null) { - svgCanvas.convertToPath(); - } - } - - var reorientPath = function() { - if (selectedElement != null) { - path.reorient(); - } - } - - var makeHyperlink = function() { - if (selectedElement != null || multiselected) { - $.prompt(uiStrings.notification.enterNewLinkURL, "http://", function(url) { - if(url) svgCanvas.makeHyperlink(url); - }); - } - } - - var moveSelected = function(dx,dy) { - if (selectedElement != null || multiselected) { - if(curConfig.gridSnapping) { - // Use grid snap value regardless of zoom level - var multi = svgCanvas.getZoom() * curConfig.snappingStep; - dx *= multi; - dy *= multi; - } - svgCanvas.moveSelectedElements(dx,dy); - } - }; - - var linkControlPoints = function() { - var linked = !$('#tool_node_link').hasClass('push_button_pressed'); - if (linked) - $('#tool_node_link').addClass('push_button_pressed').removeClass('tool_button'); - else - $('#tool_node_link').removeClass('push_button_pressed').addClass('tool_button'); - - path.linkControlPoints(linked); - } - - var clonePathNode = function() { - if (path.getNodePoint()) { - path.clonePathNode(); - } - }; - - var deletePathNode = function() { - if (path.getNodePoint()) { - path.deletePathNode(); - } - }; - - var addSubPath = function() { - var button = $('#tool_add_subpath'); - var sp = !button.hasClass('push_button_pressed'); - if (sp) { - button.addClass('push_button_pressed').removeClass('tool_button'); - } else { - button.removeClass('push_button_pressed').addClass('tool_button'); - } - - path.addSubPath(sp); - - }; - - var opencloseSubPath = function() { - path.opencloseSubPath(); - } - - var selectNext = function() { - svgCanvas.cycleElement(1); - }; - - var selectPrev = function() { - svgCanvas.cycleElement(0); - }; - - var rotateSelected = function(cw,step) { - if (selectedElement == null || multiselected) return; - if(!cw) step *= -1; - var new_angle = $('#angle').val()*1 + step; - svgCanvas.setRotationAngle(new_angle); - updateContextPanel(); - }; - - var clickClear = function(){ - var dims = curConfig.dimensions; - $.confirm(uiStrings.notification.QwantToClear, function(ok) { - if(!ok) return; - setSelectMode(); - svgCanvas.clear(); - svgCanvas.setResolution(dims[0], dims[1]); - updateCanvas(true); - zoomImage(); - populateLayers(); - updateContextPanel(); - prepPaints(); - svgCanvas.runExtensions('onNewDocument'); - }); - }; - - var clickBold = function(){ - svgCanvas.setBold( !svgCanvas.getBold() ); - updateContextPanel(); - return false; - }; - - var clickItalic = function(){ - svgCanvas.setItalic( !svgCanvas.getItalic() ); - updateContextPanel(); - return false; - }; - - var clickSave = function(){ - // In the future, more options can be provided here - var saveOpts = { - 'images': curPrefs.img_save, - 'round_digits': 6 - } - svgCanvas.save(saveOpts); - }; - - var clickExport = function() { - // Open placeholder window (prevents popup) - if(!customHandlers.pngsave) { - var str = uiStrings.notification.loadingImage; - exportWindow = window.open("data:text/html;charset=utf-8," + str + "<\/title><h1>" + str + "<\/h1>"); - } - - if(window.canvg) { - svgCanvas.rasterExport(); - } else { - $.getScript('canvg/rgbcolor.js', function() { - $.getScript('canvg/canvg.js', function() { - svgCanvas.rasterExport(); - }); - }); - } - } - - // by default, svgCanvas.open() is a no-op. - // it is up to an extension mechanism (opera widget, etc) - // to call setCustomHandlers() which will make it do something - var clickOpen = function(){ - svgCanvas.open(); - }; - var clickImport = function(){ - }; - - var flash = function($menu){ - var menu_title = $menu.prev(); - menu_title.css("background", "#09f"); - setTimeout(function(){menu_title.css("background", "")}, 200); - } - - var clickUndo = function(){ - if (undoMgr.getUndoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.undo(); - populateLayers(); - } - }; - - var clickRedo = function(){ - if (undoMgr.getRedoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.redo(); - populateLayers(); - } - }; - - var clickGroup = function(){ - // group - if (multiselected) { - svgCanvas.groupSelectedElements(); - } - // ungroup - else if(selectedElement){ - svgCanvas.ungroupSelectedElement(); - } - }; - - var clickClone = function(){ - if (window.event.type === "keydown") flash($('#edit_menu')); - svgCanvas.cloneSelectedElements(20,20); - }; - - var clickAlign = function() { - var letter = this.id.replace('tool_align','').charAt(0); - svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val()); - }; - - var clickSwitch = function() { - var stroke_rect = document.querySelector('#tool_stroke rect'); - var fill_rect = document.querySelector('#tool_fill rect'); - var fill_color = fill_rect.getAttribute("fill"); - var stroke_color = stroke_rect.getAttribute("fill"); - var stroke_opacity = parseFloat(stroke_rect.getAttribute("stroke-opacity")); - if (isNaN(stroke_opacity)) {stroke_opacity = 100;} - var fill_opacity = parseFloat(fill_rect.getAttribute("fill-opacity")); - if (isNaN(fill_opacity)) {fill_opacity = 100;} - var stroke = getPaint(stroke_color, stroke_opacity, "stroke"); - var fill = getPaint(fill_color, fill_opacity, "fill"); - paintBox.fill.setPaint(stroke, true); - paintBox.stroke.setPaint(fill, true); - - }; - - var zoomImage = function(multiplier) { - var res = svgCanvas.getResolution(); - multiplier = multiplier?res.zoom * multiplier:1; - // setResolution(res.w * multiplier, res.h * multiplier, true); - $('#zoom').val(multiplier * 100); - svgCanvas.setZoom(multiplier); - zoomDone(); - updateCanvas(true); - }; - - var zoomDone = function() { - // updateBgImage(); - updateWireFrame(); - //updateCanvas(); // necessary? - } - - var clickWireframe = function() { - var wf = !$('#tool_wireframe').hasClass('push_button_pressed'); - if (wf) - $('#tool_wireframe').addClass('push_button_pressed'); - else - $('#tool_wireframe').removeClass('push_button_pressed'); - workarea.toggleClass('wireframe'); - - if(supportsNonSS) return; - var wf_rules = $('#wireframe_rules'); - if(!wf_rules.length) { - wf_rules = $('<style id="wireframe_rules"><\/style>').appendTo('head'); - } else { - wf_rules.empty(); - } - - updateWireFrame(); - } - - var clickRulers = function() { - var rulers = !$('#tool_rulers').hasClass('push_button_pressed'); - if (rulers) { - $('#tool_rulers').addClass('push_button_pressed'); - $('#show_rulers').attr("checked", true); - curConfig.showRulers = true; - } - else { - $('#tool_rulers').removeClass('push_button_pressed'); - $('#show_rulers').attr("checked", false); - curConfig.showRulers = false; - } - $('#rulers').toggle(!!curConfig.showRulers) - } - - var updateWireFrame = function() { - // Test support - if(supportsNonSS) return; - - var rule = "#workarea.wireframe #svgcontent * { stroke-width: " + 1/svgCanvas.getZoom() + "px; }"; - $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ""); - } - - var showSourceEditor = function(e, forSaving){ - if (editingsource) return; - editingsource = true; - - $('#save_output_btns').toggle(!!forSaving); - $('#tool_source_back').toggle(!forSaving); - - var str = orig_source = svgCanvas.getSvgString(); - $('#svg_source_textarea').val(str); - $('#svg_source_editor').fadeIn(); - properlySourceSizeTextArea(); - $('#svg_source_textarea').focus(); - }; - - var showDocProperties = function(){ - if (docprops) return; - docprops = true; - - // This selects the correct radio button by using the array notation - $('#image_save_opts input').val([curPrefs.img_save]); - - // update resolution option with actual resolution - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#canvas_title').val(svgCanvas.getDocumentTitle()); - - $('#svg_docprops').show(); - }; - - var showPreferences = function(){ - if (preferences) return; - preferences = true; - - // Update background color with current one - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - var canvas_bg = $.pref('bkgd_color'); - var url = $.pref('bkgd_url'); - // if(url) url = url[1]; - blocks.each(function() { - var blk = $(this); - var is_bg = blk.css('background-color') == canvas_bg; - blk.toggleClass(cur_bg, is_bg); - if(is_bg) $('#canvas_bg_url').removeClass(cur_bg); - }); - if(!canvas_bg) blocks.eq(0).addClass(cur_bg); - if(url) { - $('#canvas_bg_url').val(url); - } - $('grid_snapping_step').attr('value', curConfig.snappingStep); - if (curConfig.gridSnapping == true) { - $('#grid_snapping_on').attr('checked', 'checked'); - } else { - $('#grid_snapping_on').removeAttr('checked'); - } - - $('#svg_prefs').show(); - }; - - var properlySourceSizeTextArea = function(){ - // TODO: remove magic numbers here and get values from CSS - var height = $('#svg_source_container').height() - 50; - $('#svg_source_textarea').css('height', height); - }; - - var saveSourceEditor = function(){ - if (!editingsource) return; - - var saveChanges = function() { - svgCanvas.clearSelection(); - hideSourceEditor(); - zoomImage(); - populateLayers(); - updateTitle(); - prepPaints(); - } - - if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { - $.confirm(uiStrings.notification.QerrorsRevertToSource, function(ok) { - if(!ok) return false; - saveChanges(); - }); - } else { - saveChanges(); - } - setSelectMode(); - }; - - var updateTitle = function(title) { - title = title || svgCanvas.getDocumentTitle(); - var new_title = orig_title + (title?': ' + title:''); - - // Remove title update with current context info, isn't really necessary -// if(cur_context) { -// new_title = new_title + cur_context; -// } - $('title:first').text(new_title); - } - - var saveDocProperties = function(){ - - // update resolution - var width = $('#canvas_width'), w = width.val(); - var height = $('#canvas_height'), h = height.val(); - - if(w != "fit" && !svgedit.units.isValidUnit('width', w)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - width.parent().addClass('error'); - return false; - } - - width.parent().removeClass('error'); - - if(h != "fit" && !svgedit.units.isValidUnit('height', h)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - height.parent().addClass('error'); - return false; - } - - height.parent().removeClass('error'); - - if(!svgCanvas.setResolution(w, h)) { - $.alert(uiStrings.notification.noContentToFitTo); - return false; - } - - // set image save option - curPrefs.img_save = $('#image_save_opts :checked').val(); - $.pref('img_save',curPrefs.img_save); - updateCanvas(); - hideDocProperties(); - }; - - var savePreferences = function() { - // set background - var color = $('#bg_blocks div.cur_background').css('background-color') || '#FFF'; - setBackground(color, $('#canvas_bg_url').val()); - - // set language - var lang = $('#lang_select').val(); - if(lang != curPrefs.lang) { - Editor.putLocale(lang); - } - - // set icon size - setIconSize($('#iconsize').val()); - - // set grid setting - curConfig.gridSnapping = $('#grid_snapping_on')[0].checked; - curConfig.snappingStep = $('#grid_snapping_step').val(); - curConfig.showRulers = $('#show_rulers')[0].checked; - - $('#rulers').toggle(curConfig.showRulers); - if(curConfig.showRulers) updateRulers(); - curConfig.baseUnit = $('#base_unit').val(); - - svgCanvas.setConfig(curConfig); - - updateCanvas(); - hidePreferences(); - } - - function setBackground(color, url) { -// if(color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return; - $.pref('bkgd_color', color); - $.pref('bkgd_url', url); - - // This should be done in svgcanvas.js for the borderRect fill - svgCanvas.setBackground(color, url); - } - - var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { - var icon = (typeof icon_id === 'string') ? $.getSvgIcon(icon_id, true) : icon_id.clone(); - if(!icon) { - console.log('NOTE: Icon image missing: ' + icon_id); - return; - } - - $(elem).empty().append(icon); - } - - 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); - - - // 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}); -// } - - // 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'} -// }, - "#tools_top": { - 'left': 50, - 'height': 72 - }, - "#tools_left": { - 'width': 31, - 'top': 74 - }, - "div#workarea": { - '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'} -// } - }; - - var rule_elem = $('#tool_size_rules'); - if(!rule_elem.length) { - rule_elem = $('<style id="tool_size_rules"><\/style>').appendTo('head'); - } else { - rule_elem.empty(); - } - - if(size != 'm') { - var style_str = ''; - $.each(cssResizeRules, function(selector, rules) { - selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor'); - style_str += selector + '{'; - $.each(rules, function(prop, values) { - 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); - } - - setFlyoutPositions(); - } - - var cancelOverlays = function() { - $('#dialog_box').hide(); - if (!editingsource && !docprops && !preferences) { - if(cur_context) { - svgCanvas.leaveContext(); - } - return; - }; - - if (editingsource) { - if (orig_source !== $('#svg_source_textarea').val()) { - $.confirm(uiStrings.notification.QignoreSourceChanges, function(ok) { - if(ok) hideSourceEditor(); - }); - } else { - hideSourceEditor(); - } - } - else if (docprops) { - hideDocProperties(); - } else if (preferences) { - hidePreferences(); - } - resetScrollPos(); - }; - - var hideSourceEditor = function(){ - $('#svg_source_editor').hide(); - editingsource = false; - $('#svg_source_textarea').blur(); - }; - - var hideDocProperties = function(){ - $('#svg_docprops').hide(); - $('#canvas_width,#canvas_height').removeAttr('disabled'); - $('#resolution')[0].selectedIndex = 0; - $('#image_save_opts input').val([curPrefs.img_save]); - docprops = false; - }; - - var hidePreferences = function(){ - $('#svg_prefs').hide(); - preferences = false; - }; - - var win_wh = {width:$(window).width(), height:$(window).height()}; - - var resetScrollPos = $.noop, curScrollPos; - - // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9) - if(svgedit.browser.isIE()) { - (function() { - resetScrollPos = function() { - if(workarea[0].scrollLeft === 0 - && workarea[0].scrollTop === 0) { - workarea[0].scrollLeft = curScrollPos.left; - workarea[0].scrollTop = curScrollPos.top; - } - } - - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - - $(window).resize(resetScrollPos); - svgEditor.ready(function() { - // TODO: Find better way to detect when to do this to minimize - // flickering effect - setTimeout(function() { - resetScrollPos(); - }, 500); - }); - - workarea.scroll(function() { - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - }); - }()); - } - - $(window).resize(function(evt) { - if (editingsource) { - properlySourceSizeTextArea(); - } - - $.each(win_wh, function(type, val) { - var curval = $(window)[type](); - workarea[0]['scroll' + (type==='width'?'Left':'Top')] -= (curval - val)/2; - win_wh[type] = curval; - }); - }); - - (function() { - workarea.scroll(function() { - // TODO: jQuery's scrollLeft/Top() wouldn't require a null check - if ($('#ruler_x').length != 0) { - $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; - } - if ($('#ruler_y').length != 0) { - $('#ruler_y')[0].scrollTop = workarea[0].scrollTop; - } - }); - - }()); - - $('#url_notice').click(function() { - $.alert(this.title); - }); - - $('#change_image_url').click(promptImgURL); - - function promptImgURL() { - var curhref = svgCanvas.getHref(selectedElement); - curhref = curhref.indexOf("data:") === 0?"":curhref; - $.prompt(uiStrings.notification.enterNewImgURL, curhref, function(url) { - if(url) setImageURL(url); - }); - } - - // added these event handlers for all the push buttons so they - // behave more like buttons being pressed-in and not images - (function() { - var toolnames = ['clear','open','save','source','delete','delete_multi','paste','clone','clone_multi','move_top','move_bottom']; - var all_tools = ''; - var cur_class = 'tool_button_current'; - - $.each(toolnames, function(i,item) { - all_tools += '#tool_' + item + (i==toolnames.length-1?',':''); - }); - - $(all_tools).mousedown(function() { - $(this).addClass(cur_class); - }).bind('mousedown mouseout', function() { - $(this).removeClass(cur_class); - }); - - $('#tool_undo, #tool_redo').mousedown(function(){ - if (!$(this).hasClass('disabled')) $(this).addClass(cur_class); - }).bind('mousedown mouseout',function(){ - $(this).removeClass(cur_class);} - ); - }()); - - // switch modifier key in tooltips if mac - // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta - // in Opera and Chrome - if (isMac && !window.opera) { - var shortcutButtons = ["tool_clear", "tool_save", "tool_source", "tool_undo", "tool_redo", "tool_clone"]; - var i = shortcutButtons.length; - while (i--) { - var button = document.getElementById(shortcutButtons[i]); - if (button != null) { - var title = button.title; - var index = title.indexOf("Ctrl+"); - button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join(''); - } - } - } - - // TODO: go back to the color boxes having white background-color and then setting - // background-image to none.png (otherwise partially transparent gradients look weird) - var colorPicker = function(elem) { - var picker = elem.attr('id') == 'stroke_color' ? 'stroke' : 'fill'; -// var opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); - var paint = paintBox[picker].paint; - var title = (picker == 'stroke' ? 'Pick a Stroke Paint and Opacity' : 'Pick a Fill Paint and Opacity'); - var was_none = false; - var pos = elem.position(); - $("#color_picker") - .draggable({cancel:'.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window'}) - .css(curConfig.colorPickerCSS || {'left': pos.left, 'bottom': 50 - pos.top}) - .jGraduate( - { - paint: paint, - window: { pickerTitle: title }, - images: { clientPath: curConfig.jGraduatePath }, - newstop: 'inverse' - }, - function(p) { - paint = new $.jGraduate.Paint(p); - - paintBox[picker].setPaint(paint); - svgCanvas.setPaint(picker, paint); - - $('#color_picker').hide(); - }, - function(p) { - $('#color_picker').hide(); - }); - }; - - var updateToolButtonState = function() { - var bNoFill = (svgCanvas.getColor('fill') == 'none'); - var bNoStroke = (svgCanvas.getColor('stroke') == 'none'); - var buttonsNeedingStroke = [ '#tool_fhpath', '#tool_line' ]; - var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; - if (bNoStroke) { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - $(button).removeClass('disabled'); - } - } - - if (bNoStroke && bNoFill) { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - $(button).removeClass('disabled'); - } - } - - svgCanvas.runExtensions("toolButtonStateUpdate", { - nofill: bNoFill, - nostroke: bNoStroke - }); - - // Disable flyouts if all inside are disabled - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var has_enabled = false; - $(this).children().each(function() { - if(!$(this).hasClass('disabled')) { - has_enabled = true; - } - }); - shower.toggleClass('disabled', !has_enabled); - }); - - operaRepaint(); - }; - - - - var PaintBox = function(container, type) { - var cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke']; - - // set up gradients to be used for the buttons - var svgdocbox = new DOMParser().parseFromString( - '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\ - fill="#' + cur.color + '" opacity="' + cur.opacity + '"/>\ - <defs><linearGradient id="gradbox_"/></defs></svg>', 'text/xml'); - var docElem = svgdocbox.documentElement; - - docElem = $(container)[0].appendChild(document.importNode(docElem, true)); - - docElem.setAttribute('width',24.5); - - this.rect = docElem.firstChild; - this.defs = docElem.getElementsByTagName('defs')[0]; - this.grad = this.defs.firstChild; - this.paint = new $.jGraduate.Paint({solidColor: cur.color}); - this.type = type; - - this.setPaint = function(paint, apply) { - this.paint = paint; - - var fillAttr = "none"; - var ptype = paint.type; - var opac = paint.alpha / 100; - - switch ( ptype ) { - case 'solidColor': - fillAttr = "#" + paint[ptype]; - break; - case 'linearGradient': - case 'radialGradient': - this.defs.removeChild(this.grad); - this.grad = this.defs.appendChild(paint[ptype]); - var id = this.grad.id = 'gradbox_' + this.type; - fillAttr = "url(#" + id + ')'; - } - - this.rect.setAttribute('fill', fillAttr); - this.rect.setAttribute('opacity', opac); - - if(apply) { - svgCanvas.setColor(this.type, fillAttr, true); - svgCanvas.setPaintOpacity(this.type, opac, true); - } - } - - this.update = function(apply) { - if(!selectedElement) return; - var type = this.type; - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - // These elements don't have fill or stroke, so don't change - // the current value - return; - case 'g': - case 'a': - var gPaint = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var elem = childs[i]; - var p = elem.getAttribute(type); - if(i === 0) { - gPaint = p; - } else if(gPaint !== p) { - gPaint = null; - break; - } - } - if(gPaint === null) { - // No common color, don't update anything - var paintColor = null; - return; - } - var paintColor = gPaint; - - var paintOpacity = 1; - break; - default: - var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity")); - if (isNaN(paintOpacity)) { - paintOpacity = 1.0; - } - - var defColor = type === "fill" ? "black" : "none"; - var paintColor = selectedElement.getAttribute(type) || defColor; - } - - if(apply) { - svgCanvas.setColor(type, paintColor, true); - svgCanvas.setPaintOpacity(type, paintOpacity, true); - } - - paintOpacity *= 100; - - var paint = getPaint(paintColor, paintOpacity, type); - // update the rect inside #fill_color/#stroke_color - this.setPaint(paint); - } - - this.prep = function() { - var ptype = this.paint.type; - - switch ( ptype ) { - case 'linearGradient': - case 'radialGradient': - var paint = new $.jGraduate.Paint({copy: this.paint}); - svgCanvas.setPaint(type, paint); - } - } - }; - - paintBox.fill = new PaintBox('#fill_color', 'fill'); - paintBox.stroke = new PaintBox('#stroke_color', 'stroke'); - - $('#stroke_width').val(curConfig.initStroke.width); - $('#group_opacity').val(curConfig.initOpacity * 100); - - // Use this SVG elem to test vectorEffect support - var test_el = paintBox.fill.rect.cloneNode(false); - test_el.setAttribute('style','vector-effect:non-scaling-stroke'); - var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke'); - test_el.removeAttribute('style'); - var svgdocbox = paintBox.fill.rect.ownerDocument; - // Use this to test support for blur element. Seems to work to test support in Webkit - var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur'); - if(typeof blur_test.stdDeviationX === "undefined") { - $('#tool_blur').hide(); - } - $(blur_test).remove(); - - - - // Test for embedImage support (use timeout to not interfere with page load) - setTimeout(function() { - svgCanvas.embedImage('images/placeholder.svg', function(datauri) { - if(!datauri) { - // Disable option - $('#image_save_opts [value=embed]').attr('disabled','disabled'); - $('#image_save_opts input').val(['ref']); - curPrefs.img_save = 'ref'; - $('#image_opt_embed').css('color','#666').attr('title',uiStrings.notification.featNotSupported); - } - }); - },1000); - - $('#tool_fill').click(function(){ - if ($('#tool_fill').hasClass('active')) { - colorPicker($('#fill_color')); - updateToolButtonState(); - } - else { - $('#tool_fill').addClass('active'); - $("#tool_stroke").removeClass('active'); - } - }); - - $('#tool_stroke').click(function(){ - - if ($('#tool_stroke').hasClass('active')) { - colorPicker($('#stroke_color')); - updateToolButtonState(); - } - else { - $('#tool_stroke').addClass('active'); - console.log($('#tool_stroke')); - $("#tool_fill").removeClass('active'); - } - }); - - $('#group_opacityLabel').click(function() { - $('#opacity_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#zoomLabel').click(function() { - $('#zoom_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#tool_move_top').mousedown(function(evt){ - $('#tools_stacking').show(); - evt.preventDefault(); - }); - - $('.layer_button').mousedown(function() { - $(this).addClass('layer_buttonpressed'); - }).mouseout(function() { - $(this).removeClass('layer_buttonpressed'); - }).mouseup(function() { - $(this).removeClass('layer_buttonpressed'); - }); - - $('.push_button').mousedown(function() { - if (!$(this).hasClass('disabled')) { - $(this).addClass('push_button_pressed').removeClass('push_button'); - } - }).mouseout(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }).mouseup(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }); - - $('#layer_new').click(function() { - var i = svgCanvas.getCurrentDrawing().getNumLayers(); - do { - var uniqName = uiStrings.layers.layer + " " + ++i; - } while(svgCanvas.getCurrentDrawing().hasLayer(uniqName)); - - $.prompt(uiStrings.notification.enterUniqueLayerName,uniqName, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.createLayer(newName); - updateContextPanel(); - populateLayers(); - }); - }); - - function deleteLayer() { - if (svgCanvas.deleteCurrentLayer()) { - updateContextPanel(); - populateLayers(); - // This matches what SvgCanvas does - // TODO: make this behavior less brittle (svg-editor should get which - // layer is selected from the canvas and then select that one in the UI) - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:first').addClass("layersel"); - } - } - - function cloneLayer() { - var name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy'; - - $.prompt(uiStrings.notification.enterUniqueLayerName, name, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.cloneLayer(newName); - updateContextPanel(); - populateLayers(); - }); - } - - function mergeLayer() { - if($('#layerlist tr.layersel').index() == svgCanvas.getCurrentDrawing().getNumLayers()-1) return; - svgCanvas.mergeLayer(); - updateContextPanel(); - populateLayers(); - } - - function moveLayer(pos) { - var curIndex = $('#layerlist tr.layersel').index(); - var total = svgCanvas.getCurrentDrawing().getNumLayers(); - if(curIndex > 0 || curIndex < total-1) { - curIndex += pos; - svgCanvas.setCurrentLayerPosition(total-curIndex-1); - populateLayers(); - } - } - - $('#layer_delete').click(deleteLayer); - - $('#layer_up').click(function() { - moveLayer(-1); - }); - - $('#layer_down').click(function() { - moveLayer(1); - }); - - $('#layer_rename').click(function() { - var curIndex = $('#layerlist tr.layersel').prevAll().length; - var oldName = $('#layerlist tr.layersel td.layername').text(); - $.prompt(uiStrings.notification.enterNewLayerName,"", function(newName) { - if (!newName) return; - if (oldName == newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.layerHasThatName); - return; - } - - svgCanvas.renameCurrentLayer(newName); - populateLayers(); - }); - }); - - var SIDEPANEL_MAXWIDTH = 300; - var SIDEPANEL_OPENWIDTH = 150; - var sidedrag = -1, sidedragging = false, allowmove = false; - - var resizePanel = function(evt) { - if (!allowmove) return; - if (sidedrag == -1) return; - sidedragging = true; - var deltax = sidedrag - evt.pageX; - - var sidepanels = $('#sidepanels'); - var sidewidth = parseInt(sidepanels.css('width')); - if (sidewidth+deltax > SIDEPANEL_MAXWIDTH) { - deltax = SIDEPANEL_MAXWIDTH - sidewidth; - sidewidth = SIDEPANEL_MAXWIDTH; - } - else if (sidewidth+deltax < 2) { - deltax = 2 - sidewidth; - sidewidth = 2; - } - - if (deltax == 0) return; - sidedrag -= deltax; - - var layerpanel = $('#layerpanel'); - workarea.css('right', parseInt(workarea.css('right'))+deltax); - sidepanels.css('width', parseInt(sidepanels.css('width'))+deltax); - layerpanel.css('width', parseInt(layerpanel.css('width'))+deltax); - var ruler_x = $('#ruler_x'); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - } - - $('#sidepanel_handle') - .mousedown(function(evt) { - sidedrag = evt.pageX; - $(window).mousemove(resizePanel); - allowmove = false; - // Silly hack for Chrome, which always runs mousemove right after mousedown - setTimeout(function() { - allowmove = true; - }, 20); - }) - .mouseup(function(evt) { - if (!sidedragging) toggleSidePanel(); - sidedrag = -1; - sidedragging = false; - }); - - $(window).mouseup(function() { - sidedrag = -1; - sidedragging = false; - $('#svg_editor').unbind('mousemove', resizePanel); - }); - - // if width is non-zero, then fully close it, otherwise fully open it - // the optional close argument forces the side panel closed - var toggleSidePanel = function(close){ - var w = parseInt($('#sidepanels').css('width')); - var deltax = (w > 2 || close ? 2 : SIDEPANEL_OPENWIDTH) - w; - var sidepanels = $('#sidepanels'); - var layerpanel = $('#layerpanel'); - var ruler_x = $('#ruler_x'); - workarea.css('right', parseInt(workarea.css('right')) + deltax); - sidepanels.css('width', parseInt(sidepanels.css('width')) + deltax); - layerpanel.css('width', parseInt(layerpanel.css('width')) + deltax); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - }; - - // this function highlights the layer passed in (by fading out the other layers) - // if no layer is passed in, this function restores the other layers - var toggleHighlightLayer = function(layerNameToHighlight) { - var curNames = new Array(svgCanvas.getCurrentDrawing().getNumLayers()); - for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getCurrentDrawing().getLayerName(i); } - - if (layerNameToHighlight) { - for (var i = 0; i < curNames.length; ++i) { - if (curNames[i] != layerNameToHighlight) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 0.5); - } - } - } - else { - for (var i = 0; i < curNames.length; ++i) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 1.0); - } - } - }; - - var populateLayers = function(){ - var layerlist = $('#layerlist tbody'); - var selLayerNames = $('#selLayerNames'); - layerlist.empty(); - selLayerNames.empty(); - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var layer = svgCanvas.getCurrentDrawing().getNumLayers(); - var icon = $.getSvgIcon('eye'); - // we get the layers in the reverse z-order (the layer rendered on top is listed first) - while (layer--) { - var name = svgCanvas.getCurrentDrawing().getLayerName(layer); - // contenteditable=\"true\" - var appendstr = "<tr class=\"layer"; - if (name == currentLayerName) { - appendstr += " layersel" - } - appendstr += "\">"; - - if (svgCanvas.getCurrentDrawing().getLayerVisibility(name)) { - appendstr += "<td class=\"layervis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - else { - appendstr += "<td class=\"layervis layerinvis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - layerlist.append(appendstr); - selLayerNames.append("<option value=\"" + name + "\">" + name + "</option>"); - } - if(icon !== undefined) { - var copy = icon.clone(); - $('td.layervis',layerlist).append(icon.clone()); - $.resizeSvgIcons({'td.layervis .svg_icon':14}); - } - // handle selection of layer - $('#layerlist td.layername') - .mouseup(function(evt){ - $('#layerlist tr.layer').removeClass("layersel"); - var row = $(this.parentNode); - row.addClass("layersel"); - svgCanvas.setCurrentLayer(this.textContent); - evt.preventDefault(); - }) - .mouseover(function(evt){ - $(this).css({"font-style": "italic", "color":"blue"}); - toggleHighlightLayer(this.textContent); - }) - .mouseout(function(evt){ - $(this).css({"font-style": "normal", "color":"black"}); - toggleHighlightLayer(); - }); - $('#layerlist td.layervis').click(function(evt){ - var row = $(this.parentNode).prevAll().length; - var name = $('#layerlist tr.layer:eq(' + row + ') td.layername').text(); - var vis = $(this).hasClass('layerinvis'); - svgCanvas.setLayerVisibility(name, vis); - if (vis) { - $(this).removeClass('layerinvis'); - } - else { - $(this).addClass('layerinvis'); - } - }); - - // if there were too few rows, let's add a few to make it not so lonely - var num = 5 - $('#layerlist tr.layer').size(); - while (num-- > 0) { - // FIXME: there must a better way to do this - layerlist.append("<tr><td style=\"color:white\">_</td><td/></tr>"); - } - }; - populateLayers(); - - // function changeResolution(x,y) { - // var zoom = svgCanvas.getResolution().zoom; - // setResolution(x * zoom, y * zoom); - // } - - var centerCanvas = function() { - // this centers the canvas vertically in the workarea (horizontal handled in CSS) - workarea.css('line-height', workarea.height() + 'px'); - }; - - $(window).bind('load resize', centerCanvas); - - function stepFontSize(elem, step) { - var orig_val = elem.value-0; - var sug_val = orig_val + step; - var increasing = sug_val >= orig_val; - if(step === 0) return orig_val; - - if(orig_val >= 24) { - if(increasing) { - return Math.round(orig_val * 1.1); - } else { - return Math.round(orig_val / 1.1); - } - } else if(orig_val <= 1) { - if(increasing) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } else { - return sug_val; - } - } - - function stepZoom(elem, step) { - var orig_val = elem.value-0; - if(orig_val === 0) return 100; - var sug_val = orig_val + step; - if(step === 0) return orig_val; - - if(orig_val >= 100) { - return sug_val; - } else { - if(sug_val >= orig_val) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } - } - - // function setResolution(w, h, center) { - // updateCanvas(); - // // w-=0; h-=0; - // // $('#svgcanvas').css( { 'width': w, 'height': h } ); - // // $('#canvas_width').val(w); - // // $('#canvas_height').val(h); - // // - // // if(center) { - // // var w_area = workarea; - // // var scroll_y = h/2 - w_area.height()/2; - // // var scroll_x = w/2 - w_area.width()/2; - // // w_area[0].scrollTop = scroll_y; - // // w_area[0].scrollLeft = scroll_x; - // // } - // } - - $('#resolution').change(function(){ - var wh = $('#canvas_width,#canvas_height'); - if(!this.selectedIndex) { - if($('#canvas_width').val() == 'fit') { - wh.removeAttr("disabled").val(100); - } - } else if(this.value == 'content') { - wh.val('fit').attr("disabled","disabled"); - } else { - var dims = this.value.split('x'); - $('#canvas_width').val(dims[0]); - $('#canvas_height').val(dims[1]); - wh.removeAttr("disabled"); - } - }); - - //Prevent browser from erroneously repopulating fields - $('input,select').attr("autocomplete","off"); - - // Associate all button actions as well as non-button keyboard shortcuts - var Actions = function() { - // sel:'selector', fn:function, evt:'event', key:[key, preventDefault, NoDisableInInput] - var tool_buttons = [ - {sel:'#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]}, - {sel:'#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]}, - {sel:'#tool_line', fn: clickLine, evt: 'click', key: ['L', true]}, - {sel:'#tool_rect', fn: clickRect, evt: 'click', key: ['R', true], icon: 'rect'}, - {sel:'#tool_ellipse', fn: clickEllipse, evt: 'mouseup', key: ['C', true], icon: 'ellipse'}, - //{sel:'#tool_circle', fn: clickCircle, evt: 'mouseup', icon: 'circle'}, - //{sel:'#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup', parent: '#tools_ellipse', icon: 'fh_ellipse'}, - {sel:'#tool_path', fn: clickPath, evt: 'click', key: ['P', true]}, - {sel:'#tool_text', fn: clickText, evt: 'click', key: ['T', true]}, - {sel:'#tool_image', fn: clickImage, evt: 'mouseup'}, - {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]}, - {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey + 'N', true]}, - {sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey + 'S', true]}, - {sel:'#tool_export', fn: clickExport, evt: 'mouseup'}, - {sel:'#tool_open', fn: clickOpen, evt: 'mouseup'}, - {sel:'#tool_import', fn: clickImport, evt: 'mouseup'}, - {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: [modKey + 'U', true]}, - {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click'}, - {sel:'#tool_rulers', fn: clickRulers, evt: 'click'}, - {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, - {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'}, - {sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'}, - {sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup'}, - {sel:'#tool_prefs_save', fn: savePreferences, evt: 'click'}, - {sel:'#tool_prefs_option', fn: function() {showPreferences();return false}, evt: 'mouseup'}, - {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]}, - {sel:'#tool_reorient', fn: reorientPath, evt: 'click'}, - {sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'}, - {sel:'#tool_node_clone', fn: clonePathNode, evt: 'click'}, - {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'}, - {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'}, - {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'}, - {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: modKey + 'shift+up'}, - {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: modKey + 'shift+down'}, - {sel:'#tool_move_up', fn: moveUpSelected, evt:'click', key: [modKey+'up', true]}, - {sel:'#tool_move_down', fn: moveDownSelected, evt:'click', key: [modKey+'down', true]}, - {sel:'#tool_topath', fn: convertToPath, evt: 'click'}, - {sel:'#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'}, - {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: [modKey + 'Z', true]}, - {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]}, - {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey + 'D', true]}, - {sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey + 'G', true]}, - {sel:'#tool_ungroup', fn: clickGroup, evt: 'click', key: modKey + 'shift+G'}, - {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, - {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, - {sel:'#tool_switch', fn: clickSwitch, evt: 'click', key: ['X', true]}, - // these two lines are required to make Opera work properly with the flyout mechanism - // {sel:'#tools_rect_show', fn: clickRect, evt: 'click'}, - // {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'}, - {sel:'#tool_bold', fn: clickBold, evt: 'mousedown', key: [modKey + 'B', true]}, - {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown', key: [modKey + 'I', true]}, - //{sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']}, - {sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'}, - - // Shortcuts not associated with buttons - - {key: 'ctrl+left', fn: function(){rotateSelected(0,1)}}, - {key: 'ctrl+right', fn: function(){rotateSelected(1,1)}}, - {key: 'ctrl+shift+left', fn: function(){rotateSelected(0,5)}}, - {key: 'ctrl+shift+right', fn: function(){rotateSelected(1,5)}}, - {key: 'shift+O', fn: selectPrev}, - {key: 'shift+P', fn: selectNext}, - {key: [modKey+'+', true], fn: function(){zoomImage(2);}}, - {key: [modKey+'-', true], fn: function(){zoomImage(.5);}}, - {key: ['up', true], fn: function(){moveSelected(0,-1);}}, - {key: ['down', true], fn: function(){moveSelected(0,1);}}, - {key: ['left', true], fn: function(){moveSelected(-1,0);}}, - {key: ['right', true], fn: function(){moveSelected(1,0);}}, - {key: 'shift+up', fn: function(){moveSelected(0,-10)}}, - {key: 'shift+down', fn: function(){moveSelected(0,10)}}, - {key: 'shift+left', fn: function(){moveSelected(-10,0)}}, - {key: 'shift+right', fn: function(){moveSelected(10,0)}}, - {key: ['alt+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-1)}}, - {key: ['alt+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,1)}}, - {key: ['alt+left', true], fn: function(){svgCanvas.cloneSelectedElements(-1,0)}}, - {key: ['alt+right', true], fn: function(){svgCanvas.cloneSelectedElements(1,0)}}, - {key: ['alt+shift+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-10)}}, - {key: ['alt+shift+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,10)}}, - {key: ['alt+shift+left', true], fn: function(){svgCanvas.cloneSelectedElements(-10,0)}}, - {key: ['alt+shift+right', true], fn: function(){svgCanvas.cloneSelectedElements(10,0)}}, - {key: modKey + 'A', fn: function(){svgCanvas.selectAllInCurrentLayer();}}, - - // Standard shortcuts - {key: modKey + 'z', fn: clickUndo}, - {key: modKey + 'shift+z', fn: clickRedo}, - {key: modKey + 'y', fn: clickRedo}, - - {key: modKey+'x', fn: cutSelected}, - {key: modKey+'c', fn: copySelected}, - {key: modKey+'v', fn: pasteInCenter} - - - ]; - - // Tooltips not directly associated with a single function - var key_assocs = { - '4/Shift+4': '#tools_rect_show', - '5/Shift+5': '#tools_ellipse_show' - }; - - return { - setAll: function() { - var flyouts = {}; - - $.each(tool_buttons, function(i, opts) { - // Bind function to button - if(opts.sel) { - var btn = $(opts.sel); - if (btn.length == 0) return true; // Skip if markup does not exist - if(opts.evt) { - if (svgedit.browser.isTouch() && opts.evt === "click") opts.evt = "mousedown" - btn[opts.evt](opts.fn); - } - - // Add to parent flyout menu, if able to be displayed - if(opts.parent && $(opts.parent + '_show').length != 0) { - var f_h = $(opts.parent); - if(!f_h.length) { - f_h = makeFlyoutHolder(opts.parent.substr(1)); - } - - f_h.append(btn); - - if(!$.isArray(flyouts[opts.parent])) { - flyouts[opts.parent] = []; - } - flyouts[opts.parent].push(opts); - } - } - - - // Bind function to shortcut key - if(opts.key) { - // Set shortcut based on options - var keyval, shortcut = '', disInInp = true, fn = opts.fn, pd = false; - if($.isArray(opts.key)) { - keyval = opts.key[0]; - if(opts.key.length > 1) pd = opts.key[1]; - if(opts.key.length > 2) disInInp = opts.key[2]; - } else { - keyval = opts.key; - } - keyval += ''; - if (svgedit.browser.isMac && keyval.indexOf("+") != -1) { - var modifier_key = keyval.split("+")[0]; - if (modifier_key == "ctrl") keyval.replace("ctrl", "cmd") - } - - $.each(keyval.split('/'), function(i, key) { - $(document).bind('keydown', key, function(e) { - fn(); - if(pd) { - e.preventDefault(); - } - // Prevent default on ALL keys? - return false; - }); - }); - - // Put shortcut in title - if(opts.sel && !opts.hidekey && btn.attr('title')) { - var new_title = btn.attr('title').split('[')[0] + ' (' + keyval + ')'; - key_assocs[keyval] = opts.sel; - // Disregard for menu items - if(!btn.parents('#main_menu').length) { - btn.attr('title', new_title); - } - } - } - }); - - // Setup flyouts - setupFlyouts(flyouts); - - - // Misc additional actions - - // Make "return" keypress trigger the change event - $('.attr_changer, #image_url').bind('keydown', 'return', - function(evt) {$(this).change();evt.preventDefault();} - ); - - $(window).bind('keydown', 'tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectNext(); - } - }).bind('keydown', 'shift+tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectPrev(); - } - }); - - $('#tool_zoom').dblclick(dblclickZoom); - }, - setTitles: function() { - $.each(key_assocs, function(keyval, sel) { - var menu = ($(sel).parents('#main_menu').length); - - $(sel).each(function() { - if(menu) { - var t = $(this).text().split(' [')[0]; - } else { - var t = this.title.split(' [')[0]; - } - var key_str = ''; - // Shift+Up - $.each(keyval.split('/'), function(i, key) { - var mod_bits = key.split('+'), mod = ''; - if(mod_bits.length > 1) { - mod = mod_bits[0] + '+'; - key = mod_bits[1]; - } - key_str += (i?'/':'') + mod + (uiStrings['key_'+key] || key); - }); - if(menu) { - this.lastChild.textContent = t +' ['+key_str+']'; - } else { - this.title = t +' ['+key_str+']'; - } - }); - }); - }, - getButtonData: function(sel) { - var b; - $.each(tool_buttons, function(i, btn) { - if(btn.sel === sel) b = btn; - }); - return b; - } - }; - }(); - - Actions.setAll(); - - // Select given tool - Editor.ready(function() { - var tool, - itool = curConfig.initTool, - container = $("#tools_left, #svg_editor .tools_flyout"), - pre_tool = container.find("#tool_" + itool), - reg_tool = container.find("#" + itool); - if(pre_tool.length) { - tool = pre_tool; - } else if(reg_tool.length){ - tool = reg_tool; - } else { - tool = $("#tool_select"); - } - tool.click().mouseup(); - - if(curConfig.wireframe) { - $('#tool_wireframe').click(); - } - - if(curConfig.showlayers) { - toggleSidePanel(); - } - - $('#rulers').toggle(!!curConfig.showRulers); - - if (curConfig.showRulers) { - $('#show_rulers')[0].checked = true; - } - - if(curConfig.gridSnapping) { - $('#grid_snapping_on')[0].checked = true; - } - - if(curConfig.baseUnit) { - $('#base_unit').val(curConfig.baseUnit); - } - - if(curConfig.snappingStep) { - $('#grid_snapping_step').val(curConfig.snappingStep); - } - }); - - $('#rect_rx').SpinButton({ min: 0, max: 1000, step: 1, callback: changeRectRadius }); - $('#stroke_width').SpinButton({ min: 0, max: 99, step: 1, smallStep: 0.1, callback: changeStrokeWidth }); - $('#angle').SpinButton({ min: -180, max: 180, step: 5, callback: changeRotationAngle }); - $('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize }); - $('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity }); - $('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur }); - $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom }) - // Set default zoom - .val(svgCanvas.getZoom() * 100); - - $("#workarea").contextMenu({ - menu: 'cmenu_canvas', - inSpeed: 0 - }, - function(action, el, pos) { - switch ( action ) { - case 'delete': - deleteSelected(); - break; - case 'cut': - cutSelected(); - break; - case 'copy': - copySelected(); - break; - case 'paste': - svgCanvas.pasteElements(); - break; - case 'paste_in_place': - svgCanvas.pasteElements('in_place'); - break; - case 'group': - svgCanvas.groupSelectedElements(); - break; - case 'ungroup': - svgCanvas.ungroupSelectedElement(); - break; - case 'move_front': - moveToTopSelected(); - break; - case 'move_up': - moveUpDownSelected('Up'); - break; - case 'move_down': - moveUpDownSelected('Down'); - break; - case 'move_back': - moveToBottomSelected(); - break; - default: - if(svgedit.contextmenu && svgedit.contextmenu.hasCustomHandler(action)){ - svgedit.contextmenu.getCustomHandler(action).call(); - } - break; - } - - if(svgCanvas.clipBoard.length) { - canv_menu.enableContextMenuItems('#paste,#paste_in_place'); - } - }); - - var lmenu_func = function(action, el, pos) { - switch ( action ) { - case 'dupe': - cloneLayer(); - break; - case 'delete': - deleteLayer(); - break; - case 'merge_down': - mergeLayer(); - break; - case 'merge_all': - svgCanvas.mergeAllLayers(); - updateContextPanel(); - populateLayers(); - break; - } - } - - $("#layerlist").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0 - }, - lmenu_func - ); - - $("#layer_moreopts").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0, - allowLeft: true - }, - lmenu_func - ); - - $('.contextMenu li').mousedown(function(ev) { - ev.preventDefault(); - }) - - $('#cmenu_canvas li').disableContextMenu(); - canv_menu.enableContextMenuItems('#delete,#cut,#copy'); - - window.onbeforeunload = function() { - // Suppress warning if page is empty - if(undoMgr.getUndoStackSize() === 0) { - Editor.show_save_warning = false; - } - - // show_save_warning is set to "false" when the page is saved. - if(!curConfig.no_save_warning && Editor.show_save_warning) { - // Browser already asks question about closing the page - return uiStrings.notification.unsavedChanges; - } - }; - - Editor.openPrep = function(func) { - $('#main_menu').hide(); - if(undoMgr.getUndoStackSize() === 0) { - func(true); - } else { - $.confirm(uiStrings.notification.QwantToOpen, func); - } - } - - // use HTML5 File API: http://www.w3.org/TR/FileAPI/ - // if browser has HTML5 File API support, then we will show the open menu item - // and provide a file input to click. When that change event fires, it will - // get the text contents of the file and send it to the canvas - if (window.FileReader) { - var inp = $('<input type="file">').change(function() { - var f = this; - Editor.openPrep(function(ok) { - if(!ok) return; - svgCanvas.clear(); - if(f.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - loadSvgString(e.target.result); - updateCanvas(); - }; - reader.readAsText(f.files[0]); - } - }); - }); - $("#tool_open").show().prepend(inp); - var inp2 = $('<input type="file">').change(function() { - $('#main_menu').hide(); - if(this.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - svgCanvas.importSvgString(e.target.result, true); - updateCanvas(); - }; - reader.readAsText(this.files[0]); - } - }); - $("#tool_import").show().prepend(inp2); - } - - var updateCanvas = Editor.updateCanvas = function(center, new_ctr) { - - var w = workarea.width(), h = workarea.height(); - var w_orig = w, h_orig = h; - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - var cnvs = $("#svgcanvas"); - - var old_ctr = { - x: w_area[0].scrollLeft + w_orig/2, - y: w_area[0].scrollTop + h_orig/2 - }; - - var multi = curConfig.canvas_expansion; - w = Math.max(w_orig, svgCanvas.contentW * zoom * multi); - h = Math.max(h_orig, svgCanvas.contentH * zoom * multi); - - if(w == w_orig && h == h_orig) { - workarea.css('overflow','hidden'); - } else { - workarea.css('overflow','scroll'); - } - - var old_can_y = cnvs.height()/2; - var old_can_x = cnvs.width()/2; - cnvs.width(w).height(h); - var new_can_y = h/2; - var new_can_x = w/2; - var offset = svgCanvas.updateCanvas(w, h); - - var ratio = new_can_x / old_can_x; - - var scroll_x = w/2 - w_orig/2; - var scroll_y = h/2 - h_orig/2; - - if(!new_ctr) { - - var old_dist_x = old_ctr.x - old_can_x; - var new_x = new_can_x + old_dist_x * ratio; - - var old_dist_y = old_ctr.y - old_can_y; - var new_y = new_can_y + old_dist_y * ratio; - - new_ctr = { - x: new_x, - y: new_y - }; - - } else { - new_ctr.x += offset.x, - new_ctr.y += offset.y; - } - - if(center) { - // Go to top-left for larger documents - if(svgCanvas.contentW > w_area.width()) { - // Top-left - workarea[0].scrollLeft = offset.x - 10; - workarea[0].scrollTop = offset.y - 10; - } else { - // Center - w_area[0].scrollLeft = scroll_x; - w_area[0].scrollTop = scroll_y; - } - } else { - w_area[0].scrollLeft = new_ctr.x - w_orig/2; - w_area[0].scrollTop = new_ctr.y - h_orig/2; - } - if(curConfig.showRulers) { - updateRulers(cnvs, zoom); - workarea.scroll(); - } - } - - // Make [1,2,5] array - var r_intervals = []; - for(var i = .1; i < 1E5; i *= 10) { - r_intervals.push(1 * i); - r_intervals.push(2 * i); - r_intervals.push(5 * i); - } - - function updateRulers(scanvas, zoom) { - var ruler_x_cursor = document.getElementById("ruler_x_cursor"); - var ruler_y_cursor = document.getElementById("ruler_y_cursor"); - var workarea = document.getElementById("workarea"); - var title_show = document.getElementById("title_show"); - var offset_x = 66; - var offset_y = 48; - $("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers", function(e){ - e.stopPropagation(); - ruler_x_cursor.style.left = (e.pageX-offset_x+workarea.scrollLeft) + "px"; - ruler_y_cursor.style.top = (e.pageY-offset_y+workarea.scrollTop) + "px"; - var title = e.target.getAttribute("title"); - if (typeof title != 'undefined' && title) title_show.innerHTML(title); - }) - if(!zoom) zoom = svgCanvas.getZoom(); - if(!scanvas) scanvas = $("#svgcanvas"); - - var limit = 30000; - - var c_elem = svgCanvas.getContentElem(); - - var units = svgedit.units.getTypeMap(); - var unit = units[curConfig.baseUnit]; // 1 = 1px - - for(var d = 0; d < 2; d++) { - var is_x = (d === 0); - var dim = is_x ? 'x' : 'y'; - var lentype = is_x?'width':'height'; - var content_d = c_elem.getAttribute(dim)-0; - - var $hcanv_orig = $('#ruler_' + dim + ' canvas:first'); - - // Bit of a hack to fully clear the canvas in Safari & IE9 - $hcanv = $hcanv_orig.clone(); - $hcanv_orig.replaceWith($hcanv); - - var hcanv = $hcanv[0]; - - // Set the canvas size to the width of the container - var ruler_len = scanvas[lentype]()*2; - var total_len = ruler_len; - hcanv.parentNode.style[lentype] = total_len + 'px'; - - var canv_count = 1; - var ctx_num = 0; - var ctx_arr; - var ctx = hcanv.getContext("2d"); - - ctx.fillStyle = "rgb(200,0,0)"; - ctx.fillRect(0,0,hcanv.width,hcanv.height); - - // Remove any existing canvasses - $hcanv.siblings().remove(); - - // Create multiple canvases when necessary (due to browser limits) - if(ruler_len >= limit) { - var num = parseInt(ruler_len / limit) + 1; - ctx_arr = Array(num); - ctx_arr[0] = ctx; - for(var i = 1; i < num; i++) { - hcanv[lentype] = limit; - var copy = hcanv.cloneNode(true); - hcanv.parentNode.appendChild(copy); - ctx_arr[i] = copy.getContext('2d'); - } - - copy[lentype] = ruler_len % limit; - - // set copy width to last - ruler_len = limit; - } - - hcanv[lentype] = ruler_len; - - var u_multi = unit * zoom; - - // Calculate the main number interval - var raw_m = 50 / u_multi; - var multi = 1; - for(var i = 0; i < r_intervals.length; i++) { - var num = r_intervals[i]; - multi = num; - if(raw_m <= num) { - break; - } - } - - var big_int = multi * u_multi; - ctx.font = "normal 9px 'Lucida Grande', sans-serif"; - ctx.fillStyle = "#777"; - - var ruler_d = ((content_d / u_multi) % multi) * u_multi; - var label_pos = ruler_d - big_int; - for (; ruler_d < total_len; ruler_d += big_int) { - label_pos += big_int; - var real_d = ruler_d - content_d; - - var cur_d = Math.round(ruler_d) + .5; - if(is_x) { - ctx.moveTo(cur_d, 15); - ctx.lineTo(cur_d, 0); - } else { - ctx.moveTo(15, cur_d); - ctx.lineTo(0, cur_d); - } - - var num = (label_pos - content_d) / u_multi; - var label; - if(multi >= 1) { - label = Math.round(num); - } else { - var decs = (multi+'').split('.')[1].length; - label = num.toFixed(decs)-0; - } - - // Do anything special for negative numbers? -// var is_neg = label < 0; -// real_d2 = Math.abs(real_d2); - - // Change 1000s to Ks - if(label !== 0 && label !== 1000 && label % 1000 === 0) { - label = (label / 1000) + 'K'; - } - - if(is_x) { - ctx.fillText(label, ruler_d+2, 8); - ctx.fillStyle = "#777"; - } else { - var str = (label+'').split(''); - for(var i = 0; i < str.length; i++) { - ctx.fillText(str[i], 1, (ruler_d+9) + i*9); - ctx.fillStyle = "#777"; - } - } - - var part = big_int / 10; - for(var i = 1; i < 10; i++) { - var sub_d = Math.round(ruler_d + part * i) + .5; - if(ctx_arr && sub_d > ruler_len) { - ctx_num++; - ctx.stroke(); - if(ctx_num >= ctx_arr.length) { - i = 10; - ruler_d = total_len; - continue; - } - ctx = ctx_arr[ctx_num]; - ruler_d -= limit; - sub_d = Math.round(ruler_d + part * i) + .5; - } - - var line_num = (i % 2)?12:10; - if(is_x) { - ctx.moveTo(sub_d, 15); - ctx.lineTo(sub_d, line_num); - } else { - ctx.moveTo(15, sub_d); - ctx.lineTo(line_num ,sub_d); - } - } - } - - // console.log('ctx', ctx); - ctx.strokeStyle = "#666"; - ctx.stroke(); - } - } - -// $(function() { - updateCanvas(true); -// }); - - // var revnums = "svg-editor.js ($Rev: 2083 $) "; - // revnums += svgCanvas.getVersion(); - // $('#copyright')[0].setAttribute("title", revnums); - - // Callback handler for embedapi.js - try{ - var json_encode = function(obj){ - //simple partial JSON encoder implementation - if(window.JSON && JSON.stringify) return JSON.stringify(obj); - var enc = arguments.callee; //for purposes of recursion - if(typeof obj == "boolean" || typeof obj == "number"){ - return obj+'' //should work... - }else if(typeof obj == "string"){ - //a large portion of this is stolen from Douglas Crockford's json2.js - return '"'+ - obj.replace( - /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g - , function (a) { - return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) - +'"'; //note that this isn't quite as purtyful as the usualness - }else if(obj.length){ //simple hackish test for arrayish-ness - for(var i = 0; i < obj.length; i++){ - obj[i] = enc(obj[i]); //encode every sub-thingy on top - } - return "["+obj.join(",")+"]"; - }else{ - var pairs = []; //pairs will be stored here - for(var k in obj){ //loop through thingys - pairs.push(enc(k)+":"+enc(obj[k])); //key: value - } - return "{"+pairs.join(",")+"}" //wrap in the braces - } - } - window.addEventListener("message", function(e){ - var cbid = parseInt(e.data.substr(0, e.data.indexOf(";"))); - try{ - e.source.postMessage("SVGe"+cbid+";"+json_encode(eval(e.data)), "*"); - }catch(err){ - e.source.postMessage("SVGe"+cbid+";error:"+err.message, "*"); - } - }, false) - }catch(err){ - window.embed_error = err; - } - - - - // For Compatibility with older extensions - $(function() { - window.svgCanvas = svgCanvas; - svgCanvas.ready = svgEditor.ready; - }); - - - Editor.setLang = function(lang, allStrings) { - $.pref('lang', lang); - $('#lang_select').val(lang); - if(allStrings) { - - var notif = allStrings.notification; - - - - // $.extend will only replace the given strings - var oldLayerName = $('#layerlist tr.layersel td.layername').text(); - var rename_layer = (oldLayerName == uiStrings.common.layer + ' 1'); - - $.extend(uiStrings, allStrings); - svgCanvas.setUiStrings(allStrings); - Actions.setTitles(); - - if(rename_layer) { - svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1'); - populateLayers(); - } - - svgCanvas.runExtensions("langChanged", lang); - - // Update flyout tooltips - setFlyoutTitles(); - - // Copy title for certain tool elements - var elems = { - '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', - '#fill_color': '#tool_fill label, #tool_fill .color_block', - '#linejoin_miter': '#cur_linejoin', - '#linecap_butt': '#cur_linecap' - } - - $.each(elems, function(source, dest) { - $(dest).attr('title', $(source)[0].title); - }); - - // Copy alignment titles - $('#multiselected_panel div[id^=tool_align]').each(function() { - $('#tool_pos' + this.id.substr(10))[0].title = this.title; - }); - - } - }; - }; - - var callbacks = []; - - function loadSvgString(str, callback) { - var success = svgCanvas.setSvgString(str) !== false; - callback = callback || $.noop; - if(success) { - callback(true); - } else { - $.alert(uiStrings.notification.errorLoadingSVG, function() { - callback(false); - }); - } - } - - Editor.ready = function(cb) { - if(!is_ready) { - callbacks.push(cb); - } else { - cb(); - } - }; - - Editor.runCallbacks = function() { - $.each(callbacks, function() { - this(); - }); - is_ready = true; - }; - - Editor.loadFromString = function(str) { - Editor.ready(function() { - loadSvgString(str); - }); - }; - - Editor.disableUI = function(featList) { -// $(function() { -// $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove(); -// $('#tools_top').css('left', 5); -// }); - }; - - Editor.loadFromURL = function(url, opts) { - if(!opts) opts = {}; - - var cache = opts.cache; - var cb = opts.callback; - - Editor.ready(function() { - $.ajax({ - 'url': url, - 'dataType': 'text', - cache: !!cache, - success: function(str) { - loadSvgString(str, cb); - }, - error: function(xhr, stat, err) { - if(xhr.status != 404 && xhr.responseText) { - loadSvgString(xhr.responseText, cb); - } else { - $.alert(uiStrings.notification.URLloadFail + ": \n"+err+'', cb); - } - } - }); - }); - }; - - Editor.loadFromDataURI = function(str) { - Editor.ready(function() { - var pre = 'data:image/svg+xml;base64,'; - var src = str.substring(pre.length); - loadSvgString(svgedit.utilities.decode64(src)); - }); - }; - - Editor.addExtension = function() { - var args = arguments; - - // Note that we don't want this on Editor.ready since some extensions - // may want to run before then (like server_opensave). - $(function() { - if(svgCanvas) svgCanvas.addExtension.apply(this, args); - }); - }; - - return Editor; - }(jQuery); - - // Run init once DOM is loaded - $(svgEditor.init); - -})(); - -// ?iconsize=s&bkgd_color=555 - -// svgEditor.setConfig({ -// // imgPath: 'foo', -// dimensions: [800, 600], -// canvas_expansion: 5, -// initStroke: { -// color: '0000FF', -// width: 3.5, -// opacity: .5 -// }, -// initFill: { -// color: '550000', -// opacity: .75 -// }, -// extensions: ['ext-helloworld.js'] -// }) diff --git a/build/opera/editor/svg-editor.manifest b/build/opera/editor/svg-editor.manifest deleted file mode 100644 index b156374..0000000 --- a/build/opera/editor/svg-editor.manifest +++ /dev/null @@ -1,121 +0,0 @@ -CACHE MANIFEST -svg-editor.html -images/logo.png -jgraduate/css/jPicker-1.0.9.css -jgraduate/css/jGraduate-0.2.0.css -svg-editor.css -spinbtn/JQuerySpinBtn.css -jquery.js -js-hotkeys/jquery.hotkeys.min.js -jquery-ui/jquery-ui-1.7.2.custom.min.js -jgraduate/jpicker-1.0.9.min.js -jgraduate/jquery.jgraduate.js -spinbtn/JQuerySpinBtn.js -svgcanvas.js -svg-editor.js -images/align-bottom.png -images/align-center.png -images/align-left.png -images/align-middle.png -images/align-right.png -images/align-top.png -images/bold.png -images/cancel.png -images/circle.png -images/clear.png -images/clone.png -images/copy.png -images/cut.png -images/delete.png -images/document-properties.png -images/dropdown.gif -images/ellipse.png -images/eye.png -images/flyouth.png -images/flyup.gif -images/freehand-circle.png -images/freehand-square.png -images/go-down.png -images/go-up.png -images/image.png -images/italic.png -images/line.png -images/logo.png -images/logo.svg -images/move_bottom.png -images/move_top.png -images/none.png -images/open.png -images/paste.png -images/path.png -images/polygon.png -images/rect.png -images/redo.png -images/save.png -images/select.png -images/sep.png -images/shape_group.png -images/shape_ungroup.png -images/source.png -images/square.png -images/text.png -images/undo.png -images/view-refresh.png -images/wave.png -images/zoom.png -locale/locale.js -locale/lang.af.js -locale/lang.ar.js -locale/lang.az.js -locale/lang.be.js -locale/lang.bg.js -locale/lang.ca.js -locale/lang.cs.js -locale/lang.cy.js -locale/lang.da.js -locale/lang.de.js -locale/lang.el.js -locale/lang.en.js -locale/lang.es.js -locale/lang.et.js -locale/lang.fa.js -locale/lang.fi.js -locale/lang.fr.js -locale/lang.ga.js -locale/lang.gl.js -locale/lang.hi.js -locale/lang.hr.js -locale/lang.hu.js -locale/lang.hy.js -locale/lang.id.js -locale/lang.is.js -locale/lang.it.js -locale/lang.iw.js -locale/lang.ja.js -locale/lang.ko.js -locale/lang.lt.js -locale/lang.lv.js -locale/lang.mk.js -locale/lang.ms.js -locale/lang.mt.js -locale/lang.nl.js -locale/lang.no.js -locale/lang.pl.js -locale/lang.pt-PT.js -locale/lang.ro.js -locale/lang.ru.js -locale/lang.sk.js -locale/lang.sl.js -locale/lang.sq.js -locale/lang.sr.js -locale/lang.sv.js -locale/lang.sw.js -locale/lang.th.js -locale/lang.tl.js -locale/lang.tr.js -locale/lang.uk.js -locale/lang.vi.js -locale/lang.yi.js -locale/lang.zh-CN.js -locale/lang.zh-TW.js -locale/lang.zh.js diff --git a/build/opera/editor/svgcanvas.js b/build/opera/editor/svgcanvas.js deleted file mode 100644 index ab1305a..0000000 --- a/build/opera/editor/svgcanvas.js +++ /dev/null @@ -1,8819 +0,0 @@ -/* - * svgcanvas.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js -// 4) math.js -// 5) units.js -// 6) svgutils.js -// 7) sanitize.js -// 8) history.js -// 9) select.js -// 10) draw.js -// 11) path.js - -/*jslint browser: true*/ - -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(window.opera) { - window.console.log = function(str) { opera.postError(str); }; - window.console.dir = function(str) {}; -} - -(function() { - - // This fixes $(...).attr() to work as expected with SVG elements. - // Does not currently use *AttributeNS() since we rarely need that. - - // See http://api.jquery.com/attr/ for basic documentation of .attr() - - // Additional functionality: - // - When getting attributes, a string that's a number is return as type number. - // - If an array is supplied as first parameter, multiple values are returned - // as an object with values for each given attributes - - var proxied = jQuery.fn.attr, svgns = "http://www.w3.org/2000/svg"; - jQuery.fn.attr = function(key, value) { - var len = this.length; - if(!len) return proxied.apply(this, arguments); - for(var i=0; i<len; i++) { - var elem = this[i]; - // set/get SVG attribute - if(elem.namespaceURI === svgns) { - // Setting attribute - if(value !== undefined) { - elem.setAttribute(key, value); - } else if($.isArray(key)) { - // Getting attributes from array - var j = key.length, obj = {}; - - while(j--) { - var aname = key[j]; - var attr = elem.getAttribute(aname); - // This returns a number when appropriate - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - obj[aname] = attr; - } - return obj; - - } else if(typeof key === "object") { - // Setting attributes form object - for(var v in key) { - elem.setAttribute(v, key[v]); - } - // Getting attribute - } else { - var attr = elem.getAttribute(key); - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - - return attr; - } - } else { - return proxied.apply(this, arguments); - } - } - return this; - }; - -}()); - -// Class: SvgCanvas -// The main SvgCanvas class that manages all SVG-related functions -// -// Parameters: -// container - The container HTML element that should hold the SVG root element -// config - An object that contains configuration data -$.SvgCanvas = function(container, config) -{ -// Namespace constants -var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - xmlns = "http://www.w3.org/XML/1998/namespace", - xmlnsns = "http://www.w3.org/2000/xmlns/", // see http://www.w3.org/TR/REC-xml-names/#xmlReserved - se_ns = "http://svg-edit.googlecode.com", - htmlns = "http://www.w3.org/1999/xhtml", - mathns = "http://www.w3.org/1998/Math/MathML"; - -// Default configuration options -var curConfig = { - show_outside_canvas: true, - selectNew: true, - dimensions: [640, 480] -}; - -// Update config with new one if given -if(config) { - $.extend(curConfig, config); -} - -// Array with width/height of canvas -var dimensions = curConfig.dimensions; - -var canvas = this; - -// "document" element associated with the container (same as window.document using default svg-editor.js) -// NOTE: This is not actually a SVG document, but a HTML document. -var svgdoc = container.ownerDocument; - -// This is a container for the document being edited, not the document itself. -var svgroot = svgdoc.importNode(svgedit.utilities.text2xml( - '<svg id="svgroot" xmlns="' + svgns + '" xlinkns="' + xlinkns + '" ' + - 'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' + - '<defs>' + - '<filter id="canvashadow" filterUnits="objectBoundingBox">' + - '<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>'+ - '<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>'+ - '<feMerge>'+ - '<feMergeNode in="offsetBlur"/>'+ - '<feMergeNode in="SourceGraphic"/>'+ - '</feMerge>'+ - '</filter>'+ - '</defs>'+ - '</svg>').documentElement, true); -container.appendChild(svgroot); - -// The actual element that represents the final output SVG element -var svgcontent = svgdoc.createElementNS(svgns, "svg"); - -// This function resets the svgcontent element while keeping it in the DOM. -var clearSvgContentElement = canvas.clearSvgContentElement = function() { - while (svgcontent.firstChild) { svgcontent.removeChild(svgcontent.firstChild); } - - // TODO: Clear out all other attributes first? - $(svgcontent).attr({ - id: 'svgcontent', - width: dimensions[0], - height: dimensions[1], - x: dimensions[0], - y: dimensions[1], - overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden', - xmlns: svgns, - "xmlns:se": se_ns, - "xmlns:xlink": xlinkns - }).appendTo(svgroot); - - // TODO: make this string optional and set by the client - var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ "); - svgcontent.appendChild(comment); -}; -clearSvgContentElement(); - -// Prefix string for element IDs -var idprefix = "svg_"; - -// Function: setIdPrefix -// Changes the ID prefix to the given value -// -// Parameters: -// p - String with the new prefix -canvas.setIdPrefix = function(p) { - idprefix = p; -}; - -// Current svgedit.draw.Drawing object -// @type {svgedit.draw.Drawing} -canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - -// Function: getCurrentDrawing -// Returns the current Drawing. -// @return {svgedit.draw.Drawing} -var getCurrentDrawing = canvas.getCurrentDrawing = function() { - return canvas.current_drawing_; -}; - -// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc) -var current_zoom = 1; - -// pointer to current group (for in-group editing) -var current_group = null; - -// Object containing data for the currently selected styles -var all_properties = { - shape: { - fill: (curConfig.initFill.color == 'none' ? '' : '#') + curConfig.initFill.color, - fill_paint: null, - fill_opacity: curConfig.initFill.opacity, - stroke: "#" + curConfig.initStroke.color, - stroke_paint: null, - stroke_opacity: curConfig.initStroke.opacity, - stroke_width: curConfig.initStroke.width, - stroke_dasharray: 'none', - stroke_linejoin: 'miter', - stroke_linecap: 'butt', - opacity: curConfig.initOpacity - } -}; - -all_properties.text = $.extend(true, {}, all_properties.shape); -$.extend(all_properties.text, { - fill: "#000000", - stroke_width: 0, - font_size: 24, - font_family: 'Junction' -}); - -// Current shape style properties -var cur_shape = all_properties.shape; - -// Array with all the currently selected elements -// default size of 1 until it needs to grow bigger -var selectedElements = new Array(1); - -// Function: addSvgElementFromJson -// Create a new SVG element based on the given object keys/values and add it to the current layer -// The element will be ran through cleanupElement before being returned -// -// Parameters: -// data - Object with the following keys/values: -// * element - tag name of the SVG element to create -// * attr - Object with attributes key-values to assign to the new element -// * curStyles - Boolean indicating that current style attributes should be applied first -// -// Returns: The new element -var addSvgElementFromJson = this.addSvgElementFromJson = function(data) { - var shape = svgedit.utilities.getElem(data.attr.id); - // if shape is a path but we need to create a rect/ellipse, then remove the path - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (shape && data.element != shape.tagName) { - current_layer.removeChild(shape); - shape = null; - } - if (!shape) { - shape = svgdoc.createElementNS(svgns, data.element); - if (current_layer) { - (current_group || current_layer).appendChild(shape); - } - } - if(data.curStyles) { - svgedit.utilities.assignAttributes(shape, { - "fill": cur_shape.fill, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - }, 100); - } - svgedit.utilities.assignAttributes(shape, data.attr, 100); - svgedit.utilities.cleanupElement(shape); - return shape; -}; - - -// import svgtransformlist.js -var getTransformList = canvas.getTransformList = svgedit.transformlist.getTransformList; - -// import from math.js. -var transformPoint = svgedit.math.transformPoint; -var matrixMultiply = canvas.matrixMultiply = svgedit.math.matrixMultiply; -var hasMatrixTransform = canvas.hasMatrixTransform = svgedit.math.hasMatrixTransform; -var transformListToTransform = canvas.transformListToTransform = svgedit.math.transformListToTransform; -var snapToAngle = svgedit.math.snapToAngle; -var getMatrix = svgedit.math.getMatrix; - -// initialize from units.js -// send in an object implementing the ElementContainer interface (see units.js) -svgedit.units.init({ - getBaseUnit: function() { return curConfig.baseUnit; }, - getElement: svgedit.utilities.getElem, - getHeight: function() { return svgcontent.getAttribute("height")/current_zoom; }, - getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; }, - getRoundDigits: function() { return save_options.round_digits; } -}); -// import from units.js -var convertToNum = canvas.convertToNum = svgedit.units.convertToNum; - -// import from svgutils.js -svgedit.utilities.init({ - getDOMDocument: function() { return svgdoc; }, - getDOMContainer: function() { return container; }, - getSVGRoot: function() { return svgroot; }, - // TODO: replace this mostly with a way to get the current drawing. - getSelectedElements: function() { return selectedElements; }, - getSVGContent: function() { return svgcontent; } -}); -var getUrlFromAttr = canvas.getUrlFromAttr = svgedit.utilities.getUrlFromAttr; -var getHref = canvas.getHref = svgedit.utilities.getHref; -var setHref = canvas.setHref = svgedit.utilities.setHref; -var getPathBBox = svgedit.utilities.getPathBBox; -var getBBox = canvas.getBBox = svgedit.utilities.getBBox; -var getRotationAngle = canvas.getRotationAngle = svgedit.utilities.getRotationAngle; -var getElem = canvas.getElem = svgedit.utilities.getElem; -var assignAttributes = canvas.assignAttributes = svgedit.utilities.assignAttributes; -var cleanupElement = this.cleanupElement = svgedit.utilities.cleanupElement; - -// import from sanitize.js -var nsMap = svgedit.sanitize.getNSMap(); -var sanitizeSvg = canvas.sanitizeSvg = svgedit.sanitize.sanitizeSvg; - -// import from history.js -var MoveElementCommand = svgedit.history.MoveElementCommand; -var InsertElementCommand = svgedit.history.InsertElementCommand; -var RemoveElementCommand = svgedit.history.RemoveElementCommand; -var ChangeElementCommand = svgedit.history.ChangeElementCommand; -var BatchCommand = svgedit.history.BatchCommand; -// Implement the svgedit.history.HistoryEventHandler interface. -canvas.undoMgr = new svgedit.history.UndoManager({ - handleHistoryEvent: function(eventType, cmd) { - var EventTypes = svgedit.history.HistoryEventTypes; - // TODO: handle setBlurOffsets. - if (eventType == EventTypes.BEFORE_UNAPPLY || eventType == EventTypes.BEFORE_APPLY) { - canvas.clearSelection(); - } else if (eventType == EventTypes.AFTER_APPLY || eventType == EventTypes.AFTER_UNAPPLY) { - var elems = cmd.elements(); - canvas.pathActions.clear(); - call("changed", elems); - - var cmdType = cmd.type(); - var isApply = (eventType == EventTypes.AFTER_APPLY); - if (cmdType == MoveElementCommand.type()) { - var parent = isApply ? cmd.newParent : cmd.oldParent; - if (parent == svgcontent) { - canvas.identifyLayers(); - } - } else if (cmdType == InsertElementCommand.type() || - cmdType == RemoveElementCommand.type()) { - if (cmd.parent == svgcontent) { - canvas.identifyLayers(); - } - if (cmdType == InsertElementCommand.type()) { - if (isApply) restoreRefElems(cmd.elem); - } else { - if (!isApply) restoreRefElems(cmd.elem); - } - - if(cmd.elem.tagName === 'use') { - setUseData(cmd.elem); - } - } else if (cmdType == ChangeElementCommand.type()) { - // if we are changing layer names, re-identify all layers - if (cmd.elem.tagName == "title" && cmd.elem.parentNode.parentNode == svgcontent) { - canvas.identifyLayers(); - } - var values = isApply ? cmd.newValues : cmd.oldValues; - // If stdDeviation was changed, update the blur. - if (values["stdDeviation"]) { - canvas.setBlurOffsets(cmd.elem.parentNode, values["stdDeviation"]); - } - - // Remove & Re-add hack for Webkit (issue 775) - if(cmd.elem.tagName === 'use' && svgedit.browser.isWebkit()) { - var elem = cmd.elem; - if(!elem.getAttribute('x') && !elem.getAttribute('y')) { - var parent = elem.parentNode; - var sib = elem.nextSibling; - parent.removeChild(elem); - parent.insertBefore(elem, sib); - } - } - } - } - } -}); -var addCommandToHistory = function(cmd) { - canvas.undoMgr.addCommandToHistory(cmd); -}; - -// import from select.js -svgedit.select.init(curConfig, { - createSVGElement: function(jsonMap) { return canvas.addSvgElementFromJson(jsonMap); }, - svgRoot: function() { return svgroot; }, - svgContent: function() { return svgcontent; }, - currentZoom: function() { return current_zoom; }, - // TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js. - getStrokedBBox: function(elems) { return canvas.getStrokedBBox([elems]); } -}); -// this object manages selectors for us -var selectorManager = this.selectorManager = svgedit.select.getSelectorManager(); - -// Import from path.js -svgedit.path.init({ - getCurrentZoom: function() { return current_zoom; }, - getSVGRoot: function() { return svgroot; } -}); - -// Function: snapToGrid -// round value to for snapping -// NOTE: This function did not move to svgutils.js since it depends on curConfig. -svgedit.utilities.snapToGrid = function(value){ - var stepSize = curConfig.snappingStep; - var unit = curConfig.baseUnit; - if(unit !== "px") { - stepSize *= svgedit.units.getTypeMap()[unit]; - } - value = Math.round(value/stepSize)*stepSize; - return value; -}; -var snapToGrid = svgedit.utilities.snapToGrid; - -// Interface strings, usually for title elements -var uiStrings = { - "exportNoBlur": "Blurred elements will appear as un-blurred", - "exportNoforeignObject": "foreignObject elements will not appear", - "exportNoDashArray": "Strokes will appear filled", - "exportNoText": "Text may not appear as expected" -}; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var ref_attrs = ["clip-path", "fill", "filter", "marker-end", "marker-mid", "marker-start", "mask", "stroke"]; - -var elData = $.data; - -// Animation element to change the opacity of any newly created element -var opac_ani = false; //document.createElementNS(svgns, 'animate'); -//$(opac_ani).attr({ -// attributeName: 'opacity', -// begin: 'indefinite', -// dur: 0, -// fill: 'freeze' -//}).appendTo(svgroot); - -var restoreRefElems = function(elem) { - // Look for missing reference elements, restore any found - var attrs = $(elem).attr(ref_attrs); - for(var o in attrs) { - var val = attrs[o]; - if (val && val.indexOf('url(') === 0) { - var id = getUrlFromAttr(val).substr(1); - var ref = getElem(id); - if(!ref) { - findDefs().appendChild(removedElements[id]); - delete removedElements[id]; - } - } - } - - var childs = elem.getElementsByTagName('*'); - - if(childs.length) { - for(var i = 0, l = childs.length; i < l; i++) { - restoreRefElems(childs[i]); - } - } -}; - -(function() { - // TODO For Issue 208: this is a start on a thumbnail - // var svgthumb = svgdoc.createElementNS(svgns, "use"); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // svgedit.utilities.setHref(svgthumb, '#svgcontent'); - // svgroot.appendChild(svgthumb); - -})(); - -// Object to contain image data for raster images that were found encodable -var encodableImages = {}, - - // String with image URL of last loadable image - last_good_img_url = curConfig.imgPath + 'logo.png', - - // Array with current disabled elements (for in-group editing) - disabled_elems = [], - - // Object with save options - save_options = {round_digits: 5}, - - // Boolean indicating whether or not a draw action has been started - started = false, - - // String with an element's initial transform attribute value - start_transform = null, - - // String indicating the current editor mode - current_mode = "select", - - // String with the current direction in which an element is being resized - current_resize_mode = "none", - - // Object with IDs for imported files, to see if one was already added - import_ids = {}; - -// Current text style properties -var cur_text = all_properties.text, - - // Current general properties - cur_properties = cur_shape, - - // Array with selected elements' Bounding box object -// selectedBBoxes = new Array(1), - - // The DOM element that was just selected - justSelected = null, - - // DOM element for selection rectangle drawn by the user - rubberBox = null, - - // Array of current BBoxes (still needed?) - curBBoxes = [], - - // Object to contain all included extensions - extensions = {}, - - // Canvas point for the most recent right click - lastClickPoint = null, - - // Map of deleted reference elements - removedElements = {} - -// Clipboard for cut, copy&pasted elements -canvas.clipBoard = []; - -// Should this return an array by default, so extension results aren't overwritten? -var runExtensions = this.runExtensions = function(action, vars, returnArray) { - var result = false; - if(returnArray) result = []; - $.each(extensions, function(name, opts) { - if(action in opts) { - if(returnArray) { - result.push(opts[action](vars)) - } else { - result = opts[action](vars); - } - } - }); - return result; -} - -// Function: addExtension -// Add an extension to the editor -// -// Parameters: -// name - String with the ID of the extension -// ext_func - Function supplied by the extension with its data -this.addExtension = function(name, ext_func) { - if(!(name in extensions)) { - // Provide private vars/funcs here. Is there a better way to do this? - - if($.isFunction(ext_func)) { - var ext = ext_func($.extend(canvas.getPrivateMethods(), { - svgroot: svgroot, - svgcontent: svgcontent, - nonce: getCurrentDrawing().getNonce(), - selectorManager: selectorManager - })); - } else { - var ext = ext_func; - } - extensions[name] = ext; - call("extension_added", ext); - } else { - console.log('Cannot add extension "' + name + '", an extension by that name already exists"'); - } -}; - -// This method rounds the incoming value to the nearest value based on the current_zoom -var round = this.round = function(val) { - return parseInt(val*current_zoom)/current_zoom; -}; - -// This method sends back an array or a NodeList full of elements that -// intersect the multi-select rubber-band-box on the current_layer only. -// -// Since the only browser that supports the SVG DOM getIntersectionList is Opera, -// we need to provide an implementation here. We brute-force it for now. -// -// Reference: -// Firefox does not implement getIntersectionList(), see https://bugzilla.mozilla.org/show_bug.cgi?id=501421 -// Webkit does not implement getIntersectionList(), see https://bugs.webkit.org/show_bug.cgi?id=11274 -var getIntersectionList = this.getIntersectionList = function(rect) { - if (rubberBox == null) { return null; } - - var parent = current_group || getCurrentDrawing().getCurrentLayer(); - - if(!curBBoxes.length) { - // Cache all bboxes - curBBoxes = getVisibleElementsAndBBoxes(parent); - } - - var resultList = null; - try { - resultList = parent.getIntersectionList(rect, null); - } catch(e) { } - - if (resultList == null || typeof(resultList.item) != "function") { - resultList = []; - - if(!rect) { - var rubberBBox = rubberBox.getBBox(); - var bb = {}; - - for(var o in rubberBBox) { - bb[o] = rubberBBox[o] / current_zoom; - } - rubberBBox = bb; - - } else { - var rubberBBox = rect; - } - var i = curBBoxes.length; - while (i--) { - if(!rubberBBox.width || !rubberBBox.width) continue; - if (svgedit.math.rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); - } - } - } - // addToSelection expects an array, but it's ok to pass a NodeList - // because using square-bracket notation is allowed: - // http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html - return resultList; -}; - -// TODO(codedread): Migrate this into svgutils.js -// Function: getStrokedBBox -// Get the bounding box for one or more stroked and/or transformed elements -// -// Parameters: -// elems - Array with DOM elements to check -// -// Returns: -// A single bounding box object -getStrokedBBox = this.getStrokedBBox = function(elems) { - if(!elems) elems = getVisibleElements(); - if(!elems.length) return false; - // Make sure the expected BBox is returned if the element is a group - 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 - // in Issue 339 comment #2). - - var bb = svgedit.utilities.getBBox(elem); - - var angle = svgedit.utilities.getRotationAngle(elem); - if ((angle && angle % 90) || - svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(elem))) { - // Accurate way to get BBox of rotated element in Firefox: - // Put element in group and get its BBox - - var good_bb = false; - - // Get the BBox from the raw path for these elements - var elemNames = ['ellipse','path','line','polyline','polygon']; - if(elemNames.indexOf(elem.tagName) >= 0) { - bb = good_bb = canvas.convertToPath(elem, true); - } else if(elem.tagName == 'rect') { - // Look for radius - var rx = elem.getAttribute('rx'); - var ry = elem.getAttribute('ry'); - if(rx || ry) { - bb = good_bb = canvas.convertToPath(elem, true); - } - } - - if(!good_bb) { - // Must use clone else FF freaks out - var clone = elem.cloneNode(true); - var g = document.createElementNS(svgns, "g"); - var parent = elem.parentNode; - parent.appendChild(g); - g.appendChild(clone); - bb = svgedit.utilities.bboxToObj(g.getBBox()); - parent.removeChild(g); - } - - - // Old method: Works by giving the rotated BBox, - // this is (unfortunately) what Opera and Safari do - // natively when getting the BBox of the parent group -// var angle = angle * Math.PI / 180.0; -// var rminx = Number.MAX_VALUE, rminy = Number.MAX_VALUE, -// rmaxx = Number.MIN_VALUE, rmaxy = Number.MIN_VALUE; -// var cx = round(bb.x + bb.width/2), -// cy = round(bb.y + bb.height/2); -// var pts = [ [bb.x - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y + bb.height - cy], -// [bb.x - cx, bb.y + bb.height - cy] ]; -// var j = 4; -// while (j--) { -// var x = pts[j][0], -// y = pts[j][1], -// r = Math.sqrt( x*x + y*y ); -// var theta = Math.atan2(y,x) + angle; -// x = round(r * Math.cos(theta) + cx); -// y = round(r * Math.sin(theta) + cy); -// -// // now set the bbox for the shape after it's been rotated -// if (x < rminx) rminx = x; -// if (y < rminy) rminy = y; -// if (x > rmaxx) rmaxx = x; -// if (y > rmaxy) rmaxy = y; -// } -// -// bb.x = rminx; -// bb.y = rminy; -// bb.width = rmaxx - rminx; -// bb.height = rmaxy - rminy; - } - return bb; - } catch(e) { - console.log(elem, e); - return null; - } - }; - - var full_bb; - $.each(elems, function() { - if(full_bb) return; - if(!this.parentNode) return; - full_bb = getCheckedBBox(this); - }); - - // This shouldn't ever happen... - if(full_bb == null) return null; - - // full_bb doesn't include the stoke, so this does no good! -// if(elems.length == 1) return full_bb; - - var max_x = full_bb.x + full_bb.width; - var max_y = full_bb.y + full_bb.height; - var min_x = full_bb.x; - var min_y = full_bb.y; - - // FIXME: same re-creation problem with this function as getCheckedBBox() above - var getOffset = function(elem) { - var sw = elem.getAttribute("stroke-width"); - var offset = 0; - if (elem.getAttribute("stroke") != "none" && !isNaN(sw)) { - offset += sw/2; - } - return offset; - } - var bboxes = []; - $.each(elems, function(i, elem) { - var cur_bb = getCheckedBBox(elem); - if(cur_bb) { - var offset = getOffset(elem); - min_x = Math.min(min_x, cur_bb.x - offset); - min_y = Math.min(min_y, cur_bb.y - offset); - bboxes.push(cur_bb); - } - }); - - full_bb.x = min_x; - full_bb.y = min_y; - - $.each(elems, function(i, elem) { - var cur_bb = bboxes[i]; - // ensure that elem is really an element node - if (cur_bb && elem.nodeType == 1) { - var offset = getOffset(elem); - max_x = Math.max(max_x, cur_bb.x + cur_bb.width + offset); - max_y = Math.max(max_y, cur_bb.y + cur_bb.height + offset); - } - }); - - full_bb.width = max_x - min_x; - full_bb.height = max_y - min_y; - return full_bb; -} - -// Function: getVisibleElements -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with all "visible" elements. -var getVisibleElements = this.getVisibleElements = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push(elem); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: getVisibleElementsAndBBoxes -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with objects that include: -// * elem - The element -// * bbox - The element's BBox as retrieved from getStrokedBBox -var getVisibleElementsAndBBoxes = this.getVisibleElementsAndBBoxes = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push({'elem':elem, 'bbox':getStrokedBBox([elem])}); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: groupSvgElem -// Wrap an SVG element into a group element, mark the group as 'gsvg' -// -// Parameters: -// elem - SVG element to wrap -var groupSvgElem = this.groupSvgElem = function(elem) { - var g = document.createElementNS(svgns, "g"); - elem.parentNode.replaceChild(g, elem); - $(g).append(elem).data('gsvg', elem)[0].id = getNextId(); -} - -// Function: copyElem -// Create a clone of an element, updating its ID and its children's IDs when needed -// -// Parameters: -// el - DOM element to clone -// -// Returns: The cloned element -var copyElem = function(el) { - var new_el = document.createElementNS(el.namespaceURI, el.nodeName); - // set the copied element's new id - new_el.removeAttribute("id"); - // manually create a copy of the element - $.each(el.attributes, function(i, attr) { - if (attr.localName != '-moz-math-font-style') { - new_el.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.nodeValue); - } - }); - - // Opera's "d" value needs to be reset for Opera/Win/non-EN - // Also needed for webkit (else does not keep curved segments on clone) - if(svgedit.browser.isWebkit() && el.nodeName == 'path') { - var fixed_d = pathActions.convertPath(el); - new_el.setAttribute('d', fixed_d); - } - - // now create copies of all children - $.each(el.childNodes, function(i, child) { - switch(child.nodeType) { - case 1: // element node - new_el.appendChild(copyElem(child)); - break; - case 3: // text node - new_el.textContent = child.nodeValue; - break; - default: - break; - } - }); - - if($(el).data('gsvg')) { - $(new_el).data('gsvg', new_el.firstChild); - } 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); - } - new_el.id = getNextId(); - console.log(new_el); - return new_el; -}; - -// Set scope for these functions -var getId, getNextId, call; - -(function(c) { - - // Object to contain editor event names and callback functions - var events = {}; - - getId = c.getId = function() { return getCurrentDrawing().getId(); }; - getNextId = c.getNextId = function() { return getCurrentDrawing().getNextId(); }; - - // Function: call - // Run the callback function associated with the given event - // - // Parameters: - // event - String with the event name - // arg - Argument to pass through to the callback function - call = c.call = function(event, arg) { - if (events[event]) { - return events[event](this, arg); - } - }; - - // Function: bind - // Attaches a callback function to an event - // - // Parameters: - // event - String indicating the name of the event - // f - The callback function to bind to the event - // - // Return: - // The previous event - c.bind = function(event, f) { - var old = events[event]; - events[event] = f; - return old; - }; - -}(canvas)); - -// Function: canvas.prepareSvg -// Runs the SVG Document through the sanitizer and then updates its paths. -// -// Parameters: -// newDoc - The SVG DOM document -this.prepareSvg = function(newDoc) { - this.sanitizeSvg(newDoc.documentElement); - - // convert paths into absolute commands - var paths = newDoc.getElementsByTagNameNS(svgns, "path"); - for (var i = 0, len = paths.length; i < len; ++i) { - var path = paths[i]; - path.setAttribute('d', pathActions.convertPath(path)); - pathActions.fixEnd(path); - } -}; - -// Function getRefElem -// Get the reference element associated with the given attribute value -// -// Parameters: -// attrVal - The attribute value as a string -var getRefElem = this.getRefElem = function(attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); -} - -// Function: ffClone -// Hack for Firefox bugs where text element features aren't updated or get -// messed up. See issue 136 and issue 137. -// This function clones the element and re-selects it -// TODO: Test for this bug on load and add it to "support" object instead of -// browser sniffing -// -// Parameters: -// elem - The (text) DOM element to clone -var ffClone = function(elem) { - if(!svgedit.browser.isGecko()) return elem; - var clone = elem.cloneNode(true) - elem.parentNode.insertBefore(clone, elem); - elem.parentNode.removeChild(elem); - selectorManager.releaseSelector(elem); - selectedElements[0] = clone; - selectorManager.requestSelector(clone).showGrips(true); - return clone; -} - - -// this.each is deprecated, if any extension used this it can be recreated by doing this: -// $(canvas.getRootElem()).children().each(...) - -// this.each = function(cb) { -// $(svgroot).children().each(cb); -// }; - - -// Function: setRotationAngle -// Removes any old rotations if present, prepends a new rotation at the -// transformed center -// -// Parameters: -// val - The new rotation angle in degrees -// preventUndo - Boolean indicating whether the action should be undoable or not -this.setRotationAngle = function(val, preventUndo) { - // ensure val is the proper type - val = parseFloat(val); - var elem = selectedElements[0]; - var oldTransform = elem.getAttribute("transform"); - var bbox = svgedit.utilities.getBBox(elem); - var cx = bbox.x+bbox.width/2, cy = bbox.y+bbox.height/2; - var tlist = getTransformList(elem); - - // only remove the real rotational transform if present (i.e. at index=0) - if (tlist.numberOfItems > 0) { - var xform = tlist.getItem(0); - if (xform.type == 4) { - tlist.removeItem(0); - } - } - // find R_nc and insert it - if (val != 0) { - var center = transformPoint(cx,cy,transformListToTransform(tlist).matrix); - var R_nc = svgroot.createSVGTransform(); - R_nc.setRotate(val, center.x, center.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(R_nc, 0); - } else { - tlist.appendItem(R_nc); - } - } - else if (tlist.numberOfItems == 0) { - elem.removeAttribute("transform"); - } - - if (!preventUndo) { - // we need to undo it, then redo it so it can be undo-able! :) - // TODO: figure out how to make changes to transform list undo-able cross-browser? - var newTransform = elem.getAttribute("transform"); - elem.setAttribute("transform", oldTransform); - changeSelectedAttribute("transform",newTransform,selectedElements); - call("changed", selectedElements); - } - var pointGripContainer = getElem("pathpointgrip_container"); -// if(elem.nodeName == "path" && pointGripContainer) { -// pathActions.setPointContainerTransform(elem.getAttribute("transform")); -// } - var selector = selectorManager.requestSelector(selectedElements[0]); - selector.resize(); - selector.updateGripCursors(val); -}; - -// Function: recalculateAllSelectedDimensions -// Runs recalculateDimensions on the selected elements, -// adding the changes to a single batch command -var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function() { - var text = (current_resize_mode == "none" ? "position" : "size"); - var batchCmd = new BatchCommand(text); - - var i = selectedElements.length; - while(i--) { - var elem = selectedElements[i]; -// if(getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) continue; - var cmd = recalculateDimensions(elem); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - } - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - call("changed", selectedElements); - } -}; - -// this is how we map paths to our preferred relative segment types -var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', - 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; - -// Debug tool to easily see the current matrix in the browser's console -var logMatrix = function(m) { - console.log([m.a,m.b,m.c,m.d,m.e,m.f]); -}; - -// Function: remapElement -// Applies coordinate changes to an element based on the given matrix -// -// Parameters: -// selected - DOM element to be changed -// changes - Object with changes to be remapped -// m - Matrix object to use for remapping coordinates -var remapElement = this.remapElement = function(selected,changes,m) { - - var remap = function(x,y) { return transformPoint(x,y,m); }, - scalew = function(w) { return m.a*w; }, - scaleh = function(h) { return m.d*h; }, - doSnapping = curConfig.gridSnapping && selected.parentNode.parentNode.localName === "svg", - finishUp = function() { - if(doSnapping) for(var o in changes) changes[o] = snapToGrid(changes[o]); - assignAttributes(selected, changes, 1000, true); - } - box = svgedit.utilities.getBBox(selected); - - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = selected.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - if(m.a < 0 || m.d < 0) { - var grad = getRefElem(attrVal); - var newgrad = grad.cloneNode(true); - - if(m.a < 0) { - //flip x - var x1 = newgrad.getAttribute('x1'); - var x2 = newgrad.getAttribute('x2'); - newgrad.setAttribute('x1', -(x1 - 1)); - newgrad.setAttribute('x2', -(x2 - 1)); - } - - if(m.d < 0) { - //flip y - var y1 = newgrad.getAttribute('y1'); - var y2 = newgrad.getAttribute('y2'); - newgrad.setAttribute('y1', -(y1 - 1)); - newgrad.setAttribute('y2', -(y2 - 1)); - } - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - selected.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - - // Not really working :( -// if(selected.tagName === 'path') { -// reorientGrads(selected, m); -// } - } - } - - - var elName = selected.tagName; - if(elName === "g" || elName === "text" || elName === "use") { - // if it was a translate, then just update x,y - if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && - (m.e != 0 || m.f != 0) ) - { - // [T][M] = [M][T'] - // therefore [T'] = [M_inv][T][M] - var existing = transformListToTransform(selected).matrix, - t_new = matrixMultiply(existing.inverse(), m, existing); - changes.x = parseFloat(changes.x) + t_new.e; - changes.y = parseFloat(changes.y) + t_new.f; - } - else { - // we just absorb all matrices into the element and don't do any remapping - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } - } - - // now we have a set of changes and an applied reduced transform list - // we apply the changes directly to the DOM - switch (elName) - { - case "foreignObject": - case "rect": - case "image": - - // Allow images to be inverted (give them matrix when flipped) - if(elName === 'image' && (m.a < 0 || m.d < 0)) { - // Convert to matrix - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } else { - var pt1 = remap(changes.x,changes.y); - - changes.width = scalew(changes.width); - changes.height = scaleh(changes.height); - - changes.x = pt1.x + Math.min(0,changes.width); - changes.y = pt1.y + Math.min(0,changes.height); - changes.width = Math.abs(changes.width); - changes.height = Math.abs(changes.height); - } - finishUp(); - break; - case "ellipse": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - changes.rx = scalew(changes.rx); - changes.ry = scaleh(changes.ry); - - changes.rx = Math.abs(changes.rx); - changes.ry = Math.abs(changes.ry); - finishUp(); - break; - case "circle": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - // take the minimum of the new selected box's dimensions for the new circle radius - var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m); - var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y; - changes.r = Math.min(w/2, h/2); - - if(changes.r) changes.r = Math.abs(changes.r); - finishUp(); - break; - case "line": - var pt1 = remap(changes.x1,changes.y1), - pt2 = remap(changes.x2,changes.y2); - changes.x1 = pt1.x; - changes.y1 = pt1.y; - changes.x2 = pt2.x; - changes.y2 = pt2.y; - - case "text": - var tspan = selected.querySelectorAll('tspan'); - var i = tspan.length - while(i--) { - var selX = convertToNum("x", selected.getAttribute('x')); - var tx = convertToNum("x", tspan[i].getAttribute('x')); - var selY = convertToNum("y", selected.getAttribute('y')); - var ty = convertToNum("y", tspan[i].getAttribute('y')); - var offset = new Object(); - if (!isNaN(selX) && !isNaN(tx) && selX!=0 && tx!=0 && changes.x) - offset.x = changes.x - (selX - tx); - if (!isNaN(selY) && !isNaN(ty) && selY!=0 && ty!=0 && changes.y) - offset.y = changes.y - (selY - ty); - if (offset.x || offset.y) - assignAttributes(tspan[i], offset, 1000, true); - } - finishUp(); - break; - case "use": - finishUp(); - break; - case "g": - var gsvg = $(selected).data('gsvg'); - if(gsvg) { - assignAttributes(gsvg, changes, 1000, true); - } - break; - case "polyline": - case "polygon": - var len = changes.points.length; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pt = remap(pt.x,pt.y); - changes.points[i].x = pt.x; - changes.points[i].y = pt.y; - } - - var len = changes.points.length; - var pstr = ""; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pstr += pt.x + "," + pt.y + " "; - } - selected.setAttribute("points", pstr); - break; - case "path": - - var segList = selected.pathSegList; - var len = segList.numberOfItems; - changes.d = new Array(len); - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - changes.d[i] = { - type: seg.pathSegType, - x: seg.x, - y: seg.y, - x1: seg.x1, - y1: seg.y1, - x2: seg.x2, - y2: seg.y2, - r1: seg.r1, - r2: seg.r2, - angle: seg.angle, - largeArcFlag: seg.largeArcFlag, - sweepFlag: seg.sweepFlag - }; - } - - var len = changes.d.length, - firstseg = changes.d[0], - currentpt = remap(firstseg.x,firstseg.y); - changes.d[0].x = currentpt.x; - changes.d[0].y = currentpt.y; - for (var i = 1; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 - // if relative, we want to scalew, scaleh - if (type % 2 == 0) { // absolute - var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands - thisy = (seg.y != undefined) ? seg.y : currentpt.y, // for H commands - pt = remap(thisx,thisy), - pt1 = remap(seg.x1,seg.y1), - pt2 = remap(seg.x2,seg.y2); - seg.x = pt.x; - seg.y = pt.y; - seg.x1 = pt1.x; - seg.y1 = pt1.y; - seg.x2 = pt2.x; - seg.y2 = pt2.y; - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - else { // relative - seg.x = scalew(seg.x); - seg.y = scaleh(seg.y); - seg.x1 = scalew(seg.x1); - seg.y1 = scaleh(seg.y1); - seg.x2 = scalew(seg.x2); - seg.y2 = scaleh(seg.y2); - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - } // for each segment - - var dstr = ""; - var len = changes.d.length; - for (var i = 0; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - dstr += pathMap[type]; - switch(type) { - case 13: // relative horizontal line (h) - case 12: // absolute horizontal line (H) - dstr += seg.x + " "; - break; - case 15: // relative vertical line (v) - case 14: // absolute vertical line (V) - dstr += seg.y + " "; - break; - case 3: // relative move (m) - case 5: // relative line (l) - case 19: // relative smooth quad (t) - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - dstr += seg.x + "," + seg.y + " "; - break; - case 7: // relative cubic (c) - case 6: // absolute cubic (C) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x2 + "," + seg.y2 + " " + - seg.x + "," + seg.y + " "; - break; - case 9: // relative quad (q) - case 8: // absolute quad (Q) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x + "," + seg.y + " "; - break; - case 11: // relative elliptical arc (a) - case 10: // absolute elliptical arc (A) - dstr += seg.r1 + "," + seg.r2 + " " + seg.angle + " " + (+seg.largeArcFlag) + - " " + (+seg.sweepFlag) + " " + seg.x + "," + seg.y + " "; - break; - case 17: // relative smooth cubic (s) - case 16: // absolute smooth cubic (S) - dstr += seg.x2 + "," + seg.y2 + " " + seg.x + "," + seg.y + " "; - break; - } - } - - selected.setAttribute("d", dstr); - break; - } -}; - -// Function: updateClipPath -// Updates a <clipPath>s values based on the given translation of an element -// -// Parameters: -// attr - The clip-path attribute value with the clipPath's ID -// tx - The translation's x value -// ty - The translation's y value -var updateClipPath = function(attr, tx, ty) { - var path = getRefElem(attr).firstChild; - - var cp_xform = getTransformList(path); - - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx, ty); - - cp_xform.appendItem(newxlate); - - // Update clipPath's dimensions - recalculateDimensions(path); -} - -// Function: recalculateDimensions -// Decides the course of action based on the element's transform list -// -// Parameters: -// selected - The DOM element to recalculate -// -// Returns: -// Undo command object with the resulting change -var recalculateDimensions = this.recalculateDimensions = function(selected) { - if (selected == null) return null; - - var tlist = getTransformList(selected); - - // remove any unnecessary transforms - if (tlist && tlist.numberOfItems > 0) { - var k = tlist.numberOfItems; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 0) { - tlist.removeItem(k); - } - // remove identity matrices - else if (xform.type === 1) { - if (svgedit.math.isIdentity(xform.matrix)) { - tlist.removeItem(k); - } - } - // remove zero-degree rotations - else if (xform.type === 4) { - if (xform.angle === 0) { - tlist.removeItem(k); - } - } - } - // End here if all it has is a rotation - if(tlist.numberOfItems === 1 && getRotationAngle(selected)) return null; - } - - // if this element had no transforms, we are done - if (!tlist || tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - return null; - } - - // TODO: Make this work for more than 2 - if (tlist) { - var k = tlist.numberOfItems; - var mxs = []; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 1) { - mxs.push([xform.matrix, k]); - } else if(mxs.length) { - mxs = []; - } - } - if(mxs.length === 2) { - var m_new = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])); - tlist.removeItem(mxs[0][1]); - tlist.removeItem(mxs[1][1]); - tlist.insertItemBefore(m_new, mxs[1][1]); - } - - // combine matrix + translate - k = tlist.numberOfItems; - if(k >= 2 && tlist.getItem(k-2).type === 1 && tlist.getItem(k-1).type === 2) { - var mt = svgroot.createSVGTransform(); - - var m = matrixMultiply( - tlist.getItem(k-2).matrix, - tlist.getItem(k-1).matrix - ); - mt.setMatrix(m); - tlist.removeItem(k-2); - tlist.removeItem(k-2); - tlist.appendItem(mt); - } - } - - // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). - switch ( selected.tagName ) { - // Ignore these elements, as they can absorb the [M] - case 'line': - case 'polyline': - case 'polygon': - case 'path': - break; - default: - if( - (tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) - || (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4) - ) { - return null; - } - } - - // Grouped SVG element - var gsvg = $(selected).data('gsvg'); - - // we know we have some transforms, so set up return variable - var batchCmd = new BatchCommand("Transform"); - - // store initial values that will be affected by reducing the transform list - var changes = {}, initial = null, attrs = []; - switch (selected.tagName) - { - case "line": - attrs = ["x1", "y1", "x2", "y2"]; - break; - case "circle": - attrs = ["cx", "cy", "r"]; - break; - case "ellipse": - attrs = ["cx", "cy", "rx", "ry"]; - break; - case "foreignObject": - case "rect": - case "image": - attrs = ["width", "height", "x", "y"]; - break; - case "use": - case "text": - case "tspan": - attrs = ["x", "y"]; - break; - case "polygon": - case "polyline": - initial = {}; - initial["points"] = selected.getAttribute("points"); - var list = selected.points; - var len = list.numberOfItems; - changes["points"] = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes["points"][i] = {x:pt.x,y:pt.y}; - } - break; - case "path": - initial = {}; - initial["d"] = selected.getAttribute("d"); - changes["d"] = selected.getAttribute("d"); - break; - } // switch on element type to get initial values - - if(attrs.length) { - changes = $(selected).attr(attrs); - $.each(changes, function(attr, val) { - changes[attr] = convertToNum(attr, val); - }); - } else if(gsvg) { - // GSVG exception - changes = { - x: $(gsvg).attr('x') || 0, - y: $(gsvg).attr('y') || 0 - }; - } - - // if we haven't created an initial array in polygon/polyline/path, then - // make a copy of initial values and include the transform - if (initial == null) { - initial = $.extend(true, {}, changes); - $.each(initial, function(attr, val) { - initial[attr] = convertToNum(attr, val); - }); - } - // save the start transform value too - initial["transform"] = start_transform ? start_transform : ""; - - // if it's a regular group, we have special processing to flatten transforms - if ((selected.tagName == "g" && !gsvg) || selected.tagName == "a") { - var box = svgedit.utilities.getBBox(selected), - oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix), - m = svgroot.createSVGMatrix(); - - - // temporarily strip off the rotate and save the old center - var gangle = getRotationAngle(selected); - if (gangle) { - var a = gangle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - var tx = 0, ty = 0, - operation = 0, - N = tlist.numberOfItems; - - if(N) { - var first_m = tlist.getItem(0).matrix; - } - - // first, if it was a scale then the second-last transform will be it - if (N >= 3 && tlist.getItem(N-2).type == 3 && - tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2) - { - operation = 3; // scale - - // if the children are unrotated, pass the scale down directly - // otherwise pass the equivalent matrix() down directly - var tm = tlist.getItem(N-3).matrix, - sm = tlist.getItem(N-2).matrix, - tmn = tlist.getItem(N-1).matrix; - - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - tx = 0; - ty = 0; - if (child.nodeType == 1) { - var childTlist = getTransformList(child); - - // some children might not have a transform (<metadata>, <defs>, etc) - 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; - var childxforms = []; - start_transform = child.getAttribute("transform"); - if(angle || hasMatrixTransform(childTlist)) { - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(matrixMultiply(tm, sm, tmn, m)); - childTlist.clear(); - childTlist.appendItem(e2t); - childxforms.push(e2t); - } - // if not rotated or skewed, push the [T][S][-T] down to the child - else { - // update the transform list with translate,scale,translate - - // slide the [T][S][-T] from the front to the back - // [T][S][-T][M] = [M][T2][S2][-T2] - - // (only bringing [-T] to the right of [M]) - // [T][S][-T][M] = [T][S][M][-T2] - // [-T2] = [M_inv][-T][M] - var t2n = matrixMultiply(m.inverse(), tmn, m); - // [T2] is always negative translation of [-T2] - var t2 = svgroot.createSVGMatrix(); - t2.e = -t2n.e; - t2.f = -t2n.f; - - // [T][S][-T][M] = [M][T2][S2][-T2] - // [S2] = [T2_inv][M_inv][T][S][-T][M][-T2_inv] - var s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()); - - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - translateOrigin.setTranslate(t2n.e, t2n.f); - scale.setScale(s2.a, s2.d); - translateBack.setTranslate(t2.e, t2.f); - childTlist.appendItem(translateBack); - childTlist.appendItem(scale); - childTlist.appendItem(translateOrigin); - childxforms.push(translateBack); - childxforms.push(scale); - childxforms.push(translateOrigin); -// logMatrix(translateBack.matrix); -// logMatrix(scale.matrix); - } // not rotated - batchCmd.addSubCommand( recalculateDimensions(child) ); - // TODO: If any <use> have this group as a parent and are - // referencing this child, then we need to impose a reverse - // scale on it so that when it won't get double-translated -// var uses = selected.getElementsByTagNameNS(svgns, "use"); -// var href = "#"+child.id; -// var u = uses.length; -// while (u--) { -// var useElem = uses.item(u); -// if(href == getHref(useElem)) { -// var usexlate = svgroot.createSVGTransform(); -// usexlate.setTranslate(-tx,-ty); -// getTransformList(useElem).insertItemBefore(usexlate,0); -// batchCmd.addSubCommand( recalculateDimensions(useElem) ); -// } -// } - start_transform = old_start_transform; - } // element - } // for each child - // Remove these transforms from group - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } - else if (N >= 3 && tlist.getItem(N-1).type == 1) - { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - } - // next, check if the first transform was a translate - // if we had [ T1 ] [ M ] we want to transform this into [ M ] [ T2 ] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var T_M = transformListToTransform(tlist).matrix; - tlist.removeItem(0); - var M_inv = transformListToTransform(tlist).matrix.inverse(); - var M2 = matrixMultiply( M_inv, T_M ); - - tx = M2.e; - ty = M2.f; - - if (tx != 0 || ty != 0) { - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - - var clipPaths_done = []; - - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - - // Check if child has clip-path - if(child.getAttribute('clip-path')) { - // tx, ty - var attr = child.getAttribute('clip-path'); - if(clipPaths_done.indexOf(attr) === -1) { - updateClipPath(attr, tx, ty); - clipPaths_done.push(attr); - } - } - - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - - var childTlist = getTransformList(child); - // some children might not have a transform (<metadata>, <defs>, etc) - if (childTlist) { - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - batchCmd.addSubCommand( recalculateDimensions(child) ); - // If any <use> have this group as a parent and are - // referencing this child, then impose a reverse translate on it - // so that when it won't get double-translated - var uses = selected.getElementsByTagNameNS(svgns, "use"); - var href = "#"+child.id; - var u = uses.length; - while (u--) { - var useElem = uses.item(u); - if(href == getHref(useElem)) { - var usexlate = svgroot.createSVGTransform(); - usexlate.setTranslate(-tx,-ty); - getTransformList(useElem).insertItemBefore(usexlate,0); - batchCmd.addSubCommand( recalculateDimensions(useElem) ); - } - } - start_transform = old_start_transform; - } - } - } - - clipPaths_done = []; - - start_transform = old_start_transform; - } - } - // else, a matrix imposition from a parent group - // keep pushing it down to the children - else if (N == 1 && tlist.getItem(0).type == 1 && !gangle) { - operation = 1; - var m = tlist.getItem(0).matrix, - children = selected.childNodes, - c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - 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); - childTlist.clear(); - childTlist.appendItem(e2m,0); - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - - // Convert stroke - // TODO: Find out if this should actually happen somewhere else - var sw = child.getAttribute("stroke-width"); - if (child.getAttribute("stroke") !== "none" && !isNaN(sw)) { - var avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; - child.setAttribute('stroke-width', sw * avg); - } - - } - } - tlist.clear(); - } - // else it was just a rotate - else { - if (gangle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (gangle) { - newcenter = { - x: oldcenter.x + first_m.e, - y: oldcenter.y + first_m.f - }; - - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // if it was a resize - else if (operation == 3) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(gangle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(gangle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(), - m_inv = m.inverse(), - extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - tx = extrat.e; - ty = extrat.f; - - if (tx != 0 || ty != 0) { - // now push this transform down to the children - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - var childTlist = getTransformList(child); - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - } - } - } - - if (gangle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } - // else, it's a non-group - else { - - // FIXME: box might be null for some elements (<metadata> etc), need to handle this - var box = svgedit.utilities.getBBox(selected); - - // Paths (and possbly other shapes) will have no BBox while still in <defs>, - // but we still may need to recalculate them (see issue 595). - // TODO: Figure out how to get BBox from these elements in case they - // have a rotation transform - - if(!box && selected.tagName != 'path') return null; - - - var m = svgroot.createSVGMatrix(), - // temporarily strip off the rotate and save the old center - angle = getRotationAngle(selected); - if (angle) { - var oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix); - - var a = angle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - - // 2 = translate, 3 = scale, 4 = rotate, 1 = matrix imposition - var operation = 0; - var N = tlist.numberOfItems; - - // Check if it has a gradient with userSpaceOnUse, in which case - // adjust it by recalculating the matrix transform. - // TODO: Make this work in Webkit using svgedit.transformlist.SVGTransformList - if(!svgedit.browser.isWebkit()) { - var fill = selected.getAttribute('fill'); - if(fill && fill.indexOf('url(') === 0) { - var paint = getRefElem(fill); - var type = 'pattern'; - if(paint.tagName !== type) type = 'gradient'; - var attrVal = paint.getAttribute(type + 'Units'); - if(attrVal === 'userSpaceOnUse') { - //Update the userSpaceOnUse element - m = transformListToTransform(tlist).matrix; - var gtlist = getTransformList(paint); - var gmatrix = transformListToTransform(gtlist).matrix; - m = matrixMultiply(m, gmatrix); - var m_str = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - paint.setAttribute(type + 'Transform', m_str); - } - } - } - - // first, if it was a scale of a non-skewed element, then the second-last - // transform will be the [S] - // 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) - - // Removed this so a <use> 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; - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } // if we had [T][S][-T][M], then this was a skewed element being resized - // Thus, we simply combine it all into one matrix - else if(N == 4 && tlist.getItem(N-1).type == 1) { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - // reset the matrix so that the element is not re-mapped - m = svgroot.createSVGMatrix(); - } // if we had [R][T][S][-T][M], then this was a rotated matrix-element - // if we had [T1][M] we want to transform this into [M][T2] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] and we can push [T2] - // down to the element - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var oldxlate = tlist.getItem(0).matrix, - meq = transformListToTransform(tlist,1).matrix, - meq_inv = meq.inverse(); - m = matrixMultiply( meq_inv, oldxlate, meq ); - tlist.removeItem(0); - } - // else if this child now has a matrix imposition (from a parent group) - // we might be able to simplify - else if (N == 1 && tlist.getItem(0).type == 1 && !angle) { - // Remap all point-based elements - m = transformListToTransform(tlist).matrix; - switch (selected.tagName) { - case 'line': - changes = $(selected).attr(["x1","y1","x2","y2"]); - case 'polyline': - case 'polygon': - changes.points = selected.getAttribute("points"); - if(changes.points) { - var list = selected.points; - var len = list.numberOfItems; - changes.points = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes.points[i] = {x:pt.x,y:pt.y}; - } - } - case 'path': - changes.d = selected.getAttribute("d"); - operation = 1; - tlist.clear(); - break; - default: - break; - } - } - // if it was a rotation, put the rotate back and return without a command - // (this function has zero work to do for a rotate()) - else { - operation = 4; // rotation - if (angle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle,newcenter.x,newcenter.y); - - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate or resize, we need to remap the element and absorb the xform - if (operation == 1 || operation == 2 || operation == 3) { - remapElement(selected,changes,m); - } // if we are remapping - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (angle) { - if(!hasMatrixTransform(tlist)) { - newcenter = { - x: oldcenter.x + m.e, - y: oldcenter.y + m.f - }; - } - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle, newcenter.x, newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // [Rold][M][T][S][-T] became [Rold][M] - // we want it to be [Rnew][M][Tr] where Tr is the - // translation required to re-center it - // Therefore, [Tr] = [M_inv][Rnew_inv][Rold][M] - else if (operation == 3 && angle) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(angle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(angle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(); - var m_inv = m.inverse(); - var extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - remapElement(selected,changes,extrat); - if (angle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } // a non-group - - // if the transform list has been emptied, remove it - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - - batchCmd.addSubCommand(new ChangeElementCommand(selected, initial)); - - return batchCmd; -}; - -// Root Current Transformation Matrix in user units -var root_sctm = null; - -// Group: Selection - -// Function: clearSelection -// Clears the selection. The 'selected' handler is then called. -// Parameters: -// noCall - Optional boolean that when true does not call the "selected" handler -var clearSelection = this.clearSelection = function(noCall) { - if (selectedElements[0] != null) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - selectorManager.releaseSelector(elem); - selectedElements[i] = null; - } -// selectedBBoxes[0] = null; - } - if(!noCall) call("selected", selectedElements); -}; - -// TODO: do we need to worry about selectedBBoxes here? - - -// Function: addToSelection -// Adds a list of elements to the selection. The 'selected' handler is then called. -// -// Parameters: -// elemsToAdd - an array of DOM elements to add to the selection -// showGrips - a boolean flag indicating whether the resize grips should be shown -var addToSelection = this.addToSelection = function(elemsToAdd, showGrips) { - if (elemsToAdd.length == 0) { return; } - // find the first null in our selectedElements array - var j = 0; - - while (j < selectedElements.length) { - if (selectedElements[j] == null) { - break; - } - ++j; - } - - // now add each element consecutively - var i = elemsToAdd.length; - while (i--) { - var elem = elemsToAdd[i]; - if (!elem || !svgedit.utilities.getBBox(elem)) continue; - - if(elem.tagName === 'a' && elem.childNodes.length === 1) { - // Make "a" element's child be the selected element - elem = elem.firstChild; - } - - // if it's not already there, add it - if (selectedElements.indexOf(elem) == -1) { - - selectedElements[j] = elem; - - // only the first selectedBBoxes element is ever used in the codebase these days -// if (j == 0) selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - j++; - var sel = selectorManager.requestSelector(elem); - - if (selectedElements.length > 1) { - sel.showGrips(false); - } - } - } - call("selected", selectedElements); - - if (showGrips || selectedElements.length == 1) { - selectorManager.requestSelector(selectedElements[0]).showGrips(true); - } - else { - selectorManager.requestSelector(selectedElements[0]).showGrips(false); - } - - // make sure the elements are in the correct order - // See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - - selectedElements.sort(function(a,b) { - if(a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); - } else if(a == null) { - return 1; - } - }); - - // Make sure first elements are not null - while(selectedElements[0] == null) selectedElements.shift(0); -}; - -// Function: selectOnly() -// Selects only the given elements, shortcut for clearSelection(); addToSelection() -// -// Parameters: -// elems - an array of DOM elements to be selected -var selectOnly = this.selectOnly = function(elems, showGrips) { - clearSelection(true); - addToSelection(elems, showGrips); -} - -// TODO: could use slice here to make this faster? -// TODO: should the 'selected' handler - -// Function: removeFromSelection -// Removes elements from the selection. -// -// Parameters: -// elemsToRemove - an array of elements to remove from selection -var removeFromSelection = this.removeFromSelection = function(elemsToRemove) { - if (selectedElements[0] == null) { return; } - if (elemsToRemove.length == 0) { return; } - - // find every element and remove it from our array copy - var newSelectedItems = new Array(selectedElements.length); - j = 0, - len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem) { - // keep the item - if (elemsToRemove.indexOf(elem) == -1) { - newSelectedItems[j] = elem; - j++; - } - else { // remove the item and its selector - selectorManager.releaseSelector(elem); - } - } - } - // the copy becomes the master now - selectedElements = newSelectedItems; -}; - -// Function: selectAllInCurrentLayer -// Clears the selection, then adds all elements in the current layer to the selection. -this.selectAllInCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (current_layer) { - current_mode = "select"; - selectOnly($(current_group || current_layer).children()); - } -}; - -// Function: getMouseTarget -// Gets the desired element from a mouse event -// -// Parameters: -// evt - Event object from the mouse event -// -// Returns: -// DOM element we want -var getMouseTarget = this.getMouseTarget = function(evt) { - if (evt == null) { - return null; - } - var mouse_target = evt.target; - - // if it was a <use>, Opera and WebKit return the SVGElementInstance - if (mouse_target.correspondingUseElement) mouse_target = mouse_target.correspondingUseElement; - - // for foreign content, go up until we find the foreignObject - // WebKit browsers set the mouse target to the svgcanvas div - if ([mathns, htmlns].indexOf(mouse_target.namespaceURI) >= 0 && - mouse_target.id != "svgcanvas") - { - while (mouse_target.nodeName != "foreignObject") { - mouse_target = mouse_target.parentNode; - if(!mouse_target) return svgroot; - } - } - - // Get the desired mouse_target with jQuery selector-fu - // If it's root-like, select the root - var current_layer = getCurrentDrawing().getCurrentLayer(); - if([svgroot, container, svgcontent, current_layer].indexOf(mouse_target) >= 0) { - return svgroot; - } - - var $target = $(mouse_target); - - // If it's a selection grip, return the grip parent - if($target.closest('#selectorParentGroup').length) { - // While we could instead have just returned mouse_target, - // this makes it easier to indentify as being a selector grip - return selectorManager.selectorParentGroup; - } - - while (mouse_target.parentNode !== (current_group || current_layer)) { - mouse_target = mouse_target.parentNode; - } - -// -// // go up until we hit a child of a layer -// while (mouse_target.parentNode.parentNode.tagName == 'g') { -// mouse_target = mouse_target.parentNode; -// } - // Webkit bubbles the mouse event all the way up to the div, so we - // set the mouse_target to the svgroot like the other browsers -// if (mouse_target.nodeName.toLowerCase() == "div") { -// mouse_target = svgroot; -// } - - return mouse_target; -}; - -// Mouse events -(function() { - var d_attr = null, - start_x = null, - start_y = null, - r_start_x = null, - r_start_y = null, - init_bbox = {}, - freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - - // - when we are in a create mode, the element is added to the canvas - // but the action is not recorded until mousing up - // - when we are in select mode, select the element, remember the position - // and do nothing else - var mouseDown = function(evt) - { - if(canvas.spaceKey || evt.button === 1) return; - - var right_click = evt.button === 2; - - if(evt.altKey) { // duplicate when dragging - svgCanvas.cloneSelectedElements(0,0); - } - - root_sctm = svgcontent.getScreenCTM().inverse(); - - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom; - - evt.preventDefault(); - - if(right_click) { - current_mode = "select"; - lastClickPoint = pt; - } - - // This would seem to be unnecessary... -// if(['select', 'resize'].indexOf(current_mode) == -1) { -// setGradient(); -// } - - var x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - mouse_target = getMouseTarget(evt); - - if(mouse_target.tagName === 'a' && mouse_target.childNodes.length === 1) { - mouse_target = mouse_target.firstChild; - } - - // real_x/y ignores grid-snap value - var real_x = r_start_x = start_x = x; - var real_y = r_start_y = start_y = y; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - - // if it is a selector grip, then it must be a single element selected, - // set the mouse_target to that and update the mode to rotate/resize - - if (mouse_target == selectorManager.selectorParentGroup && selectedElements[0] != null) { - var grip = evt.target; - var griptype = elData(grip, "type"); - // rotating - if (griptype == "rotate") { - current_mode = "rotate"; - current_rotate_mode = elData(grip, "dir"); - } - // resizing - else if(griptype == "resize") { - current_mode = "resize"; - current_resize_mode = elData(grip, "dir"); - } - mouse_target = selectedElements[0]; - } - - start_transform = mouse_target.getAttribute("transform"); - var tlist = getTransformList(mouse_target); - switch (current_mode) { - case "select": - started = true; - current_resize_mode = "none"; - if(right_click) started = false; - - if (mouse_target != svgroot) { - // if this element is not yet selected, clear selection and select it - if (selectedElements.indexOf(mouse_target) == -1) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) - if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection - clearSelection(true); - } - addToSelection([mouse_target]); - justSelected = mouse_target; - pathActions.clear(); - } - // else if it's a path, go into pathedit mode in mouseup - - if(!right_click) { - // insert a dummy transform so if the element(s) are moved it will have - // a transform to use for its translate - for (var i = 0; i < selectedElements.length; ++i) { - if(selectedElements[i] == null) continue; - var slist = getTransformList(selectedElements[i]); - if(slist.numberOfItems) { - slist.insertItemBefore(svgroot.createSVGTransform(), 0); - } else { - slist.appendItem(svgroot.createSVGTransform()); - } - } - } - } - else if(!right_click){ - clearSelection(); - current_mode = "multiselect"; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - r_start_x *= current_zoom; - r_start_y *= current_zoom; -// console.log('p',[evt.pageX, evt.pageY]); -// console.log('c',[evt.clientX, evt.clientY]); -// console.log('o',[evt.offsetX, evt.offsetY]); -// console.log('s',[start_x, start_y]); - - assignAttributes(rubberBox, { - 'x': r_start_x, - 'y': r_start_y, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - break; - case "zoom": - started = true; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': real_x * current_zoom, - 'y': real_x * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - break; - case "resize": - started = true; - start_x = x; - start_y = y; - - // Getting the BBox from the selection box, since we know we - // want to orient around it - init_bbox = svgedit.utilities.getBBox($('#selectedBox0')[0]); - var bb = {}; - $.each(init_bbox, function(key, val) { - bb[key] = val/current_zoom; - }); - init_bbox = bb; - // append three dummy transforms to the tlist so that - // we can translate,scale,translate in mousemove - var pos = getRotationAngle(mouse_target)?1:0; - - if(hasMatrixTransform(tlist)) { - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - } else { - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - - if(svgedit.browser.supportsNonScalingStroke()) { - //Handle crash for newer Chrome: https://code.google.com/p/svg-edit/issues/detail?id=904 - //Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 - // TODO: Remove this workaround (all isChrome blocks) once vendor fixes the issue - var isChrome = svgedit.browser.isChrome(); - if(isChrome) { - var delayedStroke = function(ele) { - var _stroke = ele.getAttributeNS(null, 'stroke'); - ele.removeAttributeNS(null, 'stroke'); - //Re-apply stroke after delay. Anything higher than 1 seems to cause flicker - setTimeout(function() { ele.setAttributeNS(null, 'stroke', _stroke) }, 1); - } - } - mouse_target.style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(mouse_target); - - var all = mouse_target.getElementsByTagName('*'), - len = all.length; - for(var i = 0; i < len; i++) { - all[i].style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(all[i]); - } - } - } - break; - case "fhellipse": - case "fhrect": - case "fhpath": - started = true; - d_attr = real_x + "," + real_y + " "; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "polyline", - "curStyles": true, - "attr": { - "points": d_attr, - "id": getNextId(), - "fill": "none", - "opacity": cur_shape.opacity / 2, - "stroke-linecap": "round", - "style": "pointer-events:none" - } - }); - freehand.minx = real_x; - freehand.maxx = real_x; - freehand.miny = real_y; - freehand.maxy = real_y; - break; - case "image": - started = true; - var newImage = addSvgElementFromJson({ - "element": "image", - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - } - }); - setHref(newImage, last_good_img_url); - preventClickDefault(newImage); - break; - case "square": - // FIXME: once we create the rect, we lose information that this was a square - // (for resizing purposes this could be important) - case "rect": - started = true; - start_x = x; - start_y = y; - addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "line": - started = true; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "line", - "curStyles": true, - "attr": { - "x1": x, - "y1": y, - "x2": x, - "y2": y, - "id": getNextId(), - "stroke": cur_shape.stroke, - "stroke-width": stroke_w, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill": "none", - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:none" - } - }); - break; - case "circle": - started = true; - addSvgElementFromJson({ - "element": "circle", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "r": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "ellipse": - started = true; - addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "rx": 0, - "ry": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "text": - started = true; - var newText = addSvgElementFromJson({ - "element": "text", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "id": getNextId(), - "fill": cur_text.fill, - "stroke-width": cur_text.stroke_width, - "font-size": cur_text.font_size, - "font-family": cur_text.font_family, - "text-anchor": "middle", - "xml:space": "preserve", - "opacity": cur_shape.opacity - } - }); -// newText.textContent = "text"; - break; - case "path": - // Fall through - case "pathedit": - start_x *= current_zoom; - start_y *= current_zoom; - pathActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "textedit": - start_x *= current_zoom; - start_y *= current_zoom; - textActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "rotate": - started = true; - // we are starting an undoable change (a drag-rotation) - canvas.undoMgr.beginUndoableChange("transform", selectedElements); - document.getElementById("workarea").className = "rotate"; - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseDown", { - event: evt, - start_x: start_x, - start_y: start_y, - selectedElements: selectedElements - }, true); - - $.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 - // any elements that are still being created, moved or resized on the canvas) - var mouseMove = function(evt) - { - if (!started) return; - if(evt.button === 1 || canvas.spaceKey) return; - - var selected = selectedElements[0], - pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - shape = getElem(getId()); - - var real_x = x = mouse_x / current_zoom; - var real_y = y = mouse_y / current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - evt.preventDefault(); - - switch (current_mode) - { - case "select": - // we temporarily use a translate on the element(s) being dragged - // this transform is removed upon mousing up and the element is - // relocated to the new location - if (selectedElements[0] !== null) { - var dx = x - start_x; - var dy = y - start_y; - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - } - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x,y); x=xya.x; y=xya.y; } - - if (dx != 0 || dy != 0) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; -// if (i==0) { -// var box = svgedit.utilities.getBBox(selected); -// selectedBBoxes[i].x = box.x + dx; -// selectedBBoxes[i].y = box.y + dy; -// } - - // update the dummy transform in our transform list - // 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); - } else { - tlist.appendItem(xform); - } - - // update our internal bbox that we're tracking while dragging - selectorManager.requestSelector(selected).resize(); - } - - call("transition", selectedElements); - } - } - break; - case "multiselect": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y) - },100); - - // for each selected: - // - if newList contains selected, do nothing - // - if newList doesn't contain selected, remove it from selected - // - for any newList that was not in selectedElements, add it to selected - var elemsToRemove = [], elemsToAdd = [], - newList = getIntersectionList(), - len = selectedElements.length; - - for (var i = 0; i < len; ++i) { - var ind = newList.indexOf(selectedElements[i]); - if (ind == -1) { - elemsToRemove.push(selectedElements[i]); - } - else { - newList[ind] = null; - } - } - - len = newList.length; - for (i = 0; i < len; ++i) { if (newList[i]) elemsToAdd.push(newList[i]); } - - if (elemsToRemove.length > 0) - canvas.removeFromSelection(elemsToRemove); - - if (elemsToAdd.length > 0) - addToSelection(elemsToAdd); - - break; - case "resize": - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates - var tlist = getTransformList(selected), - hasMatrix = hasMatrixTransform(tlist), - box = hasMatrix ? init_bbox : svgedit.utilities.getBBox(selected), - left=box.x, top=box.y, width=box.width, - height=box.height, dx=(x-start_x), dy=(y-start_y); - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - height = snapToGrid(height); - width = snapToGrid(width); - } - - // if rotated, adjust the dx,dy values - var angle = getRotationAngle(selected); - if (angle) { - var r = Math.sqrt( dx*dx + dy*dy ), - theta = Math.atan2(dy,dx) - angle * Math.PI / 180.0; - dx = r * Math.cos(theta); - dy = r * Math.sin(theta); - } - - // if not stretching in y direction, set dy to 0 - // if not stretching in x direction, set dx to 0 - if(current_resize_mode.indexOf("n")==-1 && current_resize_mode.indexOf("s")==-1) { - dy = 0; - } - if(current_resize_mode.indexOf("e")==-1 && current_resize_mode.indexOf("w")==-1) { - dx = 0; - } - - var ts = null, - tx = 0, ty = 0, - sy = height ? (height+dy)/height : 1, - sx = width ? (width+dx)/width : 1; - // if we are dragging on the north side, then adjust the scale factor and ty - if(current_resize_mode.indexOf("n") >= 0) { - sy = height ? (height-dy)/height : 1; - ty = height; - } - - // if we dragging on the east side, then adjust the scale factor and tx - if(current_resize_mode.indexOf("w") >= 0) { - sx = width ? (width-dx)/width : 1; - tx = width; - } - - // update the transform list with translate,scale,translate - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - - if(curConfig.gridSnapping){ - left = snapToGrid(left); - tx = snapToGrid(tx); - top = snapToGrid(top); - ty = snapToGrid(ty); - } - - translateOrigin.setTranslate(-(left+tx),-(top+ty)); - if(evt.shiftKey) { - if(sx == 1) sx = sy - else sy = sx; - } - scale.setScale(sx,sy); - - translateBack.setTranslate(left+tx,top+ty); - if(hasMatrix) { - var diff = angle?1:0; - tlist.replaceItem(translateOrigin, 2+diff); - tlist.replaceItem(scale, 1+diff); - tlist.replaceItem(translateBack, 0+diff); - } else { - var N = tlist.numberOfItems; - tlist.replaceItem(translateBack, N-3); - tlist.replaceItem(scale, N-2); - tlist.replaceItem(translateOrigin, N-1); - } - - selectorManager.requestSelector(selected).resize(); - - call("transition", selectedElements); - - break; - case "zoom": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - break; - case "text": - assignAttributes(shape,{ - 'x': x, - 'y': y - },1000); - break; - case "line": - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - var x2 = x; - var y2 = y; - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x2,y2); x2=xya.x; y2=xya.y; } - - shape.setAttributeNS(null, "x2", x2); - shape.setAttributeNS(null, "y2", y2); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "foreignObject": - // fall through - case "square": - // fall through - case "rect": - // fall through - case "image": - var square = (current_mode == 'square') || evt.shiftKey, - w = Math.abs(x - start_x), - h = Math.abs(y - start_y), - new_x, new_y; - if(square) { - w = h = Math.max(w, h); - new_x = start_x < x ? start_x : start_x - w; - new_y = start_y < y ? start_y : start_y - h; - } else { - new_x = Math.min(start_x,x); - new_y = Math.min(start_y,y); - } - - if(curConfig.gridSnapping){ - w = snapToGrid(w); - h = snapToGrid(h); - new_x = snapToGrid(new_x); - new_y = snapToGrid(new_y); - } - - assignAttributes(shape,{ - 'width': w, - 'height': h, - 'x': new_x, - 'y': new_y - },1000); - - break; - case "circle": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy, - rad = Math.sqrt( (x-cx)*(x-cx) + (y-cy)*(y-cy) ); - if(curConfig.gridSnapping){ - rad = snapToGrid(rad); - } - shape.setAttributeNS(null, "r", rad); - break; - case "ellipse": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy; - // Opera has a problem with suspendRedraw() apparently - handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - if(curConfig.gridSnapping){ - x = snapToGrid(x); - cx = snapToGrid(cx); - y = snapToGrid(y); - cy = snapToGrid(cy); - } - shape.setAttributeNS(null, "rx", Math.abs(x - cx) ); - var ry = Math.abs(evt.shiftKey?(x - cx):(y - cy)); - shape.setAttributeNS(null, "ry", ry ); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "fhellipse": - case "fhrect": - freehand.minx = Math.min(real_x, freehand.minx); - freehand.maxx = Math.max(real_x, freehand.maxx); - freehand.miny = Math.min(real_y, freehand.miny); - freehand.maxy = Math.max(real_y, freehand.maxy); - // break; missing on purpose - case "fhpath": - d_attr += + real_x + "," + real_y + " "; - shape.setAttributeNS(null, "points", d_attr); - break; - // update path stretch line coordinates - case "path": - // fall through - case "pathedit": - x *= current_zoom; - y *= current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - if(evt.shiftKey) { - var path = svgedit.path.path; - if(path) { - var x1 = path.dragging?path.dragging[0]:start_x; - var y1 = path.dragging?path.dragging[1]:start_y; - } else { - var x1 = start_x; - var y1 = start_y; - } - var xya = snapToAngle(x1,y1,x,y); - x=xya.x; y=xya.y; - } - - if(rubberBox && rubberBox.getAttribute('display') !== 'none') { - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - } - pathActions.mouseMove(evt, x, y); - - break; - case "textedit": - x *= current_zoom; - y *= current_zoom; -// if(rubberBox && rubberBox.getAttribute('display') != 'none') { -// assignAttributes(rubberBox, { -// 'x': Math.min(start_x,x), -// 'y': Math.min(start_y,y), -// 'width': Math.abs(x-start_x), -// 'height': Math.abs(y-start_y) -// },100); -// } - - textActions.mouseMove(mouse_x, mouse_y); - - break; - case "rotate": - var box = svgedit.utilities.getBBox(selected), - cx = box.x + box.width/2, - cy = box.y + box.height/2, - m = getMatrix(selected), - center = transformPoint(cx,cy,m); - cx = center.x; - cy = center.y; - var ccx = box.x // ne - var ccy = box.y // ne - if (current_rotate_mode == "nw") ccx = box.x + box.width; - if (current_rotate_mode == "se") ccy = box.y + box.height; - if (current_rotate_mode == "sw"){ ccx = box.x + box.width; ccy = box.y + box.height; } - compensation_angle = ((Math.atan2(cy-ccy,cx-ccx) * (180/Math.PI))-90) % 360; - var angle = ((Math.atan2(cy-y,cx-x) * (180/Math.PI))-90) % 360; - angle += compensation_angle; - if(curConfig.gridSnapping){ - angle = snapToGrid(angle); - } - if(evt.shiftKey) { // restrict rotations to nice angles (WRS) - var snap = 45; - angle= Math.round(angle/snap)*snap; - } - - canvas.setRotationAngle(angle<-180?(360+angle):angle, true); - call("transition", selectedElements); - break; - default: - break; - } - - runExtensions("mouseMove", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y, - selected: selected - }); - - }; // mouseMove() - - // - in create mode, the element's opacity is set properly, we create an InsertElementCommand - // and store it on the Undo stack - // - in move/resize mode, the element's attributes which were affected by the move/resize are - // identified, a ChangeElementCommand is created and stored on the stack for those attrs - // this is done in when we recalculate the selected dimensions() - var mouseUp = function(evt) - { - if(evt.button === 2) return; - var tempJustSelected = justSelected; - justSelected = null; - if (!started) return; - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - element = getElem(getId()), - keep = false; - - var real_x = x; - var real_y = y; - - // TODO: Make true when in multi-unit mode - var useUnit = false; // (curConfig.baseUnit !== 'px'); - started = false; - switch (current_mode) - { - // intentionally fall-through to select here - case "resize": - case "multiselect": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - curBBoxes = []; - } - current_mode = "select"; - case "select": - if (selectedElements[0] != null) { - // if we only have one selected element - if (selectedElements[1] == null) { - // set our current stroke/fill properties to the element's - var selected = selectedElements[0]; - switch ( selected.tagName ) { - case "g": - case "use": - case "image": - case "foreignObject": - break; - default: - cur_properties.fill = selected.getAttribute("fill"); - cur_properties.fill_opacity = selected.getAttribute("fill-opacity"); - cur_properties.stroke = selected.getAttribute("stroke"); - cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity"); - cur_properties.stroke_width = selected.getAttribute("stroke-width"); - cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray"); - cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin"); - cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap"); - } - - if (selected.tagName == "text") { - cur_text.font_size = selected.getAttribute("font-size"); - cur_text.font_family = selected.getAttribute("font-family"); - } - selectorManager.requestSelector(selected).showGrips(true); - - // This shouldn't be necessary as it was done on mouseDown... -// call("selected", [selected]); - } - // always recalculate dimensions to strip off stray identity transforms - recalculateAllSelectedDimensions(); - // if it was being dragged/resized - if (real_x != r_start_x || real_y != r_start_y) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - if(!selectedElements[i].firstChild) { - // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - selectorManager.requestSelector(selectedElements[i]).resize(); - } - } - } - // no change in position/size, so maybe we should move to pathedit - else { - var t = evt.target; - if (selectedElements[0].nodeName === "path" && selectedElements[1] == null) { - pathActions.select(selectedElements[0]); - } // if it was a path - // else, if it was selected and this is a shift-click, remove it from selection - else if (evt.shiftKey) { - if(tempJustSelected != t) { - canvas.removeFromSelection([t]); - } - } - } // no change in mouse position - - // Remove non-scaling stroke - if(svgedit.browser.supportsNonScalingStroke()) { - var elem = selectedElements[0]; - if (elem) { - elem.removeAttribute('style'); - svgedit.utilities.walkTree(elem, function(elem) { - elem.removeAttribute('style'); - }); - } - } - - } - return; - break; - case "zoom": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - } - var factor = evt.altKey?.5:2; - call("zoomed", { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y), - 'factor': factor - }); - return; - case "fhpath": - // Check that the path contains at least 2 points; a degenerate one-point path - // causes problems. - // Webkit ignores how we set the points attribute with commas and uses space - // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 - var coords = element.getAttribute('points'); - var commaIndex = coords.indexOf(','); - if (commaIndex >= 0) { - keep = coords.indexOf(',', commaIndex+1) >= 0; - } else { - keep = coords.indexOf(' ', coords.indexOf(' ')+1) >= 0; - } - if (keep) { - element = pathActions.smoothPolylineIntoPath(element); - } - break; - case "line": - var attrs = $(element).attr(["x1", "x2", "y1", "y2"]); - keep = (attrs.x1 != attrs.x2 || attrs.y1 != attrs.y2); - break; - case "foreignObject": - case "square": - case "rect": - case "image": - var attrs = $(element).attr(["width", "height"]); - // Image should be kept regardless of size (use inherit dimensions later) - keep = (attrs.width != 0 || attrs.height != 0) || current_mode === "image"; - break; - case "circle": - keep = (element.getAttribute('r') != 0); - break; - case "ellipse": - var attrs = $(element).attr(["rx", "ry"]); - keep = (attrs.rx != null || attrs.ry != null); - break; - case "fhellipse": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": (freehand.minx + freehand.maxx) / 2, - "cy": (freehand.miny + freehand.maxy) / 2, - "rx": (freehand.maxx - freehand.minx) / 2, - "ry": (freehand.maxy - freehand.miny) / 2, - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "fhrect": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": freehand.minx, - "y": freehand.miny, - "width": (freehand.maxx - freehand.minx), - "height": (freehand.maxy - freehand.miny), - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "text": - keep = true; - selectOnly([element]); - textActions.start(element); - break; - case "path": - // set element to null here so that it is not removed nor finalized - element = null; - // continue to be set to true so that mouseMove happens - started = true; - - var res = pathActions.mouseUp(evt, element, mouse_x, mouse_y); - element = res.element - keep = res.keep; - break; - case "pathedit": - keep = true; - element = null; - pathActions.mouseUp(evt); - break; - case "textedit": - keep = false; - element = null; - textActions.mouseUp(evt, mouse_x, mouse_y); - break; - case "rotate": - keep = true; - element = null; - current_mode = "select"; - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } - // perform recalculation to weed out any stray identity transforms that might get stuck - recalculateAllSelectedDimensions(); - call("changed", selectedElements); - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseUp", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y - }, true); - - $.each(ext_result, function(i, r) { - if(r) { - keep = r.keep || keep; - element = r.element; - started = r.started || started; - } - }); - - if (!keep && element != null) { - getCurrentDrawing().releaseId(getId()); - element.parentNode.removeChild(element); - element = null; - - var t = evt.target; - - // if this element is in a group, go up until we reach the top-level group - // just below the layer groups - // TODO: once we implement links, we also would have to check for <a> elements - while (t.parentNode.parentNode.tagName == "g") { - t = t.parentNode; - } - // if we are not in the middle of creating a path, and we've clicked on some shape, - // then go to Select mode. - // WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> - if ( (current_mode != "path" || !drawn_path) && - t.parentNode.id != "selectorParentGroup" && - t.id != "svgcanvas" && t.id != "svgroot") - { - // switch into "select" mode if we've clicked on an element - canvas.setMode("select"); - selectOnly([t], true); - } - - } else if (element != null) { - canvas.addedNew = true; - - if(useUnit) svgedit.units.convertAttrs(element); - - var ani_dur = .2, c_ani; - if(opac_ani.beginElement && element.getAttribute('opacity') != cur_shape.opacity) { - c_ani = $(opac_ani).clone().attr({ - to: cur_shape.opacity, - dur: ani_dur - }).appendTo(element); - try { - // Fails in FF4 on foreignObject - c_ani[0].beginElement(); - } catch(e){} - } else { - ani_dur = 0; - } - - // Ideally this would be done on the endEvent of the animation, - // but that doesn't seem to be supported in Webkit - setTimeout(function() { - if(c_ani) c_ani.remove(); - element.setAttribute("opacity", cur_shape.opacity); - element.setAttribute("style", "pointer-events:inherit"); - cleanupElement(element); - if(current_mode === "path") { - pathActions.toEditMode(element); - } else { - if(curConfig.selectNew) { - selectOnly([element], true); - } - } - // we create the insert command that is stored on the stack - // undo means to call cmd.unapply(), redo means to call cmd.apply() - addCommandToHistory(new InsertElementCommand(element)); - - call("changed",[element]); - }, ani_dur * 1000); - } - - start_transform = null; - }; - - var dblClick = function(evt) { - var evt_target = evt.target; - var parent = evt_target.parentNode; - - // Do nothing if already in current group - if(parent === current_group) return; - - var mouse_target = getMouseTarget(evt); - var tagName = mouse_target.tagName; - - if(tagName === 'text' && current_mode !== 'textedit') { - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ); - textActions.select(mouse_target, pt.x, pt.y); - } - - if((tagName === "g" || tagName === "a") && getRotationAngle(mouse_target)) { - // TODO: Allow method of in-group editing without having to do - // this (similar to editing rotated paths) - - // Ungroup and regroup - pushGroupProperties(mouse_target); - mouse_target = selectedElements[0]; - clearSelection(true); - } - // Reset context - if(current_group) { - leaveContext(); - } - - if((parent.tagName !== 'g' && parent.tagName !== 'a') || - parent === getCurrentDrawing().getCurrentLayer() || - mouse_target === selectorManager.selectorParentGroup) - { - // Escape from in-group edit - return; - } - setContext(mouse_target); - } - - // prevent links from being followed in the canvas - var handleLinkInCanvas = function(e) { - e.preventDefault(); - return false; - }; - - // Added mouseup to the container here. - // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. - $(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp); -// $(window).mouseup(mouseUp); - - $(container).bind("mousewheel DOMMouseScroll", function(e){ - if(!e.shiftKey) return; - e.preventDefault(); - - root_sctm = svgcontent.getScreenCTM().inverse(); - var pt = transformPoint( e.pageX, e.pageY, root_sctm ); - var bbox = { - 'x': pt.x, - 'y': pt.y, - 'width': 0, - 'height': 0 - }; - - // Respond to mouse wheel in IE/Webkit/Opera. - // (It returns up/dn motion in multiples of 120) - if(e.wheelDelta) { - if (e.wheelDelta >= 120) { - bbox.factor = 2; - } else if (e.wheelDelta <= -120) { - bbox.factor = .5; - } - } else if(e.detail) { - if (e.detail > 0) { - bbox.factor = .5; - } else if (e.detail < 0) { - bbox.factor = 2; - } - } - - if(!bbox.factor) return; - call("zoomed", bbox); - }); - -}()); - -// Function: preventClickDefault -// Prevents default browser click behaviour on the given element -// -// Parameters: -// img - The DOM element to prevent the cilck on -var preventClickDefault = function(img) { - $(img).click(function(e){e.preventDefault()}); -} - -// Group: Text edit functions -// Functions relating to editing text elements -var textActions = canvas.textActions = function() { - var curtext; - var textinput; - var cursor; - var selblock; - var blinker; - var chardata = []; - var textbb, transbb; - var matrix; - var last_x, last_y; - var allow_dbl; - - function setCursor(index) { - var empty = (textinput.value === ""); - $(textinput).focus(); - - if(!arguments.length) { - if(empty) { - index = 0; - } else { - if(textinput.selectionEnd !== textinput.selectionStart) return; - index = textinput.selectionEnd; - } - } - - var charbb; - charbb = chardata[index]; - if(!empty) { - textinput.setSelectionRange(index, index); - } - cursor = getElem("text_cursor"); - if (!cursor) { - cursor = document.createElementNS(svgns, "line"); - assignAttributes(cursor, { - 'id': "text_cursor", - 'stroke': "#333", - 'stroke-width': 1 - }); - cursor = getElem("selectorParentGroup").appendChild(cursor); - } - - if(!blinker) { - blinker = setInterval(function() { - var show = (cursor.getAttribute('display') === 'none'); - cursor.setAttribute('display', show?'inline':'none'); - }, 600); - - } - - - var start_pt = ptToScreen(charbb.x, textbb.y); - var end_pt = ptToScreen(charbb.x, (textbb.y + textbb.height)); - - assignAttributes(cursor, { - x1: start_pt.x, - y1: start_pt.y, - x2: end_pt.x, - y2: end_pt.y, - visibility: 'visible', - display: 'inline' - }); - - if(selblock) selblock.setAttribute('d', ''); - } - - function setSelection(start, end, skipInput) { - if(start === end) { - setCursor(end); - return; - } - - if(!skipInput) { - textinput.setSelectionRange(start, end); - } - - selblock = getElem("text_selectblock"); - if (!selblock) { - - selblock = document.createElementNS(svgns, "path"); - assignAttributes(selblock, { - 'id': "text_selectblock", - 'fill': "green", - 'opacity': .5, - 'style': "pointer-events:none" - }); - getElem("selectorParentGroup").appendChild(selblock); - } - - - var startbb = chardata[start]; - - var endbb = chardata[end]; - - cursor.setAttribute('visibility', 'hidden'); - - var tl = ptToScreen(startbb.x, textbb.y), - tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y), - bl = ptToScreen(startbb.x, textbb.y + textbb.height), - br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); - - - var dstr = "M" + tl.x + "," + tl.y - + " L" + tr.x + "," + tr.y - + " " + br.x + "," + br.y - + " " + bl.x + "," + bl.y + "z"; - - assignAttributes(selblock, { - d: dstr, - 'display': 'inline' - }); - } - - function getIndexFromPoint(mouse_x, mouse_y) { - // Position cursor here - var pt = svgroot.createSVGPoint(); - pt.x = mouse_x; - pt.y = mouse_y; - - // No content, so return 0 - if(chardata.length == 1) return 0; - // Determine if cursor should be on left or right of character - var charpos = curtext.getCharNumAtPosition(pt); - if(charpos < 0) { - // Out of text range, look at mouse coords - charpos = chardata.length - 2; - if(mouse_x <= chardata[0].x) { - charpos = 0; - } - } else if(charpos >= chardata.length - 2) { - charpos = chardata.length - 2; - } - var charbb = chardata[charpos]; - var mid = charbb.x + (charbb.width/2); - if(mouse_x > mid) { - charpos++; - } - return charpos; - } - - function setCursorFromPoint(mouse_x, mouse_y) { - setCursor(getIndexFromPoint(mouse_x, mouse_y)); - } - - function setEndSelectionFromPoint(x, y, apply) { - var i1 = textinput.selectionStart; - var i2 = getIndexFromPoint(x, y); - - var start = Math.min(i1, i2); - var end = Math.max(i1, i2); - setSelection(start, end, !apply); - } - - function screenToPt(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - out.x /= current_zoom; - out.y /= current_zoom; - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix.inverse()); - out.x = pt.x; - out.y = pt.y; - } - - return out; - } - - function ptToScreen(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix); - out.x = pt.x; - out.y = pt.y; - } - - out.x *= current_zoom; - out.y *= current_zoom; - - return out; - } - - function hideCursor() { - if(cursor) { - cursor.setAttribute('visibility', 'hidden'); - } - } - - function selectAll(evt) { - setSelection(0, curtext.textContent.length); - $(this).unbind(evt); - } - - function selectWord(evt) { - if(!allow_dbl || !curtext) return; - - var ept = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = ept.x * current_zoom, - mouse_y = ept.y * current_zoom; - var pt = screenToPt(mouse_x, mouse_y); - - var index = getIndexFromPoint(pt.x, pt.y); - var str = curtext.textContent; - var first = str.substr(0, index).replace(/[a-z0-9]+$/i, '').length; - var m = str.substr(index).match(/^[a-z0-9]+/i); - var last = (m?m[0].length:0) + index; - setSelection(first, last); - - // Set tripleclick - $(evt.target).click(selectAll); - setTimeout(function() { - $(evt.target).unbind('click', selectAll); - }, 300); - - } - - return { - select: function(target, x, y) { - curtext = target; - textActions.toEditMode(x, y); - }, - start: function(elem) { - curtext = elem; - textActions.toEditMode(); - }, - mouseDown: function(evt, mouse_target, start_x, start_y) { - var pt = screenToPt(start_x, start_y); - - textinput.focus(); - setCursorFromPoint(pt.x, pt.y); - last_x = start_x; - last_y = start_y; - - // TODO: Find way to block native selection - }, - mouseMove: function(mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - setEndSelectionFromPoint(pt.x, pt.y); - }, - mouseUp: function(evt, mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - - setEndSelectionFromPoint(pt.x, pt.y, true); - - // TODO: Find a way to make this work: Use transformed BBox instead of evt.target -// if(last_x === mouse_x && last_y === mouse_y -// && !svgedit.math.rectsIntersect(transbb, {x: pt.x, y: pt.y, width:0, height:0})) { -// textActions.toSelectMode(true); -// } - - if( - evt.target !== curtext - && mouse_x < last_x + 2 - && mouse_x > last_x - 2 - && mouse_y < last_y + 2 - && mouse_y > last_y - 2) { - - textActions.toSelectMode(true); - } - - }, - setCursor: setCursor, - toEditMode: function(x, y) { - 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'); - -// if(svgedit.browser.supportsEditableText()) { -// curtext.setAttribute('editable', 'simple'); -// return; -// } - - if(!arguments.length) { - setCursor(); - } else { - var pt = screenToPt(x, y); - setCursorFromPoint(pt.x, pt.y); - } - - setTimeout(function() { - allow_dbl = true; - }, 300); - }, - toSelectMode: function(selectElem) { - current_mode = "select"; - clearInterval(blinker); - blinker = null; - if(selblock) $(selblock).attr('display','none'); - if(cursor) $(cursor).attr('visibility','hidden'); - $(curtext).css('cursor', 'move'); - - if(selectElem) { - clearSelection(); - $(curtext).css('cursor', 'move'); - - call("selected", [curtext]); - addToSelection([curtext], true); - } - if(curtext && !curtext.textContent.length) { - // No content, so delete - canvas.deleteSelectedElements(); - } - - $(textinput).blur(); - - curtext = false; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.removeAttribute('editable'); -// } - }, - setInputElem: function(elem) { - textinput = elem; -// $(textinput).blur(hideCursor); - }, - clear: function() { - if(current_mode == "textedit") { - textActions.toSelectMode(); - } - }, - init: function(inputElem) { - if(!curtext) return; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.select(); -// return; -// } - - if(!curtext.parentNode) { - // Result of the ffClone, need to get correct element - curtext = selectedElements[0]; - selectorManager.requestSelector(curtext).showGrips(false); - } - - var str = curtext.textContent; - var len = str.length; - - var xform = curtext.getAttribute('transform'); - - textbb = svgedit.utilities.getBBox(curtext); - - matrix = xform?getMatrix(curtext):null; - - chardata = Array(len); - textinput.focus(); - - $(curtext).unbind('dblclick', selectWord).dblclick(selectWord); - - if(!len) { - var end = {x: textbb.x + (textbb.width/2), width: 0}; - } - - for(var i=0; i<len; i++) { - var start = curtext.getStartPositionOfChar(i); - var end = curtext.getEndPositionOfChar(i); - - if(!svgedit.browser.supportsGoodTextCharPos()) { - var offset = canvas.contentW * current_zoom; - start.x -= offset; - end.x -= offset; - - start.x /= current_zoom; - end.x /= current_zoom; - } - - // Get a "bbox" equivalent for each character. Uses the - // bbox data of the actual text for y, height purposes - - // TODO: Decide if y, width and height are actually necessary - chardata[i] = { - x: start.x, - y: textbb.y, // start.y? - width: end.x - start.x, - height: textbb.height - }; - } - - // Add a last bbox for cursor at end of text - chardata.push({ - x: end.x, - width: 0 - }); - setSelection(textinput.selectionStart, textinput.selectionEnd, true); - } - } -}(); - -// TODO: Migrate all of this code into path.js -// Group: Path edit functions -// Functions relating to editing path elements -var pathActions = canvas.pathActions = function() { - - var subpath = false; - var current_path; - var newPoint, firstCtrl; - - function resetD(p) { - p.setAttribute("d", pathActions.convertPath(p)); - } - - // TODO: Move into path.js - svgedit.path.Path.prototype.endChanges = function(text) { - if(svgedit.browser.isWebkit()) resetD(this.elem); - var cmd = new ChangeElementCommand(this.elem, {d: this.last_d}, text); - addCommandToHistory(cmd); - call("changed", [this.elem]); - } - - svgedit.path.Path.prototype.addPtsToSelection = function(indexes) { - if(!$.isArray(indexes)) indexes = [indexes]; - for(var i=0; i< indexes.length; i++) { - var index = indexes[i]; - var seg = this.segs[index]; - if(seg.ptgrip) { - if(this.selected_pts.indexOf(index) == -1 && index >= 0) { - this.selected_pts.push(index); - } - } - }; - this.selected_pts.sort(); - var i = this.selected_pts.length, - grips = new Array(i); - // Loop through points to be selected and highlight each - while(i--) { - var pt = this.selected_pts[i]; - var seg = this.segs[pt]; - seg.select(true); - grips[i] = seg.ptgrip; - } - // TODO: Correct this: - pathActions.canDeleteNodes = true; - - pathActions.closed_subpath = this.subpathIsClosed(this.selected_pts[0]); - - call("selected", grips); - } - - var current_path = null, - drawn_path = null, - hasMoved = false; - - // This function converts a polyline (created by the fh_path tool) into - // a path element and coverts every three line segments into a single bezier - // curve in an attempt to smooth out the free-hand - var smoothPolylineIntoPath = function(element) { - var points = element.points; - var N = points.numberOfItems; - if (N >= 4) { - // loop through every 3 points and convert to a cubic bezier curve segment - // - // NOTE: this is cheating, it means that every 3 points has the potential to - // be a corner instead of treating each point in an equal manner. In general, - // this technique does not look that good. - // - // I am open to better ideas! - // - // Reading: - // - http://www.efg2.com/Lab/Graphics/Jean-YvesQueinecBezierCurves.htm - // - http://www.codeproject.com/KB/graphics/BezierSpline.aspx?msg=2956963 - // - http://www.ian-ko.com/ET_GeoWizards/UserGuide/smooth.htm - // - http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html - var curpos = points.getItem(0), prevCtlPt = null; - var d = []; - d.push(["M",curpos.x,",",curpos.y," C"].join("")); - for (var i = 1; i <= (N-4); i += 3) { - var ct1 = points.getItem(i); - var ct2 = points.getItem(i+1); - var end = points.getItem(i+2); - - // if the previous segment had a control point, we want to smooth out - // the control points on both sides - if (prevCtlPt) { - var newpts = svgedit.path.smoothControlPoints( prevCtlPt, ct1, curpos ); - if (newpts && newpts.length == 2) { - var prevArr = d[d.length-1].split(','); - prevArr[2] = newpts[0].x; - prevArr[3] = newpts[0].y; - d[d.length-1] = prevArr.join(','); - ct1 = newpts[1]; - } - } - - d.push([ct1.x,ct1.y,ct2.x,ct2.y,end.x,end.y].join(',')); - - curpos = end; - prevCtlPt = ct2; - } - // handle remaining line segments - d.push("L"); - for(;i < N;++i) { - var pt = points.getItem(i); - d.push([pt.x,pt.y].join(",")); - } - d = d.join(" "); - - // create new path element - element = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "id": getId(), - "d": d, - "fill": "none" - } - }); - // No need to call "changed", as this is already done under mouseUp - } - return element; - }; - - return { - mouseDown: function(evt, mouse_target, start_x, start_y) { - if(current_mode === "path") { - mouse_x = start_x; - mouse_y = start_y; - - var x = mouse_x/current_zoom, - y = mouse_y/current_zoom, - stretchy = getElem("path_stretch_line"); - newPoint = [x, y]; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - mouse_x = snapToGrid(mouse_x); - mouse_y = snapToGrid(mouse_y); - } - - if (!stretchy) { - stretchy = document.createElementNS(svgns, "path"); - assignAttributes(stretchy, { - 'id': "path_stretch_line", - 'stroke': "#22C", - 'stroke-width': "0.5", - 'fill': 'none' - }); - stretchy = getElem("selectorParentGroup").appendChild(stretchy); - } - stretchy.setAttribute("display", "inline"); - - var keep = null; - - // if pts array is empty, create path element with M at current point - if (!drawn_path) { - d_attr = "M" + x + "," + y + " "; - drawn_path = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "d": d_attr, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - // set stretchy line to first point - stretchy.setAttribute('d', ['M', mouse_x, mouse_y, mouse_x, mouse_y].join(' ')); - var index = subpath ? svgedit.path.path.segs.length : 0; - svgedit.path.addPointGrip(index, mouse_x, mouse_y); - } - else { - // determine if we clicked on an existing point - var seglist = drawn_path.pathSegList; - var i = seglist.numberOfItems; - var FUZZ = 6/current_zoom; - var clickOnPoint = false; - while(i) { - i --; - var item = seglist.getItem(i); - var px = item.x, py = item.y; - // found a matching point - if ( x >= (px-FUZZ) && x <= (px+FUZZ) && y >= (py-FUZZ) && y <= (py+FUZZ) ) { - clickOnPoint = true; - break; - } - } - - // get path element that we are in the process of creating - var id = getId(); - - // Remove previous path object if previously created - svgedit.path.removePath_(id); - - var newpath = getElem(id); - - var len = seglist.numberOfItems; - // if we clicked on an existing point, then we are done this path, commit it - // (i,i+1) are the x,y that were clicked on - if (clickOnPoint) { - // if clicked on any other point but the first OR - // the first point was clicked on and there are less than 3 points - // then leave the path open - // otherwise, close the path - if (i <= 1 && len >= 2) { - // Create end segment - var abs_x = seglist.getItem(0).x; - var abs_y = seglist.getItem(0).y; - - - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(abs_x, abs_y); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - abs_x, - abs_y, - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - abs_x, - abs_y - ); - } - - var endseg = drawn_path.createSVGPathSegClosePath(); - seglist.appendItem(newseg); - seglist.appendItem(endseg); - } else if(len < 3) { - keep = false; - return keep; - } - $(stretchy).remove(); - - // this will signal to commit the path - element = newpath; - drawn_path = null; - started = false; - - if(subpath) { - if(svgedit.path.path.matrix) { - remapElement(newpath, {}, svgedit.path.path.matrix.inverse()); - } - - var new_d = newpath.getAttribute("d"); - var orig_d = $(svgedit.path.path.elem).attr("d"); - $(svgedit.path.path.elem).attr("d", orig_d + new_d); - $(newpath).remove(); - if(svgedit.path.path.matrix) { - svgedit.path.recalcRotatedPath(); - } - svgedit.path.path.init(); - pathActions.toEditMode(svgedit.path.path.elem); - svgedit.path.path.selectPt(); - return false; - } - } - // else, create a new point, update path element - else { - // Checks if current target or parents are #svgcontent - if(!$.contains(container, getMouseTarget(evt))) { - // Clicked outside canvas, so don't make point - console.log("Clicked outside canvas"); - return false; - } - - var num = drawn_path.pathSegList.numberOfItems; - var last = drawn_path.pathSegList.getItem(num -1); - var lastx = last.x, lasty = last.y; - - if(evt.shiftKey) { var xya = snapToAngle(lastx,lasty,x,y); x=xya.x; y=xya.y; } - - // Use the segment defined by stretchy - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(round(x), round(y)); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - round(x), - round(y), - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - s_seg.x2 / current_zoom, - s_seg.y2 / current_zoom - ); - } - - drawn_path.pathSegList.appendItem(newseg); - - x *= current_zoom; - y *= current_zoom; - - // set stretchy line to latest point - stretchy.setAttribute('d', ['M', x, y, x, y].join(' ')); - var index = num; - if(subpath) index += svgedit.path.path.segs.length; - svgedit.path.addPointGrip(index, x, y); - } -// keep = true; - } - - return; - } - - // TODO: Make sure current_path isn't null at this point - if(!svgedit.path.path) return; - - svgedit.path.path.storeD(); - - var id = evt.target.id; - if (id.substr(0,14) == "pathpointgrip_") { - // Select this point - var cur_pt = svgedit.path.path.cur_pt = parseInt(id.substr(14)); - svgedit.path.path.dragging = [start_x, start_y]; - var seg = svgedit.path.path.segs[cur_pt]; - - // only clear selection if shift is not pressed (otherwise, add - // node to selection) - if (!evt.shiftKey) { - if(svgedit.path.path.selected_pts.length <= 1 || !seg.selected) { - svgedit.path.path.clearSelection(); - } - svgedit.path.path.addPtsToSelection(cur_pt); - } else if(seg.selected) { - svgedit.path.path.removePtFromSelection(cur_pt); - } else { - svgedit.path.path.addPtsToSelection(cur_pt); - } - } else if(id.indexOf("ctrlpointgrip_") == 0) { - svgedit.path.path.dragging = [start_x, start_y]; - - var parts = id.split('_')[1].split('c'); - var cur_pt = parts[0]-0; - var ctrl_num = parts[1]-0; - svgedit.path.path.selectPt(cur_pt, ctrl_num); - } - - // Start selection box - if(!svgedit.path.path.dragging) { - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': start_x * current_zoom, - 'y': start_y * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - }, - mouseMove: function(evt, mouse_x, mouse_y) { - hasMoved = true; - if(current_mode === "path") { - if(!drawn_path) return; - var seglist = drawn_path.pathSegList; - var index = seglist.numberOfItems - 1; - - if(newPoint) { - // First point -// if(!index) return; - - // Set control points - var pointGrip1 = svgedit.path.addCtrlGrip('1c1'); - var pointGrip2 = svgedit.path.addCtrlGrip('0c2'); - - // dragging pointGrip1 - pointGrip1.setAttribute('cx', mouse_x); - pointGrip1.setAttribute('cy', mouse_y); - pointGrip1.setAttribute('display', 'inline'); - - var pt_x = newPoint[0]; - var pt_y = newPoint[1]; - - // set curve - var seg = seglist.getItem(index); - var cur_x = mouse_x / current_zoom; - var cur_y = mouse_y / current_zoom; - var alt_x = (pt_x + (pt_x - cur_x)); - var alt_y = (pt_y + (pt_y - cur_y)); - - if (!evt.altKey) { - pointGrip2.setAttribute('cx', alt_x * current_zoom); - pointGrip2.setAttribute('cy', alt_y * current_zoom); - pointGrip2.setAttribute('display', 'inline'); - } - - var ctrlLine = svgedit.path.getCtrlLine(1); - var ctrlLine2 = svgedit.path.getCtrlLine(2); - assignAttributes(ctrlLine, { - x1: mouse_x, - y1: mouse_y, - x2: pt_x, - y2: pt_y, - display: 'inline' - }); - - if (!evt.altKey) { - assignAttributes(ctrlLine2, { - x1: alt_x * current_zoom, - y1: alt_y * current_zoom, - x2: pt_x, - y2: pt_y, - display: 'inline' - }); - } - - if(index === 0) { - firstCtrl = [mouse_x, mouse_y]; - } else { - var last_x, last_y; - - var last = seglist.getItem(index - 1); - var last_x = last.x; - var last_y = last.y - - if(last.pathSegType === 6) { - last_x += (last_x - last.x2); - last_y += (last_y - last.y2); - } else if(firstCtrl) { - last_x = firstCtrl[0]/current_zoom; - last_y = firstCtrl[1]/current_zoom; - } - svgedit.path.replacePathSeg(6, index, [pt_x, pt_y, last_x, last_y, alt_x, alt_y], drawn_path); - } - } else { - var stretchy = getElem("path_stretch_line"); - if (stretchy) { - var prev = seglist.getItem(index); - if(prev.pathSegType === 6) { - var prev_x = prev.x + (prev.x - prev.x2); - var prev_y = prev.y + (prev.y - prev.y2); - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, prev_x * current_zoom, prev_y * current_zoom, mouse_x, mouse_y], stretchy); - } else if(firstCtrl) { - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, firstCtrl[0], firstCtrl[1], mouse_x, mouse_y], stretchy); - } else { - svgedit.path.replacePathSeg(4, 1, [mouse_x, mouse_y], stretchy); - } - } - } - return; - } - // if we are dragging a point, let's move it - if (svgedit.path.path.dragging) { - var pt = svgedit.path.getPointFromGrip({ - x: svgedit.path.path.dragging[0], - y: svgedit.path.path.dragging[1] - }, svgedit.path.path); - var mpt = svgedit.path.getPointFromGrip({ - x: mouse_x, - y: mouse_y - }, svgedit.path.path); - var diff_x = mpt.x - pt.x; - var diff_y = mpt.y - pt.y; - svgedit.path.path.dragging = [mouse_x, mouse_y]; - - if(svgedit.path.path.dragctrl) { - svgedit.path.path.moveCtrl(diff_x, diff_y); - } else { - svgedit.path.path.movePts(diff_x, diff_y); - } - } else { - svgedit.path.path.selected_pts = []; - svgedit.path.path.eachSeg(function(i) { - var seg = this; - if(!seg.next && !seg.prev) return; - - var item = seg.item; - var rbb = rubberBox.getBBox(); - - var pt = svgedit.path.getGripPt(seg); - var pt_bb = { - x: pt.x, - y: pt.y, - width: 0, - height: 0 - }; - - var sel = svgedit.math.rectsIntersect(rbb, pt_bb); - - this.select(sel); - //Note that addPtsToSelection is not being run - if(sel) svgedit.path.path.selected_pts.push(seg.index); - }); - - } - }, - mouseUp: function(evt, element, mouse_x, mouse_y) { - - // Create mode - if(current_mode === "path") { - newPoint = null; - if(!drawn_path) { - element = getElem(getId()); - started = false; - firstCtrl = null; - } - - return { - keep: true, - element: element - } - } - - // Edit mode - - if (svgedit.path.path.dragging) { - var last_pt = svgedit.path.path.cur_pt; - - svgedit.path.path.dragging = false; - svgedit.path.path.dragctrl = false; - svgedit.path.path.update(); - - - if(hasMoved) { - svgedit.path.path.endChanges("Move path point(s)"); - } - - if(!evt.shiftKey && !hasMoved) { - svgedit.path.path.selectPt(last_pt); - } - } - else if(rubberBox && rubberBox.getAttribute('display') != 'none') { - // Done with multi-node-select - rubberBox.setAttribute("display", "none"); - - if(rubberBox.getAttribute('width') <= 2 && rubberBox.getAttribute('height') <= 2) { - pathActions.toSelectMode(evt.target); - } - - // else, move back to select mode - } else { - pathActions.toSelectMode(evt.target); - } - hasMoved = false; - }, - toEditMode: function(element) { - svgedit.path.path = svgedit.path.getPath_(element); - current_mode = "pathedit"; - clearSelection(); - svgedit.path.path.show(true).update(); - svgedit.path.path.oldbbox = svgedit.utilities.getBBox(svgedit.path.path.elem); - subpath = false; - }, - toSelectMode: function(elem) { - var selPath = (elem == svgedit.path.path.elem); - current_mode = "select"; - svgedit.path.path.show(false); - current_path = false; - clearSelection(); - - if(svgedit.path.path.matrix) { - // Rotated, so may need to re-calculate the center - svgedit.path.recalcRotatedPath(); - } - - if(selPath) { - call("selected", [elem]); - addToSelection([elem], true); - } - }, - addSubPath: function(on) { - if(on) { - // Internally we go into "path" mode, but in the UI it will - // still appear as if in "pathedit" mode. - current_mode = "path"; - subpath = true; - } else { - pathActions.clear(true); - pathActions.toEditMode(svgedit.path.path.elem); - } - }, - select: function(target) { - if (current_path === target) { - pathActions.toEditMode(target); - current_mode = "pathedit"; - } // going into pathedit mode - else { - current_path = target; - } - }, - reorient: function() { - var elem = selectedElements[0]; - if(!elem) return; - var angle = getRotationAngle(elem); - if(angle == 0) return; - - var batchCmd = new BatchCommand("Reorient path"); - var changes = { - d: elem.getAttribute('d'), - transform: elem.getAttribute('transform') - }; - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - clearSelection(); - this.resetOrientation(elem); - - addCommandToHistory(batchCmd); - - // Set matrix to null - svgedit.path.getPath_(elem).show(false).matrix = null; - - this.clear(); - - addToSelection([elem], true); - call("changed", selectedElements); - }, - - clear: function(remove) { - current_path = null; - if (drawn_path) { - var elem = getElem(getId()); - $(getElem("path_stretch_line")).remove(); - $(elem).remove(); - $(getElem("pathpointgrip_container")).find('*').attr('display', 'none'); - drawn_path = firstCtrl = null; - started = false; - } else if (current_mode == "pathedit") { - this.toSelectMode(); - } - if(svgedit.path.path) svgedit.path.path.init().show(false); - }, - resetOrientation: function(path) { - if(path == null || path.nodeName != 'path') return false; - var tlist = getTransformList(path); - var m = transformListToTransform(tlist).matrix; - tlist.clear(); - path.removeAttribute("transform"); - var segList = path.pathSegList; - - // Opera/win/non-EN throws an error here. - // TODO: Find out why! - // Presumed fixed in Opera 10.5, so commented out for now - -// try { - var len = segList.numberOfItems; -// } catch(err) { -// var fixed_d = pathActions.convertPath(path); -// path.setAttribute('d', fixed_d); -// segList = path.pathSegList; -// var len = segList.numberOfItems; -// } - var last_x, last_y; - - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - var type = seg.pathSegType; - if(type == 1) continue; - var pts = []; - $.each(['',1,2], function(j, n) { - var x = seg['x'+n], y = seg['y'+n]; - if(x !== undefined && y !== undefined) { - var pt = transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); - } - }); - svgedit.path.replacePathSeg(type, i, pts, path); - } - - reorientGrads(path, m); - - - }, - zoomChange: function() { - if(current_mode == "pathedit") { - svgedit.path.path.update(); - } - }, - getNodePoint: function() { - var sel_pt = svgedit.path.path.selected_pts.length ? svgedit.path.path.selected_pts[0] : 1; - - var seg = svgedit.path.path.segs[sel_pt]; - return { - x: seg.item.x, - y: seg.item.y, - type: seg.type - }; - }, - linkControlPoints: function(linkPoints) { - svgedit.path.setLinkControlPoints(linkPoints); - }, - clonePathNode: function() { - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var segs = svgedit.path.path.segs; - - var i = sel_pts.length; - var nums = []; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.addSeg(pt); - - nums.push(pt + i); - nums.push(pt + i + 1); - } - svgedit.path.path.init().addPtsToSelection(nums); - - svgedit.path.path.endChanges("Clone path node(s)"); - }, - opencloseSubPath: function() { - var sel_pts = svgedit.path.path.selected_pts; - // Only allow one selected node for now - if(sel_pts.length !== 1) return; - - var elem = svgedit.path.path.elem; - var list = elem.pathSegList; - - var len = list.numberOfItems; - - var index = sel_pts[0]; - - var open_pt = null; - var start_item = null; - - // Check if subpath is already open - svgedit.path.path.eachSeg(function(i) { - if(this.type === 2 && i <= index) { - start_item = this.item; - } - if(i <= index) return true; - if(this.type === 2) { - // Found M first, so open - open_pt = i; - return false; - } else if(this.type === 1) { - // Found Z first, so closed - open_pt = false; - return false; - } - }); - - if(open_pt == null) { - // Single path, so close last seg - open_pt = svgedit.path.path.segs.length - 1; - } - - if(open_pt !== false) { - // Close this path - - // Create a line going to the previous "M" - var newseg = elem.createSVGPathSegLinetoAbs(start_item.x, start_item.y); - - var closer = elem.createSVGPathSegClosePath(); - if(open_pt == svgedit.path.path.segs.length - 1) { - list.appendItem(newseg); - list.appendItem(closer); - } else { - svgedit.path.insertItemBefore(elem, closer, open_pt); - svgedit.path.insertItemBefore(elem, newseg, open_pt); - } - - svgedit.path.path.init().selectPt(open_pt+1); - return; - } - - - - // M 1,1 L 2,2 L 3,3 L 1,1 z // open at 2,2 - // M 2,2 L 3,3 L 1,1 - - // M 1,1 L 2,2 L 1,1 z M 4,4 L 5,5 L6,6 L 5,5 z - // M 1,1 L 2,2 L 1,1 z [M 4,4] L 5,5 L(M)6,6 L 5,5 z - - var seg = svgedit.path.path.segs[index]; - - if(seg.mate) { - list.removeItem(index); // Removes last "L" - list.removeItem(index); // Removes the "Z" - svgedit.path.path.init().selectPt(index - 1); - return; - } - - var last_m, z_seg; - - // Find this sub-path's closing point and remove - for(var i=0; i<list.numberOfItems; i++) { - var item = list.getItem(i); - - if(item.pathSegType === 2) { - // Find the preceding M - last_m = i; - } else if(i === index) { - // Remove it - list.removeItem(last_m); -// index--; - } else if(item.pathSegType === 1 && index < i) { - // Remove the closing seg of this subpath - z_seg = i-1; - list.removeItem(i); - break; - } - } - - var num = (index - last_m) - 1; - - while(num--) { - svgedit.path.insertItemBefore(elem, list.getItem(last_m), z_seg); - } - - var pt = list.getItem(last_m); - - // Make this point the new "M" - svgedit.path.replacePathSeg(2, last_m, [pt.x, pt.y]); - - var i = index - - svgedit.path.path.init().selectPt(0); - }, - deletePathNode: function() { - if(!pathActions.canDeleteNodes) return; - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var i = sel_pts.length; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.deleteSeg(pt); - } - - // Cleanup - var cleanup = function() { - var segList = svgedit.path.path.elem.pathSegList; - var len = segList.numberOfItems; - - var remItems = function(pos, count) { - while(count--) { - segList.removeItem(pos); - } - } - - if(len <= 1) return true; - - while(len--) { - var item = segList.getItem(len); - if(item.pathSegType === 1) { - var prev = segList.getItem(len-1); - var nprev = segList.getItem(len-2); - if(prev.pathSegType === 2) { - remItems(len-1, 2); - cleanup(); - break; - } else if(nprev.pathSegType === 2) { - remItems(len-2, 3); - cleanup(); - break; - } - - } else if(item.pathSegType === 2) { - if(len > 0) { - var prev_type = segList.getItem(len-1).pathSegType; - // Path has M M - if(prev_type === 2) { - remItems(len-1, 1); - cleanup(); - break; - // Entire path ends with Z M - } else if(prev_type === 1 && segList.numberOfItems-1 === len) { - remItems(len, 1); - cleanup(); - break; - } - } - } - } - return false; - } - - cleanup(); - - // Completely delete a path with 1 or 0 segments - if(svgedit.path.path.elem.pathSegList.numberOfItems <= 1) { - pathActions.toSelectMode(svgedit.path.path.elem); - canvas.deleteSelectedElements(); - return; - } - - svgedit.path.path.init(); - - svgedit.path.path.clearSelection(); - - // TODO: Find right way to select point now - // path.selectPt(sel_pt); - if(window.opera) { // Opera repaints incorrectly - var cp = $(svgedit.path.path.elem); cp.attr('d',cp.attr('d')); - } - svgedit.path.path.endChanges("Delete path node(s)"); - }, - smoothPolylineIntoPath: smoothPolylineIntoPath, - setSegType: function(v) { - svgedit.path.path.setSegType(v); - }, - moveNode: function(attr, newValue) { - var sel_pts = svgedit.path.path.selected_pts; - if(!sel_pts.length) return; - - svgedit.path.path.storeD(); - - // Get first selected point - var seg = svgedit.path.path.segs[sel_pts[0]]; - var diff = {x:0, y:0}; - diff[attr] = newValue - seg.item[attr]; - - seg.move(diff.x, diff.y); - svgedit.path.path.endChanges("Move path point"); - }, - fixEnd: function(elem) { - // Adds an extra segment if the last seg before a Z doesn't end - // at its M point - // M0,0 L0,100 L100,100 z - var segList = elem.pathSegList; - var len = segList.numberOfItems; - var last_m; - for (var i = 0; i < len; ++i) { - var item = segList.getItem(i); - if(item.pathSegType === 2) { - last_m = item; - } - - if(item.pathSegType === 1) { - var prev = segList.getItem(i-1); - if(prev.x != last_m.x || prev.y != last_m.y) { - // Add an L segment here - var newseg = elem.createSVGPathSegLinetoAbs(last_m.x, last_m.y); - svgedit.path.insertItemBefore(elem, newseg, i); - // Can this be done better? - pathActions.fixEnd(elem); - break; - } - - } - } - if(svgedit.browser.isWebkit()) resetD(elem); - }, - // Convert a path to one with only absolute or relative values - convertPath: function(path, toRel) { - var segList = path.pathSegList; - var len = segList.numberOfItems; - var curx = 0, cury = 0; - var d = ""; - var last_m = null; - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - // if these properties are not in the segment, set them to zero - var x = seg.x || 0, - y = seg.y || 0, - x1 = seg.x1 || 0, - y1 = seg.y1 || 0, - x2 = seg.x2 || 0, - y2 = seg.y2 || 0; - - var type = seg.pathSegType; - var letter = pathMap[type]['to'+(toRel?'Lower':'Upper')+'Case'](); - - var addToD = function(pnts, more, last) { - var str = ''; - var more = more?' '+more.join(' '):''; - var last = last?' '+svgedit.units.shortFloat(last):''; - $.each(pnts, function(i, pnt) { - pnts[i] = svgedit.units.shortFloat(pnt); - }); - d += letter + pnts.join(' ') + more + last; - } - - switch (type) { - case 1: // z,Z closepath (Z/z) - d += "z"; - break; - case 12: // absolute horizontal line (H) - x -= curx; - case 13: // relative horizontal line (h) - if(toRel) { - curx += x; - letter = 'l'; - } else { - x += curx; - curx = x; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[x, cury]]); - break; - case 14: // absolute vertical line (V) - y -= cury; - case 15: // relative vertical line (v) - if(toRel) { - cury += y; - letter = 'l'; - } else { - y += cury; - cury = y; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[curx, y]]); - break; - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - x -= curx; - y -= cury; - case 5: // relative line (l) - case 3: // relative move (m) - // If the last segment was a "z", this must be relative to - if(last_m && segList.getItem(i-1).pathSegType === 1 && !toRel) { - curx = last_m[0]; - cury = last_m[1]; - } - - case 19: // relative smooth quad (t) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - if(type === 3) last_m = [curx, cury]; - - addToD([[x,y]]); - break; - case 6: // absolute cubic (C) - x -= curx; x1 -= curx; x2 -= curx; - y -= cury; y1 -= cury; y2 -= cury; - case 7: // relative cubic (c) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; x2 += curx; - y += cury; y1 += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x2,y2],[x,y]]); - break; - case 8: // absolute quad (Q) - x -= curx; x1 -= curx; - y -= cury; y1 -= cury; - case 9: // relative quad (q) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; - y += cury; y1 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x,y]]); - break; - case 10: // absolute elliptical arc (A) - x -= curx; - y -= cury; - case 11: // relative elliptical arc (a) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - addToD([[seg.r1,seg.r2]], [ - seg.angle, - (seg.largeArcFlag ? 1 : 0), - (seg.sweepFlag ? 1 : 0) - ],[x,y] - ); - break; - case 16: // absolute smooth cubic (S) - x -= curx; x2 -= curx; - y -= cury; y2 -= cury; - case 17: // relative smooth cubic (s) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x2 += curx; - y += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x2,y2],[x,y]]); - break; - } // switch on path segment type - } // for each segment - return d; - } - } -}(); -// end pathActions - -// Group: Serialization - -// Function: removeUnusedDefElems -// Looks at DOM elements inside the <defs> to see if they are referred to, -// removes them from the DOM if they are not. -// -// Returns: -// The amount of elements that were removed -var removeUnusedDefElems = this.removeUnusedDefElems = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if(!defs || !defs.length) return 0; - -// if(!defs.firstChild) return; - - var defelem_uses = [], - numRemoved = 0; - var attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']; - var alen = attrs.length; - - var all_els = svgcontent.getElementsByTagNameNS(svgns, '*'); - var all_len = all_els.length; - - for(var i=0; i<all_len; i++) { - var el = all_els[i]; - for(var j = 0; j < alen; j++) { - var ref = getUrlFromAttr(el.getAttribute(attrs[j])); - if(ref) { - defelem_uses.push(ref.substr(1)); - } - } - - // gradients can refer to other gradients - var href = getHref(el); - if (href && href.indexOf('#') === 0) { - defelem_uses.push(href.substr(1)); - } - }; - - var defelems = $(defs).find("linearGradient, radialGradient, filter, marker, svg, symbol"); - defelem_ids = [], - i = defelems.length; - while (i--) { - var defelem = defelems[i]; - var id = defelem.id; - if(defelem_uses.indexOf(id) < 0) { - // Not found, so remove (but remember) - removedElements[id] = defelem; - defelem.parentNode.removeChild(defelem); - numRemoved++; - } - } - - return numRemoved; -} - -// Function: svgCanvasToString -// Main function to set up the SVG content for output -// -// Returns: -// String containing the SVG image for output -this.svgCanvasToString = function() { - // keep calling it until there are none to remove - while (removeUnusedDefElems() > 0) {}; - - pathActions.clear(true); - - // Keep SVG-Edit comment on top - $.each(svgcontent.childNodes, function(i, node) { - if(i && node.nodeType === 8 && node.data.indexOf('Created with') >= 0) { - svgcontent.insertBefore(node, svgcontent.firstChild); - } - }); - - // Move out of in-group editing mode - if(current_group) { - leaveContext(); - selectOnly([current_group]); - } - - var naked_svgs = []; - - // Unwrap gsvg if it has no special attributes (only id and style) - $(svgcontent).find('g:data(gsvg)').each(function() { - var attrs = this.attributes; - var len = attrs.length; - for(var i=0; i<len; i++) { - if(attrs[i].nodeName == 'id' || attrs[i].nodeName == 'style') { - len--; - } - } - // No significant attributes, so ungroup - if(len <= 0) { - var svg = this.firstChild; - naked_svgs.push(svg); - $(this).replaceWith(svg); - } - }); - var output = this.svgToString(svgcontent, 0); - - // Rewrap gsvg - if(naked_svgs.length) { - $(naked_svgs).each(function() { - groupSvgElem(this); - }); - } - - return output; -}; - -// Function: svgToString -// Sub function ran on each SVG element to convert it to a string as desired -// -// Parameters: -// elem - The SVG element to convert -// indent - Integer with the amount of spaces to indent this tag -// -// Returns: -// String with the given element as an SVG tag -this.svgToString = function(elem, indent) { - var out = new Array(), toXml = svgedit.utilities.toXml; - var unit = curConfig.baseUnit; - var unit_re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - - if (elem) { - cleanupElement(elem); - var attrs = elem.attributes, - attr, - i, - childs = elem.childNodes; - - for (var i=0; i<indent; i++) out.push(" "); - out.push("<"); out.push(elem.nodeName); - if(elem.id === 'svgcontent') { - // Process root element separately - var res = getResolution(); - - var vb = ""; - // TODO: Allow this by dividing all values by current baseVal - // Note that this also means we should properly deal with this on import -// if(curConfig.baseUnit !== "px") { -// var unit = curConfig.baseUnit; -// var unit_m = svgedit.units.getTypeMap()[unit]; -// res.w = svgedit.units.shortFloat(res.w / unit_m) -// res.h = svgedit.units.shortFloat(res.h / unit_m) -// vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"'; -// res.w += unit; -// res.h += unit; -// } - - if(unit !== "px") { - res.w = svgedit.units.convertUnit(res.w, unit) + unit; - res.h = svgedit.units.convertUnit(res.h, unit) + unit; - } - - out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="'+svgns+'"'); - - var nsuris = {}; - - // Check elements for namespaces, add if found - $(elem).find('*').andSelf().each(function() { - var el = this; - $.each(this.attributes, function(i, attr) { - var uri = attr.namespaceURI; - if(uri && !nsuris[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml' ) { - nsuris[uri] = true; - out.push(" xmlns:" + nsMap[uri] + '="' + uri +'"'); - } - }); - }); - - var i = attrs.length; - var attr_names = ['width','height','xmlns','x','y','viewBox','id','overflow']; - while (i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - - // Namespaces have already been dealt with, so skip - if(attr.nodeName.indexOf('xmlns:') === 0) continue; - - // only serialize attributes we don't use internally - if (attrVal != "" && attr_names.indexOf(attr.localName) == -1) - { - - if(!attr.namespaceURI || nsMap[attr.namespaceURI]) { - out.push(' '); - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } else { - // Skip empty defs - if(elem.nodeName === 'defs' && !elem.firstChild) return; - - var moz_attrs = ['-moz-math-font-style', '_moz-math-font-style']; - for (var i=attrs.length-1; i>=0; i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - //remove bogus attributes added by Gecko - if (moz_attrs.indexOf(attr.localName) >= 0) continue; - if (attrVal != "") { - if(attrVal.indexOf('pointer-events') === 0) continue; - if(attr.localName === "class" && attrVal.indexOf('se_') === 0) continue; - out.push(" "); - if(attr.localName === 'd') attrVal = pathActions.convertPath(elem, true); - if(!isNaN(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal); - } else if(unit_re.test(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal) + unit; - } - - // Embed images when saving - if(save_options.apply - && elem.nodeName === 'image' - && attr.localName === 'href' - && save_options.images - && save_options.images === 'embed') - { - var img = encodableImages[attrVal]; - if(img) attrVal = img; - } - - // map various namespaces to our fixed namespace prefixes - // (the default xmlns attribute itself does not get a prefix) - if(!attr.namespaceURI || attr.namespaceURI == svgns || nsMap[attr.namespaceURI]) { - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } - - if (elem.hasChildNodes()) { - out.push(">"); - indent++; - var bOneLine = false; - - for (var i=0; i<childs.length; i++) - { - var child = childs.item(i); - switch(child.nodeType) { - case 1: // element node - out.push("\n"); - out.push(this.svgToString(childs.item(i), indent)); - break; - case 3: // text node - var str = child.nodeValue.replace(/^\s+|\s+$/g, ""); - if (str != "") { - bOneLine = true; - out.push(toXml(str) + ""); - } - break; - case 4: // cdata node - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<![CDATA["); - out.push(child.nodeValue); - out.push("]]>"); - break; - case 8: // comment - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<!--"); - out.push(child.data); - out.push("-->"); - break; - } // switch on node type - } - indent--; - if (!bOneLine) { - out.push("\n"); - for (var i=0; i<indent; i++) out.push(" "); - } - out.push("</"); out.push(elem.nodeName); out.push(">"); - } else { - out.push("/>"); - } - } - return out.join(''); -}; // end svgToString() - -// Function: embedImage -// Converts a given image file to a data URL when possible, then runs a given callback -// -// Parameters: -// val - String with the path/URL of the image -// callback - Optional function to run when image data is found, supplies the -// result (data URL or false) as first parameter. -this.embedImage = function(val, callback) { - - // load in the image and once it's loaded, get the dimensions - $(new Image()).load(function() { - // create a canvas the same size as the raster image - var canvas = document.createElement("canvas"); - canvas.width = this.width; - canvas.height = this.height; - // load the raster image into the canvas - canvas.getContext("2d").drawImage(this,0,0); - // retrieve the data: URL - try { - var urldata = ';svgedit_url=' + encodeURIComponent(val); - urldata = canvas.toDataURL().replace(';base64',urldata+';base64'); - encodableImages[val] = urldata; - } catch(e) { - encodableImages[val] = false; - } - last_good_img_url = val; - if(callback) callback(encodableImages[val]); - }).attr('src',val); -} - -// Function: setGoodImage -// Sets a given URL to be a "last good image" URL -this.setGoodImage = function(val) { - last_good_img_url = val; -} - -this.open = function() { - // Nothing by default, handled by optional widget/extension -}; - -// Function: save -// Serializes the current drawing into SVG XML text and returns it to the 'saved' handler. -// This function also includes the XML prolog. Clients of the SvgCanvas bind their save -// function to the 'saved' event. -// -// Returns: -// Nothing -this.save = function(opts) { - // remove the selected outline before serializing - clearSelection(); - // Update save options if provided - if(opts) $.extend(save_options, opts); - save_options.apply = true; - - // no need for doctype, see http://jwatt.org/svg/authoring/#doctype-declaration - var str = this.svgCanvasToString(); - call("saved", str); -}; - -// Function: rasterExport -// Generates a PNG Data URL based on the current image, then calls "exported" -// with an object including the string and any issues found -this.rasterExport = function() { - // remove the selected outline before serializing - clearSelection(); - - // Check for known CanVG issues - var issues = []; - - // Selector and notice - var issue_list = { - 'feGaussianBlur': uiStrings.exportNoBlur, - 'foreignObject': uiStrings.exportNoforeignObject, - '[stroke-dasharray]': uiStrings.exportNoDashArray - }; - var content = $(svgcontent); - - // Add font/text check if Canvas Text API is not implemented - if(!("font" in $('<canvas>')[0].getContext('2d'))) { - issue_list['text'] = uiStrings.exportNoText; - } - - $.each(issue_list, function(sel, descr) { - if(content.find(sel).length) { - issues.push(descr); - } - }); - - var str = this.svgCanvasToString(); - call("exported", {svg: str, issues: issues}); -}; - -// Function: getSvgString -// Returns the current drawing as raw SVG XML text. -// -// Returns: -// The current drawing as raw SVG XML text. -this.getSvgString = function() { - save_options.apply = false; - return this.svgCanvasToString(); -}; - -// Function: randomizeIds -// This function determines whether to use a nonce in the prefix, when -// generating IDs for future documents in SVG-Edit. -// -// Parameters: -// an opional boolean, which, if true, adds a nonce to the prefix. Thus -// svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true) -// -// if you're controlling SVG-Edit externally, and want randomized IDs, call -// this BEFORE calling svgCanvas.setSvgString -// -this.randomizeIds = function() { - if (arguments.length > 0 && arguments[0] == false) { - svgedit.draw.randomizeIds(false, getCurrentDrawing()); - } else { - svgedit.draw.randomizeIds(true, getCurrentDrawing()); - } -}; - -// Function: uniquifyElems -// Ensure each element has a unique ID -// -// Parameters: -// g - The parent element of the tree to give unique IDs -var uniquifyElems = this.uniquifyElems = function(g) { - var ids = {}; - // TODO: Handle markers and connectors. These are not yet re-identified properly - // as their referring elements do not get remapped. - // - // <marker id='se_marker_end_svg_7'/> - // <polyline id='svg_7' se:connector='svg_1 svg_6' marker-end='url(#se_marker_end_svg_7)'/> - // - // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute - // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute - var ref_elems = ["filter", "linearGradient", "pattern", "radialGradient", "symbol", "textPath", "use"]; - - svgedit.utilities.walkTree(g, function(n) { - // if it's an element node - if (n.nodeType == 1) { - // and the element has an ID - if (n.id) { - // and we haven't tracked this ID yet - if (!(n.id in ids)) { - // add this id to our map - ids[n.id] = {elem:null, attrs:[], hrefs:[]}; - } - ids[n.id]["elem"] = n; - } - - // now search for all attributes on this element that might refer - // to other elements - $.each(ref_attrs,function(i,attr) { - var attrnode = n.getAttributeNode(attr); - if (attrnode) { - // the incoming file has been sanitized, so we should be able to safely just strip off the leading # - var url = svgedit.utilities.getUrlFromAttr(attrnode.value), - refid = url ? url.substr(1) : null; - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["attrs"].push(attrnode); - } - } - }); - - // check xlink:href now - var href = svgedit.utilities.getHref(n); - // TODO: what if an <image> or <a> element refers to an element internally? - if(href && ref_elems.indexOf(n.nodeName) >= 0) - { - var refid = href.substr(1); - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["hrefs"].push(n); - } - } - } - }); - - // in ids, we now have a map of ids, elements and attributes, let's re-identify - for (var oldid in ids) { - if (!oldid) continue; - var elem = ids[oldid]["elem"]; - if (elem) { - var newid = getNextId(); - - // assign element its new id - elem.id = newid; - - // remap all url() attributes - var attrs = ids[oldid]["attrs"]; - var j = attrs.length; - while (j--) { - var attr = attrs[j]; - attr.ownerElement.setAttribute(attr.name, "url(#" + newid + ")"); - } - - // remap all href attributes - var hreffers = ids[oldid]["hrefs"]; - var k = hreffers.length; - while (k--) { - var hreffer = hreffers[k]; - svgedit.utilities.setHref(hreffer, "#"+newid); - } - } - } -} - -// Function setUseData -// Assigns reference data for each use element -var setUseData = this.setUseData = function(parent) { - var elems = $(parent); - - if(parent.tagName !== 'use') { - elems = elems.find('use'); - } - - elems.each(function() { - var id = getHref(this).substr(1); - var ref_elem = getElem(id); - if(!ref_elem) return; - $(this).data('ref', ref_elem); - if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') { - $(this).data('symbol', ref_elem).data('ref', ref_elem); - } - }); -} - -// Function convertGradients -// Converts gradients from userSpaceOnUse to objectBoundingBox -var convertGradients = this.convertGradients = function(elem) { - var elems = $(elem).find('linearGradient, radialGradient'); - if(!elems.length && svgedit.browser.isWebkit()) { - // Bug in webkit prevents regular *Gradient selector search - elems = $(elem).find('*').filter(function() { - return (this.tagName.indexOf('Gradient') >= 0); - }); - } - - elems.each(function() { - var grad = this; - if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { - // TODO: Support more than one element with this ref by duplicating parent grad - var elems = $(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - if(!elems.length) return; - - // get object's bounding box - var bb = svgedit.utilities.getBBox(elems[0]); - - // This will occur if the element is inside a <defs> or a <symbol>, - // in which we shouldn't need to convert anyway. - if(!bb) return; - - if(grad.tagName === 'linearGradient') { - var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); - - // If has transform, convert - var tlist = grad.gradientTransform.baseVal; - if(tlist && tlist.numberOfItems > 0) { - var m = transformListToTransform(tlist).matrix; - var pt1 = transformPoint(g_coords.x1, g_coords.y1, m); - var pt2 = transformPoint(g_coords.x2, g_coords.y2, m); - - g_coords.x1 = pt1.x; - g_coords.y1 = pt1.y; - g_coords.x2 = pt2.x; - g_coords.y2 = pt2.y; - grad.removeAttribute('gradientTransform'); - } - - $(grad).attr({ - x1: (g_coords.x1 - bb.x) / bb.width, - y1: (g_coords.y1 - bb.y) / bb.height, - x2: (g_coords.x2 - bb.x) / bb.width, - y2: (g_coords.y2 - bb.y) / bb.height - }); - grad.removeAttribute('gradientUnits'); - } else { - // Note: radialGradient elements cannot be easily converted - // because userSpaceOnUse will keep circular gradients, while - // objectBoundingBox will x/y scale the gradient according to - // its bbox. - - // For now we'll do nothing, though we should probably have - // the gradient be updated as the element is moved, as - // inkscape/illustrator do. - -// var g_coords = $(grad).attr(['cx', 'cy', 'r']); -// -// $(grad).attr({ -// cx: (g_coords.cx - bb.x) / bb.width, -// cy: (g_coords.cy - bb.y) / bb.height, -// r: g_coords.r -// }); -// -// grad.removeAttribute('gradientUnits'); - } - - - } - }); -} - -// Function: convertToGroup -// Converts selected/given <use> 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']); - - var vb = elem.getAttribute('viewBox'); - - if(vb) { - var nums = vb.split(' '); - pos.x -= +nums[0]; - pos.y -= +nums[1]; - } - - // Not ideal, but works - ts += " translate(" + (pos.x || 0) + "," + (pos.y || 0) + ")"; - - var prev = $elem.prev(); - - // Remove <use> element - batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].nextSibling, $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)); - } - - // Duplicate the gradients for Gecko, since they weren't included in the <symbol> - if(svgedit.browser.isGecko()) { - var dupeGrads = $(findDefs()).children('linearGradient,radialGradient,pattern').clone(); - $(g).append(dupeGrads); - } - - if (ts) { - g.setAttribute("transform", ts); - } - - var parent = elem.parentNode; - - uniquifyElems(g); - - // Put the dupe gradients back into <defs> (after uniquifying them) - if(svgedit.browser.isGecko()) { - $(findDefs()).append( $(g).find('linearGradient,radialGradient,pattern') ); - } - - // now give the g itself a new id - g.id = getNextId(); - - prev.after(g); - - if(parent) { - if(!has_more) { - // remove symbol/svg element - var nextSibling = elem.nextSibling; - parent.removeChild(elem); - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - } - - setUseData(g); - - if(svgedit.browser.isGecko()) { - convertGradients(findDefs()); - } else { - convertGradients(g); - } - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - // Give ID for any visible element missing one - $(g).find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - selectOnly([g]); - - var cm = pushGroupProperties(g, true); - if(cm) { - batchCmd.addSubCommand(cm); - } - - addCommandToHistory(batchCmd); - - } else { - console.log('Unexpected element to ungroup:', elem); - } -} - -// -// Function: setSvgString -// This function sets the current drawing as the input SVG XML. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the set was unsuccessful, true otherwise. -this.setSvgString = function(xmlString) { - try { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - var batchCmd = new BatchCommand("Change Source"); - - // remove old svg document - var nextSibling = svgcontent.nextSibling; - var oldzoom = svgroot.removeChild(svgcontent); - batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgroot)); - - // set new svg document - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svgcontent = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svgcontent = svgdoc.importNode(newDoc.documentElement, true); - } - - svgroot.appendChild(svgcontent); - var content = $(svgcontent); - - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - - // retrieve or set the nonce - var nonce = getCurrentDrawing().getNonce(); - if (nonce) { - call("setnonce", nonce); - } else { - call("unsetnonce"); - } - - // change image href vals if possible - content.find('image').each(function() { - var image = this; - preventClickDefault(image); - var val = getHref(this); - 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); - }); - - // Wrap child SVGs in group elements - content.find('svg').each(function() { - // Skip if it's in a <defs> - if($(this).closest('defs').length) return; - - uniquifyElems(this); - - // Check if it already has a gsvg group - var pa = this.parentNode; - if(pa.childNodes.length === 1 && pa.nodeName === 'g') { - $(pa).data('gsvg', this); - pa.id = pa.id || getNextId(); - } else { - groupSvgElem(this); - } - }); - - // For Firefox: Put all paint elems in defs - if(svgedit.browser.isGecko()) { - content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); - } - - - // Set ref element for <use> elements - - // TODO: This should also be done if the object is re-added through "redo" - setUseData(content); - - convertGradients(content[0]); - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - var attrs = { - id: 'svgcontent', - overflow: curConfig.show_outside_canvas?'visible':'hidden' - }; - - var percs = false; - - // determine proper size - if (content.attr("viewBox")) { - var vb = content.attr("viewBox").split(' '); - attrs.width = vb[2]; - attrs.height = vb[3]; - } - // handle content that doesn't have a viewBox - else { - $.each(['width', 'height'], function(i, dim) { - // Set to 100 if not given - var val = content.attr(dim); - - if(!val) val = '100%'; - - if((val+'').substr(-1) === "%") { - // Use user units if percentage given - percs = true; - } else { - attrs[dim] = convertToNum(dim, val); - } - }); - } - - // identify layers - identifyLayers(); - - // Give ID for any visible layer children missing one - content.children().find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - // Percentage width/height, so let's base it on visible elements - if(percs) { - var bb = getStrokedBBox(); - attrs.width = bb.width + bb.x; - attrs.height = bb.height + bb.y; - } - - // Just in case negative numbers are given or - // result from the percs calculation - if(attrs.width <= 0) attrs.width = 100; - if(attrs.height <= 0) attrs.height = 100; - - content.attr(attrs); - this.contentW = attrs['width']; - this.contentH = attrs['height']; - - batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); - // update root to the correct size - var changes = content.attr(["width", "height"]); - batchCmd.addSubCommand(new ChangeElementCommand(svgroot, changes)); - - // reset zoom - current_zoom = 1; - - // reset transform lists - svgedit.transformlist.resetListMap(); - clearSelection(); - svgedit.path.clearData(); - svgroot.appendChild(selectorManager.selectorParentGroup); - - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// Function: importSvgString -// This function imports the input SVG XML as a <symbol> in the <defs>, then adds a -// <use> to the current layer. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the import was unsuccessful, true otherwise. -// TODO: -// * properly handle if namespace is introduced by imported content (must add to svgcontent -// and update all prefixes in the imported node) -// * properly handle recalculating dimensions, recalculateDimensions() doesn't handle -// arbitrary transform lists, but makes some assumptions about how the transform list -// was obtained -// * import should happen in top-left of current zoomed viewport -this.importSvgString = function(xmlString) { - - try { - // Get unique ID - var uid = svgedit.utilities.encode64(xmlString.length + xmlString).substr(0,32); - - var useExisting = false; - - // Look for symbol and make sure symbol exists in image - if(import_ids[uid]) { - if( $(import_ids[uid].symbol).parents('#svgroot').length ) { - useExisting = true; - } - } - - var batchCmd = new BatchCommand("Import SVG"); - - if(useExisting) { - var symbol = import_ids[uid].symbol; - var ts = import_ids[uid].xform; - } else { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - // import new svg document into our document - var svg; - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svg = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svg = svgdoc.importNode(newDoc.documentElement, true); - } - - uniquifyElems(svg); - - 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) - vb[j] = +(vb[j]); - - // TODO: properly handle preserveAspectRatio - var canvasw = +svgcontent.getAttribute("width"), - canvash = +svgcontent.getAttribute("height"); - // imported content should be 1/3 of the canvas on its largest dimension - - if (innerh > innerw) { - var ts = "scale(" + (canvash/3)/vb[3] + ")"; - } - else { - var ts = "scale(" + (canvash/3)/vb[2] + ")"; - } - - // Hack to make recalculateDimensions understand how to scale - ts = "translate(0) " + ts + " translate(0)"; - - var symbol = svgdoc.createElementNS(svgns, "symbol"); - var defs = findDefs(); - - if(svgedit.browser.isGecko()) { - // Move all gradients into root for Firefox, workaround for this bug: - // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 - // TODO: Make this properly undo-able. - $(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); - } - - while (svg.firstChild) { - var first = svg.firstChild; - symbol.appendChild(first); - } - var attrs = svg.attributes; - for(var i=0; i < attrs.length; i++) { - var attr = attrs[i]; - symbol.setAttribute(attr.nodeName, attr.nodeValue); - } - symbol.id = getNextId(); - - // Store data - import_ids[uid] = { - symbol: symbol, - xform: ts - } - - findDefs().appendChild(symbol); - batchCmd.addSubCommand(new InsertElementCommand(symbol)); - } - - - var use_el = svgdoc.createElementNS(svgns, "use"); - use_el.id = getNextId(); - setHref(use_el, "#" + symbol.id); - - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(use_el); - batchCmd.addSubCommand(new InsertElementCommand(use_el)); - clearSelection(); - - use_el.setAttribute("transform", ts); - recalculateDimensions(use_el); - $(use_el).data('symbol', symbol).data('ref', symbol); - addToSelection([use_el]); - - // 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; - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// TODO(codedread): Move all layer/context functions in draw.js -// Layer API Functions - -// Group: Layers - -// Function: identifyLayers -// Updates layer system -var identifyLayers = canvas.identifyLayers = function() { - leaveContext(); - getCurrentDrawing().identifyLayers(); -}; - -// Function: createLayer -// Creates a new top-level layer in the drawing with the given name, sets the current layer -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.createLayer = function(name) { - var batchCmd = new BatchCommand("Create Layer"); - var new_layer = getCurrentDrawing().createLayer(name); - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [new_layer]); -}; - -// Function: cloneLayer -// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.cloneLayer = function(name) { - var batchCmd = new BatchCommand("Duplicate Layer"); - var new_layer = svgdoc.createElementNS(svgns, "g"); - var layer_title = svgdoc.createElementNS(svgns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - var current_layer = getCurrentDrawing().getCurrentLayer(); - $(current_layer).after(new_layer); - var childs = current_layer.childNodes; - for(var i = 0; i < childs.length; i++) { - var ch = childs[i]; - if(ch.localName == 'title') continue; - new_layer.appendChild(copyElem(ch)); - } - - clearSelection(); - identifyLayers(); - - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - canvas.setCurrentLayer(name); - call("changed", [new_layer]); -}; - -// Function: deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -this.deleteCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - var nextSibling = current_layer.nextSibling; - var parent = current_layer.parentNode; - current_layer = getCurrentDrawing().deleteCurrentLayer(); - if (current_layer) { - var batchCmd = new BatchCommand("Delete Layer"); - // store in our Undo History - batchCmd.addSubCommand(new RemoveElementCommand(current_layer, nextSibling, parent)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [parent]); - return true; - } - return false; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -this.setCurrentLayer = function(name) { - var result = getCurrentDrawing().setCurrentLayer(svgedit.utilities.toXml(name)); - if (result) { - clearSelection(); - } - return result; -}; - -// Function: renameCurrentLayer -// Renames the current layer. If the layer name is not valid (i.e. unique), then this function -// does nothing and returns false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// newname - the new name you want to give the current layer. This name must be unique -// among all layer names. -// -// Returns: -// true if the rename succeeded, false otherwise. -this.renameCurrentLayer = function(newname) { - 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 batchCmd = new BatchCommand("Rename Layer"); - // find the index of the layer - for (var 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 (var 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 ChangeElementCommand(child, {"#text":oldname})); - addCommandToHistory(batchCmd); - call("changed", [oldLayer]); - return true; - } - } - } - drawing.current_layer = oldLayer; - } - return false; -}; - -// Function: setCurrentLayerPosition -// Changes the position of the current layer to the new value. If the new index is not valid, -// this function does nothing and returns false, otherwise it returns true. This is an -// undo-able action. -// -// Parameters: -// newpos - The zero-based index of the new position of the layer. This should be between -// 0 and (number of layers - 1) -// -// Returns: -// true if the current layer position was changed, false otherwise. -this.setCurrentLayerPosition = function(newpos) { - var drawing = getCurrentDrawing(); - if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) { - for (var 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 MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent)); - - identifyLayers(); - canvas.setCurrentLayer(drawing.getLayerName(newpos)); - - return true; - } - } - - return false; -}; - -// Function: setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// true if the layer's visibility was set, false otherwise -this.setLayerVisibility = function(layername, bVisible) { - var drawing = getCurrentDrawing(); - var prevVisibility = drawing.getLayerVisibility(layername); - var layer = drawing.setLayerVisibility(layername, bVisible); - if (layer) { - var oldDisplay = prevVisibility ? 'inline' : 'none'; - addCommandToHistory(new ChangeElementCommand(layer, {'display':oldDisplay}, 'Layer Visibility')); - } else { - return false; - } - - if (layer == drawing.getCurrentLayer()) { - clearSelection(); - pathActions.clear(); - } -// call("changed", [selected]); - return true; -}; - -// Function: moveSelectedToLayer -// Moves the selected elements to layername. If the name is not a valid layer name, then false -// is returned. Otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer you want to which you want to move the selected elements -// -// Returns: -// true if the selected elements were moved to the layer, false otherwise. -this.moveSelectedToLayer = function(layername) { - // find the layer - var layer = null; - var drawing = getCurrentDrawing(); - for (var i = 0; i < drawing.getNumLayers(); ++i) { - if (drawing.getLayerName(i) == layername) { - layer = drawing.all_layers[i][1]; - break; - } - } - if (!layer) return false; - - var batchCmd = new BatchCommand("Move Elements to Layer"); - - // loop for each selected element and move it - var selElems = selectedElements; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (!elem) continue; - var oldNextSibling = elem.nextSibling; - // TODO: this is pretty brittle! - var oldLayer = elem.parentNode; - layer.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); - } - - addCommandToHistory(batchCmd); - - return true; -}; - -this.mergeLayer = function(skipHistory) { - var batchCmd = new 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 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 RemoveElementCommand(ch, chNextSibling, drawing.current_layer)); - drawing.current_layer.removeChild(ch); - continue; - } - var oldNextSibling = ch.nextSibling; - prev.appendChild(ch); - batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, drawing.current_layer)); - } - - // Remove current layer - svgcontent.removeChild(drawing.current_layer); - - if(!skipHistory) { - clearSelection(); - identifyLayers(); - - call("changed", [svgcontent]); - - addCommandToHistory(batchCmd); - } - - drawing.current_layer = prev; - return batchCmd; -} - -this.mergeAllLayers = function() { - var batchCmd = new 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)); - } - - clearSelection(); - identifyLayers(); - call("changed", [svgcontent]); - addCommandToHistory(batchCmd); -} - -// Function: leaveContext -// Return from a group context to the regular kind, make any previously -// disabled elements enabled again -var leaveContext = this.leaveContext = function() { - var len = disabled_elems.length; - if(len) { - for(var i = 0; i < len; i++) { - var elem = disabled_elems[i]; - - var orig = elData(elem, 'orig_opac'); - if(orig !== 1) { - elem.setAttribute('opacity', orig); - } else { - elem.removeAttribute('opacity'); - } - elem.setAttribute('style', 'pointer-events: inherit'); - } - disabled_elems = []; - clearSelection(true); - call("contextset", null); - } - current_group = null; -} - -// Function: setContext -// Set the current context (for in-group editing) -var setContext = this.setContext = function(elem) { - leaveContext(); - if(typeof elem === 'string') { - elem = getElem(elem); - } - - // Edit inside this group - current_group = elem; - - // Disable other elements - $(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function() { - var opac = this.getAttribute('opacity') || 1; - // Store the original's opacity - elData(this, 'orig_opac', opac); - this.setAttribute('opacity', opac * .33); - this.setAttribute('style', 'pointer-events: none'); - disabled_elems.push(this); - }); - - clearSelection(); - call("contextset", current_group); -} - -// Group: Document functions - -// Function: clear -// Clears the current document. This is not an undoable action. -this.clear = function() { - pathActions.clear(); - - clearSelection(); - - // clear the svgcontent node - canvas.clearSvgContentElement(); - - // create new document - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent); - - // create empty first layer - canvas.createLayer("Layer 1"); - - // clear the undo stack - canvas.undoMgr.resetUndoStack(); - - // reset the selector manager - selectorManager.initGroup(); - - // reset the rubber band box - rubberBox = selectorManager.getRubberBandBox(); - - call("cleared"); -}; - -// Function: linkControlPoints -// Alias function -this.linkControlPoints = pathActions.linkControlPoints; - -// Function: getContentElem -// Returns the content DOM element -this.getContentElem = function() { return svgcontent; }; - -// Function: getRootElem -// Returns the root DOM element -this.getRootElem = function() { return svgroot; }; - -// Function: getSelectedElems -// Returns the array with selected DOM elements -this.getSelectedElems = function() { return selectedElements; }; - -// Function: getResolution -// Returns the current dimensions and zoom level in an object -var getResolution = this.getResolution = function() { -// var vb = svgcontent.getAttribute("viewBox").split(' '); -// return {'w':vb[2], 'h':vb[3], 'zoom': current_zoom}; - - var width = svgcontent.getAttribute("width")/current_zoom; - var height = svgcontent.getAttribute("height")/current_zoom; - - return { - 'w': width, - 'h': height, - 'zoom': current_zoom - }; -}; - -// Function: getZoom -// Returns the current zoom level -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: 2082 $)"; -}; - -// Function: setUiStrings -// Update interface strings with given values -// -// Parameters: -// strs - Object with strings (see uiStrings for examples) -this.setUiStrings = function(strs) { - $.extend(uiStrings, strs.notification); -} - -// Function: setConfig -// Update configuration options with given values -// -// Parameters: -// opts - Object with options (see curConfig for examples) -this.setConfig = function(opts) { - $.extend(curConfig, opts); -} - -// Function: getTitle -// 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<childs.length; i++) { - if(childs[i].nodeName == 'title') { - return childs[i].textContent; - } - } - return ''; -} - -// Function: setGroupTitle -// Sets the group/SVG's title content -// TODO: Combine this with setDocumentTitle -this.setGroupTitle = function(val) { - var elem = selectedElements[0]; - elem = $(elem).data('gsvg') || elem; - - var ts = $(elem).children('title'); - - var batchCmd = new BatchCommand("Set Label"); - - if(!val.length) { - // Remove title element - var tsNextSibling = ts.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)); - ts.remove(); - } else if(ts.length) { - // Change title contents - var title = ts[0]; - batchCmd.addSubCommand(new ChangeElementCommand(title, {'#text': title.textContent})); - title.textContent = val; - } else { - // Add title element - title = svgdoc.createElementNS(svgns, "title"); - title.textContent = val; - $(elem).prepend(title); - batchCmd.addSubCommand(new InsertElementCommand(title)); - } - - addCommandToHistory(batchCmd); -} - -// Function: getDocumentTitle -// Returns the current document title or an empty string if not found -this.getDocumentTitle = function() { - return canvas.getTitle(svgcontent); -} - -// Function: setDocumentTitle -// Adds/updates a title element for the document with the given name. -// This is an undoable action -// -// Parameters: -// newtitle - String with the new title -this.setDocumentTitle = function(newtitle) { - var childs = svgcontent.childNodes, doc_title = false, old_title = ''; - - var batchCmd = new BatchCommand("Change Image Title"); - - for (var i=0; i<childs.length; i++) { - if(childs[i].nodeName == 'title') { - doc_title = childs[i]; - old_title = doc_title.textContent; - break; - } - } - if(!doc_title) { - doc_title = svgdoc.createElementNS(svgns, "title"); - svgcontent.insertBefore(doc_title, svgcontent.firstChild); - } - - if(newtitle.length) { - doc_title.textContent = newtitle; - } else { - // No title given, so element is not necessary - doc_title.parentNode.removeChild(doc_title); - } - batchCmd.addSubCommand(new ChangeElementCommand(doc_title, {'#text': old_title})); - addCommandToHistory(batchCmd); -} - -// Function: getEditorNS -// Returns the editor's namespace URL, optionally adds it to root element -// -// Parameters: -// add - Boolean to indicate whether or not to add the namespace value -this.getEditorNS = function(add) { - if(add) { - svgcontent.setAttribute('xmlns:se', se_ns); - } - return se_ns; -} - -// Function: setResolution -// Changes the document's dimensions to the given size -// -// Parameters: -// x - Number with the width of the new dimensions in user units. -// Can also be the string "fit" to indicate "fit to content" -// y - Number with the height of the new dimensions in user units. -// -// Returns: -// Boolean to indicate if resolution change was succesful. -// It will fail on "fit to content" option with no content to fit to. -this.setResolution = function(x, y) { - var res = getResolution(); - var w = res.w, h = res.h; - var batchCmd; - - if(x == 'fit') { - // Get bounding box - var bbox = getStrokedBBox(); - - if(bbox) { - batchCmd = new BatchCommand("Fit Canvas to Content"); - var visEls = getVisibleElements(); - addToSelection(visEls); - var dx = [], dy = []; - $.each(visEls, function(i, item) { - dx.push(bbox.x*-1); - dy.push(bbox.y*-1); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - clearSelection(); - - x = Math.round(bbox.width); - y = Math.round(bbox.height); - } else { - return false; - } - } - if (x != w || y != h) { - var handle = svgroot.suspendRedraw(1000); - if(!batchCmd) { - batchCmd = new BatchCommand("Change Image Dimensions"); - } - - x = convertToNum('width', x); - y = convertToNum('height', y); - - svgcontent.setAttribute('width', x); - svgcontent.setAttribute('height', y); - - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"width":w, "height":h})); - - svgcontent.setAttribute("viewBox", [0, 0, x/current_zoom, y/current_zoom].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"viewBox": ["0 0", w, h].join(' ')})); - - addCommandToHistory(batchCmd); - svgroot.unsuspendRedraw(handle); - call("changed", [svgcontent]); - } - return true; -}; - -// Function: getOffset -// Returns an object with x, y values indicating the svgcontent element's -// position in the editor's canvas. -this.getOffset = function() { - return $(svgcontent).attr(['x', 'y']); -} - -// Function: setBBoxZoom -// Sets the zoom level on the canvas-side based on the given value -// -// Parameters: -// val - Bounding box object to zoom to or string indicating zoom option -// editor_w - Integer with the editor's workarea box's width -// editor_h - Integer with the editor's workarea box's height -this.setBBoxZoom = function(val, editor_w, editor_h) { - var spacer = .85; - var bb; - var calcZoom = function(bb) { - if(!bb) return false; - var w_zoom = Math.round((editor_w / bb.width)*100 * spacer)/100; - var h_zoom = Math.round((editor_h / bb.height)*100 * spacer)/100; - var zoomlevel = Math.min(w_zoom,h_zoom); - canvas.setZoom(zoomlevel); - return {'zoom': zoomlevel, 'bbox': bb}; - } - - if(typeof val == 'object') { - bb = val; - if(bb.width == 0 || bb.height == 0) { - var newzoom = bb.zoom?bb.zoom:current_zoom * bb.factor; - canvas.setZoom(newzoom); - return {'zoom': current_zoom, 'bbox': bb}; - } - return calcZoom(bb); - } - - switch (val) { - case 'selection': - if(!selectedElements[0]) return; - var sel_elems = $.map(selectedElements, function(n){ if(n) return n; }); - bb = getStrokedBBox(sel_elems); - break; - case 'canvas': - var res = getResolution(); - spacer = .95; - bb = {width:res.w, height:res.h ,x:0, y:0}; - break; - case 'content': - bb = getStrokedBBox(); - break; - case 'layer': - bb = getStrokedBBox(getVisibleElements(getCurrentDrawing().getCurrentLayer())); - break; - default: - return; - } - return calcZoom(bb); -} - -// Function: setZoom -// Sets the zoom to the given level -// -// Parameters: -// zoomlevel - Float indicating the zoom level to change to -this.setZoom = function(zoomlevel) { - var res = getResolution(); - svgcontent.setAttribute("viewBox", "0 0 " + res.w/zoomlevel + " " + res.h/zoomlevel); - current_zoom = zoomlevel; - $.each(selectedElements, function(i, elem) { - if(!elem) return; - selectorManager.requestSelector(elem).resize(); - }); - pathActions.zoomChange(); - runExtensions("zoomChanged", zoomlevel); -} - -// Function: getMode -// Returns the current editor mode string -this.getMode = function() { - return current_mode; -}; - -// Function: setMode -// Sets the editor's mode to the given string -// -// Parameters: -// name - String with the new mode to change to -this.setMode = function(name) { - pathActions.clear(true); - textActions.clear(); - $("#workarea").attr("class", name); - cur_properties = (selectedElements[0] && selectedElements[0].nodeName == 'text') ? cur_text : cur_shape; - current_mode = name; -}; - -// Group: Element Styling - -// Function: getColor -// Returns the current fill/stroke option -this.getColor = function(type) { - return cur_properties[type]; -}; - -// Function: setColor -// Change the current stroke/fill color/gradient value -// -// Parameters: -// type - String indicating fill or stroke -// val - The value to set the stroke attribute to -// preventUndo - Boolean indicating whether or not this should be and undoable option -this.setColor = function(type, val, preventUndo) { - cur_shape[type] = val; - cur_properties[type + '_paint'] = {type:"solidColor"}; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else { - if(type == 'fill') { - if(elem.tagName != "polyline" && elem.tagName != "line") { - elems.push(elem); - } - } else { - elems.push(elem); - } - } - } - } - if (elems.length > 0) { - if (!preventUndo) { - changeSelectedAttribute(type, val, elems); - call("changed", elems); - } else - changeSelectedAttributeNoUndo(type, val, elems); - } -} - - -// Function: findDefs -// Return the document's <defs> element, create it first if necessary -var findDefs = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - defs = svgdoc.createElementNS(svgns, "defs" ); - if(svgcontent.firstChild) { - // first child is a comment, so call nextSibling - svgcontent.insertBefore( defs, svgcontent.firstChild.nextSibling); - } else { - svgcontent.appendChild(defs); - } - } - return defs; -}; - -// Function: setGradient -// Apply the current gradient to selected element's fill or stroke -// -// Parameters -// type - String indicating "fill" or "stroke" to apply to an element -var setGradient = this.setGradient = function(type) { - if(!cur_properties[type + '_paint'] || cur_properties[type + '_paint'].type == "solidColor") return; - var grad = canvas[type + 'Grad']; - // find out if there is a duplicate gradient already in the defs - var duplicate_grad = findDuplicateGradient(grad); - var defs = findDefs(); - // no duplicate found, so import gradient into defs - if (!duplicate_grad) { - var orig_grad = grad; - grad = defs.appendChild( svgdoc.importNode(grad, true) ); - // get next id and set it on the grad - grad.id = getNextId(); - } - else { // use existing gradient - grad = duplicate_grad; - } - canvas.setColor(type, "url(#" + grad.id + ")"); -} - -// Function: findDuplicateGradient -// Check if exact gradient already exists -// -// Parameters: -// grad - The gradient DOM element to compare to others -// -// Returns: -// The existing gradient if found, null if not -var findDuplicateGradient = function(grad) { - var defs = findDefs(); - var existing_grads = $(defs).find("linearGradient, radialGradient"); - var i = existing_grads.length; - var rad_attrs = ['r','cx','cy','fx','fy']; - while (i--) { - var og = existing_grads[i]; - if(grad.tagName == "linearGradient") { - if (grad.getAttribute('x1') != og.getAttribute('x1') || - grad.getAttribute('y1') != og.getAttribute('y1') || - grad.getAttribute('x2') != og.getAttribute('x2') || - grad.getAttribute('y2') != og.getAttribute('y2')) - { - continue; - } - } else { - var grad_attrs = $(grad).attr(rad_attrs); - var og_attrs = $(og).attr(rad_attrs); - - var diff = false; - $.each(rad_attrs, function(i, attr) { - if(grad_attrs[attr] != og_attrs[attr]) diff = true; - }); - - if(diff) continue; - } - - // else could be a duplicate, iterate through stops - var stops = grad.getElementsByTagNameNS(svgns, "stop"); - var ostops = og.getElementsByTagNameNS(svgns, "stop"); - - if (stops.length != ostops.length) { - continue; - } - - var j = stops.length; - while(j--) { - var stop = stops[j]; - var ostop = ostops[j]; - - if (stop.getAttribute('offset') != ostop.getAttribute('offset') || - stop.getAttribute('stop-opacity') != ostop.getAttribute('stop-opacity') || - stop.getAttribute('stop-color') != ostop.getAttribute('stop-color')) - { - break; - } - } - - if (j == -1) { - return og; - } - } // for each gradient in defs - - return null; -}; - -function reorientGrads(elem, m) { - var bb = svgedit.utilities.getBBox(elem); - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = elem.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - var grad = getRefElem(attrVal); - if(grad.tagName === 'linearGradient') { - var x1 = grad.getAttribute('x1') || 0; - var y1 = grad.getAttribute('y1') || 0; - var x2 = grad.getAttribute('x2') || 1; - var y2 = grad.getAttribute('y2') || 0; - - // Convert to USOU points - x1 = (bb.width * x1) + bb.x; - y1 = (bb.height * y1) + bb.y; - x2 = (bb.width * x2) + bb.x; - y2 = (bb.height * y2) + bb.y; - - // Transform those points - var pt1 = transformPoint(x1, y1, m); - var pt2 = transformPoint(x2, y2, m); - - // Convert back to BB points - var g_coords = {}; - - g_coords.x1 = (pt1.x - bb.x) / bb.width; - g_coords.y1 = (pt1.y - bb.y) / bb.height; - g_coords.x2 = (pt2.x - bb.x) / bb.width; - g_coords.y2 = (pt2.y - bb.y) / bb.height; - - var newgrad = grad.cloneNode(true); - $(newgrad).attr(g_coords); - - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - elem.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - } - } -} - -// Function: setPaint -// Set a color/gradient to a fill/stroke -// -// Parameters: -// type - String with "fill" or "stroke" -// paint - The jGraduate paint object to apply -this.setPaint = function(type, paint) { - // make a copy - var p = new $.jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha/100, true); - - // now set the current paint object - cur_properties[type + '_paint'] = p; - switch ( p.type ) { - case "solidColor": - - if (p.solidColor != "none") { - this.setColor(type, "#"+p.solidColor) - } - else { - this.setColor(type, "none"); - var selector = (type == "fill") ? "#fill_color rect" : "#stroke_color rect" - document.querySelector(selector).setAttribute('fill', 'transparent'); - } - break; - case "linearGradient": - case "radialGradient": - canvas[type + 'Grad'] = p[p.type]; - setGradient(type); - break; - default: -// console.log("none!"); - } -}; - - -// this.setStrokePaint = function(p) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setStrokeOpacity(p.alpha/100); -// -// // now set the current paint object -// cur_properties.stroke_paint = p; -// switch ( p.type ) { -// case "solidColor": -// this.setColor('stroke', p.solidColor != "none" ? "#"+p.solidColor : "none");; -// break; -// case "linearGradient" -// case "radialGradient" -// canvas.strokeGrad = p[p.type]; -// setGradient(type); -// default: -// // console.log("none!"); -// } -// }; -// -// this.setFillPaint = function(p, addGrad) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setFillOpacity(p.alpha/100, true); -// -// // now set the current paint object -// cur_properties.fill_paint = p; -// if (p.type == "solidColor") { -// this.setColor('fill', p.solidColor != "none" ? "#"+p.solidColor : "none"); -// } -// else if(p.type == "linearGradient") { -// canvas.fillGrad = p.linearGradient; -// if(addGrad) setGradient(); -// } -// else if(p.type == "radialGradient") { -// canvas.fillGrad = p.radialGradient; -// if(addGrad) setGradient(); -// } -// else { -// // console.log("none!"); -// } -// }; - -// Function: getStrokeWidth -// Returns the current stroke-width value -this.getStrokeWidth = function() { - return cur_properties.stroke_width; -}; - -// Function: setStrokeWidth -// Sets the stroke width for the current selected elements -// When attempting to set a line's width to 0, this changes it to 1 instead -// -// Parameters: -// val - A Float indicating the new stroke width value -this.setStrokeWidth = function(val) { - if(val == 0 && ['line', 'path'].indexOf(current_mode) >= 0) { - canvas.setStrokeWidth(1); - return; - } - cur_properties.stroke_width = val; - - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute("stroke-width", val, elems); - call("changed", selectedElements); - } -}; - -// Function: setStrokeAttr -// Set the given stroke-related attribute the given value for selected elements -// -// Parameters: -// attr - String with the attribute name -// val - String or number with the attribute value -this.setStrokeAttr = function(attr, val) { - cur_shape[attr.replace('-','_')] = val; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute(attr, val, elems); - call("changed", selectedElements); - } -}; - -// Function: getStyle -// Returns current style options -this.getStyle = function() { - return cur_shape; -} - -// Function: getOpacity -// Returns the current opacity -this.getOpacity = function() { - return cur_shape.opacity; -}; - -// Function: setOpacity -// Sets the given opacity to the current selected elements -this.setOpacity = function(val) { - cur_shape.opacity = val; - changeSelectedAttribute("opacity", val); -}; - -// Function: getOpacity -// Returns the current fill opacity -this.getFillOpacity = function() { - return cur_shape.fill_opacity; -}; - -// Function: getStrokeOpacity -// Returns the current stroke opacity -this.getStrokeOpacity = function() { - return cur_shape.stroke_opacity; -}; - -// Function: setPaintOpacity -// Sets the current fill/stroke opacity -// -// Parameters: -// type - String with "fill" or "stroke" -// val - Float with the new opacity value -// preventUndo - Boolean indicating whether or not this should be an undoable action -this.setPaintOpacity = function(type, val, preventUndo) { - cur_shape[type + '_opacity'] = val; - if (!preventUndo) - changeSelectedAttribute(type + "-opacity", val); - else - changeSelectedAttributeNoUndo(type + "-opacity", val); -}; - -// Function: getBlur -// Gets the stdDeviation blur value of the given element -// -// Parameters: -// elem - The element to check the blur value for -this.getBlur = function(elem) { - var val = 0; -// var elem = selectedElements[0]; - - if(elem) { - var filter_url = elem.getAttribute('filter'); - if(filter_url) { - var blur = getElem(elem.id + '_blur'); - if(blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } - } - } - return val; -}; - -(function() { - var cur_command = null; - var filter = null; - var filterHidden = false; - - // Function: setBlurNoUndo - // Sets the stdDeviation blur value on the selected element without being undoable - // - // Parameters: - // val - The new stdDeviation value - canvas.setBlurNoUndo = function(val) { - if(!filter) { - canvas.setBlur(val); - return; - } - if(val === 0) { - // Don't change the StdDev, as that will hide the element. - // Instead, just remove the value for "filter" - changeSelectedAttributeNoUndo("filter", ""); - filterHidden = true; - } else { - var elem = selectedElements[0]; - if(filterHidden) { - changeSelectedAttributeNoUndo("filter", 'url(#' + elem.id + '_blur)'); - } - if(svgedit.browser.isWebkit()) { - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); - } - changeSelectedAttributeNoUndo("stdDeviation", val, [filter.firstChild]); - canvas.setBlurOffsets(filter, val); - } - } - - function finishChange() { - var bCmd = canvas.undoMgr.finishUndoableChange(); - cur_command.addSubCommand(bCmd); - addCommandToHistory(cur_command); - cur_command = null; - filter = null; - } - - // Function: setBlurOffsets - // Sets the x, y, with, height values of the filter element in order to - // make the blur not be clipped. Removes them if not neeeded - // - // Parameters: - // filter - The filter DOM element to update - // stdDev - The standard deviation value on which to base the offset size - canvas.setBlurOffsets = function(filter, stdDev) { - if(stdDev > 3) { - // TODO: Create algorithm here where size is based on expected blur - assignAttributes(filter, { - x: '-50%', - y: '-50%', - width: '200%', - height: '200%' - }, 100); - } else { - // Removing these attributes hides text in Chrome (see Issue 579) - if(!svgedit.browser.isWebkit()) { - filter.removeAttribute('x'); - filter.removeAttribute('y'); - filter.removeAttribute('width'); - filter.removeAttribute('height'); - } - } - } - - // Function: setBlur - // Adds/updates the blur filter to the selected element - // - // Parameters: - // val - Float with the new stdDeviation blur value - // complete - Boolean indicating whether or not the action should be completed (to add to the undo manager) - canvas.setBlur = function(val, complete) { - if(cur_command) { - finishChange(); - return; - } - - // Looks for associated blur, creates one if not found - var elem = selectedElements[0]; - var elem_id = elem.id; - filter = getElem(elem_id + '_blur'); - - val -= 0; - - var batchCmd = new BatchCommand(); - - // Blur found! - if(filter) { - if(val === 0) { - filter = null; - } - } else { - // Not found, so create - var newblur = addSvgElementFromJson({ "element": "feGaussianBlur", - "attr": { - "in": 'SourceGraphic', - "stdDeviation": val - } - }); - - filter = addSvgElementFromJson({ "element": "filter", - "attr": { - "id": elem_id + '_blur' - } - }); - - filter.appendChild(newblur); - findDefs().appendChild(filter); - - batchCmd.addSubCommand(new InsertElementCommand(filter)); - } - - var changes = {filter: elem.getAttribute('filter')}; - - if(val === 0) { - elem.removeAttribute("filter"); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - return; - } else { - changeSelectedAttribute("filter", 'url(#' + elem_id + '_blur)'); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - - canvas.setBlurOffsets(filter, val); - } - - cur_command = batchCmd; - canvas.undoMgr.beginUndoableChange("stdDeviation", [filter?filter.firstChild:null]); - if(complete) { - canvas.setBlurNoUndo(val); - finishChange(); - } - }; -}()); - -// Function: getBold -// Check whether selected element is bold or not -// -// Returns: -// Boolean indicating whether or not element is bold -this.getBold = function() { - // should only have one element selected - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-weight") == "bold"); - } - return false; -}; - -// Function: setBold -// Make the selected element bold or normal -// -// Parameters: -// b - Boolean indicating bold (true) or normal (false) -this.setBold = function(b) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-weight", b ? "bold" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getItalic -// Check whether selected element is italic or not -// -// Returns: -// Boolean indicating whether or not element is italic -this.getItalic = function() { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-style") == "italic"); - } - return false; -}; - -// Function: setItalic -// Make the selected element italic or normal -// -// Parameters: -// b - Boolean indicating italic (true) or normal (false) -this.setItalic = function(i) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-style", i ? "italic" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getFontFamily -// Returns the current font family -this.getFontFamily = function() { - return cur_text.font_family; -}; - -// Function: setFontFamily -// Set the new font family -// -// Parameters: -// val - String with the new font family -this.setFontFamily = function(val) { - cur_text.font_family = val; - changeSelectedAttribute("font-family", val); - if(selectedElements[0] && !selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - - -// Function: setFontColor -// Set the new font color -// -// Parameters: -// val - String with the new font color -this.setFontColor = function(val) { - cur_text.fill = val; - changeSelectedAttribute("fill", val); -}; - -// Function: getFontColor -// Returns the current font color -this.getFontSize = function() { - return cur_text.fill; -}; - -// Function: getFontSize -// Returns the current font size -this.getFontSize = function() { - return cur_text.font_size; -}; - -// Function: setFontSize -// Applies the given font size to the selected element -// -// Parameters: -// val - Float with the new font size -this.setFontSize = function(val) { - cur_text.font_size = val; - changeSelectedAttribute("font-size", val); - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getText -// Returns the current text (textContent) of the selected element -this.getText = function() { - var selected = selectedElements[0]; - if (selected == null) { return ""; } - return selected.textContent; -}; - -// Function: setTextContent -// Updates the text element with the given string -// -// Parameters: -// val - String with the new text -this.setTextContent = function(val) { - changeSelectedAttribute("#text", val); - textActions.init(val); - textActions.setCursor(); -}; - -// Function: setImageURL -// Sets the new image URL for the selected image element. Updates its size if -// a new URL is given -// -// Parameters: -// val - String with the image URL/path -this.setImageURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - - var attrs = $(elem).attr(['width', 'height']); - var setsize = (!attrs.width || !attrs.height); - - var cur_href = getHref(elem); - - // Do nothing if no URL change or size change - if(cur_href !== val) { - setsize = true; - } else if(!setsize) return; - - var batchCmd = new BatchCommand("Change Image URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - if(setsize) { - $(new Image()).load(function() { - var changes = $(elem).attr(['width', 'height']); - - $(elem).attr({ - width: this.width, - height: this.height - }); - - selectorManager.requestSelector(elem).resize(); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - addCommandToHistory(batchCmd); - call("changed", [elem]); - }).attr('src',val); - } else { - addCommandToHistory(batchCmd); - } -}; - -// Function: setLinkURL -// Sets the new link URL for the selected anchor element. -// -// Parameters: -// val - String with the link URL/path -this.setLinkURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - if(elem.tagName !== 'a') { - // See if parent is an anchor - var parents_a = $(elem).parents('a'); - if(parents_a.length) { - elem = parents_a[0]; - } else { - return; - } - } - - var cur_href = getHref(elem); - - if(cur_href === val) return; - - var batchCmd = new BatchCommand("Change Link URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - addCommandToHistory(batchCmd); -}; - - -// Function: setRectRadius -// Sets the rx & ry values to the selected rect element to change its corner radius -// -// Parameters: -// val - The new radius -this.setRectRadius = function(val) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "rect") { - var r = selected.getAttribute("rx"); - if (r != val) { - selected.setAttribute("rx", val); - selected.setAttribute("ry", val); - addCommandToHistory(new ChangeElementCommand(selected, {"rx":r, "ry":r}, "Radius")); - call("changed", [selected]); - } - } -}; - -// Function: makeHyperlink -// Wraps the selected element(s) in an anchor element or converts group to one -this.makeHyperlink = function(url) { - canvas.groupSelectedElements('a', url); - - // TODO: If element is a single "g", convert to "a" - // if(selectedElements.length > 1 && selectedElements[1]) { - -} - -// Function: removeHyperlink -this.removeHyperlink = function() { - canvas.ungroupSelectedElement(); -} - -// Group: Element manipulation - -// Function: setSegType -// Sets the new segment type to the selected segment(s). -// -// Parameters: -// new_type - Integer with the new segment type -// See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list -this.setSegType = function(new_type) { - pathActions.setSegType(new_type); -} - -// TODO(codedread): Remove the getBBox argument and split this function into two. -// Function: convertToPath -// Convert selected element to a path, or get the BBox of an element-as-path -// -// Parameters: -// elem - The DOM element to be converted -// getBBox - Boolean on whether or not to only return the path's BBox -// -// Returns: -// If the getBBox flag is true, the resulting path's bounding box object. -// Otherwise the resulting path element is returned. -this.convertToPath = function(elem, getBBox) { - if(elem == null) { - var elems = selectedElements; - $.each(selectedElements, function(i, elem) { - if(elem) canvas.convertToPath(elem); - }); - return; - } - - if(!getBBox) { - var batchCmd = new BatchCommand("Convert element to Path"); - } - - var attrs = getBBox?{}:{ - "fill": cur_shape.fill, - "fill-opacity": cur_shape.fill_opacity, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "opacity": cur_shape.opacity, - "visibility":"hidden" - }; - - // any attribute on the element not covered by the above - // TODO: make this list global so that we can properly maintain it - // TODO: what about @transform, @clip-rule, @fill-rule, etc? - $.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function() { - if (elem.getAttribute(this)) { - attrs[this] = elem.getAttribute(this); - } - }); - - var path = addSvgElementFromJson({ - "element": "path", - "attr": attrs - }); - - var eltrans = elem.getAttribute("transform"); - if(eltrans) { - path.setAttribute("transform",eltrans); - } - - var id = elem.id; - var parent = elem.parentNode; - if(elem.nextSibling) { - parent.insertBefore(path, elem); - } else { - parent.appendChild(path); - } - - var d = ''; - - var joinSegs = function(segs) { - $.each(segs, function(j, seg) { - var l = seg[0], pts = seg[1]; - d += l; - for(var i=0; i < pts.length; i+=2) { - d += (pts[i] +','+pts[i+1]) + ' '; - } - }); - } - - // Possibly the cubed root of 6, but 1.81 works best - var num = 1.81; - - switch (elem.tagName) { - case 'ellipse': - case 'circle': - var a = $(elem).attr(['rx', 'ry', 'cx', 'cy']); - var cx = a.cx, cy = a.cy, rx = a.rx, ry = a.ry; - if(elem.tagName == 'circle') { - rx = ry = $(elem).attr('r'); - } - - joinSegs([ - ['M',[(cx-rx),(cy)]], - ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]], - ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]], - ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]], - ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]], - ['Z',[]] - ]); - break; - case 'path': - d = elem.getAttribute('d'); - break; - case 'line': - var a = $(elem).attr(["x1", "y1", "x2", "y2"]); - d = "M"+a.x1+","+a.y1+"L"+a.x2+","+a.y2; - break; - case 'polyline': - case 'polygon': - d = "M" + elem.getAttribute('points'); - break; - case 'rect': - var r = $(elem).attr(['rx', 'ry']); - var rx = r.rx, ry = r.ry; - var b = elem.getBBox(); - var x = b.x, y = b.y, w = b.width, h = b.height; - var num = 4-num; // Why? Because! - - if(!rx && !ry) { - // Regular rect - joinSegs([ - ['M',[x, y]], - ['L',[x+w, y]], - ['L',[x+w, y+h]], - ['L',[x, y+h]], - ['L',[x, y]], - ['Z',[]] - ]); - } else { - joinSegs([ - ['M',[x, y+ry]], - ['C',[x,y+ry/num, x+rx/num,y, x+rx,y]], - ['L',[x+w-rx, y]], - ['C',[x+w-rx/num,y, x+w,y+ry/num, x+w,y+ry]], - ['L',[x+w, y+h-ry]], - ['C',[x+w, y+h-ry/num, x+w-rx/num,y+h, x+w-rx,y+h]], - ['L',[x+rx, y+h]], - ['C',[x+rx/num, y+h, x,y+h-ry/num, x,y+h-ry]], - ['L',[x, y+ry]], - ['Z',[]] - ]); - } - break; - default: - path.parentNode.removeChild(path); - break; - } - - if(d) { - path.setAttribute('d',d); - } - - if(!getBBox) { - // Replace the current element with the converted one - - // Reorient if it has a matrix - if(eltrans) { - var tlist = getTransformList(path); - if(hasMatrixTransform(tlist)) { - pathActions.resetOrientation(path); - } - } - - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - batchCmd.addSubCommand(new InsertElementCommand(path)); - - clearSelection(); - elem.parentNode.removeChild(elem) - path.setAttribute('id', id); - path.removeAttribute("visibility"); - addToSelection([path], true); - - addCommandToHistory(batchCmd); - - } else { - // Get the correct BBox of the new path, then discard it - pathActions.resetOrientation(path); - var bb = false; - try { - bb = path.getBBox(); - } catch(e) { - // Firefox fails - } - path.parentNode.removeChild(path); - return bb; - } -}; - - -// Function: changeSelectedAttributeNoUndo -// This function makes the changes to the elements. It does not add the change -// to the history stack. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttributeNoUndo = function(attr, newValue, elems) { - var handle = svgroot.suspendRedraw(1000); - if(current_mode == 'pathedit') { - // Editing node - pathActions.moveNode(attr, newValue); - } - var elems = elems || selectedElements; - var i = elems.length; - var no_xy_elems = ['g', 'polyline', 'path']; - var good_g_attrs = ['transform', 'opacity', 'filter']; - - while (i--) { - var elem = elems[i]; - if (elem == null) continue; - - // Go into "select" mode for text changes - if(current_mode === "textedit" && attr !== "#text" && elem.textContent.length) { - textActions.toSelectMode(elem); - } - - // Set x,y vals on elements that don't have them - if((attr === 'x' || attr === 'y') && no_xy_elems.indexOf(elem.tagName) >= 0) { - var bbox = getStrokedBBox([elem]); - var diff_x = attr === 'x' ? newValue - bbox.x : 0; - var diff_y = attr === 'y' ? newValue - bbox.y : 0; - canvas.moveSelectedElements(diff_x*current_zoom, diff_y*current_zoom, true); - continue; - } - - // only allow the transform/opacity/filter attribute to change on <g> elements, slightly hacky - // if (elem.tagName === "g" && good_g_attrs.indexOf(attr) >= 0); - var oldval = attr === "#text" ? elem.textContent : elem.getAttribute(attr); - if (oldval == null) oldval = ""; - if (oldval !== String(newValue)) { - if (attr == "#text") { - var old_w = svgedit.utilities.getBBox(elem).width; - elem.textContent = newValue; - - // FF bug occurs on on rotated elements - if(/rotate/.test(elem.getAttribute('transform'))) { - elem = ffClone(elem); - } - - // Hoped to solve the issue of moving text with text-anchor="start", - // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd - -// var box=getBBox(elem), left=box.x, top=box.y, width=box.width, -// height=box.height, dx = width - old_w, dy=0; -// var angle = getRotationAngle(elem, true); -// if (angle) { -// var r = Math.sqrt( dx*dx + dy*dy ); -// var theta = Math.atan2(dy,dx) - angle; -// dx = r * Math.cos(theta); -// dy = r * Math.sin(theta); -// -// elem.setAttribute('x', elem.getAttribute('x')-dx); -// elem.setAttribute('y', elem.getAttribute('y')-dy); -// } - - } else if (attr == "#href") { - setHref(elem, newValue); - } - else elem.setAttribute(attr, newValue); -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - // Use the Firefox ffClone hack for text elements with gradients or - // where other text attributes are changed. - if(svgedit.browser.isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) { - if((newValue+'').indexOf('url') === 0 || ['font-size','font-family','x','y'].indexOf(attr) >= 0 && elem.textContent) { - elem = ffClone(elem); - } - } - // Timeout needed for Opera & Firefox - // codedread: it is now possible for this function to be called with elements - // that are not in the selectedElements array, we need to only request a - // selector if the element is in that array - if (selectedElements.indexOf(elem) >= 0) { - setTimeout(function() { - // Due to element replacement, this element may no longer - // be part of the DOM - if(!elem.parentNode) return; - selectorManager.requestSelector(elem).resize(); - },0); - } - // if this element was rotated, and we changed the position of this element - // we need to update the rotational transform attribute - var angle = getRotationAngle(elem); - if (angle != 0 && attr != "transform") { - var tlist = getTransformList(elem); - var n = tlist.numberOfItems; - while (n--) { - var xform = tlist.getItem(n); - if (xform.type == 4) { - // remove old rotate - tlist.removeItem(n); - - var box = svgedit.utilities.getBBox(elem); - var center = transformPoint(box.x+box.width/2, box.y+box.height/2, transformListToTransform(tlist).matrix); - var cx = center.x, - cy = center.y; - var newrot = svgroot.createSVGTransform(); - newrot.setRotate(angle, cx, cy); - tlist.insertItemBefore(newrot, n); - break; - } - } - } - } // if oldValue != newValue - } // for each elem - svgroot.unsuspendRedraw(handle); -}; - -// Function: changeSelectedAttribute -// Change the given/selected element and add the original value to the history stack -// If you want to change all selectedElements, ignore the elems argument. -// If you want to change only a subset of selectedElements, then send the -// subset to this function in the elems argument. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttribute = this.changeSelectedAttribute = function(attr, val, elems) { - var elems = elems || selectedElements; - canvas.undoMgr.beginUndoableChange(attr, elems); - var i = elems.length; - - changeSelectedAttributeNoUndo(attr, val, elems); - - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } -}; - -// Function: deleteSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack -this.deleteSelectedElements = function() { - var batchCmd = new BatchCommand("Delete Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - // Get the parent if it's a single-child anchor - if(parent.tagName === 'a' && parent.childNodes.length === 1) { - t = parent; - parent = parent.parentNode; - } - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); -}; - -// Function: cutSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack. Remembers removed elements on the clipboard - -// TODO: Combine similar code with deleteSelectedElements -this.cutSelectedElements = function() { - var batchCmd = new BatchCommand("Cut Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); - - canvas.clipBoard = selectedCopy; -}; - -// Function: copySelectedElements -// Remembers the current selected elements on the clipboard -this.copySelectedElements = function() { - canvas.clipBoard = $.merge([], selectedElements); -}; - -this.pasteElements = function(type, x, y) { - var cb = canvas.clipBoard; - var len = cb.length; - if(!len) return; - - var pasted = []; - var batchCmd = new BatchCommand('Paste elements'); - - // Move elements to lastClickPoint - - while (len--) { - var elem = cb[len]; - if(!elem) continue; - var copy = copyElem(elem); - - // See if elem with elem ID is in the DOM already - if(!getElem(elem.id)) copy.id = elem.id; - pasted.push(copy); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(copy); - batchCmd.addSubCommand(new InsertElementCommand(copy)); - } - - selectOnly(pasted); - if(type != 'in_place') { - if(lastClickPoint == null) { - lastClickPoint.x = 0; - lastClickPoint.y = 0; - } - var ctr_x, ctr_y; - if(!type) { - ctr_x = lastClickPoint.x; - ctr_y = lastClickPoint.y; - } else if(type === 'point') { - ctr_x = x; - ctr_y = y; - } - - var bbox = getStrokedBBox(pasted); - var cx = ctr_x - (bbox.x + bbox.width/2), - cy = ctr_y - (bbox.y + bbox.height/2), - dx = [], - dy = []; - - $.each(pasted, function(i, item) { - dx.push(cx); - dy.push(cy); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, false); - batchCmd.addSubCommand(cmd); - } - - - - addCommandToHistory(batchCmd); - call("changed", pasted); -} - -// Function: groupSelectedElements -// Wraps all the selected elements in a group (g) element - -// Parameters: -// type - type of element to group into, defaults to <g> -this.groupSelectedElements = function(type) { - if(!type) type = 'g'; - var cmd_str = ''; - - switch ( type ) { - case "a": - cmd_str = "Make hyperlink"; - var url = ''; - if(arguments.length > 1) { - url = arguments[1]; - } - break; - default: - type = 'g'; - cmd_str = "Group Elements"; - break; - } - - var batchCmd = new BatchCommand(cmd_str); - - // create and insert the group element - var g = addSvgElementFromJson({ - "element": type, - "attr": { - "id": getNextId() - } - }); - if(type === 'a') { - setHref(g, url); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - - // now move all children into the group - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem == null) continue; - - if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { - elem = elem.parentNode; - } - - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - g.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - selectOnly([g], true); -}; - - -// Function: pushGroupProperties -// Pushes all appropriate parent group properties down to its children, then -// removes them from the group -var pushGroupProperties = this.pushGroupProperties = function(g, undoable) { - - var children = g.childNodes; - var len = children.length; - var xform = g.getAttribute("transform"); - - var glist = getTransformList(g); - var m = transformListToTransform(glist).matrix; - - var batchCmd = new BatchCommand("Push group properties"); - - // TODO: get all fill/stroke properties from the group that we are about to destroy - // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", - // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", - // "stroke-width" - // and then for each child, if they do not have the attribute (or the value is 'inherit') - // then set the child's attribute - - var i = 0; - var gangle = getRotationAngle(g); - - var gattrs = $(g).attr(['filter', 'opacity']); - var gfilter, gblur; - - for(var i = 0; i < len; i++) { - var elem = children[i]; - - if(elem.nodeType !== 1) continue; - - if(gattrs.opacity !== null && gattrs.opacity !== 1) { - var c_opac = elem.getAttribute('opacity') || 1; - var new_opac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100)/100; - changeSelectedAttribute('opacity', new_opac, [elem]); - } - - if(gattrs.filter) { - var cblur = this.getBlur(elem); - var orig_cblur = cblur; - if(!gblur) gblur = this.getBlur(g); - if(cblur) { - // Is this formula correct? - cblur = (gblur-0) + (cblur-0); - } else if(cblur === 0) { - cblur = gblur; - } - - // If child has no current filter, get group's filter or clone it. - if(!orig_cblur) { - // Set group's filter to use first child's ID - if(!gfilter) { - gfilter = getRefElem(gattrs.filter); - } else { - // Clone the group's filter - gfilter = copyElem(gfilter); - findDefs().appendChild(gfilter); - } - } else { - gfilter = getRefElem(elem.getAttribute('filter')); - } - - // Change this in future for different filters - var suffix = (gfilter.firstChild.tagName === 'feGaussianBlur')?'blur':'filter'; - gfilter.id = elem.id + '_' + suffix; - changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); - - // Update blur value - if(cblur) { - changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); - canvas.setBlurOffsets(gfilter, cblur); - } - } - - var chtlist = getTransformList(elem); - - // Don't process gradient transforms - if(~elem.tagName.indexOf('Gradient')) chtlist = null; - - // Hopefully not a problem to add this. Necessary for elements like <desc/> - if(!chtlist) continue; - - // Apparently <defs> can get get a transformlist, but we don't want it to have one! - if(elem.tagName === 'defs') 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 - // out any translates) - if (gangle && glist.numberOfItems == 1) { - // [Rg] [Rc] [Mc] - // we want [Tr] [Rc2] [Mc] where: - // - [Rc2] is at the child's current center but has the - // sum of the group and child's rotation angles - // - [Tr] is the equivalent translation that this child - // undergoes if the group wasn't there - - // [Tr] = [Rg] [Rc] [Rc2_inv] - - // get group's rotation matrix (Rg) - var rgm = glist.getItem(0).matrix; - - // get child's rotation matrix (Rc) - var rcm = svgroot.createSVGMatrix(); - var cangle = getRotationAngle(elem); - if (cangle) { - rcm = chtlist.getItem(0).matrix; - } - - // get child's old center of rotation - var cbox = svgedit.utilities.getBBox(elem); - var ceqm = transformListToTransform(chtlist).matrix; - var coldc = transformPoint(cbox.x+cbox.width/2, cbox.y+cbox.height/2,ceqm); - - // sum group and child's angles - var sangle = gangle + cangle; - - // get child's rotation at the old center (Rc2_inv) - var r2 = svgroot.createSVGTransform(); - r2.setRotate(sangle, coldc.x, coldc.y); - - // calculate equivalent translate - var trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); - - // set up tlist - if (cangle) { - chtlist.removeItem(0); - } - - if (sangle) { - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(r2, 0); - } else { - chtlist.appendItem(r2); - } - } - - if (trm.e || trm.f) { - var tr = svgroot.createSVGTransform(); - tr.setTranslate(trm.e, trm.f); - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(tr, 0); - } else { - chtlist.appendItem(tr); - } - } - } - else { // more complicated than just a rotate - - // transfer the group's transform down to each child and then - // call recalculateDimensions() - var oldxform = elem.getAttribute("transform"); - var changes = {}; - changes["transform"] = oldxform ? oldxform : ""; - - var newxform = svgroot.createSVGTransform(); - - // [ gm ] [ chm ] = [ chm ] [ gm' ] - // [ gm' ] = [ chm_inv ] [ gm ] [ chm ] - var chm = transformListToTransform(chtlist).matrix, - chm_inv = chm.inverse(); - var gm = matrixMultiply( chm_inv, m, chm ); - newxform.setMatrix(gm); - chtlist.appendItem(newxform); - } - var cmd = recalculateDimensions(elem); - if(cmd) batchCmd.addSubCommand(cmd); - } - } - - - // remove transform and make it undo-able - if (xform) { - var changes = {}; - changes["transform"] = xform; - g.setAttribute("transform", ""); - g.removeAttribute("transform"); - batchCmd.addSubCommand(new ChangeElementCommand(g, changes)); - } - - if (undoable && !batchCmd.isEmpty()) { - return batchCmd; - } -} - - -// Function: ungroupSelectedElement -// Unwraps all the elements in a selected group (g) element. This requires -// significant recalculations to apply group's transforms, etc to its children -this.ungroupSelectedElement = function() { - var g = selectedElements[0]; - if($(g).data('gsvg') || $(g).data('symbol')) { - // Is svg, so actually convert to group - - convertToGroup(g); - return; - } else if(g.tagName === 'use') { - // Somehow doesn't have data set, so retrieve - var symbol = getElem(getHref(g).substr(1)); - $(g).data('symbol', symbol).data('ref', symbol); - convertToGroup(g); - return; - } - var parents_a = $(g).parents('a'); - if(parents_a.length) { - g = parents_a[0]; - } - - // Look for parent "a" - if (g.tagName === "g" || g.tagName === "a") { - - var batchCmd = new BatchCommand("Ungroup Elements"); - var cmd = pushGroupProperties(g, true); - if(cmd) batchCmd.addSubCommand(cmd); - - var parent = g.parentNode; - var anchor = g.nextSibling; - var children = new Array(g.childNodes.length); - - var i = 0; - - while (g.firstChild) { - var elem = g.firstChild; - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - - // Remove child title elements - if(elem.tagName === 'title') { - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent)); - oldParent.removeChild(elem); - continue; - } - - children[i++] = elem = parent.insertBefore(elem, anchor); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - - // remove the group from the selection - clearSelection(); - - // delete the group element (but make undo-able) - var gNextSibling = g.nextSibling; - g = parent.removeChild(g); - batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)); - - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - addToSelection(children); - } -}; - -// Function: moveToTopSelectedElement -// Repositions the selected element to the bottom in the DOM to appear on top of -// other elements -this.moveToTopSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - t = t.parentNode.appendChild(t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "top")); - call("changed", [t]); - } - } -}; - -// Function: moveToBottomSelectedElement -// Repositions the selected element to the top in the DOM to appear under -// other elements -this.moveToBottomSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - var firstChild = t.parentNode.firstChild; - if (firstChild.tagName == 'title') { - firstChild = firstChild.nextSibling; - } - // This can probably be removed, as the defs should not ever apppear - // inside a layer group - if (firstChild.tagName == 'defs') { - firstChild = firstChild.nextSibling; - } - t = t.parentNode.insertBefore(t, firstChild); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "bottom")); - call("changed", [t]); - } - } -}; - -// Function: moveUpDownSelected -// Moves the select element up or down the stack, based on the visibly -// intersecting elements -// -// Parameters: -// dir - String that's either 'Up' or 'Down' -this.moveUpDownSelected = function(dir) { - var selected = selectedElements[0]; - if (!selected) return; - - curBBoxes = []; - var closest, found_cur; - // jQuery sorts this list - var list = $(getIntersectionList(getStrokedBBox([selected]))).toArray(); - if(dir == 'Down') list.reverse(); - - $.each(list, function() { - if(!found_cur) { - if(this == selected) { - found_cur = true; - } - return; - } - closest = this; - return false; - }); - if(!closest) return; - - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - $(closest)[dir == 'Down'?'before':'after'](t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "Move " + dir)); - call("changed", [t]); - } -}; - -// Function: moveSelectedElements -// Moves selected elements on the X/Y axis -// -// Parameters: -// dx - Float with the distance to move on the x-axis -// dy - Float with the distance to move on the y-axis -// undoable - Boolean indicating whether or not the action should be undoable -// -// Returns: -// Batch command for the move -this.moveSelectedElements = function(dx, dy, undoable) { - // if undoable is not sent, default to true - // if single values, scale them to the zoom - if (dx.constructor != Array) { - dx /= current_zoom; - dy /= current_zoom; - } - var undoable = undoable || true; - var batchCmd = new BatchCommand("position"); - var i = selectedElements.length; - while (i--) { - var selected = selectedElements[i]; - if (selected != null) { -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(selected); - -// var b = {}; -// for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; -// selectedBBoxes[i] = b; - - var xform = svgroot.createSVGTransform(); - var tlist = getTransformList(selected); - - // dx and dy could be arrays - if (dx.constructor == Array) { -// if (i==0) { -// selectedBBoxes[0].x += dx[0]; -// selectedBBoxes[0].y += dy[0]; -// } - xform.setTranslate(dx[i],dy[i]); - } else { -// if (i==0) { -// selectedBBoxes[0].x += dx; -// selectedBBoxes[0].y += dy; -// } - xform.setTranslate(dx,dy); - } - - if(tlist.numberOfItems) { - tlist.insertItemBefore(xform, 0); - } else { - tlist.appendItem(xform); - } - - var cmd = recalculateDimensions(selected); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - - selectorManager.requestSelector(selected).resize(); - } - } - if (!batchCmd.isEmpty()) { - if (undoable) - addCommandToHistory(batchCmd); - call("changed", selectedElements); - return batchCmd; - } -}; - -// Function: cloneSelectedElements -// Create deep DOM copies (clones) of all selected elements and move them slightly -// from their originals -this.cloneSelectedElements = function(x,y) { - var batchCmd = new BatchCommand("Clone Elements"); - // find all the elements selected (stop at first null) - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - } - // use slice to quickly get the subset of elements we need - var copiedElements = selectedElements.slice(0,i); - this.clearSelection(true); - // note that we loop in the reverse way because of the way elements are added - // to the selectedElements array (top-first) - var i = copiedElements.length; - while (i--) { - // clone each element and replace it within copiedElements - var elem = copiedElements[i] = copyElem(copiedElements[i]); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(elem); - batchCmd.addSubCommand(new InsertElementCommand(elem)); - } - - if (!batchCmd.isEmpty()) { - addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - this.moveSelectedElements(x,y,false); - addCommandToHistory(batchCmd); - } -}; - -// Function: alignSelectedElements -// Aligns selected elements -// -// Parameters: -// type - String with single character indicating the alignment type -// relative_to - String that must be one of the following: -// "selected", "largest", "smallest", "page" -this.alignSelectedElements = function(type, relative_to) { - var bboxes = [], angles = []; - var minx = Number.MAX_VALUE, maxx = Number.MIN_VALUE, miny = Number.MAX_VALUE, maxy = Number.MIN_VALUE; - var curwidth = Number.MIN_VALUE, curheight = Number.MIN_VALUE; - var len = selectedElements.length; - if (!len) return; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - bboxes[i] = getStrokedBBox([elem]); - - // now bbox is axis-aligned and handles rotation - switch (relative_to) { - case 'smallest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth > bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight > bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - case 'largest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth < bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight < bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - default: // 'selected' - if (bboxes[i].x < minx) minx = bboxes[i].x; - if (bboxes[i].y < miny) miny = bboxes[i].y; - if (bboxes[i].x + bboxes[i].width > maxx) maxx = bboxes[i].x + bboxes[i].width; - if (bboxes[i].y + bboxes[i].height > maxy) maxy = bboxes[i].y + bboxes[i].height; - break; - } - } // loop for each element to find the bbox and adjust min/max - - if (relative_to == 'page') { - minx = 0; - miny = 0; - maxx = canvas.contentW; - maxy = canvas.contentH; - } - - var dx = new Array(len); - var dy = new Array(len); - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - var bbox = bboxes[i]; - dx[i] = 0; - dy[i] = 0; - switch (type) { - case 'l': // left (horizontal) - dx[i] = minx - bbox.x; - break; - case 'c': // center (horizontal) - dx[i] = (minx+maxx)/2 - (bbox.x + bbox.width/2); - break; - case 'r': // right (horizontal) - dx[i] = maxx - (bbox.x + bbox.width); - break; - case 't': // top (vertical) - dy[i] = miny - bbox.y; - break; - case 'm': // middle (vertical) - dy[i] = (miny+maxy)/2 - (bbox.y + bbox.height/2); - break; - case 'b': // bottom (vertical) - dy[i] = maxy - (bbox.y + bbox.height); - break; - } - } - this.moveSelectedElements(dx,dy); -}; - -// Group: Additional editor tools - -this.contentW = getResolution().w; -this.contentH = getResolution().h; - -// Function: updateCanvas -// Updates the editor canvas width/height/position after a zoom has occurred -// -// Parameters: -// w - Float with the new width -// h - Float with the new height -// -// Returns: -// Object with the following values: -// * x - The canvas' new x coordinate -// * y - The canvas' new y coordinate -// * old_x - The canvas' old x coordinate -// * old_y - The canvas' old y coordinate -// * d_x - The x position difference -// * d_y - The y position difference -this.updateCanvas = function(w, h) { - svgroot.setAttribute("width", w); - svgroot.setAttribute("height", h); - var bg = $('#canvasBackground')[0]; - var old_x = svgcontent.getAttribute('x'); - var old_y = svgcontent.getAttribute('y'); - var x = (w/2 - this.contentW*current_zoom/2); - var y = (h/2 - this.contentH*current_zoom/2); - - assignAttributes(svgcontent, { - width: this.contentW*current_zoom, - height: this.contentH*current_zoom, - 'x': x, - 'y': y, - "viewBox" : "0 0 " + this.contentW + " " + this.contentH - }); - - assignAttributes(bg, { - width: svgcontent.getAttribute('width'), - height: svgcontent.getAttribute('height'), - x: x, - y: y - }); - - var bg_img = getElem('background_image'); - if (bg_img) { - assignAttributes(bg_img, { - 'width': '100%', - 'height': '100%' - }); - } - - selectorManager.selectorParentGroup.setAttribute("transform","translate(" + x + "," + y + ")"); - - return {x:x, y:y, old_x:old_x, old_y:old_y, d_x:x - old_x, d_y:y - old_y}; -} - -// Function: setBackground -// Set the background of the editor (NOT the actual document) -// -// Parameters: -// color - String with fill color to apply -// url - URL or path to image to use -this.setBackground = function(color, url) { - var bg = getElem('canvasBackground'); - var border = $(bg).find('rect')[0]; - var bg_img = getElem('background_image'); - border.setAttribute('fill',color); - if(url) { - if(!bg_img) { - bg_img = svgdoc.createElementNS(svgns, "image"); - assignAttributes(bg_img, { - 'id': 'background_image', - 'width': '100%', - 'height': '100%', - 'preserveAspectRatio': 'xMinYMin', - 'style':'pointer-events:none' - }); - } - setHref(bg_img, url); - bg.appendChild(bg_img); - } else if(bg_img) { - bg_img.parentNode.removeChild(bg_img); - } -} - -// Function: cycleElement -// Select the next/previous element within the current layer -// -// Parameters: -// next - Boolean where true = next and false = previous element -this.cycleElement = function(next) { - var cur_elem = selectedElements[0]; - var elem = false; - var all_elems = getVisibleElements(current_group || getCurrentDrawing().getCurrentLayer()); - if(!all_elems.length) return; - if (cur_elem == null) { - var num = next?all_elems.length-1:0; - elem = all_elems[num]; - } else { - var i = all_elems.length; - while(i--) { - if(all_elems[i] == cur_elem) { - var num = next?i-1:i+1; - if(num >= all_elems.length) { - num = 0; - } else if(num < 0) { - num = all_elems.length-1; - } - elem = all_elems[num]; - break; - } - } - } - selectOnly([elem], true); - call("selected", selectedElements); -} - -this.clear(); - - -// DEPRECATED: getPrivateMethods -// Since all methods are/should be public somehow, this function should be removed - -// Being able to access private methods publicly seems wrong somehow, -// but currently appears to be the best way to allow testing and provide -// access to them to plugins. -this.getPrivateMethods = function() { - var obj = { - addCommandToHistory: addCommandToHistory, - setGradient: setGradient, - addSvgElementFromJson: addSvgElementFromJson, - assignAttributes: assignAttributes, - BatchCommand: BatchCommand, - call: call, - ChangeElementCommand: ChangeElementCommand, - copyElem: copyElem, - ffClone: ffClone, - findDefs: findDefs, - findDuplicateGradient: findDuplicateGradient, - getElem: getElem, - getId: getId, - getIntersectionList: getIntersectionList, - getMouseTarget: getMouseTarget, - getNextId: getNextId, - getPathBBox: getPathBBox, - getUrlFromAttr: getUrlFromAttr, - hasMatrixTransform: hasMatrixTransform, - identifyLayers: identifyLayers, - InsertElementCommand: InsertElementCommand, - isIdentity: svgedit.math.isIdentity, - logMatrix: logMatrix, - matrixMultiply: matrixMultiply, - MoveElementCommand: MoveElementCommand, - preventClickDefault: preventClickDefault, - recalculateAllSelectedDimensions: recalculateAllSelectedDimensions, - recalculateDimensions: recalculateDimensions, - remapElement: remapElement, - RemoveElementCommand: RemoveElementCommand, - removeUnusedDefElems: removeUnusedDefElems, - round: round, - runExtensions: runExtensions, - sanitizeSvg: sanitizeSvg, - SVGEditTransformList: svgedit.transformlist.SVGTransformList, - toString: toString, - transformBox: svgedit.math.transformBox, - transformListToTransform: transformListToTransform, - transformPoint: transformPoint, - walkTree: svgedit.utilities.walkTree - } - return obj; -}; - -} diff --git a/build/opera/editor/svgedit.compiled.js b/build/opera/editor/svgedit.compiled.js deleted file mode 100644 index 56075ab..0000000 --- a/build/opera/editor/svgedit.compiled.js +++ /dev/null @@ -1,527 +0,0 @@ -(function(a){function H(h){if(typeof h.data==="string"){var i=h.handler,u=h.data.toLowerCase().split(" ");h.handler=function(E){if(!(this!==E.target&&(/textarea|select/i.test(E.target.nodeName)||E.target.type==="text"))){var e=E.type!=="keypress"&&a.hotkeys.specialKeys[E.which],f=String.fromCharCode(E.which).toLowerCase(),g="",p={};if(E.altKey&&e!=="alt")g+="alt+";if(E.ctrlKey&&e!=="ctrl")g+="ctrl+";if(E.metaKey&&!E.ctrlKey&&e!=="meta")g+="meta+";if(E.shiftKey&&e!=="shift")g+="shift+";if(e)p[g+e]= -true;else{p[g+f]=true;p[g+a.hotkeys.shiftNums[f]]=true;if(g==="shift+")p[a.hotkeys.shiftNums[f]]=true}e=0;for(f=u.length;e<f;e++)if(p[u[e]])return i.apply(this,arguments)}}}}a.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9", -106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta",219:"[",221:"]"},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};a.each(["keydown","keyup","keypress"],function(){a.event.special[this]={add:H}})})(jQuery);(function(a,H){function h(U){return typeof U==="string"}function i(U){var Z=g.call(arguments,1);return function(){return U.apply(this,Z.concat(g.call(arguments)))}}function u(U,Z,ea,ra,ja){var la;if(ra!==f){Z=ea.match(U?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);ea=Z[3]||"";if(ja===2&&h(ra))ra=ra.replace(U?va:Na,"");else{la=q(Z[2]);ra=h(ra)?q[U?X:ka](ra):ra;ra=ja===2?ra:ja===1?a.extend({},ra,la):a.extend({},la,ra);ra=z(ra);if(U)ra=ra.replace(ha,p)}U=Z[1]+(U?"#":ra||!Z[1]?"?":"")+ra+ea}else U= -Z(ea!==f?ea:H[qa][ga]);return U}function E(U,Z,ea){if(Z===f||typeof Z==="boolean"){ea=Z;Z=z[U?X:ka]()}else Z=h(Z)?Z.replace(U?va:Na,""):Z;return q(Z,ea)}function e(U,Z,ea,ra){if(!h(ea)&&typeof ea!=="object"){ra=ea;ea=Z;Z=f}return this.each(function(){var ja=a(this),la=Z||ma()[(this.nodeName||"").toLowerCase()]||"",T=la&&ja.attr(la)||"";ja.attr(la,z[U](T,ea,ra))})}var f,g=Array.prototype.slice,p=decodeURIComponent,z=a.param,D,q,M,ba=a.bbq=a.bbq||{},N,I,ma,ia=a.event.special,ka="querystring",X="fragment", -qa="location",ga="href",Na=/^.*\?|#.*$/g,va=/^.*\#/,ha,Ra={};z[ka]=i(u,0,function(U){return U.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")});z[X]=D=i(u,1,function(U){return U.replace(/^[^#]*#?(.*)$/,"$1")});D.noEscape=function(U){U=U||"";U=a.map(U.split(""),encodeURIComponent);ha=RegExp(U.join("|"),"g")};D.noEscape(",/");a.deparam=q=function(U,Z){var ea={},ra={"true":true,"false":false,"null":null};a.each(U.replace(/\+/g," ").split("&"),function(ja,la){var T=la.split("="),wa=p(T[0]),Da=ea,Ma=0,Fa=wa.split("]["), -Oa=Fa.length-1;if(/\[/.test(Fa[0])&&/\]$/.test(Fa[Oa])){Fa[Oa]=Fa[Oa].replace(/\]$/,"");Fa=Fa.shift().split("[").concat(Fa);Oa=Fa.length-1}else Oa=0;if(T.length===2){T=p(T[1]);if(Z)T=T&&!isNaN(T)?+T:T==="undefined"?f:ra[T]!==f?ra[T]:T;if(Oa)for(;Ma<=Oa;Ma++){wa=Fa[Ma]===""?Da.length:Fa[Ma];Da=Da[wa]=Ma<Oa?Da[wa]||(Fa[Ma+1]&&isNaN(Fa[Ma+1])?{}:[]):T}else if(a.isArray(ea[wa]))ea[wa].push(T);else ea[wa]=ea[wa]!==f?[ea[wa],T]:T}else if(wa)ea[wa]=Z?f:""});return ea};q[ka]=i(E,0);q[X]=M=i(E,1);a.elemUrlAttr|| -(a.elemUrlAttr=function(U){return a.extend(Ra,U)})({a:ga,base:ga,iframe:"src",img:"src",input:"src",form:"action",link:ga,script:"src"});ma=a.elemUrlAttr;a.fn[ka]=i(e,ka);a.fn[X]=i(e,X);ba.pushState=N=function(U,Z){if(h(U)&&/^#/.test(U)&&Z===f)Z=2;var ea=U!==f;ea=D(H[qa][ga],ea?U:{},ea?Z:2);H[qa][ga]=ea+(/#/.test(ea)?"":"#")};ba.getState=I=function(U,Z){return U===f||typeof U==="boolean"?M(U):M(Z)[U]};ba.removeState=function(U){var Z={};if(U!==f){Z=I();a.each(a.isArray(U)?U:arguments,function(ea, -ra){delete Z[ra]})}N(Z,2)};ia.hashchange=a.extend(ia.hashchange,{add:function(U){function Z(ra){var ja=ra[X]=D();ra.getState=function(la,T){return la===f||typeof la==="boolean"?q(ja,la):q(ja,T)[la]};ea.apply(this,arguments)}var ea;if(a.isFunction(U)){ea=U;return Z}else{ea=U.handler;U.handler=Z}}})})(jQuery,this); -(function(a,H,h){function i(D){D=D||H[e][f];return D.replace(/^[^#]*#?(.*)$/,"$1")}var u,E=a.event.special,e="location",f="href",g=document.documentMode,p=a.browser.msie&&(g===h||g<8),z="onhashchange"in H&&!p;a.hashchangeDelay=100;E.hashchange=a.extend(E.hashchange,{setup:function(){if(z)return false;a(u.start)},teardown:function(){if(z)return false;a(u.stop)}});u=function(){function D(){N=I=function(ma){return ma};if(p){ba=a('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow; -I=function(){return i(ba.document[e][f])};N=function(ma,ia){if(ma!==ia){var ka=ba.document;ka.open().close();ka[e].hash="#"+ma}};N(i())}}var q={},M,ba,N,I;q.start=function(){if(!M){var ma=i();N||D();(function ia(){var ka=i(),X=I(ma);if(ka!==ma){N(ma=ka,X);a(H).trigger("hashchange")}else if(X!==ma)H[e][f]=H[e][f].replace(/#.*/,"")+"#"+X;M=setTimeout(ia,a.hashchangeDelay)})()}};q.stop=function(){if(!ba){M&&clearTimeout(M);M=0}};return q}()})(jQuery,this);(function(a){var H={},h;a.svgIcons=function(i,u){function E(U,Z){if(U!=="ajax"){if(ma)return;var ea=(ba=ga[0].contentDocument)&&ba.getElementById("svg_eof");if(!ea&&!(Z&&ea)){ia++;if(ia<50)setTimeout(E,20);else{f();ma=true}return}ma=true}M=a(ba.firstChild).children();if(u.no_img)setTimeout(function(){I||e()},500);else{ea=qa+"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D";N=a(new Image).attr({src:ea,width:0,height:0}).appendTo("body").load(function(){e(true)}).error(function(){e()})}} -function e(U,Z){if(!I){if(u.no_img)U=false;if(U){var ea=a(document.createElement("div"));ea.hide().appendTo("body")}if(Z){var ra=u.fallback_path?u.fallback_path:"";a.each(Z,function(Oa,Qa){a("#"+Oa);var Ga=a(new Image).attr({"class":"svg_icon",src:ra+Qa,width:D,height:q,alt:"icon"});Ra(Ga,Oa)})}else for(var ja=M.length,la=0;la<ja;la++){var T=M[la],wa=T.id;if(wa==="svg_eof")break;a("#"+wa);T=T.getElementsByTagNameNS(p,"svg")[0];var Da=document.createElementNS(p,"svg");Da.setAttributeNS(p,"viewBox", -[0,0,D,q].join(" "));var Ma=T.getAttribute("width"),Fa=T.getAttribute("height");T.removeAttribute("width");T.removeAttribute("height");T.getAttribute("viewBox")||T.setAttribute("viewBox",[0,0,Ma,Fa].join(" "));Da.setAttribute("xmlns",p);Da.setAttribute("width",D);Da.setAttribute("height",q);Da.setAttribute("xmlns:xlink",z);Da.setAttribute("class","svg_icon");X||(T=T.cloneNode(true));Da.appendChild(T);if(U){X||Da.cloneNode(true);ea.empty().append(Da);T=qa+g(ea.html());T=a(new Image).attr({"class":"svg_icon", -src:T})}else T=h(a(Da),la);Ra(T,wa)}u.placement&&a.each(u.placement,function(Oa,Qa){H[Qa]&&a(Oa).each(function(Ga){var Ca=H[Qa].clone();if(Ga>0&&!U)Ca=h(Ca,Ga,true);ha(a(this),Ca,Qa)})});if(!Z){U&&ea.remove();ga&&ga.remove();N&&N.remove()}u.resize&&a.resizeSvgIcons(u.resize);I=true;u.callback&&u.callback(H)}}function f(){if(i.indexOf(".svgz")!=-1){var U=i.replace(".svgz",".svg");window.console&&console.log(".svgz failed, trying with .svg");a.svgIcons(U,u)}else u.fallback&&e(false,u.fallback)}function g(U){if(window.btoa)return window.btoa(U); -var Z=Array(Math.floor((U.length+2)/3)*4),ea,ra,ja,la,T,wa,Da=0,Ma=0;do{ea=U.charCodeAt(Da++);ra=U.charCodeAt(Da++);ja=U.charCodeAt(Da++);la=ea>>2;ea=(ea&3)<<4|ra>>4;T=(ra&15)<<2|ja>>6;wa=ja&63;if(isNaN(ra))T=wa=64;else if(isNaN(ja))wa=64;Z[Ma++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(la);Z[Ma++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(ea);Z[Ma++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(T);Z[Ma++]= -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(wa)}while(Da<U.length);return Z.join("")}var p="http://www.w3.org/2000/svg",z="http://www.w3.org/1999/xlink",D=u.w?u.w:24,q=u.h?u.h:24,M,ba,N,I=false,ma=false,ia=0,ka=navigator.userAgent,X=!!window.opera;ka.indexOf("Safari/")>-1&&ka.indexOf("Chrome/");var qa="data:image/svg+xml;charset=utf-8;base64,";if(u.svgz){var ga=a('<object data="'+i+'" type=image/svg+xml>').appendTo("body").hide();try{ba=ga[0].contentDocument;ga.load(E); -E(0,true)}catch(Na){f()}}else{var va=new DOMParser;a.ajax({url:i,dataType:"string",success:function(U){if(U){ba=va.parseFromString(U,"text/xml");a(function(){E("ajax")})}else a(f)},error:function(U){if(window.opera)a(function(){f()});else if(U.responseText){ba=va.parseFromString(U.responseText,"text/xml");ba.childNodes.length||a(f);a(function(){E("ajax")})}else a(f)}})}var ha=function(U,Z,ea,ra){X&&Z.css("visibility","hidden");if(u.replace){ra&&Z.attr("id",ea);(ea=U.attr("class"))&&Z.attr("class", -"svg_icon "+ea);U.replaceWith(Z)}else U.append(Z);X&&setTimeout(function(){Z.removeAttr("style")},1)},Ra=function(U,Z){if(u.id_match===undefined||u.id_match!==false)ha(holder,U,Z,true);H[Z]=U};h=function(U,Z){var ea=U.find("defs");if(!ea.length)return U;ea=X?ea.find("*").filter(function(){return!!this.id}):ea.find("[id]");var ra=U[0].getElementsByTagName("*"),ja=ra.length;ea.each(function(la){var T=this.id;a(ba).find("#"+T);this.id=la="x"+T+Z+la;T="url(#"+T+")";var wa="url(#"+la+")";for(la=0;la<ja;la++){var Da= -ra[la];Da.getAttribute("fill")===T&&Da.setAttribute("fill",wa);Da.getAttribute("stroke")===T&&Da.setAttribute("stroke",wa);Da.getAttribute("filter")===T&&Da.setAttribute("filter",wa)}});return U}};a.getSvgIcon=function(i,u){var E=H[i];if(u&&E)E=h(E,0,true).clone(true);return E};a.resizeSvgIcons=function(i){var u=!a(".svg_icon:first").length;a.each(i,function(E,e){var f=a.isArray(e),g=f?e[0]:e,p=f?e[1]:e;if(u)E=E.replace(/\.svg_icon/g,"svg");a(E).each(function(){this.setAttribute("width",g);this.setAttribute("height", -p);if(window.opera&&window.widget){this.parentNode.style.width=g+"px";this.parentNode.style.height=p+"px"}})})}})(jQuery);(function(){function a(i,u,E){i=document.createElementNS(H.svg,i);if(h)for(var e in u)i.setAttribute(e,u[e]);else for(e in u){var f=u[e],g=i[e];if(g&&g.constructor==="SVGLength")g.baseVal.value=f;else i.setAttribute(e,f)}E&&E.appendChild(i);return i}var H={svg:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};if(!window.console)window.console=new function(){this.log=function(){};this.dir=function(){}};$.jGraduate={Paint:function(i){i=i||{};this.alpha=isNaN(i.alpha)?100:i.alpha;if(i.copy){this.type= -i.copy.type;this.alpha=i.copy.alpha;this.radialGradient=this.linearGradient=this.solidColor=null;switch(this.type){case "solidColor":this.solidColor=i.copy.solidColor;break;case "linearGradient":this.linearGradient=i.copy.linearGradient.cloneNode(true);break;case "radialGradient":this.radialGradient=i.copy.radialGradient.cloneNode(true)}}else if(i.linearGradient){this.type="linearGradient";this.radialGradient=this.solidColor=null;this.linearGradient=i.linearGradient.cloneNode(true)}else if(i.radialGradient){this.type= -"radialGradient";this.linearGradient=this.solidColor=null;this.radialGradient=i.radialGradient.cloneNode(true)}else if(i.solidColor){this.type="solidColor";this.solidColor=i.solidColor}else{this.type="none";this.radialGradient=this.linearGradient=this.solidColor=null}}};jQuery.fn.jGraduateDefaults={paint:new $.jGraduate.Paint,window:{pickerTitle:"Drag markers to pick a paint"},images:{clientPath:"images/"},newstop:"inverse"};var h=navigator.userAgent.indexOf("Gecko/")>=0;jQuery.fn.jGraduate=function(i){var u= -arguments;return this.each(function(){function E(pa,V,ua,ya,aa){var Sa=aa||a("stop",{"stop-color":V,"stop-opacity":ua,offset:pa},va);if(aa){V=aa.getAttribute("stop-color");ua=aa.getAttribute("stop-opacity");pa=aa.getAttribute("offset")}else va.appendChild(Sa);if(ua===null)ua=1;aa=a("path",{d:"M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z",fill:"url(#jGraduate_trans)",transform:"translate("+(10+pa*X)+", 26)"},zb); -var Eb=a("path",{d:"M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z",fill:V,"fill-opacity":ua,transform:"translate("+(10+pa*X)+", 26)",stroke:"#000","stroke-width":1.5},zb);$(Eb).mousedown(function(Ab){e(this);Va=gb;ma.mousemove(p).mouseup(f);Bb=Pb.offset();Ab.preventDefault();return false}).data("stop",Sa).data("bg",aa).dblclick(function(){$("div.jGraduate_LightBox").show();for(var Ab=this,wb=+Sa.getAttribute("stop-opacity")|| -1,tb=Sa.getAttribute("stop-color")||1,Fb=(parseFloat(wb)*255).toString(16);Fb.length<2;)Fb="0"+Fb;V=tb.substr(1)+Fb;$("#"+q+"_jGraduate_stopPicker").css({left:100,bottom:15}).jPicker({window:{title:"Pick the start color and opacity for the gradient"},images:{clientPath:D.images.clientPath},color:{active:V,alphaSupport:true}},function(Qb){tb=Qb.val("hex")?"#"+Qb.val("hex"):"none";wb=Qb.val("a")!==null?Qb.val("a")/256:1;Ab.setAttribute("fill",tb);Ab.setAttribute("fill-opacity",wb);Sa.setAttribute("stop-color", -tb);Sa.setAttribute("stop-opacity",wb);$("div.jGraduate_LightBox").hide();$("#"+q+"_jGraduate_stopPicker").hide()},null,function(){$("div.jGraduate_LightBox").hide();$("#"+q+"_jGraduate_stopPicker").hide()})});$(va).find("stop").each(function(){var Ab=$(this);if(+this.getAttribute("offset")>pa){if(!V){var wb=this.getAttribute("stop-color"),tb=this.getAttribute("stop-opacity");Sa.setAttribute("stop-color",wb);Eb.setAttribute("fill",wb);Sa.setAttribute("stop-opacity",tb===null?1:tb);Eb.setAttribute("fill-opacity", -tb===null?1:tb)}Ab.before(Sa);return false}});ya&&e(Eb);return Sa}function e(pa){gb&&gb.setAttribute("stroke","#000");pa.setAttribute("stroke","blue");gb=pa;gb.parentNode.appendChild(gb)}function f(){ma.unbind("mousemove",p);if(ub.getAttribute("display")!=="none"){ub.setAttribute("display","none");var pa=$(gb),V=pa.data("stop");pa=pa.data("bg");$([gb,V,pa]).remove()}Va=null}function g(){var pa=Wa?"rotate("+Wa+","+Ia+","+kb+") ":"";Ua===1&&Ja===1?va.removeAttribute("gradientTransform"):va.setAttribute("gradientTransform", -pa+"translate("+-Ia*(Ua-1)+","+-kb*(Ja-1)+") scale("+Ua+","+Ja+")")}function p(pa){var V=pa.pageX-Bb.left;pa=pa.pageY-Bb.top;V=V<10?10:V>X+10?X+10:V;var ua="translate("+V+", 26)";if(pa<-60||pa>130){ub.setAttribute("display","block");ub.setAttribute("transform",ua)}else ub.setAttribute("display","none");Va.setAttribute("transform",ua);$.data(Va,"bg").setAttribute("transform",ua);$.data(Va,"stop").setAttribute("offset",(V-10)/X);var ya=0;$(va).find("stop").each(function(){var aa=this.getAttribute("offset"), -Sa=$(this);if(aa<ya){Sa.prev().before(Sa);Aa=$(va).find("stop")}ya=aa})}var z=$(this),D=$.extend(true,{},jQuery.fn.jGraduateDefaults,i),q=z.attr("id"),M="#"+z.attr("id")+" ";if(M){var ba=function(){switch(z.paint.type){case "radialGradient":z.paint.linearGradient=null;break;case "linearGradient":z.paint.radialGradient=null;break;case "solidColor":z.paint.radialGradient=z.paint.linearGradient=null}$.isFunction(z.okCallback)&&z.okCallback(z.paint);z.hide()},N=function(){$.isFunction(z.cancelCallback)&& -z.cancelCallback();z.hide()};$.extend(true,z,{paint:new $.jGraduate.Paint({copy:D.paint}),okCallback:$.isFunction(u[1])&&u[1]||null,cancelCallback:$.isFunction(u[2])&&u[2]||null});z.position();var I=null,ma=$(window);if(z.paint.type=="none")z.paint=$.jGraduate.Paint({solidColor:"ffffff"});z.addClass("jGraduate_Picker");z.html('<ul class="jGraduate_tabs"><li class="jGraduate_tab_color jGraduate_tab_current" data-type="col">Solid Color</li><li class="jGraduate_tab_lingrad" data-type="lg">Linear Gradient</li><li class="jGraduate_tab_radgrad" data-type="rg">Radial Gradient</li></ul><div class="jGraduate_colPick"></div><div class="jGraduate_gradPick"></div><div class="jGraduate_LightBox"></div><div id="'+ -q+'_jGraduate_stopPicker" class="jGraduate_stopPicker"></div>');var ia=$(M+"> .jGraduate_colPick"),ka=$(M+"> .jGraduate_gradPick");ka.html('<div id="'+q+'_jGraduate_Swatch" class="jGraduate_Swatch"><h2 class="jGraduate_Title">'+D.window.pickerTitle+'</h2><div id="'+q+'_jGraduate_GradContainer" class="jGraduate_GradContainer"></div><div id="'+q+'_jGraduate_StopSlider" class="jGraduate_StopSlider"></div></div><div class="jGraduate_Form jGraduate_Points jGraduate_lg_field"><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Begin Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+ -q+'_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+q+'_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/></div></div><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">End Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+q+'_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+ -q+'_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/></div></div></div><div class="jGraduate_Form jGraduate_Points jGraduate_rg_field"><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Center Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+q+'_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+q+'_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/></div></div><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Focal Point</label><div class="jGraduate_Form_Section"><label>Match center: <input type="checkbox" checked="checked" id="'+ -q+'_jGraduate_match_ctr"/></label><br/><label>x:</label><input type="text" id="'+q+'_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+q+'_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/></div></div></div><div class="jGraduate_StopSection jGraduate_SpreadMethod"><label class="jGraduate_Form_Heading">Spread method</label><div class="jGraduate_Form_Section"><select class="jGraduate_spreadMethod"><option value=pad selected>Pad</option><option value=reflect>Reflect</option><option value=repeat>Repeat</option></select></div></div><div class="jGraduate_Form"><div class="jGraduate_Slider jGraduate_RadiusField jGraduate_rg_field"><label class="prelabel">Radius:</label><div id="'+ -q+'_jGraduate_Radius" class="jGraduate_SliderBar jGraduate_Radius" title="Click to set radius"><img id="'+q+'_jGraduate_RadiusArrows" class="jGraduate_RadiusArrows" src="'+D.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_RadiusInput" size="3" value="100"/>%</label></div><div class="jGraduate_Slider jGraduate_EllipField jGraduate_rg_field"><label class="prelabel">Ellip:</label><div id="'+q+'_jGraduate_Ellip" class="jGraduate_SliderBar jGraduate_Ellip" title="Click to set Ellip"><img id="'+ -q+'_jGraduate_EllipArrows" class="jGraduate_EllipArrows" src="'+D.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_EllipInput" size="3" value="0"/>%</label></div><div class="jGraduate_Slider jGraduate_AngleField jGraduate_rg_field"><label class="prelabel">Angle:</label><div id="'+q+'_jGraduate_Angle" class="jGraduate_SliderBar jGraduate_Angle" title="Click to set Angle"><img id="'+q+'_jGraduate_AngleArrows" class="jGraduate_AngleArrows" src="'+D.images.clientPath+ -'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_AngleInput" size="3" value="0"/>\u00ba </label></div><div class="jGraduate_Slider jGraduate_OpacField"><label class="prelabel">Opac:</label><div id="'+q+'_jGraduate_Opac" class="jGraduate_SliderBar jGraduate_Opac" title="Click to set Opac"><img id="'+q+'_jGraduate_OpacArrows" class="jGraduate_OpacArrows" src="'+D.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+q+'_jGraduate_OpacInput" size="3" value="100"/>%</label></div></div><div class="jGraduate_OkCancel"><input type="button" id="'+ -q+'_jGraduate_Ok" class="jGraduate_Ok" value="OK"/><input type="button" id="'+q+'_jGraduate_Cancel" class="jGraduate_Cancel" value="Cancel"/></div>');var X=256,qa=X-0,ga=X-0,Na,va,ha,Ra={};$(".jGraduate_SliderBar").width(145);var U=$("#"+q+"_jGraduate_GradContainer")[0],Z=a("svg",{id:q+"_jgraduate_svg",width:X,height:X,xmlns:H.svg},U);Na=Na||z.paint.type;var ea=va=z.paint[Na],ra=z.paint.alpha,ja=Na==="solidColor";switch(Na){case "solidColor":case "linearGradient":if(!ja){va.id=q+"_lg_jgraduate_grad"; -ea=va=Z.appendChild(va)}a("radialGradient",{id:q+"_rg_jgraduate_grad"},Z);if(Na==="linearGradient")break;case "radialGradient":if(!ja){va.id=q+"_rg_jgraduate_grad";ea=va=Z.appendChild(va)}a("linearGradient",{id:q+"_lg_jgraduate_grad"},Z)}if(ja){ea=va=$("#"+q+"_lg_jgraduate_grad")[0];I=z.paint[Na];E(0,"#"+I,1);var la=typeof D.newstop;if(la==="string")switch(D.newstop){case "same":E(1,"#"+I,1);break;case "inverse":la="";for(var T=0;T<6;T+=2){I.substr(T,2);var wa=(255-parseInt(I.substr(T,2),16)).toString(16); -if(wa.length<2)wa=0+wa;la+=wa}E(1,"#"+la,1);break;case "white":E(1,"#ffffff",1);break;case "black":E(1,"#000000",1)}else if(la==="object")E(1,D.newstop.color||"#"+I,"opac"in D.newstop?D.newstop.opac:1)}I=parseFloat(ea.getAttribute("x1")||0);la=parseFloat(ea.getAttribute("y1")||0);T=parseFloat(ea.getAttribute("x2")||1);wa=parseFloat(ea.getAttribute("y2")||0);var Da=parseFloat(ea.getAttribute("cx")||0.5),Ma=parseFloat(ea.getAttribute("cy")||0.5),Fa=parseFloat(ea.getAttribute("fx")||Da),Oa=parseFloat(ea.getAttribute("fy")|| -Ma);ha=a("rect",{id:q+"_jgraduate_rect",x:0,y:0,width:qa,height:ga,fill:"url(#"+q+"_jgraduate_grad)","fill-opacity":ra/100},Z);var Qa=$("<div/>").attr({"class":"grad_coord jGraduate_lg_field",title:"Begin Stop"}).text(1).css({top:la*X,left:I*X}).data("coord","start").appendTo(U),Ga=Qa.clone().text(2).css({top:wa*X,left:T*X}).attr("title","End stop").data("coord","end").appendTo(U),Ca=$("<div/>").attr({"class":"grad_coord jGraduate_rg_field",title:"Center stop"}).text("C").css({top:Ma*X,left:Da*X}).data("coord", -"center").appendTo(U),Ha=Ca.clone().text("F").css({top:Oa*X,left:Fa*X,display:"none"}).attr("title","Focus point").data("coord","focus").appendTo(U);Ha[0].id=q+"_jGraduate_focusCoord";$(M+" .grad_coord");$.each(["x1","y1","x2","y2","cx","cy","fx","fy"],function(pa,V){var ua=va.getAttribute(V),ya=isNaN(V[1]);ua||(ua=ya?"0.5":V==="x2"?"1.0":"0.0");Ra[V]=$("#"+q+"_jGraduate_"+V).val(ua).change(function(){if(isNaN(parseFloat(this.value))||this.value<0)this.value=0;else if(this.value>1)this.value=1;if(!(V[0]=== -"f"&&!lb))if(ya&&Na==="radialGradient"||!ya&&Na==="linearGradient")va.setAttribute(V,this.value);var aa=ya?V[0]==="c"?Ca:Ha:V[1]==="1"?Qa:Ga,Sa=V.indexOf("x")>=0?"left":"top";aa.css(Sa,this.value*X)}).change()});var Aa,zb,Pb=$("#"+q+"_jGraduate_StopSlider"),gb,mb,Va,ub=a("path",{d:"m9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5",fill:"none",stroke:"#D00","stroke-width":5,display:"none"},mb),Bb,Ua=1,Ja=1,Wa=0,Ia=Da,kb=Ma;mb=a("svg",{width:"100%",height:45},Pb[0]);U=a("pattern",{width:16,height:16,patternUnits:"userSpaceOnUse", -id:"jGraduate_trans"},mb);a("image",{width:16,height:16},U).setAttributeNS(H.xlink,"xlink:href",D.images.clientPath+"map-opacity.png");$(mb).click(function(pa){Bb=Pb.offset();if(pa.target.tagName!=="path"){var V=pa.pageX-Bb.left-8;V=V<10?10:V>X+10?X+10:V;E(V/X,0,0,true);pa.stopPropagation()}});$(mb).mouseover(function(){mb.appendChild(ub)});zb=a("g",{},mb);a("line",{x1:10,y1:15,x2:X+10,y2:15,"stroke-width":2,stroke:"#000"},mb);var Cb=ka.find(".jGraduate_spreadMethod").change(function(){va.setAttribute("spreadMethod", -$(this).val())}),ab=null,cb=function(pa){var V=pa.pageX-vb.left,ua=pa.pageY-vb.top;V=V<0?0:V>X?X:V;ua=ua<0?0:ua>X?X:ua;ab.css("left",V).css("top",ua);V/=qa;ua/=ga;var ya=ab.data("coord"),aa=va;switch(ya){case "start":Ra.x1.val(V);Ra.y1.val(ua);aa.setAttribute("x1",V);aa.setAttribute("y1",ua);break;case "end":Ra.x2.val(V);Ra.y2.val(ua);aa.setAttribute("x2",V);aa.setAttribute("y2",ua);break;case "center":Ra.cx.val(V);Ra.cy.val(ua);aa.setAttribute("cx",V);aa.setAttribute("cy",ua);Ia=V;kb=ua;g();break; -case "focus":Ra.fx.val(V);Ra.fy.val(ua);aa.setAttribute("fx",V);aa.setAttribute("fy",ua);g()}pa.preventDefault()},db=function(){ab=null;ma.unbind("mousemove",cb).unbind("mouseup",db)};Aa=va.getElementsByTagNameNS(H.svg,"stop");if(za<2){for(;za<2;){va.appendChild(document.createElementNS(H.svg,"stop"));++za}Aa=va.getElementsByTagNameNS(H.svg,"stop")}var za=Aa.length;for(T=0;T<za;T++)E(0,0,0,0,Aa[T]);Cb.val(va.getAttribute("spreadMethod")||"pad");var vb,lb=false;ha.setAttribute("fill-opacity",ra/100); -$("#"+q+" div.grad_coord").mousedown(function(pa){pa.preventDefault();ab=$(this);ab.offset();vb=ab.parent().offset();ma.mousemove(cb).mouseup(db)});$("#"+q+"_jGraduate_Ok").bind("click",function(){z.paint.type=Na;z.paint[Na]=va.cloneNode(true);z.paint.solidColor=null;ba()});$("#"+q+"_jGraduate_Cancel").bind("click",function(){N()});if(Na==="radialGradient")if(lb)Ha.show();else{Ha.hide();Ra.fx.val("");Ra.fy.val("")}$("#"+q+"_jGraduate_match_ctr")[0].checked=!lb;var xb,Jb;$("#"+q+"_jGraduate_match_ctr").change(function(){lb= -!this.checked;Ha.toggle(lb);Ra.fx.val("");Ra.fy.val("");var pa=va;if(lb){var V=xb||0.5,ua=Jb||0.5;pa.setAttribute("fx",V);pa.setAttribute("fy",ua);Ra.fx.val(V);Ra.fy.val(ua)}else{xb=pa.getAttribute("fx");Jb=pa.getAttribute("fy");pa.removeAttribute("fx");pa.removeAttribute("fy")}});Aa=va.getElementsByTagNameNS(H.svg,"stop");za=Aa.length;if(za<2){for(;za<2;){va.appendChild(document.createElementNS(H.svg,"stop"));++za}Aa=va.getElementsByTagNameNS(H.svg,"stop")}var pb;ra=ka=0;if(Na==="radialGradient"){Z= -va.gradientTransform.baseVal;if(Z.numberOfItems===2){za=Z.getItem(0);Z=Z.getItem(1);if(za.type===2&&Z.type===3){za=Z.matrix;if(za.a!==1)ka=Math.round(-(1-za.a)*100);else if(za.d!==1)ka=Math.round((1-za.d)*100)}}else if(Z.numberOfItems===3){U=Z.getItem(0);za=Z.getItem(1);Z=Z.getItem(2);if(U.type===4&&za.type===2&&Z.type===3){ra=Math.round(U.angle);za=Z.matrix;if(za.a!==1)ka=Math.round(-(1-za.a)*100);else if(za.d!==1)ka=Math.round((1-za.d)*100)}}}ka={radius:{handle:"#"+q+"_jGraduate_RadiusArrows",input:"#"+ -q+"_jGraduate_RadiusInput",val:(va.getAttribute("r")||0.5)*100},opacity:{handle:"#"+q+"_jGraduate_OpacArrows",input:"#"+q+"_jGraduate_OpacInput",val:z.paint.alpha||100},ellip:{handle:"#"+q+"_jGraduate_EllipArrows",input:"#"+q+"_jGraduate_EllipInput",val:ka},angle:{handle:"#"+q+"_jGraduate_AngleArrows",input:"#"+q+"_jGraduate_AngleInput",val:ra}};$.each(ka,function(pa,V){var ua=$(V.handle);ua.mousedown(function(ya){var aa=ua.parent();pb={type:pa,elem:ua,input:$(V.input),parent:aa,offset:aa.offset()}; -ma.mousemove(Kb).mouseup(Rb);ya.preventDefault()});$(V.input).val(V.val).change(function(){var ya=+this.value,aa=0,Sa=Na==="radialGradient";switch(pa){case "radius":Sa&&va.setAttribute("r",ya/100);aa=Math.pow(ya/100,0.4)/2*145;break;case "opacity":z.paint.alpha=ya;ha.setAttribute("fill-opacity",ya/100);aa=ya*1.45;break;case "ellip":Ua=Ja=1;if(ya===0){aa=72.5;break}if(ya>99.5)ya=99.5;if(ya>0)Ja=1-ya/100;else Ua=-(ya/100)-1;aa=145*((ya+100)/2)/100;Sa&&g();break;case "angle":Wa=ya;aa=Wa/180;aa+=0.5; -aa*=145;Sa&&g()}if(aa>145)aa=145;else if(aa<0)aa=0;ua.css({"margin-left":aa-5})}).change()});var Kb=function(pa){var V=pa.pageX-pb.offset.left-parseInt(pb.parent.css("border-left-width"));if(V>145)V=145;if(V<=0)V=0;var ua=V-5;V/=145;switch(pb.type){case "radius":V=Math.pow(V*2,2.5);if(V>0.98&&V<1.02)V=1;if(V<=0.01)V=0.01;va.setAttribute("r",V);break;case "opacity":z.paint.alpha=parseInt(V*100);ha.setAttribute("fill-opacity",V);break;case "ellip":Ja=Ua=1;if(V<0.5){V/=0.5;Ua=V<=0?0.01:V}else if(V>0.5){V/= -0.5;V=2-V;Ja=V<=0?0.01:V}g();V-=1;if(Ja===V+1)V=Math.abs(V);break;case "angle":V-=0.5;Wa=V*=180;g();V/=100}pb.elem.css({"margin-left":ua});V=Math.round(V*100);pb.input.val(V);pa.preventDefault()},Rb=function(){ma.unbind("mousemove",Kb).unbind("mouseup",Rb);pb=null};for(ka=(z.paint.alpha*255/100).toString(16);ka.length<2;)ka="0"+ka;ka=ka.split(".")[0];I=z.paint.solidColor=="none"?"":z.paint.solidColor+ka;ja||(I=Aa[0].getAttribute("stop-color"));$.extend($.fn.jPicker.defaults.window,{alphaSupport:true, -effects:{type:"show",speed:0}});ia.jPicker({window:{title:D.window.pickerTitle},images:{clientPath:D.images.clientPath},color:{active:I,alphaSupport:true}},function(pa){z.paint.type="solidColor";z.paint.alpha=pa.val("ahex")?Math.round(pa.val("a")/255*100):100;z.paint.solidColor=pa.val("hex")?pa.val("hex"):"none";z.paint.radialGradient=null;ba()},null,function(){N()});var Lb=$(M+" .jGraduate_tabs li");Lb.click(function(){Lb.removeClass("jGraduate_tab_current");$(this).addClass("jGraduate_tab_current"); -$(M+" > div").hide();var pa=$(this).attr("data-type");$(M+" .jGraduate_gradPick").show();if(pa==="rg"||pa==="lg"){$(".jGraduate_"+pa+"_field").show();$(".jGraduate_"+(pa==="lg"?"rg":"lg")+"_field").hide();$("#"+q+"_jgraduate_rect")[0].setAttribute("fill","url(#"+q+"_"+pa+"_jgraduate_grad)");Na=pa==="lg"?"linearGradient":"radialGradient";$("#"+q+"_jGraduate_OpacInput").val(z.paint.alpha).change();var V=$("#"+q+"_"+pa+"_jgraduate_grad")[0];if(va!==V){var ua=$(va).find("stop");$(V).empty().append(ua); -va=V;V=Cb.val();va.setAttribute("spreadMethod",V)}lb=pa==="rg"&&va.getAttribute("fx")!=null&&!(Da==Fa&&Ma==Oa);$("#"+q+"_jGraduate_focusCoord").toggle(lb);if(lb)$("#"+q+"_jGraduate_match_ctr")[0].checked=false}else{$(M+" .jGraduate_gradPick").hide();$(M+" .jGraduate_colPick").show()}});$(M+" > div").hide();Lb.removeClass("jGraduate_tab_current");var Sb;switch(z.paint.type){case "linearGradient":Sb=$(M+" .jGraduate_tab_lingrad");break;case "radialGradient":Sb=$(M+" .jGraduate_tab_radgrad");break;default:Sb= -$(M+" .jGraduate_tab_color")}z.show();setTimeout(function(){Sb.addClass("jGraduate_tab_current").click()},10)}else alert("Container element must have an id attribute to maintain unique id strings for sub-elements.")})}})();$.fn.SpinButton=function(a){function H(h,i){for(var u=h[i],E=document.body;(h=h.offsetParent)&&h!=E;)if(!$.browser.msie||h.currentStyle.position!="relative")u+=h[i];return u}return this.each(function(){this.repeating=false;this.spinCfg={min:a&&!isNaN(parseFloat(a.min))?Number(a.min):null,max:a&&!isNaN(parseFloat(a.max))?Number(a.max):null,step:a&&a.step?Number(a.step):1,stepfunc:a&&a.stepfunc?a.stepfunc:false,page:a&&a.page?Number(a.page):10,upClass:a&&a.upClass?a.upClass:"up",downClass:a&&a.downClass? -a.downClass:"down",reset:a&&a.reset?a.reset:this.value,delay:a&&a.delay?Number(a.delay):500,interval:a&&a.interval?Number(a.interval):100,_btn_width:20,_direction:null,_delay:null,_repeat:null,callback:a&&a.callback?a.callback:null};this.spinCfg.smallStep=a&&a.smallStep?a.smallStep:this.spinCfg.step/2;this.adjustValue=function(h){h=isNaN(this.value)?this.spinCfg.reset:$.isFunction(this.spinCfg.stepfunc)?this.spinCfg.stepfunc(this,h):Number((Number(this.value)+Number(h)).toFixed(5));if(this.spinCfg.min!== -null)h=Math.max(h,this.spinCfg.min);if(this.spinCfg.max!==null)h=Math.min(h,this.spinCfg.max);this.value=h;$.isFunction(this.spinCfg.callback)&&this.spinCfg.callback(this)};$(this).addClass(a&&a.spinClass?a.spinClass:"spin-button").mousemove(function(h){var i=h.pageX||h.x,u=h.pageY||h.y;h=h.target||h.srcElement;var E=svgEditor.tool_scale||1,e=$(h).height()/2;i=i>H(h,"offsetLeft")+h.offsetWidth*E-this.spinCfg._btn_width?u<H(h,"offsetTop")+e*E?1:-1:0;if(i!==this.spinCfg._direction){switch(i){case 1:$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass); -break;case -1:$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);break;default:$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass)}this.spinCfg._direction=i}}).mouseout(function(){$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);this.spinCfg._direction=null;window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).mousedown(function(h){if(h.button===0&&this.spinCfg._direction!=0){var i=this, -u=h.shiftKey?i.spinCfg.smallStep:i.spinCfg.step,E=function(){i.adjustValue(i.spinCfg._direction*u)};E();i.spinCfg._delay=window.setTimeout(function(){E();i.spinCfg._repeat=window.setInterval(E,i.spinCfg.interval)},i.spinCfg.delay)}}).mouseup(function(){window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).dblclick(function(){$.browser.msie&&this.adjustValue(this.spinCfg._direction*this.spinCfg.step)}).keydown(function(h){switch(h.keyCode){case 38:this.adjustValue(this.spinCfg.step); -break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}}).keypress(function(h){if(this.repeating)switch(h.keyCode){case 38:this.adjustValue(this.spinCfg.step);break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}else this.repeating=true}).keyup(function(h){this.repeating=false;switch(h.keyCode){case 38:case 40:case 33:case 34:case 13:this.adjustValue(0)}}).bind("mousewheel", -function(h){if(h.wheelDelta>=120)this.adjustValue(this.spinCfg.step);else h.wheelDelta<=-120&&this.adjustValue(-this.spinCfg.step);h.preventDefault()}).change(function(){this.adjustValue(0)});this.addEventListener&&this.addEventListener("DOMMouseScroll",function(h){if(h.detail>0)this.adjustValue(-this.spinCfg.step);else h.detail<0&&this.adjustValue(this.spinCfg.step);h.preventDefault()},false)})};function touchHandler(a){var H=a.changedTouches,h=H[0],i="";switch(a.type){case "touchstart":i="mousedown";break;case "touchmove":i="mousemove";break;case "touchend":i="mouseup";break;default:return}var u=document.createEvent("MouseEvent");u.initMouseEvent(i,true,true,window,1,h.screenX,h.screenY,h.clientX,h.clientY,false,false,false,false,0,null);if(H.length<2){h.target.dispatchEvent(u);a.preventDefault()}};jQuery&&function(){var a=$(window),H=$(document);$.extend($.fn,{contextMenu:function(h,i){if(h.menu==undefined)return false;if(h.inSpeed==undefined)h.inSpeed=150;if(h.outSpeed==undefined)h.outSpeed=75;if(h.inSpeed==0)h.inSpeed=-1;if(h.outSpeed==0)h.outSpeed=-1;$(this).each(function(){var u=$(this),E=$(u).offset(),e=$("#"+h.menu);e.addClass("contextMenu");$(this).bind("mousedown",function(f){$(this).mouseup(function(g){var p=$(this);p.unbind("mouseup");$(".contextMenu").hide();if(f.button===2||h.allowLeft|| -f.ctrlKey&&svgedit.browser.isMac()){g.stopPropagation();if(u.hasClass("disabled"))return false;var z=g.pageX,D=g.pageY;g=a.width()-e.width();var q=a.height()-e.height();if(z>g-15)z=g-15;if(D>q-30)D=q-30;H.unbind("click");e.css({top:D,left:z}).fadeIn(h.inSpeed);e.find("A").mouseover(function(){e.find("LI.hover").removeClass("hover");$(this).parent().addClass("hover")}).mouseout(function(){e.find("LI.hover").removeClass("hover")});H.keypress(function(M){switch(M.keyCode){case 38:if(e.find("LI.hover").length){e.find("LI.hover").removeClass("hover").prevAll("LI:not(.disabled)").eq(0).addClass("hover"); -e.find("LI.hover").length||e.find("LI:last").addClass("hover")}else e.find("LI:last").addClass("hover");break;case 40:if(e.find("LI.hover").length==0)e.find("LI:first").addClass("hover");else{e.find("LI.hover").removeClass("hover").nextAll("LI:not(.disabled)").eq(0).addClass("hover");e.find("LI.hover").length||e.find("LI:first").addClass("hover")}break;case 13:e.find("LI.hover A").trigger("click");break;case 27:H.trigger("click")}});e.find("A").unbind("mouseup");e.find("LI:not(.disabled) A").mouseup(function(){H.unbind("click").unbind("keypress"); -$(".contextMenu").hide();i&&i($(this).attr("href").substr(1),$(p),{x:z-E.left,y:D-E.top,docX:z,docY:D});return false});setTimeout(function(){H.click(function(){H.unbind("click").unbind("keypress");e.fadeOut(h.outSpeed);return false})},0)}})});if($.browser.mozilla)$("#"+h.menu).each(function(){$(this).css({MozUserSelect:"none"})});else $.browser.msie?$("#"+h.menu).each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})}):$("#"+h.menu).each(function(){$(this).bind("mousedown.disableTextSelect", -function(){return false})});$(u).add($("UL.contextMenu")).bind("contextmenu",function(){return false})});return $(this)},disableContextMenuItems:function(h){if(h==undefined){$(this).find("LI").addClass("disabled");return $(this)}$(this).each(function(){if(h!=undefined)for(var i=h.split(","),u=0;u<i.length;u++)$(this).find('A[href="'+i[u]+'"]').parent().addClass("disabled")});return $(this)},enableContextMenuItems:function(h){if(h==undefined){$(this).find("LI.disabled").removeClass("disabled");return $(this)}$(this).each(function(){if(h!= -undefined)for(var i=h.split(","),u=0;u<i.length;u++)$(this).find('A[href="'+i[u]+'"]').parent().removeClass("disabled")});return $(this)},disableContextMenu:function(){$(this).each(function(){$(this).addClass("disabled")});return $(this)},enableContextMenu:function(){$(this).each(function(){$(this).removeClass("disabled")});return $(this)},destroyContextMenu:function(){$(this).each(function(){$(this).unbind("mousedown").unbind("mouseup")});return $(this)}})}(jQuery);var svgedit=svgedit||{}; -(function(){if(!svgedit.browser)svgedit.browser={};var a=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect;svgedit.browser.supportsSvg=function(){return a};if(svgedit.browser.supportsSvg()){var H=navigator.userAgent,h=document.createElementNS("http://www.w3.org/2000/svg","svg"),i=!!window.opera,u=H.indexOf("AppleWebKit")>=0,E=H.indexOf("Gecko/")>=0,e=H.indexOf("MSIE")>=0,f=H.indexOf("Chrome/")>=0,g=H.indexOf("Windows")>=0,p=H.indexOf("Macintosh")>= -0,z="ontouchstart"in window,D=!!h.querySelector,q=!!document.evaluate,M=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","path");qa.setAttribute("d","M0,0 10,10");var ga=qa.pathSegList;qa=qa.createSVGPathSegLinetoAbs(5,5);try{ga.replaceItem(qa,0);return true}catch(Na){}return false}(),ba=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","path");qa.setAttribute("d","M0,0 10,10");var ga=qa.pathSegList;qa=qa.createSVGPathSegLinetoAbs(5,5);try{ga.insertItemBefore(qa, -0);return true}catch(Na){}return false}(),N=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","svg"),ga=document.createElementNS("http://www.w3.org/2000/svg","svg");document.documentElement.appendChild(qa);ga.setAttribute("x",5);qa.appendChild(ga);var Na=document.createElementNS("http://www.w3.org/2000/svg","text");Na.textContent="a";ga.appendChild(Na);ga=Na.getStartPositionOfChar(0).x;document.documentElement.removeChild(qa);return ga===0}(),I=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg", -"svg");document.documentElement.appendChild(qa);var ga=document.createElementNS("http://www.w3.org/2000/svg","path");ga.setAttribute("d","M0,0 C0,0 10,10 10,0");qa.appendChild(ga);ga=ga.getBBox();document.documentElement.removeChild(qa);return ga.height>4&&ga.height<5}(),ma=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","svg");document.documentElement.appendChild(qa);var ga=document.createElementNS("http://www.w3.org/2000/svg","path");ga.setAttribute("d","M0,0 10,0");var Na= -document.createElementNS("http://www.w3.org/2000/svg","path");Na.setAttribute("d","M5,0 15,0");var va=document.createElementNS("http://www.w3.org/2000/svg","g");va.appendChild(ga);va.appendChild(Na);qa.appendChild(va);ga=va.getBBox();document.documentElement.removeChild(qa);return ga.width==15}(),ia=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","rect");qa.setAttribute("x",0.1);(qa=qa.cloneNode(false).getAttribute("x").indexOf(",")==-1)||$.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\t\tPlease upgrade to the <a href='http://opera.com'>latest version</a> in which the problems have been fixed."); -return qa}(),ka=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","rect");qa.setAttribute("style","vector-effect:non-scaling-stroke");return qa.style.vectorEffect==="non-scaling-stroke"}(),X=function(){var qa=document.createElementNS("http://www.w3.org/2000/svg","rect").transform.baseVal,ga=h.createSVGTransform();qa.appendItem(ga);return qa.getItem(0)==ga}();svgedit.browser.isOpera=function(){return i};svgedit.browser.isWebkit=function(){return u};svgedit.browser.isGecko=function(){return E}; -svgedit.browser.isIE=function(){return e};svgedit.browser.isChrome=function(){return f};svgedit.browser.isWindows=function(){return g};svgedit.browser.isMac=function(){return p};svgedit.browser.isTouch=function(){return z};svgedit.browser.supportsSelectors=function(){return D};svgedit.browser.supportsXpath=function(){return q};svgedit.browser.supportsPathReplaceItem=function(){return M};svgedit.browser.supportsPathInsertItemBefore=function(){return ba};svgedit.browser.supportsPathBBox=function(){return I}; -svgedit.browser.supportsHVLineContainerBBox=function(){return ma};svgedit.browser.supportsGoodTextCharPos=function(){return N};svgedit.browser.supportsEditableText=function(){return i};svgedit.browser.supportsGoodDecimals=function(){return ia};svgedit.browser.supportsNonScalingStroke=function(){return ka};svgedit.browser.supportsNativeTransformLists=function(){return X}}else window.location="browser-not-supported.html"})();svgedit=svgedit||{}; -(function(){if(!svgedit.transformlist)svgedit.transformlist={};var a=document.createElementNS("http://www.w3.org/2000/svg","svg"),H={};svgedit.transformlist.SVGTransformList=function(h){this._elem=h||null;this._xforms=[];this._update=function(){var i="";a.createSVGMatrix();for(var u=0;u<this.numberOfItems;++u){var E=this._list.getItem(u);i=i;E=E;var e=E.matrix,f="";switch(E.type){case 1:f="matrix("+[e.a,e.b,e.c,e.d,e.e,e.f].join(",")+")";break;case 2:f="translate("+e.e+","+e.f+")";break;case 3:f= -e.a==e.d?"scale("+e.a+")":"scale("+e.a+","+e.d+")";break;case 4:var g=0;f=0;if(E.angle!=0){g=1-e.a;f=(g*e.f+e.b*e.e)/(g*g+e.b*e.b);g=(e.e-e.b*f)/g}f="rotate("+E.angle+" "+g+","+f+")"}i=i+(f+" ")}this._elem.setAttribute("transform",i)};this._list=this;this._init=function(){var i=this._elem.getAttribute("transform");if(i)for(var u=/\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/,E=true;E;){E=i.match(u);i=i.replace(u,"");if(E&&E[1]){var e=E[1].split(/\s*\(/),f=e[0];e=e[1].match(/\s*(.*?)\s*\)/); -e[1]=e[1].replace(/(\d)-/g,"$1 -");var g=e[1].split(/[, ]+/),p="abcdef".split(""),z=a.createSVGMatrix();$.each(g,function(M,ba){g[M]=parseFloat(ba);if(f=="matrix")z[p[M]]=g[M]});e=a.createSVGTransform();var D="set"+f.charAt(0).toUpperCase()+f.slice(1),q=f=="matrix"?[z]:g;if(f=="scale"&&q.length==1)q.push(q[0]);else if(f=="translate"&&q.length==1)q.push(0);else if(f=="rotate"&&q.length==1){q.push(0);q.push(0)}e[D].apply(e,q);this._list.appendItem(e)}}};this._removeFromOtherLists=function(i){if(i){var u= -false,E;for(E in H){for(var e=H[E],f=0,g=e._xforms.length;f<g;++f)if(e._xforms[f]==i){u=true;e.removeItem(f);break}if(u)break}}};this.numberOfItems=0;this.clear=function(){this.numberOfItems=0;this._xforms=[]};this.initialize=function(i){this.numberOfItems=1;this._removeFromOtherLists(i);this._xforms=[i]};this.getItem=function(i){if(i<this.numberOfItems&&i>=0)return this._xforms[i];throw{code:1};};this.insertItemBefore=function(i,u){var E=null;if(u>=0)if(u<this.numberOfItems){this._removeFromOtherLists(i); -E=Array(this.numberOfItems+1);for(var e=0;e<u;++e)E[e]=this._xforms[e];E[e]=i;for(var f=e+1;e<this.numberOfItems;++f,++e)E[f]=this._xforms[e];this.numberOfItems++;this._xforms=E;E=i;this._list._update()}else E=this._list.appendItem(i);return E};this.replaceItem=function(i,u){var E=null;if(u<this.numberOfItems&&u>=0){this._removeFromOtherLists(i);E=this._xforms[u]=i;this._list._update()}return E};this.removeItem=function(i){if(i<this.numberOfItems&&i>=0){for(var u=this._xforms[i],E=Array(this.numberOfItems- -1),e=0;e<i;++e)E[e]=this._xforms[e];for(i=e;i<this.numberOfItems-1;++i,++e)E[i]=this._xforms[e+1];this.numberOfItems--;this._xforms=E;this._list._update();return u}else throw{code:1};};this.appendItem=function(i){this._removeFromOtherLists(i);this._xforms.push(i);this.numberOfItems++;this._list._update();return i}};svgedit.transformlist.resetListMap=function(){H={}};svgedit.transformlist.removeElementFromListMap=function(h){h.id&&H[h.id]&&delete H[h.id]};svgedit.transformlist.getTransformList=function(h){if(svgedit.browser.supportsNativeTransformLists())if(h.transform)return h.transform.baseVal; -else if(h.gradientTransform)return h.gradientTransform.baseVal;else{if(h.patternTransform)return h.patternTransform.baseVal}else{var i=h.id;i||(i="temp");var u=H[i];if(!u||i=="temp"){H[i]=new svgedit.transformlist.SVGTransformList(h);H[i]._init();u=H[i]}return u}return null}})();svgedit=svgedit||{}; -(function(){if(!svgedit.math)svgedit.math={};var a=document.createElementNS("http://www.w3.org/2000/svg","svg");svgedit.math.transformPoint=function(H,h,i){return{x:i.a*H+i.c*h+i.e,y:i.b*H+i.d*h+i.f}};svgedit.math.isIdentity=function(H){return H.a===1&&H.b===0&&H.c===0&&H.d===1&&H.e===0&&H.f===0};svgedit.math.matrixMultiply=function(){for(var H=arguments,h=H.length,i=H[h-1];h-- >1;)i=H[h-1].multiply(i);if(Math.abs(i.a)<1.0E-14)i.a=0;if(Math.abs(i.b)<1.0E-14)i.b=0;if(Math.abs(i.c)<1.0E-14)i.c=0;if(Math.abs(i.d)< -1.0E-14)i.d=0;if(Math.abs(i.e)<1.0E-14)i.e=0;if(Math.abs(i.f)<1.0E-14)i.f=0;return i};svgedit.math.hasMatrixTransform=function(H){if(!H)return false;for(var h=H.numberOfItems;h--;){var i=H.getItem(h);if(i.type==1&&!svgedit.math.isIdentity(i.matrix))return true}return false};svgedit.math.transformBox=function(H,h,i,u,E){var e={x:H,y:h},f={x:H+i,y:h};i={x:H+i,y:h+u};H={x:H,y:h+u};h=svgedit.math.transformPoint;e=h(e.x,e.y,E);var g=u=e.x,p=e.y,z=e.y;f=h(f.x,f.y,E);u=Math.min(u,f.x);g=Math.max(g,f.x); -p=Math.min(p,f.y);z=Math.max(z,f.y);H=h(H.x,H.y,E);u=Math.min(u,H.x);g=Math.max(g,H.x);p=Math.min(p,H.y);z=Math.max(z,H.y);i=h(i.x,i.y,E);u=Math.min(u,i.x);g=Math.max(g,i.x);p=Math.min(p,i.y);z=Math.max(z,i.y);return{tl:e,tr:f,bl:H,br:i,aabox:{x:u,y:p,width:g-u,height:z-p}}};svgedit.math.transformListToTransform=function(H,h,i){if(H==null)return a.createSVGTransformFromMatrix(a.createSVGMatrix());h=h==undefined?0:h;i=i==undefined?H.numberOfItems-1:i;h=parseInt(h);i=parseInt(i);if(h>i){var u=i;i=h; -h=u}u=a.createSVGMatrix();for(h=h;h<=i;++h){var E=h>=0&&h<H.numberOfItems?H.getItem(h).matrix:a.createSVGMatrix();u=svgedit.math.matrixMultiply(u,E)}return a.createSVGTransformFromMatrix(u)};svgedit.math.getMatrix=function(H){H=svgedit.transformlist.getTransformList(H);return svgedit.math.transformListToTransform(H).matrix};svgedit.math.snapToAngle=function(H,h,i,u){var E=Math.PI/4;i=i-H;var e=u-h;u=Math.sqrt(i*i+e*e);E=Math.round(Math.atan2(e,i)/E)*E;return{x:H+u*Math.cos(E),y:h+u*Math.sin(E),a:E}}; -svgedit.math.rectsIntersect=function(H,h){return h.x<H.x+H.width&&h.x+h.width>H.x&&h.y<H.y+H.height&&h.y+h.height>H.y}})();svgedit=svgedit||{}; -(function(){if(!svgedit.units)svgedit.units={};var a=["x","x1","cx","rx","width"],H=["y","y1","cy","ry","height"],h=$.merge(["r","radius"],a);$.merge(h,H);var i,u={px:1};svgedit.units.init=function(e){i=e;e=document.createElementNS("http://www.w3.org/2000/svg","svg");document.body.appendChild(e);var f=document.createElementNS("http://www.w3.org/2000/svg","rect");f.setAttribute("width","1em");f.setAttribute("height","1ex");f.setAttribute("x","1in");e.appendChild(f);f=f.getBBox();document.body.removeChild(e); -e=f.x;u.em=f.width;u.ex=f.height;u["in"]=e;u.cm=e/2.54;u.mm=e/25.4;u.pt=e/72;u.pc=e/6;u["%"]=0};svgedit.units.getTypeMap=function(){return u};svgedit.units.shortFloat=function(e){var f=i.getRoundDigits();if(isNaN(e)){if($.isArray(e))return svgedit.units.shortFloat(e[0])+","+svgedit.units.shortFloat(e[1])}else return+(+e).toFixed(f);return parseFloat(e).toFixed(f)-0};svgedit.units.convertUnit=function(e,f){f=f||i.getBaseUnit();return svgedit.unit.shortFloat(e/u[f])};svgedit.units.setUnitAttr=function(e, -f,g){isNaN(g)||e.getAttribute(f);e.setAttribute(f,g)};var E={line:["x1","x2","y1","y2"],circle:["cx","cy","r"],ellipse:["cx","cy","rx","ry"],foreignObject:["x","y","width","height"],rect:["x","y","width","height"],image:["x","y","width","height"],use:["x","y","width","height"],text:["x","y"]};svgedit.units.convertAttrs=function(e){var f=e.tagName,g=i.getBaseUnit();if(f=E[f])for(var p=f.length,z=0;z<p;z++){var D=f[z],q=e.getAttribute(D);if(q)isNaN(q)||e.setAttribute(D,q/u[g]+g)}};svgedit.units.convertToNum= -function(e,f){if(!isNaN(f))return f-0;if(f.substr(-1)==="%"){var g=f.substr(0,f.length-1)/100,p=i.getWidth(),z=i.getHeight();return a.indexOf(e)>=0?g*p:H.indexOf(e)>=0?g*z:g*Math.sqrt(p*p+z*z)/Math.sqrt(2)}else{p=f.substr(-2);g=f.substr(0,f.length-2);return g*u[p]}};svgedit.units.isValidUnit=function(e,f,g){var p=false;if(h.indexOf(e)>=0)if(isNaN(f)){f=f.toLowerCase();$.each(u,function(q){if(!p)if(RegExp("^-?[\\d\\.]+"+q+"$").test(f))p=true})}else p=true;else if(e=="id"){e=false;try{var z=i.getElement(f); -e=z==null||z===g}catch(D){}return e}else p=true;return p}})();svgedit=svgedit||{}; -(function(){function a(e){if(svgedit.browser.supportsHVLineContainerBBox())try{return e.getBBox()}catch(f){}var g=$.data(e,"ref"),p=null;if(g){var z=$(g).children().clone().attr("visibility","hidden");$(E).append(z);p=z.filter("line, path")}else p=$(e).find("line, path");var D=false;if(p.length){p.each(function(){var q=this.getBBox();if(!q.width||!q.height)D=true});if(D){e=g?z:$(e).children();ret=getStrokedBBox(e)}else ret=e.getBBox()}else ret=e.getBBox();g&&z.remove();return ret}if(!svgedit.utilities)svgedit.utilities= -{};var H="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use".split(","),h=null,i=null,u=null,E=null;svgedit.utilities.init=function(e){h=e;i=e.getDOMDocument();u=e.getDOMContainer();E=e.getSVGRoot()};svgedit.utilities.toXml=function(e){return $("<p/>").text(e).html()};svgedit.utilities.fromXml=function(e){return $("<p/>").html(e).text()};svgedit.utilities.encode64=function(e){e=svgedit.utilities.convertToXMLReferences(e);if(window.btoa)return window.btoa(e); -var f=Array(Math.floor((e.length+2)/3)*4),g,p,z,D,q,M,ba=0,N=0;do{g=e.charCodeAt(ba++);p=e.charCodeAt(ba++);z=e.charCodeAt(ba++);D=g>>2;g=(g&3)<<4|p>>4;q=(p&15)<<2|z>>6;M=z&63;if(isNaN(p))q=M=64;else if(isNaN(z))M=64;f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(D);f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(g);f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(q);f[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(M)}while(ba< -e.length);return f.join("")};svgedit.utilities.decode64=function(e){if(window.atob)return window.atob(e);var f="",g,p,z="",D,q="",M=0;e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{g="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++));p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++));D="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++));q="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(e.charAt(M++)); -g=g<<2|p>>4;p=(p&15)<<4|D>>2;z=(D&3)<<6|q;f+=String.fromCharCode(g);if(D!=64)f+=String.fromCharCode(p);if(q!=64)f+=String.fromCharCode(z)}while(M<e.length);return unescape(f)};svgedit.utilities.convertToXMLReferences=function(e){for(var f="",g=0;g<e.length;g++){var p=e.charCodeAt(g);if(p<128)f+=e[g];else if(p>127)f+="&#"+p+";"}return f};svgedit.utilities.text2xml=function(e){if(e.indexOf("<svg:svg")>=0)e=e.replace(/<(\/?)svg:/g,"<$1").replace("xmlns:svg","xmlns");var f;try{var g=window.DOMParser? -new DOMParser:new ActiveXObject("Microsoft.XMLDOM");g.async=false}catch(p){throw Error("XML Parser could not be instantiated");}try{f=g.loadXML?g.loadXML(e)?g:false:g.parseFromString(e,"text/xml")}catch(z){throw Error("Error parsing XML string");}return f};svgedit.utilities.bboxToObj=function(e){return{x:e.x,y:e.y,width:e.width,height:e.height}};svgedit.utilities.walkTree=function(e,f){if(e&&e.nodeType==1){f(e);for(var g=e.childNodes.length;g--;)svgedit.utilities.walkTree(e.childNodes.item(g),f)}}; -svgedit.utilities.walkTreePost=function(e,f){if(e&&e.nodeType==1){for(var g=e.childNodes.length;g--;)svgedit.utilities.walkTree(e.childNodes.item(g),f);f(e)}};svgedit.utilities.getUrlFromAttr=function(e){if(e)if(e.indexOf('url("')===0)return e.substring(5,e.indexOf('"',6));else if(e.indexOf("url('")===0)return e.substring(5,e.indexOf("'",6));else if(e.indexOf("url(")===0)return e.substring(4,e.indexOf(")"));return null};svgedit.utilities.getHref=function(e){return e.getAttributeNS("http://www.w3.org/1999/xlink", -"href")};svgedit.utilities.setHref=function(e,f){e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",f)};svgedit.utilities.findDefs=function(e){e=h.getSVGContent().documentElement;var f=e.getElementsByTagNameNS("http://www.w3.org/2000/svg","defs");return f=f.length>0?f[0]:e.insertBefore(e.ownerDocument.createElementNS("http://www.w3.org/2000/svg","defs"),e.firstChild.nextSibling)};svgedit.utilities.getPathBBox=function(e){var f=e.pathSegList,g=f.numberOfItems;e=[[],[]];var p=f.getItem(0), -z=[p.x,p.y];for(p=0;p<g;p++){var D=f.getItem(p);if(typeof D.x!="undefined"){e[0].push(z[0]);e[1].push(z[1]);if(D.x1){for(var q=[D.x1,D.y1],M=[D.x2,D.y2],ba=[D.x,D.y],N=0;N<2;N++){D=function(X){return Math.pow(1-X,3)*z[N]+3*Math.pow(1-X,2)*X*q[N]+3*(1-X)*Math.pow(X,2)*M[N]+Math.pow(X,3)*ba[N]};var I=6*z[N]-12*q[N]+6*M[N],ma=-3*z[N]+9*q[N]-9*M[N]+3*ba[N],ia=3*q[N]-3*z[N];if(ma==0){if(I!=0){I=-ia/I;0<I&&I<1&&e[N].push(D(I))}}else{ia=Math.pow(I,2)-4*ia*ma;if(!(ia<0)){var ka=(-I+Math.sqrt(ia))/(2*ma); -0<ka&&ka<1&&e[N].push(D(ka));I=(-I-Math.sqrt(ia))/(2*ma);0<I&&I<1&&e[N].push(D(I))}}}z=ba}else{e[0].push(D.x);e[1].push(D.y)}}}f=Math.min.apply(null,e[0]);g=Math.max.apply(null,e[0])-f;p=Math.min.apply(null,e[1]);e=Math.max.apply(null,e[1])-p;return{x:f,y:p,width:g,height:e}};svgedit.utilities.getBBox=function(e){var f=e||h.geSelectedElements()[0];if(e.nodeType!=1)return null;e=null;var g=f.nodeName;switch(g){case "text":if(f.textContent===""){f.textContent="a";e=f.getBBox();f.textContent=""}else try{e= -f.getBBox()}catch(p){}break;case "path":if(svgedit.browser.supportsPathBBox())try{e=f.getBBox()}catch(z){}else e=svgedit.utilities.getPathBBox(f);break;case "g":case "a":e=a(f);break;default:if(g==="use")e=a(f,true);if(g==="use"){e||(e=f.getBBox());if(!svgedit.browser.isWebkit()){g={};g.width=e.width;g.height=e.height;g.x=e.x+parseFloat(f.getAttribute("x")||0);g.y=e.y+parseFloat(f.getAttribute("y")||0);e=g}}else if(~H.indexOf(g))try{e=f.getBBox()}catch(D){f=$(f).closest("foreignObject");if(f.length)try{e= -f[0].getBBox()}catch(q){e=null}else e=null}}if(e)e=svgedit.utilities.bboxToObj(e);return e};svgedit.utilities.getRotationAngle=function(e,f){var g=e||h.getSelectedElements()[0];g=svgedit.transformlist.getTransformList(g);if(!g)return 0;for(var p=g.numberOfItems,z=0;z<p;++z){var D=g.getItem(z);if(D.type==4)return f?D.angle*Math.PI/180:D.angle}return 0};svgedit.utilities.getElem=svgedit.browser.supportsSelectors()?function(e){return E.querySelector("#"+e)}:svgedit.browser.supportsXpath()?function(e){return i.evaluate('svg:svg[@id="svgroot"]//svg:*[@id="'+ -e+'"]',u,function(){return"http://www.w3.org/2000/svg"},9,null).singleNodeValue}:function(e){return $(E).find("[id="+e+"]")[0]};svgedit.utilities.assignAttributes=function(e,f,g,p){g||(g=0);svgedit.browser.isOpera()||E.suspendRedraw(g);for(var z in f)if(g=z.substr(0,4)==="xml:"?"http://www.w3.org/XML/1998/namespace":z.substr(0,6)==="xlink:"?"http://www.w3.org/1999/xlink":null)e.setAttributeNS(g,z,f[z]);else p?svgedit.units.setUnitAttr(e,z,f[z]):e.setAttribute(z,f[z]);svgedit.browser.isOpera()||E.unsuspendRedraw(null)}; -svgedit.utilities.cleanupElement=function(e){var f=E.suspendRedraw(60),g={"fill-opacity":1,"stop-opacity":1,opacity:1,stroke:"none","stroke-dasharray":"none","stroke-linejoin":"miter","stroke-linecap":"butt","stroke-opacity":1,"stroke-width":1,rx:0,ry:0},p;for(p in g){var z=g[p];e.getAttribute(p)==z&&e.removeAttribute(p)}E.unsuspendRedraw(f)}})();svgedit=svgedit||{}; -(function(){if(!svgedit.sanitize)svgedit.sanitize={};var a={};a["http://www.w3.org/1999/xlink"]="xlink";a["http://www.w3.org/XML/1998/namespace"]="xml";a["http://www.w3.org/2000/xmlns/"]="xmlns";a["http://svg-edit.googlecode.com"]="se";a["http://www.w3.org/1999/xhtml"]="xhtml";a["http://www.w3.org/1998/Math/MathML"]="mathml";var H={};$.each(a,function(u,E){H[E]=u});var h={a:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","id","mask","opacity","stroke","stroke-dasharray", -"stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","xlink:href","xlink:title"],circle:["class","clip-path","clip-rule","cx","cy","fill","fill-opacity","fill-rule","filter","id","mask","opacity","r","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],clipPath:["class", -"clipPathUnits","id"],defs:[],style:["type"],desc:[],ellipse:["class","clip-path","clip-rule","cx","cy","fill","fill-opacity","fill-rule","filter","id","mask","opacity","requiredFeatures","rx","ry","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],feGaussianBlur:["class","color-interpolation-filters","id","requiredFeatures","stdDeviation"],filter:["class","color-interpolation-filters", -"filterRes","filterUnits","height","id","primitiveUnits","requiredFeatures","width","x","xlink:href","y"],foreignObject:["class","font-size","height","id","opacity","requiredFeatures","style","transform","width","x","y"],g:["class","clip-path","clip-rule","id","display","fill","fill-opacity","fill-rule","filter","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage", -"transform","font-family","font-size","font-style","font-weight","text-anchor"],image:["class","clip-path","clip-rule","filter","height","id","mask","opacity","requiredFeatures","style","systemLanguage","transform","width","x","xlink:href","xlink:title","y"],line:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","id","marker-end","marker-mid","marker-start","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin", -"stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","x1","x2","y1","y2"],linearGradient:["class","id","gradientTransform","gradientUnits","requiredFeatures","spreadMethod","systemLanguage","x1","x2","xlink:href","y1","y2"],marker:["id","class","markerHeight","markerUnits","markerWidth","orient","preserveAspectRatio","refX","refY","systemLanguage","viewBox"],mask:["class","height","id","maskContentUnits","maskUnits","width","x","y"],metadata:["class","id"],path:["class", -"clip-path","clip-rule","d","fill","fill-opacity","fill-rule","filter","id","marker-end","marker-mid","marker-start","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],pattern:["class","height","id","patternContentUnits","patternTransform","patternUnits","requiredFeatures","style","systemLanguage","viewBox","width","x","xlink:href","y"],polygon:["class", -"clip-path","clip-rule","id","fill","fill-opacity","fill-rule","filter","id","class","marker-end","marker-mid","marker-start","mask","opacity","points","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],polyline:["class","clip-path","clip-rule","id","fill","fill-opacity","fill-rule","filter","marker-end","marker-mid","marker-start","mask","opacity","points", -"requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],radialGradient:["class","cx","cy","fx","fy","gradientTransform","gradientUnits","id","r","requiredFeatures","spreadMethod","systemLanguage","xlink:href"],rect:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","height","id","mask","opacity","requiredFeatures","rx","ry","stroke","stroke-dasharray", -"stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","width","x","y"],stop:["class","id","offset","requiredFeatures","stop-color","stop-opacity","style","systemLanguage"],svg:["class","clip-path","clip-rule","filter","id","height","mask","preserveAspectRatio","requiredFeatures","style","systemLanguage","viewBox","width","x","xmlns","xmlns:se","xmlns:xlink","y"],"switch":["class","id","requiredFeatures","systemLanguage"], -symbol:["class","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight","id","opacity","preserveAspectRatio","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","viewBox"],text:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight","id","mask","opacity", -"requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","text-anchor","transform","x","xml:space","y"],textPath:["class","id","method","requiredFeatures","spacing","startOffset","style","systemLanguage","transform","xlink:href"],title:[],tspan:["class","clip-path","clip-rule","dx","dy","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight", -"id","mask","opacity","requiredFeatures","rotate","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","text-anchor","textLength","transform","x","xml:space","y"],use:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","height","id","mask","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width", -"style","transform","width","x","xlink:href","y"],annotation:["encoding"],"annotation-xml":["encoding"],maction:["actiontype","other","selection"],math:["class","id","display","xmlns"],menclose:["notation"],merror:[],mfrac:["linethickness"],mi:["mathvariant"],mmultiscripts:[],mn:[],mo:["fence","lspace","maxsize","minsize","rspace","stretchy"],mover:[],mpadded:["lspace","width","height","depth","voffset"],mphantom:[],mprescripts:[],mroot:[],mrow:["xlink:href","xlink:type","xmlns:xlink"],mspace:["depth", -"height","width"],msqrt:[],mstyle:["displaystyle","mathbackground","mathcolor","mathvariant","scriptlevel"],msub:[],msubsup:[],msup:[],mtable:["align","columnalign","columnlines","columnspacing","displaystyle","equalcolumns","equalrows","frame","rowalign","rowlines","rowspacing","width"],mtd:["columnalign","columnspan","rowalign","rowspan"],mtext:[],mtr:["columnalign","rowalign"],munder:[],munderover:[],none:[],semantics:[]},i={};$.each(h,function(u,E){var e={};$.each(E,function(f,g){if(g.indexOf(":")>= -0){var p=g.split(":");e[p[1]]=H[p[0]]}else e[g]=g=="xmlns"?"http://www.w3.org/2000/xmlns/":null});i[u]=e});svgedit.sanitize.getNSMap=function(){return a};svgedit.sanitize.sanitizeSvg=function(u){if(u.nodeType==3){u.nodeValue=u.nodeValue.replace(/^\s+|\s+$/g,"");u.nodeValue.length||u.parentNode.removeChild(u)}if(u.nodeType==1){var E=u.parentNode;if(u.ownerDocument&&E){var e=h[u.nodeName],f=i[u.nodeName];if(e!=undefined){for(var g=[],p=u.attributes.length;p--;){var z=u.attributes.item(p),D=z.nodeName, -q=z.localName,M=z.namespaceURI;if(!(f.hasOwnProperty(q)&&M==f[q]&&M!="http://www.w3.org/2000/xmlns/")&&!(M=="http://www.w3.org/2000/xmlns/"&&a[z.nodeValue])){D.indexOf("se:")==0&&g.push([D,z.nodeValue]);u.removeAttributeNS(M,q)}if(svgedit.browser.isGecko())switch(D){case "transform":case "gradientTransform":case "patternTransform":q=z.nodeValue.replace(/(\d)-/g,"$1 -");u.setAttribute(D,q)}if(D=="style"){z=z.nodeValue.split(";");for(D=z.length;D--;){q=z[D].split(":");e.indexOf(q[0])>=0&&u.setAttribute(q[0], -q[1])}u.removeAttribute("style")}}$.each(g,function(ba,N){u.setAttributeNS("http://svg-edit.googlecode.com",N[0],N[1])});if((p=svgedit.utilities.getHref(u))&&["filter","linearGradient","pattern","radialGradient","textPath","use"].indexOf(u.nodeName)>=0)if(p[0]!="#"){svgedit.utilities.setHref(u,"");u.removeAttributeNS("http://www.w3.org/1999/xlink","href")}if(u.nodeName=="use"&&!svgedit.utilities.getHref(u))E.removeChild(u);else{$.each(["clip-path","fill","filter","marker-end","marker-mid","marker-start", -"mask","stroke"],function(ba,N){var I=u.getAttribute(N);if(I)if((I=svgedit.utilities.getUrlFromAttr(I))&&I[0]!=="#"){u.setAttribute(N,"");u.removeAttribute(N)}});for(p=u.childNodes.length;p--;)svgedit.sanitize.sanitizeSvg(u.childNodes.item(p))}}else{for(e=[];u.hasChildNodes();)e.push(E.insertBefore(u.firstChild,u));E.removeChild(u);for(p=e.length;p--;)svgedit.sanitize.sanitizeSvg(e[p])}}}}})();svgedit=svgedit||{}; -(function(){if(!svgedit.history)svgedit.history={};svgedit.history.HistoryEventTypes={BEFORE_APPLY:"before_apply",AFTER_APPLY:"after_apply",BEFORE_UNAPPLY:"before_unapply",AFTER_UNAPPLY:"after_unapply"};svgedit.history.MoveElementCommand=function(a,H,h,i){this.elem=a;this.text=i?"Move "+a.tagName+" to "+i:"Move "+a.tagName;this.oldNextSibling=H;this.oldParent=h;this.newNextSibling=a.nextSibling;this.newParent=a.parentNode};svgedit.history.MoveElementCommand.type=function(){return"svgedit.history.MoveElementCommand"};svgedit.history.MoveElementCommand.prototype.type= -svgedit.history.MoveElementCommand.type;svgedit.history.MoveElementCommand.prototype.getText=function(){return this.text};svgedit.history.MoveElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);this.elem=this.newParent.insertBefore(this.elem,this.newNextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.MoveElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, -this);this.elem=this.oldParent.insertBefore(this.elem,this.oldNextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.MoveElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.InsertElementCommand=function(a,H){this.elem=a;this.text=H||"Create "+a.tagName;this.parent=a.parentNode;this.nextSibling=this.elem.nextSibling};svgedit.history.InsertElementCommand.type=function(){return"svgedit.history.InsertElementCommand"};svgedit.history.InsertElementCommand.prototype.type= -svgedit.history.InsertElementCommand.type;svgedit.history.InsertElementCommand.prototype.getText=function(){return this.text};svgedit.history.InsertElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);this.elem=this.parent.insertBefore(this.elem,this.nextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.InsertElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, -this);this.parent=this.elem.parentNode;this.elem=this.elem.parentNode.removeChild(this.elem);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.InsertElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.RemoveElementCommand=function(a,H,h,i){this.elem=a;this.text=i||"Delete "+a.tagName;this.nextSibling=H;this.parent=h;svgedit.transformlist.removeElementFromListMap(a)};svgedit.history.RemoveElementCommand.type=function(){return"svgedit.history.RemoveElementCommand"}; -svgedit.history.RemoveElementCommand.prototype.type=svgedit.history.RemoveElementCommand.type;svgedit.history.RemoveElementCommand.prototype.getText=function(){return this.text};svgedit.history.RemoveElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);svgedit.transformlist.removeElementFromListMap(this.elem);this.parent=this.elem.parentNode;this.elem=this.parent.removeChild(this.elem);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, -this)};svgedit.history.RemoveElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);svgedit.transformlist.removeElementFromListMap(this.elem);this.nextSibling==null&&window.console&&console.log("Error: reference element was lost");this.parent.insertBefore(this.elem,this.nextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.RemoveElementCommand.prototype.elements=function(){return[this.elem]}; -svgedit.history.ChangeElementCommand=function(a,H,h){this.elem=a;this.text=h?"Change "+a.tagName+" "+h:"Change "+a.tagName;this.newValues={};this.oldValues=H;for(var i in H)this.newValues[i]=i=="#text"?a.textContent:i=="#href"?svgedit.utilities.getHref(a):a.getAttribute(i)};svgedit.history.ChangeElementCommand.type=function(){return"svgedit.history.ChangeElementCommand"};svgedit.history.ChangeElementCommand.prototype.type=svgedit.history.ChangeElementCommand.type;svgedit.history.ChangeElementCommand.prototype.getText= -function(){return this.text};svgedit.history.ChangeElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);var H=false,h;for(h in this.newValues){if(this.newValues[h])if(h=="#text")this.elem.textContent=this.newValues[h];else h=="#href"?svgedit.utilities.setHref(this.elem,this.newValues[h]):this.elem.setAttribute(h,this.newValues[h]);else if(h=="#text")this.elem.textContent="";else{this.elem.setAttribute(h,"");this.elem.removeAttribute(h)}if(h== -"transform")H=true}if(!H)if(H=svgedit.utilities.getRotationAngle(this.elem)){h=elem.getBBox();H=["rotate(",H," ",h.x+h.width/2,",",h.y+h.height/2,")"].join("");H!=elem.getAttribute("transform")&&elem.setAttribute("transform",H)}a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this);return true};svgedit.history.ChangeElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);var H=false,h;for(h in this.oldValues){if(this.oldValues[h])if(h== -"#text")this.elem.textContent=this.oldValues[h];else h=="#href"?svgedit.utilities.setHref(this.elem,this.oldValues[h]):this.elem.setAttribute(h,this.oldValues[h]);else if(h=="#text")this.elem.textContent="";else this.elem.removeAttribute(h);if(h=="transform")H=true}if(!H)if(H=svgedit.utilities.getRotationAngle(this.elem)){h=elem.getBBox();H=["rotate(",H," ",h.x+h.width/2,",",h.y+h.height/2,")"].join("");H!=elem.getAttribute("transform")&&elem.setAttribute("transform",H)}svgedit.transformlist.removeElementFromListMap(this.elem); -a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this);return true};svgedit.history.ChangeElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.BatchCommand=function(a){this.text=a||"Batch Command";this.stack=[]};svgedit.history.BatchCommand.type=function(){return"svgedit.history.BatchCommand"};svgedit.history.BatchCommand.prototype.type=svgedit.history.BatchCommand.type;svgedit.history.BatchCommand.prototype.getText=function(){return this.text};svgedit.history.BatchCommand.prototype.apply= -function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);for(var H=this.stack.length,h=0;h<H;++h)this.stack[h].apply(a);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.BatchCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);for(var H=this.stack.length-1;H>=0;H--)this.stack[H].unapply(a);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, -this)};svgedit.history.BatchCommand.prototype.elements=function(){for(var a=[],H=this.stack.length;H--;)for(var h=this.stack[H].elements(),i=h.length;i--;)a.indexOf(h[i])==-1&&a.push(h[i]);return a};svgedit.history.BatchCommand.prototype.addSubCommand=function(a){this.stack.push(a)};svgedit.history.BatchCommand.prototype.isEmpty=function(){return this.stack.length==0};svgedit.history.UndoManager=function(a){this.handler_=a||null;this.undoStackPointer=0;this.undoStack=[];this.undoChangeStackPointer= --1;this.undoableChangeStack=[]};svgedit.history.UndoManager.prototype.resetUndoStack=function(){this.undoStack=[];this.undoStackPointer=0};svgedit.history.UndoManager.prototype.getUndoStackSize=function(){return this.undoStackPointer};svgedit.history.UndoManager.prototype.getRedoStackSize=function(){return this.undoStack.length-this.undoStackPointer};svgedit.history.UndoManager.prototype.getNextUndoCommandText=function(){return this.undoStackPointer>0?this.undoStack[this.undoStackPointer-1].getText(): -""};svgedit.history.UndoManager.prototype.getNextRedoCommandText=function(){return this.undoStackPointer<this.undoStack.length?this.undoStack[this.undoStackPointer].getText():""};svgedit.history.UndoManager.prototype.undo=function(){this.undoStackPointer>0&&this.undoStack[--this.undoStackPointer].unapply(this.handler_)};svgedit.history.UndoManager.prototype.redo=function(){this.undoStackPointer<this.undoStack.length&&this.undoStack.length>0&&this.undoStack[this.undoStackPointer++].apply(this.handler_)}; -svgedit.history.UndoManager.prototype.addCommandToHistory=function(a){if(this.undoStackPointer<this.undoStack.length&&this.undoStack.length>0)this.undoStack=this.undoStack.splice(0,this.undoStackPointer);this.undoStack.push(a);this.undoStackPointer=this.undoStack.length};svgedit.history.UndoManager.prototype.beginUndoableChange=function(a,H){for(var h=++this.undoChangeStackPointer,i=H.length,u=Array(i),E=Array(i);i--;){var e=H[i];if(e!=null){E[i]=e;u[i]=e.getAttribute(a)}}this.undoableChangeStack[h]= -{attrName:a,oldValues:u,elements:E}};svgedit.history.UndoManager.prototype.finishUndoableChange=function(){for(var a=this.undoChangeStackPointer--,H=this.undoableChangeStack[a],h=H.elements.length,i=H.attrName,u=new svgedit.history.BatchCommand("Change "+i);h--;){var E=H.elements[h];if(E!=null){var e={};e[i]=H.oldValues[h];e[i]!=E.getAttribute(i)&&u.addSubCommand(new svgedit.history.ChangeElementCommand(E,e,i))}}this.undoableChangeStack[a]=null;return u}})();svgedit=svgedit||{}; -(function(){if(!svgedit.select)svgedit.select={};var a,H,h;svgedit.select.Selector=function(i,u){this.id=i;this.selectedElement=u;this.locked=true;this.selectorGroup=a.createSVGElement({element:"g",attr:{id:"selectorGroup"+this.id}});this.selectorRect=this.selectorGroup.appendChild(a.createSVGElement({element:"path",attr:{id:"selectedBox"+this.id,fill:"none",stroke:"#4F80FF","stroke-width":"1",style:"pointer-events:none"}}));this.gripCoords={nw:null,n:null,ne:null,e:null,se:null,s:null,sw:null,w:null}; -this.reset(this.selectedElement)};svgedit.select.Selector.prototype.reset=function(i){this.locked=true;this.selectedElement=i;this.resize();this.selectorGroup.setAttribute("display","inline")};svgedit.select.Selector.prototype.updateGripCursors=function(i){var u=[];i=Math.round(i/45);if(i<0)i+=8;for(var E in h.selectorGrips)u.push(E);for(;i>0;){u.push(u.shift());i--}i=0;for(E in h.selectorGrips){h.selectorGrips[E].setAttribute("style","cursor:"+u[i]+"-resize");i++}};svgedit.select.Selector.prototype.showGrips= -function(i){h.selectorGripsGroup.setAttribute("display",i?"inline":"none");var u=this.selectedElement;this.hasGrips=i;if(u&&i){this.selectorGroup.appendChild(h.selectorGripsGroup);this.updateGripCursors(svgedit.utilities.getRotationAngle(u))}};svgedit.select.Selector.prototype.resize=function(){var i=this.selectorRect,u=h,E=u.selectorGrips,e=this.selectedElement,f=e.getAttribute("stroke-width"),g=a.currentZoom(),p=1/g;if(e.getAttribute("stroke")!=="none"&&!isNaN(f))p+=f/2;var z=e.tagName;if(z==="text")p+= -2/g;f=svgedit.transformlist.getTransformList(e);f=svgedit.math.transformListToTransform(f).matrix;f.e*=g;f.f*=g;var D=svgedit.utilities.getBBox(e);if(z==="g"&&!$.data(e,"gsvg"))if(z=a.getStrokedBBox(e.childNodes))D=z;z=D.x;var q=D.y,M=D.width;D=D.height;p*=g;g=svgedit.math.transformBox(z*g,q*g,M*g,D*g,f);f=g.aabox;z=f.x-p;q=f.y-p;M=f.width+p*2;var ba=f.height+p*2;f=z+M/2;D=q+ba/2;if(e=svgedit.utilities.getRotationAngle(e)){z=a.svgRoot().createSVGTransform();z.setRotate(-e,f,D);z=z.matrix;g.tl=svgedit.math.transformPoint(g.tl.x, -g.tl.y,z);g.tr=svgedit.math.transformPoint(g.tr.x,g.tr.y,z);g.bl=svgedit.math.transformPoint(g.bl.x,g.bl.y,z);g.br=svgedit.math.transformPoint(g.br.x,g.br.y,z);z=g.tl;M=z.x;ba=z.y;var N=z.x,I=z.y;z=Math.min;q=Math.max;M=z(M,z(g.tr.x,z(g.bl.x,g.br.x)))-p;ba=z(ba,z(g.tr.y,z(g.bl.y,g.br.y)))-p;N=q(N,q(g.tr.x,q(g.bl.x,g.br.x)))+p;I=q(I,q(g.tr.y,q(g.bl.y,g.br.y)))+p;z=M;q=ba;M=N-M;ba=I-ba}p=a.svgRoot().suspendRedraw(100);i.setAttribute("d","M"+z+","+q+" L"+(z+M)+","+q+" "+(z+M)+","+(q+ba)+" "+z+","+(q+ -ba)+"z");this.selectorGroup.setAttribute("transform",e?"rotate("+[e,f,D].join(",")+")":"");z-=3.5;q-=3.5;this.gripCoords={nw:[z,q],ne:[z+M,q],sw:[z,q+ba],se:[z+M,q+ba],n:[z+M/2,q],w:[z,q+ba/2],e:[z+M,q+ba/2],s:[z+M/2,q+ba]};for(var ma in this.gripCoords){i=this.gripCoords[ma];E[ma].setAttribute("x",i[0]);E[ma].setAttribute("y",i[1])}this.rotateCoords={nw:[z,q],ne:[z+M+8,q],sw:[z,q+ba+8],se:[z+M+8,q+ba+8]};for(ma in this.rotateCoords){i=this.rotateCoords[ma];u.rotateGrips[ma].setAttribute("cx",i[0]); -u.rotateGrips[ma].setAttribute("cy",i[1])}a.svgRoot().unsuspendRedraw(p)};svgedit.select.SelectorManager=function(){this.rubberBandBox=this.selectorParentGroup=null;this.selectors=[];this.selectorMap={};this.selectorGrips={nw:null,n:null,ne:null,e:null,se:null,s:null,sw:null,w:null};this.selectorGripsGroup=null;this.rotateGrips={nw:null,ne:null,se:null,sw:null};this.initGroup()};svgedit.select.SelectorManager.prototype.initGroup=function(){this.selectorParentGroup&&this.selectorParentGroup.parentNode&& -this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);this.selectorParentGroup=a.createSVGElement({element:"g",attr:{id:"selectorParentGroup"}});this.selectorGripsGroup=a.createSVGElement({element:"g",attr:{display:"none"}});this.selectorParentGroup.appendChild(this.selectorGripsGroup);a.svgRoot().appendChild(this.selectorParentGroup);this.selectorMap={};this.selectors=[];this.rubberBandBox=null;for(var i in this.rotateGrips){var u=a.createSVGElement({element:"circle",attr:{id:"selectorGrip_rotate_"+ -i,fill:"transparent",r:8,stroke:"transparent","stroke-width":0,style:"cursor:url("+H.imgPath+"rotate.png) 12 12, auto;"}});$.data(u,"dir",i);$.data(u,"type","rotate");this.rotateGrips[i]=this.selectorGripsGroup.appendChild(u)}for(i in this.selectorGrips){u=a.createSVGElement({element:"rect",attr:{id:"selectorGrip_resize_"+i,width:7,height:7,fill:"#4F80FF",stroke:"transparent","stroke-width":2,style:"cursor:"+i+"-resize","pointer-events":"all"}});$.data(u,"dir",i);$.data(u,"type","resize");this.selectorGrips[i]= -this.selectorGripsGroup.appendChild(u)}if(!$("#canvasBackground").length){i=H.dimensions;i=a.createSVGElement({element:"svg",attr:{id:"canvasBackground",width:i[0],height:i[1],x:0,y:0,overflow:svgedit.browser.isWebkit()?"none":"visible",style:"pointer-events:none"}});u=a.createSVGElement({element:"rect",attr:{width:"100%",height:"100%",x:0,y:0,"stroke-width":1,stroke:"#000",fill:"#FFF",style:"pointer-events:none"}});i.appendChild(u);a.svgRoot().insertBefore(i,a.svgContent())}};svgedit.select.SelectorManager.prototype.requestSelector= -function(i){if(i==null)return null;var u=this.selectors.length;if(typeof this.selectorMap[i.id]=="object"){this.selectorMap[i.id].locked=true;return this.selectorMap[i.id]}for(var E=0;E<u;++E)if(this.selectors[E]&&!this.selectors[E].locked){this.selectors[E].locked=true;this.selectors[E].reset(i);this.selectorMap[i.id]=this.selectors[E];return this.selectors[E]}this.selectors[u]=new svgedit.select.Selector(u,i);this.selectorParentGroup.appendChild(this.selectors[u].selectorGroup);this.selectorMap[i.id]= -this.selectors[u];return this.selectors[u]};svgedit.select.SelectorManager.prototype.releaseSelector=function(i){if(i!=null)for(var u=this.selectors.length,E=this.selectorMap[i.id],e=0;e<u;++e)if(this.selectors[e]&&this.selectors[e]==E){E.locked==false&&console.log("WARNING! selector was released but was already unlocked");delete this.selectorMap[i.id];E.locked=false;E.selectedElement=null;E.showGrips(false);try{E.selectorGroup.setAttribute("display","none")}catch(f){}break}};svgedit.select.SelectorManager.prototype.getRubberBandBox= -function(){if(!this.rubberBandBox)this.rubberBandBox=this.selectorParentGroup.appendChild(a.createSVGElement({element:"rect",attr:{id:"selectorRubberBand",fill:"transparent",stroke:"#666","stroke-width":1,"stroke-dasharray":"3,2",display:"none",style:"pointer-events:none"}}));return this.rubberBandBox};svgedit.select.init=function(i,u){H=i;a=u;h=new svgedit.select.SelectorManager};svgedit.select.getSelectorManager=function(){return h}})();svgedit=svgedit||{}; -(function(){if(!svgedit.draw)svgedit.draw={};var a="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use".split(","),H={LET_DOCUMENT_DECIDE:0,ALWAYS_RANDOMIZE:1,NEVER_RANDOMIZE:2},h=H.LET_DOCUMENT_DECIDE;svgedit.draw.Layer=function(i,u){this.name_=i;this.group_=u};svgedit.draw.Layer.prototype.getName=function(){return this.name_};svgedit.draw.Layer.prototype.getGroup=function(){return this.group_};svgedit.draw.randomizeIds=function(i,u){h=i==false?H.NEVER_RANDOMIZE: -H.ALWAYS_RANDOMIZE;if(h==H.ALWAYS_RANDOMIZE&&!u.getNonce())u.setNonce(Math.floor(Math.random()*100001));else h==H.NEVER_RANDOMIZE&&u.getNonce()&&u.clearNonce()};svgedit.draw.Drawing=function(i,u){if(!i||!i.tagName||!i.namespaceURI||i.tagName!="svg"||i.namespaceURI!="http://www.w3.org/2000/svg")throw"Error: svgedit.draw.Drawing instance initialized without a <svg> element";this.svgElem_=i;this.obj_num=0;this.idPrefix=u||"svg_";this.releasedNums=[];this.all_layers=[];this.current_layer=null;this.nonce_= -"";var E=this.svgElem_.getAttributeNS("http://svg-edit.googlecode.com","nonce");if(E&&h!=H.NEVER_RANDOMIZE)this.nonce_=E;else h==H.ALWAYS_RANDOMIZE&&this.setNonce(Math.floor(Math.random()*100001))};svgedit.draw.Drawing.prototype.getElem_=function(i){return this.svgElem_.querySelector?this.svgElem_.querySelector("#"+i):$(this.svgElem_).find("[id="+i+"]")[0]};svgedit.draw.Drawing.prototype.getSvgElem=function(){return this.svgElem_};svgedit.draw.Drawing.prototype.getNonce=function(){return this.nonce_}; -svgedit.draw.Drawing.prototype.setNonce=function(i){this.svgElem_.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:se","http://svg-edit.googlecode.com");this.svgElem_.setAttributeNS("http://svg-edit.googlecode.com","se:nonce",i);this.nonce_=i};svgedit.draw.Drawing.prototype.clearNonce=function(){this.nonce_=""};svgedit.draw.Drawing.prototype.getId=function(){return this.nonce_?this.idPrefix+this.nonce_+"_"+this.obj_num:this.idPrefix+this.obj_num};svgedit.draw.Drawing.prototype.getNextId=function(){var i= -this.obj_num,u=false;if(this.releasedNums.length>0){this.obj_num=this.releasedNums.pop();u=true}else this.obj_num++;for(var E=this.getId();this.getElem_(E);){if(u){this.obj_num=i;u=false}this.obj_num++;E=this.getId()}if(u)this.obj_num=i;return E};svgedit.draw.Drawing.prototype.releaseId=function(i){var u=this.idPrefix+(this.nonce_?this.nonce_+"_":"");if(typeof i!="string"||i.indexOf(u)!=0)return false;i=parseInt(i.substr(u.length));if(typeof i!="number"||i<=0||this.releasedNums.indexOf(i)!=-1)return false; -this.releasedNums.push(i);return true};svgedit.draw.Drawing.prototype.getNumLayers=function(){return this.all_layers.length};svgedit.draw.Drawing.prototype.hasLayer=function(i){for(var u=0;u<this.getNumLayers();u++)if(this.all_layers[u][0]==i)return true;return false};svgedit.draw.Drawing.prototype.getLayerName=function(i){if(i>=0&&i<this.getNumLayers())return this.all_layers[i][0];return""};svgedit.draw.Drawing.prototype.getCurrentLayer=function(){return this.current_layer};svgedit.draw.Drawing.prototype.getCurrentLayerName= -function(){for(var i=0;i<this.getNumLayers();++i)if(this.all_layers[i][1]==this.current_layer)return this.getLayerName(i);return""};svgedit.draw.Drawing.prototype.setCurrentLayer=function(i){for(var u=0;u<this.getNumLayers();++u)if(i==this.getLayerName(u)){if(this.current_layer!=this.all_layers[u][1]){this.current_layer.setAttribute("style","pointer-events:none");this.current_layer=this.all_layers[u][1];this.current_layer.setAttribute("style","pointer-events:all")}return true}return false};svgedit.draw.Drawing.prototype.deleteCurrentLayer= -function(){if(this.current_layer&&this.getNumLayers()>1){var i=this.current_layer.parentNode.removeChild(this.current_layer);this.identifyLayers();return i}return null};svgedit.draw.Drawing.prototype.identifyLayers=function(){this.all_layers=[];for(var i=this.svgElem_.childNodes.length,u=[],E=[],e=null,f=false,g=0;g<i;++g){var p=this.svgElem_.childNodes.item(g);if(p&&p.nodeType==1)if(p.tagName=="g"){f=true;var z=$("title",p).text();if(!z&&svgedit.browser.isOpera()&&p.querySelectorAll)z=$(p.querySelectorAll("title")).text(); -if(z){E.push(z);this.all_layers.push([z,p]);e=p;svgedit.utilities.walkTree(p,function(D){D.setAttribute("style","pointer-events:inherit")});e.setAttribute("style","pointer-events:none")}else u.push(p)}else if(~a.indexOf(p.nodeName)){svgedit.utilities.getBBox(p);u.push(p)}}i=this.svgElem_.ownerDocument;if(u.length>0||!f){for(g=1;E.indexOf("Layer "+g)>=0;)g++;E="Layer "+g;e=i.createElementNS("http://www.w3.org/2000/svg","g");f=i.createElementNS("http://www.w3.org/2000/svg","title");f.textContent=E; -e.appendChild(f);for(f=0;f<u.length;++f)e.appendChild(u[f]);this.svgElem_.appendChild(e);this.all_layers.push([E,e])}svgedit.utilities.walkTree(e,function(D){D.setAttribute("style","pointer-events:inherit")});this.current_layer=e;this.current_layer.setAttribute("style","pointer-events:all")};svgedit.draw.Drawing.prototype.createLayer=function(i){var u=this.svgElem_.ownerDocument,E=u.createElementNS("http://www.w3.org/2000/svg","g");u=u.createElementNS("http://www.w3.org/2000/svg","title");u.textContent= -i;E.appendChild(u);this.svgElem_.appendChild(E);this.identifyLayers();return E};svgedit.draw.Drawing.prototype.getLayerVisibility=function(i){for(var u=null,E=0;E<this.getNumLayers();++E)if(this.getLayerName(E)==i){u=this.all_layers[E][1];break}if(!u)return false;return u.getAttribute("display")!="none"};svgedit.draw.Drawing.prototype.setLayerVisibility=function(i,u){if(typeof u!="boolean")return null;for(var E=null,e=0;e<this.getNumLayers();++e)if(this.getLayerName(e)==i){E=this.all_layers[e][1]; -break}if(!E)return null;E.getAttribute("display");E.setAttribute("display",u?"inline":"none");return E};svgedit.draw.Drawing.prototype.getLayerOpacity=function(i){for(var u=0;u<this.getNumLayers();++u)if(this.getLayerName(u)==i){(i=this.all_layers[u][1].getAttribute("opacity"))||(i="1.0");return parseFloat(i)}return null};svgedit.draw.Drawing.prototype.setLayerOpacity=function(i,u){if(!(typeof u!="number"||u<0||u>1))for(var E=0;E<this.getNumLayers();++E)if(this.getLayerName(E)==i){this.all_layers[E][1].setAttribute("opacity", -u);break}}})();svgedit=svgedit||{}; -(function(){if(!svgedit.path)svgedit.path={};var a={pathNodeTooltip:"Drag node to move it. Double-click node to change segment type",pathCtrlPtTooltip:"Drag control point to adjust curve properties"},H={2:["x","y"],4:["x","y"],6:["x","y","x1","y1","x2","y2"],8:["x","y","x1","y1"],10:["x","y","r1","r2","angle","largeArcFlag","sweepFlag"],12:["x"],14:["y"],16:["x","y","x2","y2"],18:["x","y"]},h=[],i=true,u={};svgedit.path.setLinkControlPoints=function(f){i=f};var E=svgedit.path.path=null;svgedit.path.init= -function(f){E=f;h=[0,"ClosePath"];$.each(["Moveto","Lineto","CurvetoCubic","CurvetoQuadratic","Arc","LinetoHorizontal","LinetoVertical","CurvetoCubicSmooth","CurvetoQuadraticSmooth"],function(g,p){h.push(p+"Abs");h.push(p+"Rel")})};svgedit.path.insertItemBefore=function(f,g,p){f=f.pathSegList;if(svgedit.browser.supportsPathInsertItemBefore())f.insertItemBefore(g,p);else{for(var z=f.numberOfItems,D=[],q=0;q<z;q++){var M=f.getItem(q);D.push(M)}f.clear();for(q=0;q<z;q++){q==p&&f.appendItem(g);f.appendItem(D[q])}}}; -svgedit.path.ptObjToArr=function(f,g){for(var p=H[f],z=p.length,D=Array(z),q=0;q<z;q++)D[q]=g[p[q]];return D};svgedit.path.getGripPt=function(f,g){var p={x:g?g.x:f.item.x,y:g?g.y:f.item.y},z=f.path;if(z.matrix)p=svgedit.math.transformPoint(p.x,p.y,z.matrix);p.x*=E.getCurrentZoom();p.y*=E.getCurrentZoom();return p};svgedit.path.getPointFromGrip=function(f,g){var p={x:f.x,y:f.y};if(g.matrix){f=svgedit.math.transformPoint(p.x,p.y,g.imatrix);p.x=f.x;p.y=f.y}p.x/=E.getCurrentZoom();p.y/=E.getCurrentZoom(); -return p};svgedit.path.addPointGrip=function(f,g,p){var z=svgedit.path.getGripContainer(),D=svgedit.utilities.getElem("pathpointgrip_"+f);if(!D){D=document.createElementNS("http://www.w3.org/2000/svg","rect");svgedit.utilities.assignAttributes(D,{id:"pathpointgrip_"+f,display:"none",width:5,height:5,fill:"#fff",stroke:"#4F80FF","stroke-width":1,cursor:"move",style:"pointer-events:all","xlink:title":a.pathNodeTooltip});D=z.appendChild(D);$("#pathpointgrip_"+f).dblclick(function(){svgedit.path.path&& -svgedit.path.path.setSegType()})}g&&p&&svgedit.utilities.assignAttributes(D,{x:g-2.5,y:p-2.5,display:"inline"});return D};svgedit.path.getGripContainer=function(){var f=svgedit.utilities.getElem("pathpointgrip_container");if(!f){f=svgedit.utilities.getElem("selectorParentGroup").appendChild(document.createElementNS("http://www.w3.org/2000/svg","g"));f.id="pathpointgrip_container"}return f};svgedit.path.addCtrlGrip=function(f){var g=svgedit.utilities.getElem("ctrlpointgrip_"+f);if(g)return g;g=document.createElementNS("http://www.w3.org/2000/svg", -"circle");svgedit.utilities.assignAttributes(g,{id:"ctrlpointgrip_"+f,display:"none",r:3,fill:"#4F80FF",cursor:"move",style:"pointer-events:all","xlink:title":a.pathCtrlPtTooltip});svgedit.path.getGripContainer().appendChild(g);return g};svgedit.path.getCtrlLine=function(f){var g=svgedit.utilities.getElem("ctrlLine_"+f);if(g)return g;g=document.createElementNS("http://www.w3.org/2000/svg","line");svgedit.utilities.assignAttributes(g,{id:"ctrlLine_"+f,stroke:"#4F80FF","stroke-width":1,style:"pointer-events:none"}); -svgedit.path.getGripContainer().appendChild(g);return g};svgedit.path.getPointGrip=function(f,g){var p=svgedit.path.addPointGrip(f.index);if(g){var z=svgedit.path.getGripPt(f);svgedit.utilities.assignAttributes(p,{cx:z.x,cy:z.y,display:"inline"})}return p};svgedit.path.getControlPoints=function(f){var g=f.item,p=f.index;if(!("x1"in g)||!("x2"in g))return null;var z={};svgedit.path.getGripContainer();for(var D=[svgedit.path.path.segs[p-1].item,g],q=1;q<3;q++){var M=p+"c"+q,ba=z["c"+q+"_line"]=svgedit.path.getCtrlLine(M), -N=svgedit.path.getGripPt(f,{x:g["x"+q],y:g["y"+q]}),I=svgedit.path.getGripPt(f,{x:D[q-1].x,y:D[q-1].y});svgedit.utilities.assignAttributes(ba,{x1:N.x,y1:N.y,x2:I.x,y2:I.y,display:"inline"});z["c"+q+"_line"]=ba;pointGrip=z["c"+q]=svgedit.path.addCtrlGrip(M);svgedit.utilities.assignAttributes(pointGrip,{cx:N.x,cy:N.y,display:"inline"});z["c"+q]=pointGrip}return z};svgedit.path.replacePathSeg=function(f,g,p,z){z=z||svgedit.path.path.elem;f=z["createSVGPathSeg"+h[f]].apply(z,p);if(svgedit.browser.supportsPathReplaceItem())z.pathSegList.replaceItem(f, -g);else{p=z.pathSegList;z=p.numberOfItems;for(var D=[],q=0;q<z;q++){var M=p.getItem(q);D.push(M)}p.clear();for(q=0;q<z;q++)q==g?p.appendItem(f):p.appendItem(D[q])}};svgedit.path.getSegSelector=function(f,g){var p=f.index,z=svgedit.utilities.getElem("segline_"+p);if(!z){var D=svgedit.path.getGripContainer();z=document.createElementNS("http://www.w3.org/2000/svg","path");svgedit.utilities.assignAttributes(z,{id:"segline_"+p,display:"none",fill:"none",stroke:"#0FF","stroke-width":2,style:"pointer-events:none", -d:"M0,0 0,0"});D.appendChild(z)}if(g){p=f.prev;if(!p){z.setAttribute("display","none");return z}p=svgedit.path.getGripPt(p);svgedit.path.replacePathSeg(2,0,[p.x,p.y],z);D=svgedit.path.ptObjToArr(f.type,f.item,true);for(var q=0;q<D.length;q+=2){p=svgedit.path.getGripPt(f,{x:D[q],y:D[q+1]});D[q]=p.x;D[q+1]=p.y}svgedit.path.replacePathSeg(f.type,1,D,z)}return z};svgedit.path.smoothControlPoints=this.smoothControlPoints=function(f,g,p){var z=f.x-p.x,D=f.y-p.y,q=g.x-p.x,M=g.y-p.y;if((z!=0||D!=0)&&(q!= -0||M!=0)){f=Math.atan2(D,z);g=Math.atan2(M,q);z=Math.sqrt(z*z+D*D);q=Math.sqrt(q*q+M*M);D=E.getSVGRoot().createSVGPoint();M=E.getSVGRoot().createSVGPoint();if(f<0)f+=2*Math.PI;if(g<0)g+=2*Math.PI;var ba=Math.abs(f-g),N=Math.abs(Math.PI-ba)/2;if(f-g>0){f=ba<Math.PI?f+N:f-N;g=ba<Math.PI?g-N:g+N}else{f=ba<Math.PI?f-N:f+N;g=ba<Math.PI?g+N:g-N}D.x=z*Math.cos(f)+p.x;D.y=z*Math.sin(f)+p.y;M.x=q*Math.cos(g)+p.x;M.y=q*Math.sin(g)+p.y;return[D,M]}};svgedit.path.Segment=function(f,g){this.selected=false;this.index= -f;this.item=g;this.type=g.pathSegType;this.ctrlpts=[];this.segsel=this.ptgrip=null};svgedit.path.Segment.prototype.showCtrlPts=function(f){for(var g in this.ctrlpts)this.ctrlpts[g].setAttribute("display",f?"inline":"none")};svgedit.path.Segment.prototype.selectCtrls=function(){$("#ctrlpointgrip_"+this.index+"c1, #ctrlpointgrip_"+this.index+"c2").attr("fill","#4F80FF")};svgedit.path.Segment.prototype.show=function(f){if(this.ptgrip){this.ptgrip.setAttribute("display",f?"inline":"none");this.segsel.setAttribute("display", -f?"inline":"none");this.showCtrlPts(f)}};svgedit.path.Segment.prototype.select=function(f){if(this.ptgrip){this.ptgrip.setAttribute("stroke",f?"#0FF":"#00F");this.segsel.setAttribute("display",f?"inline":"none");this.ctrlpts&&this.selectCtrls(f);this.selected=f}};svgedit.path.Segment.prototype.addGrip=function(){this.ptgrip=svgedit.path.getPointGrip(this,true);this.ctrlpts=svgedit.path.getControlPoints(this,true);this.segsel=svgedit.path.getSegSelector(this,true)};svgedit.path.Segment.prototype.update= -function(f){if(this.ptgrip){var g=svgedit.path.getGripPt(this);svgedit.utilities.assignAttributes(this.ptgrip,this.ptgrip.nodeName=="rect"?{x:g.x-2.5,y:g.y-2.5}:{cx:g.x,cy:g.y});svgedit.path.getSegSelector(this,true);if(this.ctrlpts){if(f){this.item=svgedit.path.path.elem.pathSegList.getItem(this.index);this.type=this.item.pathSegType}svgedit.path.getControlPoints(this)}}};svgedit.path.Segment.prototype.move=function(f,g){var p=this.item;p=this.ctrlpts?[p.x+=f,p.y+=g,p.x1,p.y1,p.x2+=f,p.y2+=g]:[p.x+= -f,p.y+=g];svgedit.path.replacePathSeg(this.type,this.index,p);if(this.next&&this.next.ctrlpts){p=this.next.item;p=[p.x,p.y,p.x1+=f,p.y1+=g,p.x2,p.y2];svgedit.path.replacePathSeg(this.next.type,this.next.index,p)}if(this.mate){p=this.mate.item;p=[p.x+=f,p.y+=g];svgedit.path.replacePathSeg(this.mate.type,this.mate.index,p)}this.update(true);this.next&&this.next.update(true)};svgedit.path.Segment.prototype.setLinked=function(f){var g,p,z;if(f==2){p=1;g=this.next;if(!g)return;z=this.item}else{p=2;g=this.prev; -if(!g)return;z=g.item}var D=g.item;D["x"+p]=z.x+(z.x-this.item["x"+f]);D["y"+p]=z.y+(z.y-this.item["y"+f]);svgedit.path.replacePathSeg(g.type,g.index,[D.x,D.y,D.x1,D.y1,D.x2,D.y2]);g.update(true)};svgedit.path.Segment.prototype.moveCtrl=function(f,g,p){var z=this.item;z["x"+f]+=g;z["y"+f]+=p;svgedit.path.replacePathSeg(this.type,this.index,[z.x,z.y,z.x1,z.y1,z.x2,z.y2]);this.update(true)};svgedit.path.Segment.prototype.setType=function(f,g){svgedit.path.replacePathSeg(f,this.index,g);this.type=f; -this.item=svgedit.path.path.elem.pathSegList.getItem(this.index);this.showCtrlPts(f===6);this.ctrlpts=svgedit.path.getControlPoints(this);this.update(true)};svgedit.path.Path=function(f){if(!f||f.tagName!=="path")throw"svgedit.path.Path constructed without a <path> element";this.elem=f;this.segs=[];this.selected_pts=[];svgedit.path.path=this;this.init()};svgedit.path.Path.prototype.init=function(){$(svgedit.path.getGripContainer()).find("*").attr("display","none");var f=this.elem.pathSegList,g=f.numberOfItems; -this.segs=[];this.selected_pts=[];this.first_seg=null;for(var p=0;p<g;p++){var z=f.getItem(p);z=new svgedit.path.Segment(p,z);z.path=this;this.segs.push(z)}f=this.segs;z=null;for(p=0;p<g;p++){var D=f[p],q=p+1>=g?null:f[p+1],M=p-1<0?null:f[p-1];if(D.type===2){if(M&&M.type!==1){q=f[z];q.next=f[z+1];q.next.prev=q;q.addGrip()}z=p}else if(q&&q.type===1){D.next=f[z+1];D.next.prev=D;D.mate=f[z];D.addGrip();if(this.first_seg==null)this.first_seg=D}else if(q){if(D.type!==1){D.addGrip();if(q&&q.type!==2){D.next= -q;D.next.prev=D}}}else if(D.type!==1){q=f[z];q.next=f[z+1];q.next.prev=q;q.addGrip();D.addGrip();if(!this.first_seg)this.first_seg=f[z]}}return this};svgedit.path.Path.prototype.eachSeg=function(f){for(var g=this.segs.length,p=0;p<g;p++)if(f.call(this.segs[p],p)===false)break};svgedit.path.Path.prototype.addSeg=function(f){var g=this.segs[f];if(g.prev){var p=g.prev,z;switch(g.item.pathSegType){case 4:var D=(g.item.x+p.item.x)/2,q=(g.item.y+p.item.y)/2;z=this.elem.createSVGPathSegLinetoAbs(D,q);break; -case 6:z=(p.item.x+g.item.x1)/2;var M=(g.item.x1+g.item.x2)/2,ba=(g.item.x2+g.item.x)/2,N=(z+M)/2;M=(M+ba)/2;D=(N+M)/2;var I=(p.item.y+g.item.y1)/2,ma=(g.item.y1+g.item.y2)/2;p=(g.item.y2+g.item.y)/2;var ia=(I+ma)/2;ma=(ma+p)/2;q=(ia+ma)/2;z=this.elem.createSVGPathSegCurvetoCubicAbs(D,q,z,I,N,ia);svgedit.path.replacePathSeg(g.type,f,[g.item.x,g.item.y,M,ma,ba,p])}svgedit.path.insertItemBefore(this.elem,z,f)}};svgedit.path.Path.prototype.deleteSeg=function(f){var g=this.segs[f],p=this.elem.pathSegList; -g.show(false);var z=g.next;if(g.mate){var D=[z.item.x,z.item.y];svgedit.path.replacePathSeg(2,z.index,D);svgedit.path.replacePathSeg(4,g.index,D);p.removeItem(g.mate.index)}else{if(!g.prev){D=[z.item.x,z.item.y];svgedit.path.replacePathSeg(2,g.next.index,D)}p.removeItem(f)}};svgedit.path.Path.prototype.subpathIsClosed=function(f){var g=false;svgedit.path.path.eachSeg(function(p){if(p<=f)return true;if(this.type===2)return false;else if(this.type===1){g=true;return false}});return g};svgedit.path.Path.prototype.removePtFromSelection= -function(f){var g=this.selected_pts.indexOf(f);if(g!=-1){this.segs[f].select(false);this.selected_pts.splice(g,1)}};svgedit.path.Path.prototype.clearSelection=function(){this.eachSeg(function(){this.select(false)});this.selected_pts=[]};svgedit.path.Path.prototype.storeD=function(){this.last_d=this.elem.getAttribute("d")};svgedit.path.Path.prototype.show=function(f){this.eachSeg(function(){this.show(f)});f&&this.selectPt(this.first_seg.index);return this};svgedit.path.Path.prototype.movePts=function(f, -g){for(var p=this.selected_pts.length;p--;)this.segs[this.selected_pts[p]].move(f,g)};svgedit.path.Path.prototype.moveCtrl=function(f,g){var p=this.segs[this.selected_pts[0]];p.moveCtrl(this.dragctrl,f,g);i&&p.setLinked(this.dragctrl)};svgedit.path.Path.prototype.setSegType=function(f){this.storeD();for(var g=this.selected_pts.length,p;g--;){var z=this.segs[this.selected_pts[g]],D=z.prev;if(D){if(!f){p="Toggle Path Segment Type";f=z.type==6?4:6}f-=0;var q=z.item.x,M=z.item.y,ba=D.item.x;D=D.item.y; -var N;switch(f){case 6:if(z.olditem){ba=z.olditem;N=[q,M,ba.x1,ba.y1,ba.x2,ba.y2]}else{N=q-ba;var I=M-D;N=[q,M,ba+N/3,D+I/3,q-N/3,M-I/3]}break;case 4:N=[q,M];z.olditem=z.item}z.setType(f,N)}}svgedit.path.path.endChanges(p)};svgedit.path.Path.prototype.selectPt=function(f,g){this.clearSelection();f==null&&this.eachSeg(function(p){if(this.prev)f=p});this.addPtsToSelection(f);if(g){this.dragctrl=g;i&&this.segs[f].setLinked(g)}};svgedit.path.Path.prototype.update=function(){var f=this.elem;if(svgedit.utilities.getRotationAngle(f)){this.matrix= -svgedit.math.getMatrix(f);this.imatrix=this.matrix.inverse()}else this.imatrix=this.matrix=null;this.eachSeg(function(g){this.item=f.pathSegList.getItem(g);this.update()});return this};svgedit.path.getPath_=function(f){var g=u[f.id];g||(g=u[f.id]=new svgedit.path.Path(f));return g};svgedit.path.removePath_=function(f){f in u&&delete u[f]};var e=function(f,g){dx=f-oldcx;dy=g-oldcy;r=Math.sqrt(dx*dx+dy*dy);theta=Math.atan2(dy,dx)+angle;dx=r*Math.cos(theta)+oldcx;dy=r*Math.sin(theta)+oldcy;dx-=newcx; -dy-=newcy;r=Math.sqrt(dx*dx+dy*dy);theta=Math.atan2(dy,dx)-angle;return{x:(r*Math.cos(theta)+newcx)/1,y:(r*Math.sin(theta)+newcy)/1}};svgedit.path.recalcRotatedPath=function(){var f=svgedit.path.path.elem,g=svgedit.utilities.getRotationAngle(f,true);if(g){var p=svgedit.utilities.getBBox(f),z=svgedit.path.path.oldbbox,D=z.x+z.width/2,q=z.y+z.height/2;z=p.x+p.width/2;p=p.y+p.height/2;z=z-D;var M=p-q;p=Math.sqrt(z*z+M*M);M=Math.atan2(M,z)+g;z=p*Math.cos(M)+D;p=p*Math.sin(M)+q;D=f.pathSegList;for(q=D.numberOfItems;q;){q-= -1;M=D.getItem(q);var ba=M.pathSegType;if(ba!=1){var N=e(M.x,M.y);N=[N.x,N.y];if(M.x1!=null&&M.x2!=null){c_vals1=e(M.x1,M.y1);c_vals2=e(M.x2,M.y2);N.splice(N.length,0,c_vals1.x,c_vals1.y,c_vals2.x,c_vals2.y)}svgedit.path.replacePathSeg(ba,q,N)}}svgedit.utilities.getBBox(f);D=svgroot.createSVGTransform();f=svgedit.transformlist.getTransformList(f);D.setRotate(g*180/Math.PI,z,p);f.replaceItem(D,0)}};svgedit.path.clearData=function(){u={}}})();if(!window.console){window.console={};window.console.log=function(){};window.console.dir=function(){}}if(window.opera){window.console.log=function(a){opera.postError(a)};window.console.dir=function(){}} -(function(){var a=jQuery.fn.attr;jQuery.fn.attr=function(H,h){var i=this.length;if(!i)return a.apply(this,arguments);for(var u=0;u<i;u++){var E=this[u];if(E.namespaceURI==="http://www.w3.org/2000/svg")if(h!==undefined)E.setAttribute(H,h);else if($.isArray(H)){i=H.length;for(u={};i--;){var e=H[i],f=E.getAttribute(e);if(f||f==="0")f=isNaN(f)?f:f-0;u[e]=f}return u}else if(typeof H==="object")for(e in H)E.setAttribute(e,H[e]);else{if((f=E.getAttribute(H))||f==="0")f=isNaN(f)?f:f-0;return f}else return a.apply(this, -arguments)}return this}})(); -$.SvgCanvas=function(a,H){function h(b,c){for(var d=svgedit.utilities.getBBox(b),n=0;n<2;n++){var m=n===0?"fill":"stroke",A=b.getAttribute(m);if(A&&A.indexOf("url(")===0){A=Sa(A);if(A.tagName==="linearGradient"){var o=A.getAttribute("x1")||0,l=A.getAttribute("y1")||0,s=A.getAttribute("x2")||1,B=A.getAttribute("y2")||0;o=d.width*o+d.x;l=d.height*l+d.y;s=d.width*s+d.x;B=d.height*B+d.y;o=ka(o,l,c);B=ka(s,B,c);s={};s.x1=(o.x-d.x)/d.width;s.y1=(o.y-d.y)/d.height;s.x2=(B.x-d.x)/d.width;s.y2=(B.y-d.y)/d.height; -A=A.cloneNode(true);$(A).attr(s);A.id=ya();ib().appendChild(A);b.setAttribute(m,"url(#"+A.id+")")}}}}var i="http://www.w3.org/2000/svg",u={show_outside_canvas:true,selectNew:true,dimensions:[640,480]};H&&$.extend(u,H);var E=u.dimensions,e=this,f=a.ownerDocument,g=f.importNode(svgedit.utilities.text2xml('<svg id="svgroot" xmlns="'+i+'" xlinkns="http://www.w3.org/1999/xlink" width="'+E[0]+'" height="'+E[1]+'" x="'+E[0]+'" y="'+E[1]+'" overflow="visible"><defs><filter id="canvashadow" filterUnits="objectBoundingBox"><feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/><feOffset in="blur" dx="5" dy="5" result="offsetBlur"/><feMerge><feMergeNode in="offsetBlur"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs></svg>').documentElement, -true);a.appendChild(g);var p=f.createElementNS(i,"svg");(e.clearSvgContentElement=function(){for(;p.firstChild;)p.removeChild(p.firstChild);$(p).attr({id:"svgcontent",width:E[0],height:E[1],x:E[0],y:E[1],overflow:u.show_outside_canvas?"visible":"hidden",xmlns:i,"xmlns:se":"http://svg-edit.googlecode.com","xmlns:xlink":"http://www.w3.org/1999/xlink"}).appendTo(g);var b=f.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");p.appendChild(b)})();var z="svg_";e.setIdPrefix=function(b){z= -b};e.current_drawing_=new svgedit.draw.Drawing(p,z);var D=e.getCurrentDrawing=function(){return e.current_drawing_},q=1,M=null,ba={shape:{fill:(u.initFill.color=="none"?"":"#")+u.initFill.color,fill_paint:null,fill_opacity:u.initFill.opacity,stroke:"#"+u.initStroke.color,stroke_paint:null,stroke_opacity:u.initStroke.opacity,stroke_width:u.initStroke.width,stroke_dasharray:"none",stroke_linejoin:"miter",stroke_linecap:"butt",opacity:u.initOpacity}};ba.text=$.extend(true,{},ba.shape);$.extend(ba.text, -{fill:"#000000",stroke_width:0,font_size:24,font_family:"Junction"});var N=ba.shape,I=Array(1),ma=this.addSvgElementFromJson=function(b){var c=svgedit.utilities.getElem(b.attr.id),d=D().getCurrentLayer();if(c&&b.element!=c.tagName){d.removeChild(c);c=null}if(!c){c=f.createElementNS(i,b.element);if(d)(M||d).appendChild(c)}b.curStyles&&svgedit.utilities.assignAttributes(c,{fill:N.fill,stroke:N.stroke,"stroke-width":N.stroke_width,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin, -"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,"fill-opacity":N.fill_opacity,opacity:N.opacity/2,style:"pointer-events:inherit"},100);svgedit.utilities.assignAttributes(c,b.attr,100);svgedit.utilities.cleanupElement(c);return c},ia=e.getTransformList=svgedit.transformlist.getTransformList,ka=svgedit.math.transformPoint,X=e.matrixMultiply=svgedit.math.matrixMultiply,qa=e.hasMatrixTransform=svgedit.math.hasMatrixTransform,ga=e.transformListToTransform=svgedit.math.transformListToTransform, -Na=svgedit.math.snapToAngle,va=svgedit.math.getMatrix;svgedit.units.init({getBaseUnit:function(){return u.baseUnit},getElement:svgedit.utilities.getElem,getHeight:function(){return p.getAttribute("height")/q},getWidth:function(){return p.getAttribute("width")/q},getRoundDigits:function(){return Ua.round_digits}});var ha=e.convertToNum=svgedit.units.convertToNum;svgedit.utilities.init({getDOMDocument:function(){return f},getDOMContainer:function(){return a},getSVGRoot:function(){return g},getSelectedElements:function(){return I}, -getSVGContent:function(){return p}});var Ra=e.getUrlFromAttr=svgedit.utilities.getUrlFromAttr,U=e.getHref=svgedit.utilities.getHref,Z=e.setHref=svgedit.utilities.setHref,ea=svgedit.utilities.getPathBBox;e.getBBox=svgedit.utilities.getBBox;var ra=e.getRotationAngle=svgedit.utilities.getRotationAngle,ja=e.getElem=svgedit.utilities.getElem,la=e.assignAttributes=svgedit.utilities.assignAttributes,T=this.cleanupElement=svgedit.utilities.cleanupElement,wa=svgedit.sanitize.getNSMap(),Da=e.sanitizeSvg=svgedit.sanitize.sanitizeSvg, -Ma=svgedit.history.MoveElementCommand,Fa=svgedit.history.InsertElementCommand,Oa=svgedit.history.RemoveElementCommand,Qa=svgedit.history.ChangeElementCommand,Ga=svgedit.history.BatchCommand;e.undoMgr=new svgedit.history.UndoManager({handleHistoryEvent:function(b,c){var d=svgedit.history.HistoryEventTypes;if(b==d.BEFORE_UNAPPLY||b==d.BEFORE_APPLY)e.clearSelection();else if(b==d.AFTER_APPLY||b==d.AFTER_UNAPPLY){var n=c.elements();e.pathActions.clear();aa("changed",n);n=c.type();d=b==d.AFTER_APPLY;if(n== -Ma.type()){d=d?c.newParent:c.oldParent;d==p&&e.identifyLayers()}else if(n==Fa.type()||n==Oa.type()){c.parent==p&&e.identifyLayers();if(n==Fa.type())d&&mb(c.elem);else d||mb(c.elem);c.elem.tagName==="use"&&Tb(c.elem)}else if(n==Qa.type()){c.elem.tagName=="title"&&c.elem.parentNode.parentNode==p&&e.identifyLayers();d=d?c.newValues:c.oldValues;d.stdDeviation&&e.setBlurOffsets(c.elem.parentNode,d.stdDeviation);if(c.elem.tagName==="use"&&svgedit.browser.isWebkit()){n=c.elem;if(!n.getAttribute("x")&&!n.getAttribute("y")){d= -n.parentNode;var m=n.nextSibling;d.removeChild(n);d.insertBefore(n,m)}}}}}});var Ca=function(b){e.undoMgr.addCommandToHistory(b)};svgedit.select.init(u,{createSVGElement:function(b){return e.addSvgElementFromJson(b)},svgRoot:function(){return g},svgContent:function(){return p},currentZoom:function(){return q},getStrokedBBox:function(b){return e.getStrokedBBox([b])}});var Ha=this.selectorManager=svgedit.select.getSelectorManager();svgedit.path.init({getCurrentZoom:function(){return q},getSVGRoot:function(){return g}}); -svgedit.utilities.snapToGrid=function(b){var c=u.snappingStep,d=u.baseUnit;if(d!=="px")c*=svgedit.units.getTypeMap()[d];return b=Math.round(b/c)*c};var Aa=svgedit.utilities.snapToGrid,zb={exportNoBlur:"Blurred elements will appear as un-blurred",exportNoforeignObject:"foreignObject elements will not appear",exportNoDashArray:"Strokes will appear filled",exportNoText:"Text may not appear as expected"},Pb=["clip-path","fill","filter","marker-end","marker-mid","marker-start","mask","stroke"],gb=$.data, -mb=function(b){var c=$(b).attr(Pb),d;for(d in c){var n=c[d];if(n&&n.indexOf("url(")===0){n=Ra(n).substr(1);if(!ja(n)){ib().appendChild(Jb[n]);delete Jb[n]}}}b=b.getElementsByTagName("*");if(b.length){c=0;for(d=b.length;c<d;c++)mb(b[c])}},Va={},ub=u.imgPath+"logo.png",Bb=[],Ua={round_digits:5},Ja=false,Wa=null,Ia="select",kb="none",Cb={},ab=ba.text,cb=N,db=null,za=null,vb=[],lb={},xb=null,Jb={};e.clipBoard=[];var pb=this.runExtensions=function(b,c,d){var n=false;if(d)n=[];$.each(lb,function(m,A){if(b in -A)if(d)n.push(A[b](c));else n=A[b](c)});return n};this.addExtension=function(b,c){if(b in lb)console.log('Cannot add extension "'+b+'", an extension by that name already exists"');else{var d=$.isFunction(c)?c($.extend(e.getPrivateMethods(),{svgroot:g,svgcontent:p,nonce:D().getNonce(),selectorManager:Ha})):c;lb[b]=d;aa("extension_added",d)}};var Kb=this.round=function(b){return parseInt(b*q)/q},Rb=this.getIntersectionList=function(b){if(za==null)return null;var c=M||D().getCurrentLayer();vb.length|| -(vb=Sb(c));var d=null;try{d=c.getIntersectionList(b,null)}catch(n){}if(d==null||typeof d.item!="function"){d=[];if(b)b=b;else{b=za.getBBox();c={};for(var m in b)c[m]=b[m]/q;b=c}for(m=vb.length;m--;)b.width&&b.width&&svgedit.math.rectsIntersect(b,vb[m].bbox)&&d.push(vb[m].elem)}return d};getStrokedBBox=this.getStrokedBBox=function(b){b||(b=Lb());if(!b.length)return false;var c=function(B){try{var w=svgedit.utilities.getBBox(B),v=svgedit.utilities.getRotationAngle(B);if(v&&v%90||svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(B))){v= -false;if(["ellipse","path","line","polyline","polygon"].indexOf(B.tagName)>=0)w=v=e.convertToPath(B,true);else if(B.tagName=="rect"){var C=B.getAttribute("rx"),F=B.getAttribute("ry");if(C||F)w=v=e.convertToPath(B,true)}if(!v){var J=B.cloneNode(true),K=document.createElementNS(i,"g"),P=B.parentNode;P.appendChild(K);K.appendChild(J);w=svgedit.utilities.bboxToObj(K.getBBox());P.removeChild(K)}}return w}catch(ca){console.log(B,ca);return null}},d;$.each(b,function(){if(!d)if(this.parentNode)d=c(this)}); -if(d==null)return null;var n=d.x+d.width,m=d.y+d.height,A=d.x,o=d.y,l=function(B){var w=B.getAttribute("stroke-width"),v=0;if(B.getAttribute("stroke")!="none"&&!isNaN(w))v+=w/2;return v},s=[];$.each(b,function(B,w){var v=c(w);if(v){var C=l(w);A=Math.min(A,v.x-C);o=Math.min(o,v.y-C);s.push(v)}});d.x=A;d.y=o;$.each(b,function(B,w){var v=s[B];if(v&&w.nodeType==1){var C=l(w);n=Math.max(n,v.x+v.width+C);m=Math.max(m,v.y+v.height+C)}});d.width=n-A;d.height=m-o;return d};var Lb=this.getVisibleElements=function(b){b|| -(b=$(p).children());var c=[];$(b).children().each(function(d,n){try{n.getBBox()&&c.push(n)}catch(m){}});return c.reverse()},Sb=this.getVisibleElementsAndBBoxes=function(b){b||(b=$(p).children());var c=[];$(b).children().each(function(d,n){try{n.getBBox()&&c.push({elem:n,bbox:getStrokedBBox([n])})}catch(m){}});return c.reverse()},pa=this.groupSvgElem=function(b){var c=document.createElementNS(i,"g");b.parentNode.replaceChild(c,b);$(c).append(b).data("gsvg",b)[0].id=ya()},V=function(b){var c=document.createElementNS(b.namespaceURI, -b.nodeName);c.removeAttribute("id");$.each(b.attributes,function(n,m){m.localName!="-moz-math-font-style"&&c.setAttributeNS(m.namespaceURI,m.nodeName,m.nodeValue)});if(svgedit.browser.isWebkit()&&b.nodeName=="path"){var d=La.convertPath(b);c.setAttribute("d",d)}$.each(b.childNodes,function(n,m){switch(m.nodeType){case 1:c.appendChild(V(m));break;case 3:c.textContent=m.nodeValue}});if($(b).data("gsvg"))$(c).data("gsvg",c.firstChild);else if($(b).data("symbol")){b=$(b).data("symbol");$(c).data("ref", -b).data("symbol",b)}else c.tagName=="image"&&Yb(c);c.id=ya();console.log(c);return c},ua,ya,aa;(function(b){var c={};ua=b.getId=function(){return D().getId()};ya=b.getNextId=function(){return D().getNextId()};aa=b.call=function(d,n){if(c[d])return c[d](this,n)};b.bind=function(d,n){var m=c[d];c[d]=n;return m}})(e);this.prepareSvg=function(b){this.sanitizeSvg(b.documentElement);b=b.getElementsByTagNameNS(i,"path");for(var c=0,d=b.length;c<d;++c){var n=b[c];n.setAttribute("d",La.convertPath(n));La.fixEnd(n)}}; -var Sa=this.getRefElem=function(b){return ja(Ra(b).substr(1))},Eb=function(b){if(!svgedit.browser.isGecko())return b;var c=b.cloneNode(true);b.parentNode.insertBefore(c,b);b.parentNode.removeChild(b);Ha.releaseSelector(b);I[0]=c;Ha.requestSelector(c).showGrips(true);return c};this.setRotationAngle=function(b,c){b=parseFloat(b);var d=I[0],n=d.getAttribute("transform"),m=svgedit.utilities.getBBox(d),A=m.x+m.width/2,o=m.y+m.height/2;m=ia(d);m.numberOfItems>0&&m.getItem(0).type==4&&m.removeItem(0);if(b!= -0){A=ka(A,o,ga(m).matrix);o=g.createSVGTransform();o.setRotate(b,A.x,A.y);m.numberOfItems?m.insertItemBefore(o,0):m.appendItem(o)}else m.numberOfItems==0&&d.removeAttribute("transform");if(!c){m=d.getAttribute("transform");d.setAttribute("transform",n);jb("transform",m,I);aa("changed",I)}ja("pathpointgrip_container");d=Ha.requestSelector(I[0]);d.resize();d.updateGripCursors(b)};var Ab=this.recalculateAllSelectedDimensions=function(){for(var b=new Ga(kb=="none"?"position":"size"),c=I.length;c--;){var d= -nb(I[c]);d&&b.addSubCommand(d)}if(!b.isEmpty()){Ca(b);aa("changed",I)}},wb=[0,"z","M","m","L","l","C","c","Q","q","A","a","H","h","V","v","S","s","T","t"],tb=function(b){console.log([b.a,b.b,b.c,b.d,b.e,b.f])},Fb=this.remapElement=function(b,c,d){var n=u.gridSnapping&&b.parentNode.parentNode.localName==="svg",m=function(){if(n)for(var v in c)c[v]=Aa(c[v]);la(b,c,1E3,true)};box=svgedit.utilities.getBBox(b);for(var A=0;A<2;A++){var o=A===0?"fill":"stroke",l=b.getAttribute(o);if(l&&l.indexOf("url(")=== -0)if(d.a<0||d.d<0){l=Sa(l).cloneNode(true);if(d.a<0){var s=l.getAttribute("x1"),B=l.getAttribute("x2");l.setAttribute("x1",-(s-1));l.setAttribute("x2",-(B-1))}if(d.d<0){s=l.getAttribute("y1");B=l.getAttribute("y2");l.setAttribute("y1",-(s-1));l.setAttribute("y2",-(B-1))}l.id=ya();ib().appendChild(l);b.setAttribute(o,"url(#"+l.id+")")}}A=b.tagName;if(A==="g"||A==="text"||A==="use")if(d.a==1&&d.b==0&&d.c==0&&d.d==1&&(d.e!=0||d.f!=0)){o=ga(b).matrix;o=X(o.inverse(),d,o);c.x=parseFloat(c.x)+o.e;c.y=parseFloat(c.y)+ -o.f}else{o=ia(b);l=g.createSVGTransform();l.setMatrix(X(ga(o).matrix,d));o.clear();o.appendItem(l)}switch(A){case "foreignObject":case "rect":case "image":if(A==="image"&&(d.a<0||d.d<0)){o=ia(b);l=g.createSVGTransform();l.setMatrix(X(ga(o).matrix,d));o.clear();o.appendItem(l)}else{o=ka(c.x,c.y,d);c.width=d.a*c.width;c.height=d.d*c.height;c.x=o.x+Math.min(0,c.width);c.y=o.y+Math.min(0,c.height);c.width=Math.abs(c.width);c.height=Math.abs(c.height)}m();break;case "ellipse":A=ka(c.cx,c.cy,d);c.cx=A.x; -c.cy=A.y;c.rx=d.a*c.rx;c.ry=d.d*c.ry;c.rx=Math.abs(c.rx);c.ry=Math.abs(c.ry);m();break;case "circle":A=ka(c.cx,c.cy,d);c.cx=A.x;c.cy=A.y;A=svgedit.math.transformBox(box.x,box.y,box.width,box.height,d);c.r=Math.min((A.tr.x-A.tl.x)/2,(A.bl.y-A.tl.y)/2);if(c.r)c.r=Math.abs(c.r);m();break;case "line":o=ka(c.x1,c.y1,d);s=ka(c.x2,c.y2,d);c.x1=o.x;c.y1=o.y;c.x2=s.x;c.y2=s.y;case "text":d=b.querySelectorAll("tspan");for(A=d.length;A--;){o=ha("x",b.getAttribute("x"));l=ha("x",d[A].getAttribute("x"));s=ha("y", -b.getAttribute("y"));B=ha("y",d[A].getAttribute("y"));var w={};if(!isNaN(o)&&!isNaN(l)&&o!=0&&l!=0&&c.x)w.x=c.x-(o-l);if(!isNaN(s)&&!isNaN(B)&&s!=0&&B!=0&&c.y)w.y=c.y-(s-B);if(w.x||w.y)la(d[A],w,1E3,true)}m();break;case "use":m();break;case "g":(m=$(b).data("gsvg"))&&la(m,c,1E3,true);break;case "polyline":case "polygon":m=c.points.length;for(A=0;A<m;++A){B=c.points[A];B=ka(B.x,B.y,d);c.points[A].x=B.x;c.points[A].y=B.y}m=c.points.length;d="";for(A=0;A<m;++A){B=c.points[A];d+=B.x+","+B.y+" "}b.setAttribute("points", -d);break;case "path":o=b.pathSegList;m=o.numberOfItems;c.d=Array(m);for(A=0;A<m;++A){l=o.getItem(A);c.d[A]={type:l.pathSegType,x:l.x,y:l.y,x1:l.x1,y1:l.y1,x2:l.x2,y2:l.y2,r1:l.r1,r2:l.r2,angle:l.angle,largeArcFlag:l.largeArcFlag,sweepFlag:l.sweepFlag}}m=c.d.length;A=c.d[0];w=ka(A.x,A.y,d);c.d[0].x=w.x;c.d[0].y=w.y;for(A=1;A<m;++A){l=c.d[A];o=l.type;if(o%2==0){B=ka(l.x!=undefined?l.x:w.x,l.y!=undefined?l.y:w.y,d);o=ka(l.x1,l.y1,d);s=ka(l.x2,l.y2,d);l.x=B.x;l.y=B.y;l.x1=o.x;l.y1=o.y;l.x2=s.x;l.y2=s.y}else{l.x= -d.a*l.x;l.y=d.d*l.y;l.x1=d.a*l.x1;l.y1=d.d*l.y1;l.x2=d.a*l.x2;l.y2=d.d*l.y2}l.r1=d.a*l.r1;l.r2=d.d*l.r2}d="";m=c.d.length;for(A=0;A<m;++A){l=c.d[A];o=l.type;d+=wb[o];switch(o){case 13:case 12:d+=l.x+" ";break;case 15:case 14:d+=l.y+" ";break;case 3:case 5:case 19:case 2:case 4:case 18:d+=l.x+","+l.y+" ";break;case 7:case 6:d+=l.x1+","+l.y1+" "+l.x2+","+l.y2+" "+l.x+","+l.y+" ";break;case 9:case 8:d+=l.x1+","+l.y1+" "+l.x+","+l.y+" ";break;case 11:case 10:d+=l.r1+","+l.r2+" "+l.angle+" "+ +l.largeArcFlag+ -" "+ +l.sweepFlag+" "+l.x+","+l.y+" ";break;case 17:case 16:d+=l.x2+","+l.y2+" "+l.x+","+l.y+" "}}b.setAttribute("d",d)}},Qb=function(b,c,d){b=Sa(b).firstChild;var n=ia(b),m=g.createSVGTransform();m.setTranslate(c,d);n.appendItem(m);nb(b)},nb=this.recalculateDimensions=function(b){if(b==null)return null;var c=ia(b);if(c&&c.numberOfItems>0){for(var d=c.numberOfItems;d--;){var n=c.getItem(d);if(n.type===0)c.removeItem(d);else if(n.type===1)svgedit.math.isIdentity(n.matrix)&&c.removeItem(d);else n.type=== -4&&n.angle===0&&c.removeItem(d)}if(c.numberOfItems===1&&ra(b))return null}if(!c||c.numberOfItems==0){b.removeAttribute("transform");return null}if(c){d=c.numberOfItems;for(var m=[];d--;){n=c.getItem(d);if(n.type===1)m.push([n.matrix,d]);else if(m.length)m=[]}if(m.length===2){d=g.createSVGTransformFromMatrix(X(m[1][0],m[0][0]));c.removeItem(m[0][1]);c.removeItem(m[1][1]);c.insertItemBefore(d,m[1][1])}d=c.numberOfItems;if(d>=2&&c.getItem(d-2).type===1&&c.getItem(d-1).type===2){m=g.createSVGTransform(); -n=X(c.getItem(d-2).matrix,c.getItem(d-1).matrix);m.setMatrix(n);c.removeItem(d-2);c.removeItem(d-2);c.appendItem(m)}}switch(b.tagName){case "line":case "polyline":case "polygon":case "path":break;default:if(c.numberOfItems===1&&c.getItem(0).type===1||c.numberOfItems===2&&c.getItem(0).type===1&&c.getItem(0).type===4)return null}var A=$(b).data("gsvg");d=new Ga("Transform");var o={},l=null;n=[];switch(b.tagName){case "line":n=["x1","y1","x2","y2"];break;case "circle":n=["cx","cy","r"];break;case "ellipse":n= -["cx","cy","rx","ry"];break;case "foreignObject":case "rect":case "image":n=["width","height","x","y"];break;case "use":case "text":case "tspan":n=["x","y"];break;case "polygon":case "polyline":l={};l.points=b.getAttribute("points");m=b.points;var s=m.numberOfItems;o.points=Array(s);for(var B=0;B<s;++B){var w=m.getItem(B);o.points[B]={x:w.x,y:w.y}}break;case "path":l={};l.d=b.getAttribute("d");o.d=b.getAttribute("d")}if(n.length){o=$(b).attr(n);$.each(o,function(yb,Gb){o[yb]=ha(yb,Gb)})}else if(A)o= -{x:$(A).attr("x")||0,y:$(A).attr("y")||0};if(l==null){l=$.extend(true,{},o);$.each(l,function(yb,Gb){l[yb]=ha(yb,Gb)})}l.transform=Wa?Wa:"";if(b.tagName=="g"&&!A||b.tagName=="a"){m=svgedit.utilities.getBBox(b);var v={x:m.x+m.width/2,y:m.y+m.height/2},C=ka(m.x+m.width/2,m.y+m.height/2,ga(c).matrix);n=g.createSVGMatrix();if(m=ra(b)){B=m*Math.PI/180;s=Math.abs(B)>1.0E-10?Math.sin(B)/(1-Math.cos(B)):2/B;for(B=0;B<c.numberOfItems;++B){n=c.getItem(B);if(n.type==4){n=n.matrix;v.y=(s*n.e+n.f)/2;v.x=(n.e- -s*n.f)/2;c.removeItem(B);break}}}B=n=A=0;var F=c.numberOfItems;if(F)var J=c.getItem(0).matrix;if(F>=3&&c.getItem(F-2).type==3&&c.getItem(F-3).type==2&&c.getItem(F-1).type==2){B=3;var K=c.getItem(F-3).matrix,P=c.getItem(F-2).matrix,ca=c.getItem(F-1).matrix;s=b.childNodes;for(w=s.length;w--;){var fa=s.item(w);n=A=0;if(fa.nodeType==1){var R=ia(fa);if(R){n=ga(R).matrix;A=ra(fa);var W=Wa,Y=[];Wa=fa.getAttribute("transform");if(A||qa(R)){var na=g.createSVGTransform();na.setMatrix(X(K,P,ca,n));R.clear(); -R.appendItem(na);Y.push(na)}else{A=X(n.inverse(),ca,n);na=g.createSVGMatrix();na.e=-A.e;na.f=-A.f;n=X(na.inverse(),n.inverse(),K,P,ca,n,A.inverse());var Xa=g.createSVGTransform(),qb=g.createSVGTransform(),Hb=g.createSVGTransform();Xa.setTranslate(A.e,A.f);qb.setScale(n.a,n.d);Hb.setTranslate(na.e,na.f);R.appendItem(Hb);R.appendItem(qb);R.appendItem(Xa);Y.push(Hb);Y.push(qb);Y.push(Xa)}d.addSubCommand(nb(fa));Wa=W}}}c.removeItem(F-1);c.removeItem(F-2);c.removeItem(F-3)}else if(F>=3&&c.getItem(F-1).type== -1){B=3;n=ga(c).matrix;na=g.createSVGTransform();na.setMatrix(n);c.clear();c.appendItem(na)}else if((F==1||F>1&&c.getItem(1).type!=3)&&c.getItem(0).type==2){B=2;A=ga(c).matrix;c.removeItem(0);n=ga(c).matrix.inverse();n=X(n,A);A=n.e;n=n.f;if(A!=0||n!=0){s=b.childNodes;w=s.length;for(F=[];w--;){fa=s.item(w);if(fa.nodeType==1){if(fa.getAttribute("clip-path")){W=fa.getAttribute("clip-path");if(F.indexOf(W)===-1){Qb(W,A,n);F.push(W)}}W=Wa;Wa=fa.getAttribute("transform");if(R=ia(fa)){K=g.createSVGTransform(); -K.setTranslate(A,n);R.numberOfItems?R.insertItemBefore(K,0):R.appendItem(K);d.addSubCommand(nb(fa));R=b.getElementsByTagNameNS(i,"use");fa="#"+fa.id;for(K=R.length;K--;){P=R.item(K);if(fa==U(P)){ca=g.createSVGTransform();ca.setTranslate(-A,-n);ia(P).insertItemBefore(ca,0);d.addSubCommand(nb(P))}}Wa=W}}}F=[];Wa=W}}else if(F==1&&c.getItem(0).type==1&&!m){B=1;n=c.getItem(0).matrix;s=b.childNodes;for(w=s.length;w--;){fa=s.item(w);if(fa.nodeType==1){W=Wa;Wa=fa.getAttribute("transform");if(R=ia(fa)){A= -X(n,ga(R).matrix);F=g.createSVGTransform();F.setMatrix(A);R.clear();R.appendItem(F,0);d.addSubCommand(nb(fa));Wa=W;W=fa.getAttribute("stroke-width");fa.getAttribute("stroke")!=="none"&&!isNaN(W)&&fa.setAttribute("stroke-width",W*((Math.abs(A.a)+Math.abs(A.d))/2))}}}c.clear()}else{if(m){v=g.createSVGTransform();v.setRotate(m,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}c.numberOfItems==0&&b.removeAttribute("transform");return null}if(B==2){if(m){C={x:v.x+J.e,y:v.y+J.f};v=g.createSVGTransform(); -v.setRotate(m,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}else if(B==3){n=ga(c).matrix;J=g.createSVGTransform();J.setRotate(m,v.x,v.y);J=J.matrix;v=g.createSVGTransform();v.setRotate(m,C.x,C.y);C=v.matrix.inverse();W=n.inverse();C=X(W,C,J,n);A=C.e;n=C.f;if(A!=0||n!=0){s=b.childNodes;for(w=s.length;w--;){fa=s.item(w);if(fa.nodeType==1){W=Wa;Wa=fa.getAttribute("transform");R=ia(fa);K=g.createSVGTransform();K.setTranslate(A,n);R.numberOfItems?R.insertItemBefore(K,0):R.appendItem(K); -d.addSubCommand(nb(fa));Wa=W}}}if(m)c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}else{m=svgedit.utilities.getBBox(b);if(!m&&b.tagName!="path")return null;n=g.createSVGMatrix();if(A=ra(b)){v={x:m.x+m.width/2,y:m.y+m.height/2};C=ka(m.x+m.width/2,m.y+m.height/2,ga(c).matrix);B=A*Math.PI/180;s=Math.abs(B)>1.0E-10?Math.sin(B)/(1-Math.cos(B)):2/B;for(B=0;B<c.numberOfItems;++B){n=c.getItem(B);if(n.type==4){n=n.matrix;v.y=(s*n.e+n.f)/2;v.x=(n.e-s*n.f)/2;c.removeItem(B);break}}}B=0;F=c.numberOfItems; -if(!svgedit.browser.isWebkit())if((J=b.getAttribute("fill"))&&J.indexOf("url(")===0){J=Sa(J);W="pattern";if(J.tagName!==W)W="gradient";if(J.getAttribute(W+"Units")==="userSpaceOnUse"){n=ga(c).matrix;m=ia(J);m=ga(m).matrix;n=X(n,m);m="matrix("+[n.a,n.b,n.c,n.d,n.e,n.f].join(",")+")";J.setAttribute(W+"Transform",m)}}if(F>=3&&c.getItem(F-2).type==3&&c.getItem(F-3).type==2&&c.getItem(F-1).type==2){B=3;n=ga(c,F-3,F-1).matrix;c.removeItem(F-1);c.removeItem(F-2);c.removeItem(F-3)}else if(F==4&&c.getItem(F- -1).type==1){B=3;n=ga(c).matrix;na=g.createSVGTransform();na.setMatrix(n);c.clear();c.appendItem(na);n=g.createSVGMatrix()}else if((F==1||F>1&&c.getItem(1).type!=3)&&c.getItem(0).type==2){B=2;J=c.getItem(0).matrix;W=ga(c,1).matrix;m=W.inverse();n=X(m,J,W);c.removeItem(0)}else if(F==1&&c.getItem(0).type==1&&!A){n=ga(c).matrix;switch(b.tagName){case "line":o=$(b).attr(["x1","y1","x2","y2"]);case "polyline":case "polygon":o.points=b.getAttribute("points");if(o.points){m=b.points;s=m.numberOfItems;o.points= -Array(s);for(B=0;B<s;++B){w=m.getItem(B);o.points[B]={x:w.x,y:w.y}}}case "path":o.d=b.getAttribute("d");B=1;c.clear()}}else{B=4;if(A){v=g.createSVGTransform();v.setRotate(A,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}c.numberOfItems==0&&b.removeAttribute("transform");return null}if(B==1||B==2||B==3)Fb(b,o,n);if(B==2){if(A){qa(c)||(C={x:v.x+n.e,y:v.y+n.f});v=g.createSVGTransform();v.setRotate(A,C.x,C.y);c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}else if(B==3&&A){n= -ga(c).matrix;J=g.createSVGTransform();J.setRotate(A,v.x,v.y);J=J.matrix;v=g.createSVGTransform();v.setRotate(A,C.x,C.y);C=v.matrix.inverse();W=n.inverse();C=X(W,C,J,n);Fb(b,o,C);if(A)c.numberOfItems?c.insertItemBefore(v,0):c.appendItem(v)}}c.numberOfItems==0&&b.removeAttribute("transform");d.addSubCommand(new Qa(b,l));return d},Mb=null,Ta=this.clearSelection=function(b){if(I[0]!=null)for(var c=I.length,d=0;d<c;++d){var n=I[d];if(n==null)break;Ha.releaseSelector(n);I[d]=null}b||aa("selected",I)},eb= -this.addToSelection=function(b,c){if(b.length!=0){for(var d=0;d<I.length;){if(I[d]==null)break;++d}for(var n=b.length;n--;){var m=b[n];if(m&&svgedit.utilities.getBBox(m)){if(m.tagName==="a"&&m.childNodes.length===1)m=m.firstChild;if(I.indexOf(m)==-1){I[d]=m;d++;m=Ha.requestSelector(m);I.length>1&&m.showGrips(false)}}}aa("selected",I);c||I.length==1?Ha.requestSelector(I[0]).showGrips(true):Ha.requestSelector(I[0]).showGrips(false);for(I.sort(function(A,o){if(A&&o&&A.compareDocumentPosition)return 3- -(o.compareDocumentPosition(A)&6);else if(A==null)return 1});I[0]==null;)I.shift(0)}},Ib=this.selectOnly=function(b,c){Ta(true);eb(b,c)};this.removeFromSelection=function(b){if(I[0]!=null)if(b.length!=0){var c=Array(I.length);j=0;len=I.length;for(var d=0;d<len;++d){var n=I[d];if(n)if(b.indexOf(n)==-1){c[j]=n;j++}else Ha.releaseSelector(n)}I=c}};this.selectAllInCurrentLayer=function(){var b=D().getCurrentLayer();if(b){Ia="select";Ib($(M||b).children())}};var Zb=this.getMouseTarget=function(b){if(b== -null)return null;b=b.target;if(b.correspondingUseElement)b=b.correspondingUseElement;if(["http://www.w3.org/1998/Math/MathML","http://www.w3.org/1999/xhtml"].indexOf(b.namespaceURI)>=0&&b.id!="svgcanvas")for(;b.nodeName!="foreignObject";){b=b.parentNode;if(!b)return g}var c=D().getCurrentLayer();if([g,a,p,c].indexOf(b)>=0)return g;if($(b).closest("#selectorParentGroup").length)return Ha.selectorParentGroup;for(;b.parentNode!==(M||c);)b=b.parentNode;return b};(function(){var b=null,c=null,d=null,n= -null,m=null,A={},o={minx:null,miny:null,maxx:null,maxy:null};$(a).mousedown(function(l){if(!(e.spaceKey||l.button===1)){var s=l.button===2;l.altKey&&svgCanvas.cloneSelectedElements(0,0);Mb=p.getScreenCTM().inverse();var B=ka(l.pageX,l.pageY,Mb),w=B.x*q,v=B.y*q;l.preventDefault();if(s){Ia="select";xb=B}B=w/q;v=v/q;var C=Zb(l);if(C.tagName==="a"&&C.childNodes.length===1)C=C.firstChild;w=n=c=B;var F=m=d=v;if(u.gridSnapping){B=Aa(B);v=Aa(v);c=Aa(c);d=Aa(d)}if(C==Ha.selectorParentGroup&&I[0]!=null){C= -l.target;var J=gb(C,"type");if(J=="rotate"){Ia="rotate";current_rotate_mode=gb(C,"dir")}else if(J=="resize"){Ia="resize";kb=gb(C,"dir")}C=I[0]}Wa=C.getAttribute("transform");J=ia(C);switch(Ia){case "select":Ja=true;kb="none";if(s)Ja=false;if(C!=g){if(I.indexOf(C)==-1){l.shiftKey||Ta(true);eb([C]);db=C;La.clear()}if(!s)for(s=0;s<I.length;++s)if(I[s]!=null){var K=ia(I[s]);K.numberOfItems?K.insertItemBefore(g.createSVGTransform(),0):K.appendItem(g.createSVGTransform())}}else if(!s){Ta();Ia="multiselect"; -if(za==null)za=Ha.getRubberBandBox();n*=q;m*=q;la(za,{x:n,y:m,width:0,height:0,display:"inline"},100)}break;case "zoom":Ja=true;if(za==null)za=Ha.getRubberBandBox();la(za,{x:w*q,y:w*q,width:0,height:0,display:"inline"},100);break;case "resize":Ja=true;c=B;d=v;A=svgedit.utilities.getBBox($("#selectedBox0")[0]);var P={};$.each(A,function(ca,fa){P[ca]=fa/q});A=P;s=ra(C)?1:0;if(qa(J)){J.insertItemBefore(g.createSVGTransform(),s);J.insertItemBefore(g.createSVGTransform(),s);J.insertItemBefore(g.createSVGTransform(), -s)}else{J.appendItem(g.createSVGTransform());J.appendItem(g.createSVGTransform());J.appendItem(g.createSVGTransform());if(svgedit.browser.supportsNonScalingStroke()){if(B=svgedit.browser.isChrome())K=function(ca){var fa=ca.getAttributeNS(null,"stroke");ca.removeAttributeNS(null,"stroke");setTimeout(function(){ca.setAttributeNS(null,"stroke",fa)},1)};C.style.vectorEffect="non-scaling-stroke";B&&K(C);v=C.getElementsByTagName("*");w=v.length;for(s=0;s<w;s++){v[s].style.vectorEffect="non-scaling-stroke"; -B&&K(v[s])}}}break;case "fhellipse":case "fhrect":case "fhpath":Ja=true;b=w+","+F+" ";K=N.stroke_width==0?1:N.stroke_width;ma({element:"polyline",curStyles:true,attr:{points:b,id:ya(),fill:"none",opacity:N.opacity/2,"stroke-linecap":"round",style:"pointer-events:none"}});o.minx=w;o.maxx=w;o.miny=F;o.maxy=F;break;case "image":Ja=true;K=ma({element:"image",attr:{x:B,y:v,width:0,height:0,id:ya(),opacity:N.opacity/2,style:"pointer-events:inherit"}});Z(K,ub);Yb(K);break;case "square":case "rect":Ja=true; -c=B;d=v;ma({element:"rect",curStyles:true,attr:{x:B,y:v,width:0,height:0,id:ya(),opacity:N.opacity/2}});break;case "line":Ja=true;K=N.stroke_width==0?1:N.stroke_width;ma({element:"line",curStyles:true,attr:{x1:B,y1:v,x2:B,y2:v,id:ya(),stroke:N.stroke,"stroke-width":K,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,fill:"none",opacity:N.opacity/2,style:"pointer-events:none"}});break;case "circle":Ja=true; -ma({element:"circle",curStyles:true,attr:{cx:B,cy:v,r:0,id:ya(),opacity:N.opacity/2}});break;case "ellipse":Ja=true;ma({element:"ellipse",curStyles:true,attr:{cx:B,cy:v,rx:0,ry:0,id:ya(),opacity:N.opacity/2}});break;case "text":Ja=true;ma({element:"text",curStyles:true,attr:{x:B,y:v,id:ya(),fill:ab.fill,"stroke-width":ab.stroke_width,"font-size":ab.font_size,"font-family":ab.font_family,"text-anchor":"middle","xml:space":"preserve",opacity:N.opacity}});break;case "path":case "pathedit":c*=q;d*=q; -La.mouseDown(l,C,c,d);Ja=true;break;case "textedit":c*=q;d*=q;fb.mouseDown(l,C,c,d);Ja=true;break;case "rotate":Ja=true;e.undoMgr.beginUndoableChange("transform",I);document.getElementById("workarea").className="rotate"}l=pb("mouseDown",{event:l,start_x:c,start_y:d,selectedElements:I},true);$.each(l,function(ca,fa){if(fa&&fa.started)Ja=true})}}).mousemove(function(l){if(Ja)if(!(l.button===1||e.spaceKey)){var s=I[0],B=ka(l.pageX,l.pageY,Mb),w=B.x*q;B=B.y*q;var v=ja(ua()),C=x=w/q,F=y=B/q;if(u.gridSnapping){x= -Aa(x);y=Aa(y)}l.preventDefault();switch(Ia){case "select":if(I[0]!==null){C=x-c;var J=y-d;if(u.gridSnapping){C=Aa(C);J=Aa(J)}if(l.shiftKey){var K=Na(c,d,x,y);x=K.x;y=K.y}if(C!=0||J!=0){K=I.length;for(F=0;F<K;++F){s=I[F];if(s==null)break;var P=g.createSVGTransform();v=ia(s);P.setTranslate(C,J);v.numberOfItems?v.replaceItem(P,0):v.appendItem(P);Ha.requestSelector(s).resize()}aa("transition",I)}}break;case "multiselect":C*=q;F*=q;la(za,{x:Math.min(n,C),y:Math.min(m,F),width:Math.abs(C-n),height:Math.abs(F- -m)},100);v=[];C=[];P=Rb();K=I.length;for(F=0;F<K;++F){J=P.indexOf(I[F]);if(J==-1)v.push(I[F]);else P[J]=null}K=P.length;for(F=0;F<K;++F)P[F]&&C.push(P[F]);v.length>0&&e.removeFromSelection(v);C.length>0&&eb(C);break;case "resize":v=ia(s);C=(K=qa(v))?A:svgedit.utilities.getBBox(s);F=C.x;P=C.y;var ca=C.width,fa=C.height;C=x-c;J=y-d;if(u.gridSnapping){C=Aa(C);J=Aa(J);fa=Aa(fa);ca=Aa(ca)}var R=ra(s);if(R){var W=Math.sqrt(C*C+J*J);J=Math.atan2(J,C)-R*Math.PI/180;C=W*Math.cos(J);J=W*Math.sin(J)}if(kb.indexOf("n")== --1&&kb.indexOf("s")==-1)J=0;if(kb.indexOf("e")==-1&&kb.indexOf("w")==-1)C=0;var Y=W=0,na=fa?(fa+J)/fa:1,Xa=ca?(ca+C)/ca:1;if(kb.indexOf("n")>=0){na=fa?(fa-J)/fa:1;Y=fa}if(kb.indexOf("w")>=0){Xa=ca?(ca-C)/ca:1;W=ca}C=g.createSVGTransform();J=g.createSVGTransform();ca=g.createSVGTransform();if(u.gridSnapping){F=Aa(F);W=Aa(W);P=Aa(P);Y=Aa(Y)}C.setTranslate(-(F+W),-(P+Y));if(l.shiftKey)if(Xa==1)Xa=na;else na=Xa;J.setScale(Xa,na);ca.setTranslate(F+W,P+Y);if(K){K=R?1:0;v.replaceItem(C,2+K);v.replaceItem(J, -1+K);v.replaceItem(ca,0+K)}else{K=v.numberOfItems;v.replaceItem(ca,K-3);v.replaceItem(J,K-2);v.replaceItem(C,K-1)}Ha.requestSelector(s).resize();aa("transition",I);break;case "zoom":C*=q;F*=q;la(za,{x:Math.min(n*q,C),y:Math.min(m*q,F),width:Math.abs(C-n*q),height:Math.abs(F-m*q)},100);break;case "text":la(v,{x:x,y:y},1E3);break;case "line":C=null;window.opera||g.suspendRedraw(1E3);if(u.gridSnapping){x=Aa(x);y=Aa(y)}F=x;K=y;if(l.shiftKey){K=Na(c,d,F,K);F=K.x;K=K.y}v.setAttributeNS(null,"x2",F);v.setAttributeNS(null, -"y2",K);window.opera||g.unsuspendRedraw(C);break;case "foreignObject":case "square":case "rect":case "image":C=Math.abs(x-c);K=Math.abs(y-d);if(Ia=="square"||l.shiftKey){C=K=Math.max(C,K);F=c<x?c:c-C;P=d<y?d:d-K}else{F=Math.min(c,x);P=Math.min(d,y)}if(u.gridSnapping){C=Aa(C);K=Aa(K);F=Aa(F);P=Aa(P)}la(v,{width:C,height:K,x:F,y:P},1E3);break;case "circle":C=$(v).attr(["cx","cy"]);K=C.cx;F=C.cy;C=Math.sqrt((x-K)*(x-K)+(y-F)*(y-F));if(u.gridSnapping)C=Aa(C);v.setAttributeNS(null,"r",C);break;case "ellipse":C= -$(v).attr(["cx","cy"]);K=C.cx;F=C.cy;C=null;window.opera||g.suspendRedraw(1E3);if(u.gridSnapping){x=Aa(x);K=Aa(K);y=Aa(y);F=Aa(F)}v.setAttributeNS(null,"rx",Math.abs(x-K));v.setAttributeNS(null,"ry",Math.abs(l.shiftKey?x-K:y-F));window.opera||g.unsuspendRedraw(C);break;case "fhellipse":case "fhrect":o.minx=Math.min(C,o.minx);o.maxx=Math.max(C,o.maxx);o.miny=Math.min(F,o.miny);o.maxy=Math.max(F,o.maxy);case "fhpath":b+=+C+","+F+" ";v.setAttributeNS(null,"points",b);break;case "path":case "pathedit":x*= -q;y*=q;if(u.gridSnapping){x=Aa(x);y=Aa(y);c=Aa(c);d=Aa(d)}if(l.shiftKey){if(K=svgedit.path.path){v=K.dragging?K.dragging[0]:c;K=K.dragging?K.dragging[1]:d}else{v=c;K=d}K=Na(v,K,x,y);x=K.x;y=K.y}if(za&&za.getAttribute("display")!=="none"){C*=q;F*=q;la(za,{x:Math.min(n*q,C),y:Math.min(m*q,F),width:Math.abs(C-n*q),height:Math.abs(F-m*q)},100)}La.mouseMove(l,x,y);break;case "textedit":x*=q;y*=q;fb.mouseMove(w,B);break;case "rotate":C=svgedit.utilities.getBBox(s);K=C.x+C.width/2;F=C.y+C.height/2;v=va(s); -v=ka(K,F,v);K=v.x;F=v.y;v=C.x;P=C.y;if(current_rotate_mode=="nw")v=C.x+C.width;if(current_rotate_mode=="se")P=C.y+C.height;if(current_rotate_mode=="sw"){v=C.x+C.width;P=C.y+C.height}compensation_angle=(Math.atan2(F-P,K-v)*(180/Math.PI)-90)%360;R=(Math.atan2(F-y,K-x)*(180/Math.PI)-90)%360;R+=compensation_angle;if(u.gridSnapping)R=Aa(R);if(l.shiftKey)R=Math.round(R/45)*45;e.setRotationAngle(R<-180?360+R:R,true);aa("transition",I)}pb("mouseMove",{event:l,mouse_x:w,mouse_y:B,selected:s})}}).click(function(l){l.preventDefault(); -return false}).dblclick(function(l){var s=l.target.parentNode;if(s!==M){var B=Zb(l),w=B.tagName;if(w==="text"&&Ia!=="textedit"){l=ka(l.pageX,l.pageY,Mb);fb.select(B,l.x,l.y)}if((w==="g"||w==="a")&&ra(B)){ec(B);B=I[0];Ta(true)}M&&$b();s.tagName!=="g"&&s.tagName!=="a"||s===D().getCurrentLayer()||B===Ha.selectorParentGroup||mc(B)}}).mouseup(function(l){if(l.button!==2){var s=db;db=null;if(Ja){var B=ka(l.pageX,l.pageY,Mb),w=B.x*q;B=B.y*q;var v=w/q,C=B/q,F=ja(ua()),J=false;Ja=false;switch(Ia){case "resize":case "multiselect":if(za!= -null){za.setAttribute("display","none");vb=[]}Ia="select";case "select":if(I[0]!=null){if(I[1]==null){w=I[0];switch(w.tagName){case "g":case "use":case "image":case "foreignObject":break;default:cb.fill=w.getAttribute("fill");cb.fill_opacity=w.getAttribute("fill-opacity");cb.stroke=w.getAttribute("stroke");cb.stroke_opacity=w.getAttribute("stroke-opacity");cb.stroke_width=w.getAttribute("stroke-width");cb.stroke_dasharray=w.getAttribute("stroke-dasharray");cb.stroke_linejoin=w.getAttribute("stroke-linejoin"); -cb.stroke_linecap=w.getAttribute("stroke-linecap")}if(w.tagName=="text"){ab.font_size=w.getAttribute("font-size");ab.font_family=w.getAttribute("font-family")}Ha.requestSelector(w).showGrips(true)}Ab();if(v!=n||C!=m){l=I.length;for(w=0;w<l;++w){if(I[w]==null)break;I[w].firstChild||Ha.requestSelector(I[w]).resize()}}else{w=l.target;if(I[0].nodeName==="path"&&I[1]==null)La.select(I[0]);else l.shiftKey&&s!=w&&e.removeFromSelection([w])}if(svgedit.browser.supportsNonScalingStroke())if(l=I[0]){l.removeAttribute("style"); -svgedit.utilities.walkTree(l,function(ca){ca.removeAttribute("style")})}}return;case "zoom":za!=null&&za.setAttribute("display","none");aa("zoomed",{x:Math.min(n,v),y:Math.min(m,C),width:Math.abs(v-n),height:Math.abs(C-m),factor:l.altKey?0.5:2});return;case "fhpath":s=F.getAttribute("points");v=s.indexOf(",");if(J=v>=0?s.indexOf(",",v+1)>=0:s.indexOf(" ",s.indexOf(" ")+1)>=0)F=La.smoothPolylineIntoPath(F);break;case "line":s=$(F).attr(["x1","x2","y1","y2"]);J=s.x1!=s.x2||s.y1!=s.y2;break;case "foreignObject":case "square":case "rect":case "image":s= -$(F).attr(["width","height"]);J=s.width!=0||s.height!=0||Ia==="image";break;case "circle":J=F.getAttribute("r")!=0;break;case "ellipse":s=$(F).attr(["rx","ry"]);J=s.rx!=null||s.ry!=null;break;case "fhellipse":if(o.maxx-o.minx>0&&o.maxy-o.miny>0){F=ma({element:"ellipse",curStyles:true,attr:{cx:(o.minx+o.maxx)/2,cy:(o.miny+o.maxy)/2,rx:(o.maxx-o.minx)/2,ry:(o.maxy-o.miny)/2,id:ua()}});aa("changed",[F]);J=true}break;case "fhrect":if(o.maxx-o.minx>0&&o.maxy-o.miny>0){F=ma({element:"rect",curStyles:true, -attr:{x:o.minx,y:o.miny,width:o.maxx-o.minx,height:o.maxy-o.miny,id:ua()}});aa("changed",[F]);J=true}break;case "text":J=true;Ib([F]);fb.start(F);break;case "path":F=null;Ja=true;s=La.mouseUp(l,F,w,B);F=s.element;J=s.keep;break;case "pathedit":J=true;F=null;La.mouseUp(l);break;case "textedit":J=false;F=null;fb.mouseUp(l,w,B);break;case "rotate":J=true;F=null;Ia="select";s=e.undoMgr.finishUndoableChange();s.isEmpty()||Ca(s);Ab();aa("changed",I)}w=pb("mouseUp",{event:l,mouse_x:w,mouse_y:B},true);$.each(w, -function(ca,fa){if(fa){J=fa.keep||J;F=fa.element;Ja=fa.started||Ja}});if(!J&&F!=null){D().releaseId(ua());F.parentNode.removeChild(F);F=null;for(w=l.target;w.parentNode.parentNode.tagName=="g";)w=w.parentNode;if((Ia!="path"||!drawn_path)&&w.parentNode.id!="selectorParentGroup"&&w.id!="svgcanvas"&&w.id!="svgroot"){e.setMode("select");Ib([w],true)}}else if(F!=null){e.addedNew=true;l=0.2;var K;if(false.beginElement&&F.getAttribute("opacity")!=N.opacity){K=$(false).clone().attr({to:N.opacity,dur:l}).appendTo(F); -try{K[0].beginElement()}catch(P){}}else l=0;setTimeout(function(){K&&K.remove();F.setAttribute("opacity",N.opacity);F.setAttribute("style","pointer-events:inherit");T(F);if(Ia==="path")La.toEditMode(F);else u.selectNew&&Ib([F],true);Ca(new Fa(F));aa("changed",[F])},l*1E3)}Wa=null}}});$(a).bind("mousewheel DOMMouseScroll",function(l){if(l.shiftKey){l.preventDefault();Mb=p.getScreenCTM().inverse();var s=ka(l.pageX,l.pageY,Mb);s={x:s.x,y:s.y,width:0,height:0};if(l.wheelDelta)if(l.wheelDelta>=120)s.factor= -2;else{if(l.wheelDelta<=-120)s.factor=0.5}else if(l.detail)if(l.detail>0)s.factor=0.5;else if(l.detail<0)s.factor=2;s.factor&&aa("zoomed",s)}})})();var Yb=function(b){$(b).click(function(c){c.preventDefault()})},fb=e.textActions=function(){function b(R){var W=B.value==="";$(B).focus();if(!arguments.length)if(W)R=0;else{if(B.selectionEnd!==B.selectionStart)return;R=B.selectionEnd}var Y;Y=F[R];W||B.setSelectionRange(R,R);w=ja("text_cursor");if(!w){w=document.createElementNS(i,"line");la(w,{id:"text_cursor", -stroke:"#333","stroke-width":1});w=ja("selectorParentGroup").appendChild(w)}C||(C=setInterval(function(){var na=w.getAttribute("display")==="none";w.setAttribute("display",na?"inline":"none")},600));W=A(Y.x,J.y);Y=A(Y.x,J.y+J.height);la(w,{x1:W.x,y1:W.y,x2:Y.x,y2:Y.y,visibility:"visible",display:"inline"});v&&v.setAttribute("d","")}function c(R,W,Y){if(R===W)b(W);else{Y||B.setSelectionRange(R,W);v=ja("text_selectblock");if(!v){v=document.createElementNS(i,"path");la(v,{id:"text_selectblock",fill:"green", -opacity:0.5,style:"pointer-events:none"});ja("selectorParentGroup").appendChild(v)}R=F[R];var na=F[W];w.setAttribute("visibility","hidden");W=A(R.x,J.y);Y=A(R.x+(na.x-R.x),J.y);var Xa=A(R.x,J.y+J.height);R=A(R.x+(na.x-R.x),J.y+J.height);la(v,{d:"M"+W.x+","+W.y+" L"+Y.x+","+Y.y+" "+R.x+","+R.y+" "+Xa.x+","+Xa.y+"z",display:"inline"})}}function d(R,W){var Y=g.createSVGPoint();Y.x=R;Y.y=W;if(F.length==1)return 0;Y=s.getCharNumAtPosition(Y);if(Y<0){Y=F.length-2;if(R<=F[0].x)Y=0}else if(Y>=F.length-2)Y= -F.length-2;var na=F[Y];R>na.x+na.width/2&&Y++;return Y}function n(R,W,Y){var na=B.selectionStart;R=d(R,W);c(Math.min(na,R),Math.max(na,R),!Y)}function m(R,W){var Y={x:R,y:W};Y.x/=q;Y.y/=q;if(K){var na=ka(Y.x,Y.y,K.inverse());Y.x=na.x;Y.y=na.y}return Y}function A(R,W){var Y={x:R,y:W};if(K){var na=ka(Y.x,Y.y,K);Y.x=na.x;Y.y=na.y}Y.x*=q;Y.y*=q;return Y}function o(R){c(0,s.textContent.length);$(this).unbind(R)}function l(R){if(fa&&s){var W=ka(R.pageX,R.pageY,Mb);W=m(W.x*q,W.y*q);W=d(W.x,W.y);var Y=s.textContent, -na=Y.substr(0,W).replace(/[a-z0-9]+$/i,"").length;Y=Y.substr(W).match(/^[a-z0-9]+/i);c(na,(Y?Y[0].length:0)+W);$(R.target).click(o);setTimeout(function(){$(R.target).unbind("click",o)},300)}}var s,B,w,v,C,F=[],J,K,P,ca,fa;return{select:function(R,W,Y){s=R;fb.toEditMode(W,Y)},start:function(R){s=R;fb.toEditMode()},mouseDown:function(R,W,Y,na){R=m(Y,na);B.focus();b(d(R.x,R.y));P=Y;ca=na},mouseMove:function(R,W){var Y=m(R,W);n(Y.x,Y.y)},mouseUp:function(R,W,Y){var na=m(W,Y);n(na.x,na.y,true);R.target!== -s&&W<P+2&&W>P-2&&Y<ca+2&&Y>ca-2&&fb.toSelectMode(true)},setCursor:b,toEditMode:function(R,W){fa=false;Ia="textedit";Ha.requestSelector(s).showGrips(false);Ha.requestSelector(s);fb.init();$(s).css("cursor","text");if(arguments.length){var Y=m(R,W);b(d(Y.x,Y.y))}else b();setTimeout(function(){fa=true},300)},toSelectMode:function(R){Ia="select";clearInterval(C);C=null;v&&$(v).attr("display","none");w&&$(w).attr("visibility","hidden");$(s).css("cursor","move");if(R){Ta();$(s).css("cursor","move");aa("selected", -[s]);eb([s],true)}s&&!s.textContent.length&&e.deleteSelectedElements();$(B).blur();s=false},setInputElem:function(R){B=R},clear:function(){Ia=="textedit"&&fb.toSelectMode()},init:function(){if(s){if(!s.parentNode){s=I[0];Ha.requestSelector(s).showGrips(false)}var R=s.textContent.length,W=s.getAttribute("transform");J=svgedit.utilities.getBBox(s);K=W?va(s):null;F=Array(R);B.focus();$(s).unbind("dblclick",l).dblclick(l);if(!R)var Y={x:J.x+J.width/2,width:0};for(W=0;W<R;W++){var na=s.getStartPositionOfChar(W); -Y=s.getEndPositionOfChar(W);if(!svgedit.browser.supportsGoodTextCharPos()){var Xa=e.contentW*q;na.x-=Xa;Y.x-=Xa;na.x/=q;Y.x/=q}F[W]={x:na.x,y:J.y,width:Y.x-na.x,height:J.height}}F.push({x:Y.x,width:0});c(B.selectionStart,B.selectionEnd,true)}}}}(),La=e.pathActions=function(){var b=false,c,d,n;svgedit.path.Path.prototype.endChanges=function(o){if(svgedit.browser.isWebkit()){var l=this.elem;l.setAttribute("d",La.convertPath(l))}o=new Qa(this.elem,{d:this.last_d},o);Ca(o);aa("changed",[this.elem])}; -svgedit.path.Path.prototype.addPtsToSelection=function(o){$.isArray(o)||(o=[o]);for(var l=0;l<o.length;l++){var s=o[l],B=this.segs[s];B.ptgrip&&this.selected_pts.indexOf(s)==-1&&s>=0&&this.selected_pts.push(s)}this.selected_pts.sort();l=this.selected_pts.length;for(o=Array(l);l--;){B=this.segs[this.selected_pts[l]];B.select(true);o[l]=B.ptgrip}La.canDeleteNodes=true;La.closed_subpath=this.subpathIsClosed(this.selected_pts[0]);aa("selected",o)};var m=c=null,A=false;return{mouseDown:function(o,l,s, -B){if(Ia==="path"){mouse_x=s;mouse_y=B;B=mouse_x/q;l=mouse_y/q;s=ja("path_stretch_line");d=[B,l];if(u.gridSnapping){B=Aa(B);l=Aa(l);mouse_x=Aa(mouse_x);mouse_y=Aa(mouse_y)}if(!s){s=document.createElementNS(i,"path");la(s,{id:"path_stretch_line",stroke:"#22C","stroke-width":"0.5",fill:"none"});s=ja("selectorParentGroup").appendChild(s)}s.setAttribute("display","inline");var w=null;if(m){w=m.pathSegList;for(var v=w.numberOfItems,C=6/q,F=false;v;){v--;var J=w.getItem(v),K=J.x;J=J.y;if(B>=K-C&&B<=K+C&& -l>=J-C&&l<=J+C){F=true;break}}C=ua();svgedit.path.removePath_(C);C=ja(C);K=w.numberOfItems;if(F){if(v<=1&&K>=2){B=w.getItem(0).x;l=w.getItem(0).y;o=s.pathSegList.getItem(1);o=o.pathSegType===4?m.createSVGPathSegLinetoAbs(B,l):m.createSVGPathSegCurvetoCubicAbs(B,l,o.x1/q,o.y1/q,B,l);B=m.createSVGPathSegClosePath();w.appendItem(o);w.appendItem(B)}else if(K<3)return w=false;$(s).remove();element=C;m=null;Ja=false;if(b){svgedit.path.path.matrix&&Fb(C,{},svgedit.path.path.matrix.inverse());s=C.getAttribute("d"); -o=$(svgedit.path.path.elem).attr("d");$(svgedit.path.path.elem).attr("d",o+s);$(C).remove();svgedit.path.path.matrix&&svgedit.path.recalcRotatedPath();svgedit.path.path.init();La.toEditMode(svgedit.path.path.elem);svgedit.path.path.selectPt();return false}}else{if(!$.contains(a,Zb(o))){console.log("Clicked outside canvas");return false}w=m.pathSegList.numberOfItems;v=m.pathSegList.getItem(w-1);C=v.x;v=v.y;if(o.shiftKey){o=Na(C,v,B,l);B=o.x;l=o.y}o=s.pathSegList.getItem(1);o=o.pathSegType===4?m.createSVGPathSegLinetoAbs(Kb(B), -Kb(l)):m.createSVGPathSegCurvetoCubicAbs(Kb(B),Kb(l),o.x1/q,o.y1/q,o.x2/q,o.y2/q);m.pathSegList.appendItem(o);B*=q;l*=q;s.setAttribute("d",["M",B,l,B,l].join(" "));s=w;if(b)s+=svgedit.path.path.segs.length;svgedit.path.addPointGrip(s,B,l)}}else{d_attr="M"+B+","+l+" ";m=ma({element:"path",curStyles:true,attr:{d:d_attr,id:ya(),opacity:N.opacity/2}});s.setAttribute("d",["M",mouse_x,mouse_y,mouse_x,mouse_y].join(" "));s=b?svgedit.path.path.segs.length:0;svgedit.path.addPointGrip(s,mouse_x,mouse_y)}}else if(svgedit.path.path){svgedit.path.path.storeD(); -C=o.target.id;if(C.substr(0,14)=="pathpointgrip_"){l=svgedit.path.path.cur_pt=parseInt(C.substr(14));svgedit.path.path.dragging=[s,B];w=svgedit.path.path.segs[l];if(o.shiftKey)w.selected?svgedit.path.path.removePtFromSelection(l):svgedit.path.path.addPtsToSelection(l);else{if(svgedit.path.path.selected_pts.length<=1||!w.selected)svgedit.path.path.clearSelection();svgedit.path.path.addPtsToSelection(l)}}else if(C.indexOf("ctrlpointgrip_")==0){svgedit.path.path.dragging=[s,B];o=C.split("_")[1].split("c"); -l=o[0]-0;svgedit.path.path.selectPt(l,o[1]-0)}if(!svgedit.path.path.dragging){if(za==null)za=Ha.getRubberBandBox();la(za,{x:s*q,y:B*q,width:0,height:0,display:"inline"},100)}}},mouseMove:function(o,l,s){A=true;if(Ia==="path"){if(m){var B=m.pathSegList,w=B.numberOfItems-1;if(d){var v=svgedit.path.addCtrlGrip("1c1"),C=svgedit.path.addCtrlGrip("0c2");v.setAttribute("cx",l);v.setAttribute("cy",s);v.setAttribute("display","inline");v=d[0];var F=d[1];B.getItem(w);var J=v+(v-l/q),K=F+(F-s/q);if(!o.altKey){C.setAttribute("cx", -J*q);C.setAttribute("cy",K*q);C.setAttribute("display","inline")}C=svgedit.path.getCtrlLine(1);var P=svgedit.path.getCtrlLine(2);la(C,{x1:l,y1:s,x2:v,y2:F,display:"inline"});o.altKey||la(P,{x1:J*q,y1:K*q,x2:v,y2:F,display:"inline"});if(w===0)n=[l,s];else{B=B.getItem(w-1);l=B.x;s=B.y;if(B.pathSegType===6){l+=l-B.x2;s+=s-B.y2}else if(n){l=n[0]/q;s=n[1]/q}svgedit.path.replacePathSeg(6,w,[v,F,l,s,J,K],m)}}else if(v=ja("path_stretch_line")){w=B.getItem(w);if(w.pathSegType===6)svgedit.path.replacePathSeg(6, -1,[l,s,(w.x+(w.x-w.x2))*q,(w.y+(w.y-w.y2))*q,l,s],v);else n?svgedit.path.replacePathSeg(6,1,[l,s,n[0],n[1],l,s],v):svgedit.path.replacePathSeg(4,1,[l,s],v)}}}else if(svgedit.path.path.dragging){v=svgedit.path.getPointFromGrip({x:svgedit.path.path.dragging[0],y:svgedit.path.path.dragging[1]},svgedit.path.path);F=svgedit.path.getPointFromGrip({x:l,y:s},svgedit.path.path);w=F.x-v.x;v=F.y-v.y;svgedit.path.path.dragging=[l,s];svgedit.path.path.dragctrl?svgedit.path.path.moveCtrl(w,v):svgedit.path.path.movePts(w, -v)}else{svgedit.path.path.selected_pts=[];svgedit.path.path.eachSeg(function(){if(this.next||this.prev){var ca=za.getBBox(),fa=svgedit.path.getGripPt(this);ca=svgedit.math.rectsIntersect(ca,{x:fa.x,y:fa.y,width:0,height:0});this.select(ca);ca&&svgedit.path.path.selected_pts.push(this.index)}})}},mouseUp:function(o,l){if(Ia==="path"){d=null;if(!m){l=ja(ua());Ja=false;n=null}return{keep:true,element:l}}if(svgedit.path.path.dragging){var s=svgedit.path.path.cur_pt;svgedit.path.path.dragging=false;svgedit.path.path.dragctrl= -false;svgedit.path.path.update();A&&svgedit.path.path.endChanges("Move path point(s)");!o.shiftKey&&!A&&svgedit.path.path.selectPt(s)}else if(za&&za.getAttribute("display")!="none"){za.setAttribute("display","none");za.getAttribute("width")<=2&&za.getAttribute("height")<=2&&La.toSelectMode(o.target)}else La.toSelectMode(o.target);A=false},toEditMode:function(o){svgedit.path.path=svgedit.path.getPath_(o);Ia="pathedit";Ta();svgedit.path.path.show(true).update();svgedit.path.path.oldbbox=svgedit.utilities.getBBox(svgedit.path.path.elem); -b=false},toSelectMode:function(o){var l=o==svgedit.path.path.elem;Ia="select";svgedit.path.path.show(false);c=false;Ta();svgedit.path.path.matrix&&svgedit.path.recalcRotatedPath();if(l){aa("selected",[o]);eb([o],true)}},addSubPath:function(o){if(o){Ia="path";b=true}else{La.clear(true);La.toEditMode(svgedit.path.path.elem)}},select:function(o){if(c===o){La.toEditMode(o);Ia="pathedit"}else c=o},reorient:function(){var o=I[0];if(o)if(ra(o)!=0){var l=new Ga("Reorient path"),s={d:o.getAttribute("d"),transform:o.getAttribute("transform")}; -l.addSubCommand(new Qa(o,s));Ta();this.resetOrientation(o);Ca(l);svgedit.path.getPath_(o).show(false).matrix=null;this.clear();eb([o],true);aa("changed",I)}},clear:function(){c=null;if(m){var o=ja(ua());$(ja("path_stretch_line")).remove();$(o).remove();$(ja("pathpointgrip_container")).find("*").attr("display","none");m=n=null;Ja=false}else Ia=="pathedit"&&this.toSelectMode();svgedit.path.path&&svgedit.path.path.init().show(false)},resetOrientation:function(o){if(o==null||o.nodeName!="path")return false; -var l=ia(o),s=ga(l).matrix;l.clear();o.removeAttribute("transform");l=o.pathSegList;for(var B=l.numberOfItems,w=0;w<B;++w){var v=l.getItem(w),C=v.pathSegType;if(C!=1){var F=[];$.each(["",1,2],function(J,K){var P=v["x"+K],ca=v["y"+K];if(P!==undefined&&ca!==undefined){P=ka(P,ca,s);F.splice(F.length,0,P.x,P.y)}});svgedit.path.replacePathSeg(C,w,F,o)}}h(o,s)},zoomChange:function(){Ia=="pathedit"&&svgedit.path.path.update()},getNodePoint:function(){var o=svgedit.path.path.segs[svgedit.path.path.selected_pts.length? -svgedit.path.path.selected_pts[0]:1];return{x:o.item.x,y:o.item.y,type:o.type}},linkControlPoints:function(o){svgedit.path.setLinkControlPoints(o)},clonePathNode:function(){svgedit.path.path.storeD();for(var o=svgedit.path.path.selected_pts,l=o.length,s=[];l--;){var B=o[l];svgedit.path.path.addSeg(B);s.push(B+l);s.push(B+l+1)}svgedit.path.path.init().addPtsToSelection(s);svgedit.path.path.endChanges("Clone path node(s)")},opencloseSubPath:function(){var o=svgedit.path.path.selected_pts;if(o.length=== -1){var l=svgedit.path.path.elem,s=l.pathSegList,B=o[0],w=null,v=null;svgedit.path.path.eachSeg(function(K){if(this.type===2&&K<=B)v=this.item;if(K<=B)return true;if(this.type===2){w=K;return false}else if(this.type===1)return w=false});if(w==null)w=svgedit.path.path.segs.length-1;if(w!==false){var C=l.createSVGPathSegLinetoAbs(v.x,v.y),F=l.createSVGPathSegClosePath();if(w==svgedit.path.path.segs.length-1){s.appendItem(C);s.appendItem(F)}else{svgedit.path.insertItemBefore(l,F,w);svgedit.path.insertItemBefore(l, -C,w)}svgedit.path.path.init().selectPt(w+1)}else if(svgedit.path.path.segs[B].mate){s.removeItem(B);s.removeItem(B);svgedit.path.path.init().selectPt(B-1)}else{for(o=0;o<s.numberOfItems;o++){var J=s.getItem(o);if(J.pathSegType===2)C=o;else if(o===B)s.removeItem(C);else if(J.pathSegType===1&&B<o){F=o-1;s.removeItem(o);break}}for(o=B-C-1;o--;)svgedit.path.insertItemBefore(l,s.getItem(C),F);l=s.getItem(C);svgedit.path.replacePathSeg(2,C,[l.x,l.y]);o=B;svgedit.path.path.init().selectPt(0)}}},deletePathNode:function(){if(La.canDeleteNodes){svgedit.path.path.storeD(); -for(var o=svgedit.path.path.selected_pts,l=o.length;l--;)svgedit.path.path.deleteSeg(o[l]);var s=function(){var B=svgedit.path.path.elem.pathSegList,w=B.numberOfItems,v=function(J,K){for(;K--;)B.removeItem(J)};if(w<=1)return true;for(;w--;){var C=B.getItem(w);if(C.pathSegType===1){C=B.getItem(w-1);var F=B.getItem(w-2);if(C.pathSegType===2){v(w-1,2);s();break}else if(F.pathSegType===2){v(w-2,3);s();break}}else if(C.pathSegType===2)if(w>0){C=B.getItem(w-1).pathSegType;if(C===2){v(w-1,1);s();break}else if(C=== -1&&B.numberOfItems-1===w){v(w,1);s();break}}}return false};s();if(svgedit.path.path.elem.pathSegList.numberOfItems<=1){La.toSelectMode(svgedit.path.path.elem);e.deleteSelectedElements()}else{svgedit.path.path.init();svgedit.path.path.clearSelection();if(window.opera){o=$(svgedit.path.path.elem);o.attr("d",o.attr("d"))}svgedit.path.path.endChanges("Delete path node(s)")}}},smoothPolylineIntoPath:function(o){var l=o.points,s=l.numberOfItems;if(s>=4){var B=l.getItem(0),w=null;o=[];o.push(["M",B.x,",", -B.y," C"].join(""));for(var v=1;v<=s-4;v+=3){var C=l.getItem(v),F=l.getItem(v+1),J=l.getItem(v+2);if(w)if((B=svgedit.path.smoothControlPoints(w,C,B))&&B.length==2){C=o[o.length-1].split(",");C[2]=B[0].x;C[3]=B[0].y;o[o.length-1]=C.join(",");C=B[1]}o.push([C.x,C.y,F.x,F.y,J.x,J.y].join(","));B=J;w=F}for(o.push("L");v<s;++v){F=l.getItem(v);o.push([F.x,F.y].join(","))}o=o.join(" ");o=ma({element:"path",curStyles:true,attr:{id:ua(),d:o,fill:"none"}})}return o},setSegType:function(o){svgedit.path.path.setSegType(o)}, -moveNode:function(o,l){var s=svgedit.path.path.selected_pts;if(s.length){svgedit.path.path.storeD();s=svgedit.path.path.segs[s[0]];var B={x:0,y:0};B[o]=l-s.item[o];s.move(B.x,B.y);svgedit.path.path.endChanges("Move path point")}},fixEnd:function(o){for(var l=o.pathSegList,s=l.numberOfItems,B,w=0;w<s;++w){var v=l.getItem(w);if(v.pathSegType===2)B=v;if(v.pathSegType===1){v=l.getItem(w-1);if(v.x!=B.x||v.y!=B.y){l=o.createSVGPathSegLinetoAbs(B.x,B.y);svgedit.path.insertItemBefore(o,l,w);La.fixEnd(o); -break}}}svgedit.browser.isWebkit()&&o.setAttribute("d",La.convertPath(o))},convertPath:function(o,l){for(var s=o.pathSegList,B=s.numberOfItems,w=0,v=0,C="",F=null,J=0;J<B;++J){var K=s.getItem(J),P=K.x||0,ca=K.y||0,fa=K.x1||0,R=K.y1||0,W=K.x2||0,Y=K.y2||0,na=K.pathSegType,Xa=wb[na]["to"+(l?"Lower":"Upper")+"Case"](),qb=function(Hb,yb,Gb){yb=yb?" "+yb.join(" "):"";Gb=Gb?" "+svgedit.units.shortFloat(Gb):"";$.each(Hb,function(ac,jc){Hb[ac]=svgedit.units.shortFloat(jc)});C+=Xa+Hb.join(" ")+yb+Gb};switch(na){case 1:C+= -"z";break;case 12:P-=w;case 13:if(l){w+=P;Xa="l"}else{P+=w;w=P;Xa="L"}qb([[P,v]]);break;case 14:ca-=v;case 15:if(l){v+=ca;Xa="l"}else{ca+=v;v=ca;Xa="L"}qb([[w,ca]]);break;case 2:case 4:case 18:P-=w;ca-=v;case 5:case 3:if(F&&s.getItem(J-1).pathSegType===1&&!l){w=F[0];v=F[1]}case 19:if(l){w+=P;v+=ca}else{P+=w;ca+=v;w=P;v=ca}if(na===3)F=[w,v];qb([[P,ca]]);break;case 6:P-=w;fa-=w;W-=w;ca-=v;R-=v;Y-=v;case 7:if(l){w+=P;v+=ca}else{P+=w;fa+=w;W+=w;ca+=v;R+=v;Y+=v;w=P;v=ca}qb([[fa,R],[W,Y],[P,ca]]);break; -case 8:P-=w;fa-=w;ca-=v;R-=v;case 9:if(l){w+=P;v+=ca}else{P+=w;fa+=w;ca+=v;R+=v;w=P;v=ca}qb([[fa,R],[P,ca]]);break;case 10:P-=w;ca-=v;case 11:if(l){w+=P;v+=ca}else{P+=w;ca+=v;w=P;v=ca}qb([[K.r1,K.r2]],[K.angle,K.largeArcFlag?1:0,K.sweepFlag?1:0],[P,ca]);break;case 16:P-=w;W-=w;ca-=v;Y-=v;case 17:if(l){w+=P;v+=ca}else{P+=w;W+=w;ca+=v;Y+=v;w=P;v=ca}qb([[W,Y],[P,ca]])}}return C}}}(),fc=this.removeUnusedDefElems=function(){var b=p.getElementsByTagNameNS(i,"defs");if(!b||!b.length)return 0;for(var c=[], -d=0,n=["fill","stroke","filter","marker-start","marker-mid","marker-end"],m=n.length,A=p.getElementsByTagNameNS(i,"*"),o=A.length,l=0;l<o;l++){for(var s=A[l],B=0;B<m;B++){var w=Ra(s.getAttribute(n[B]));w&&c.push(w.substr(1))}(s=U(s))&&s.indexOf("#")===0&&c.push(s.substr(1))}b=$(b).find("linearGradient, radialGradient, filter, marker, svg, symbol");defelem_ids=[];for(l=b.length;l--;){n=b[l];m=n.id;if(c.indexOf(m)<0){Jb[m]=n;n.parentNode.removeChild(n);d++}}return d};this.svgCanvasToString=function(){for(;fc()> -0;);La.clear(true);$.each(p.childNodes,function(d,n){d&&n.nodeType===8&&n.data.indexOf("Created with")>=0&&p.insertBefore(n,p.firstChild)});if(M){$b();Ib([M])}var b=[];$(p).find("g:data(gsvg)").each(function(){for(var d=this.attributes,n=d.length,m=0;m<n;m++)if(d[m].nodeName=="id"||d[m].nodeName=="style")n--;if(n<=0){d=this.firstChild;b.push(d);$(this).replaceWith(d)}});var c=this.svgToString(p,0);b.length&&$(b).each(function(){pa(this)});return c};this.svgToString=function(b,c){var d=[],n=svgedit.utilities.toXml, -m=u.baseUnit,A=RegExp("^-?[\\d\\.]+"+m+"$");if(b){T(b);var o=b.attributes,l,s,B=b.childNodes;for(s=0;s<c;s++)d.push(" ");d.push("<");d.push(b.nodeName);if(b.id==="svgcontent"){s=Ub();if(m!=="px"){s.w=svgedit.units.convertUnit(s.w,m)+m;s.h=svgedit.units.convertUnit(s.h,m)+m}d.push(' width="'+s.w+'" height="'+s.h+'" xmlns="'+i+'"');var w={};$(b).find("*").andSelf().each(function(){$.each(this.attributes,function(J,K){var P=K.namespaceURI;if(P&&!w[P]&&wa[P]!=="xmlns"&&wa[P]!=="xml"){w[P]=true;d.push(" xmlns:"+ -wa[P]+'="'+P+'"')}})});s=o.length;for(m=["width","height","xmlns","x","y","viewBox","id","overflow"];s--;){l=o.item(s);var v=n(l.nodeValue);if(l.nodeName.indexOf("xmlns:")!==0)if(v!=""&&m.indexOf(l.localName)==-1)if(!l.namespaceURI||wa[l.namespaceURI]){d.push(" ");d.push(l.nodeName);d.push('="');d.push(v);d.push('"')}}}else{if(b.nodeName==="defs"&&!b.firstChild)return;var C=["-moz-math-font-style","_moz-math-font-style"];for(s=o.length-1;s>=0;s--){l=o.item(s);v=n(l.nodeValue);if(!(C.indexOf(l.localName)>= -0))if(v!="")if(v.indexOf("pointer-events")!==0)if(!(l.localName==="class"&&v.indexOf("se_")===0)){d.push(" ");if(l.localName==="d")v=La.convertPath(b,true);if(isNaN(v)){if(A.test(v))v=svgedit.units.shortFloat(v)+m}else v=svgedit.units.shortFloat(v);if(Ua.apply&&b.nodeName==="image"&&l.localName==="href"&&Ua.images&&Ua.images==="embed"){var F=Va[v];if(F)v=F}if(!l.namespaceURI||l.namespaceURI==i||wa[l.namespaceURI]){d.push(l.nodeName);d.push('="');d.push(v);d.push('"')}}}}if(b.hasChildNodes()){d.push(">"); -c++;o=false;for(s=0;s<B.length;s++){m=B.item(s);switch(m.nodeType){case 1:d.push("\n");d.push(this.svgToString(B.item(s),c));break;case 3:m=m.nodeValue.replace(/^\s+|\s+$/g,"");if(m!=""){o=true;d.push(n(m)+"")}break;case 4:d.push("\n");d.push(Array(c+1).join(" "));d.push("<![CDATA[");d.push(m.nodeValue);d.push("]]\>");break;case 8:d.push("\n");d.push(Array(c+1).join(" "));d.push("<!--");d.push(m.data);d.push("--\>")}}c--;if(!o){d.push("\n");for(s=0;s<c;s++)d.push(" ")}d.push("</");d.push(b.nodeName); -d.push(">")}else d.push("/>")}return d.join("")};this.embedImage=function(b,c){$(new Image).load(function(){var d=document.createElement("canvas");d.width=this.width;d.height=this.height;d.getContext("2d").drawImage(this,0,0);try{var n=";svgedit_url="+encodeURIComponent(b);n=d.toDataURL().replace(";base64",n+";base64");Va[b]=n}catch(m){Va[b]=false}ub=b;c&&c(Va[b])}).attr("src",b)};this.setGoodImage=function(b){ub=b};this.open=function(){};this.save=function(b){Ta();b&&$.extend(Ua,b);Ua.apply=true; -b=this.svgCanvasToString();aa("saved",b)};this.rasterExport=function(){Ta();var b=[],c={feGaussianBlur:zb.exportNoBlur,foreignObject:zb.exportNoforeignObject,"[stroke-dasharray]":zb.exportNoDashArray},d=$(p);if(!("font"in $("<canvas>")[0].getContext("2d")))c.text=zb.exportNoText;$.each(c,function(n,m){d.find(n).length&&b.push(m)});c=this.svgCanvasToString();aa("exported",{svg:c,issues:b})};this.getSvgString=function(){Ua.apply=false;return this.svgCanvasToString()};this.randomizeIds=function(){arguments.length> -0&&arguments[0]==false?svgedit.draw.randomizeIds(false,D()):svgedit.draw.randomizeIds(true,D())};var bc=this.uniquifyElems=function(b){var c={},d=["filter","linearGradient","pattern","radialGradient","symbol","textPath","use"];svgedit.utilities.walkTree(b,function(l){if(l.nodeType==1){if(l.id){l.id in c||(c[l.id]={elem:null,attrs:[],hrefs:[]});c[l.id].elem=l}$.each(Pb,function(B,w){var v=l.getAttributeNode(w);if(v){var C=svgedit.utilities.getUrlFromAttr(v.value);if(C=C?C.substr(1):null){C in c||(c[C]= -{elem:null,attrs:[],hrefs:[]});c[C].attrs.push(v)}}});var s=svgedit.utilities.getHref(l);if(s&&d.indexOf(l.nodeName)>=0)if(s=s.substr(1)){s in c||(c[s]={elem:null,attrs:[],hrefs:[]});c[s].hrefs.push(l)}}});for(var n in c)if(n){var m=c[n].elem;if(m){b=ya();m.id=b;m=c[n].attrs;for(var A=m.length;A--;){var o=m[A];o.ownerElement.setAttribute(o.name,"url(#"+b+")")}m=c[n].hrefs;for(A=m.length;A--;)svgedit.utilities.setHref(m[A],"#"+b)}}},Tb=this.setUseData=function(b){var c=$(b);if(b.tagName!=="use")c= -c.find("use");c.each(function(){var d=U(this).substr(1);if(d=ja(d)){$(this).data("ref",d);if(d.tagName=="symbol"||d.tagName=="svg")$(this).data("symbol",d).data("ref",d)}})},gc=this.convertGradients=function(b){var c=$(b).find("linearGradient, radialGradient");if(!c.length&&svgedit.browser.isWebkit())c=$(b).find("*").filter(function(){return this.tagName.indexOf("Gradient")>=0});c.each(function(){if($(this).attr("gradientUnits")==="userSpaceOnUse"){var d=$(p).find('[fill="url(#'+this.id+')"],[stroke="url(#'+ -this.id+')"]');if(d.length)if(d=svgedit.utilities.getBBox(d[0]))if(this.tagName==="linearGradient"){var n=$(this).attr(["x1","y1","x2","y2"]),m=this.gradientTransform.baseVal;if(m&&m.numberOfItems>0){var A=ga(m).matrix;m=ka(n.x1,n.y1,A);A=ka(n.x2,n.y2,A);n.x1=m.x;n.y1=m.y;n.x2=A.x;n.y2=A.y;this.removeAttribute("gradientTransform")}$(this).attr({x1:(n.x1-d.x)/d.width,y1:(n.y1-d.y)/d.height,x2:(n.x2-d.x)/d.width,y2:(n.y2-d.y)/d.height});this.removeAttribute("gradientUnits")}}})},kc=this.convertToGroup= -function(b){b||(b=I[0]);var c=$(b),d=new Ga,n;if(c.data("gsvg")){d=$(b.firstChild).attr(["x","y"]);$(b.firstChild.firstChild).unwrap();$(b).removeData("gsvg");n=ia(b);var m=g.createSVGTransform();m.setTranslate(d.x,d.y);n.appendItem(m);nb(b);aa("selected",[b])}else if(c.data("symbol")){b=c.data("symbol");n=c.attr("transform");m=c.attr(["x","y"]);var A=b.getAttribute("viewBox");if(A){A=A.split(" ");m.x-=+A[0];m.y-=+A[1]}n+=" translate("+(m.x||0)+","+(m.y||0)+")";m=c.prev();d.addSubCommand(new Oa(c[0], -c[0].nextSibling,c[0].parentNode));c.remove();A=$(p).find("use:data(symbol)").length;c=f.createElementNS(i,"g");for(var o=b.childNodes,l=0;l<o.length;l++)c.appendChild(o[l].cloneNode(true));if(svgedit.browser.isGecko()){o=$(ib()).children("linearGradient,radialGradient,pattern").clone();$(c).append(o)}n&&c.setAttribute("transform",n);n=b.parentNode;bc(c);svgedit.browser.isGecko()&&$(ib()).append($(c).find("linearGradient,radialGradient,pattern"));c.id=ya();m.after(c);if(n){if(!A){m=b.nextSibling; -n.removeChild(b);d.addSubCommand(new Oa(b,m,n))}d.addSubCommand(new Fa(c))}Tb(c);svgedit.browser.isGecko()?gc(ib()):gc(c);svgedit.utilities.walkTreePost(c,function(s){try{nb(s)}catch(B){console.log(B)}});$(c).find("a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use").each(function(){if(!this.id)this.id=ya()});Ib([c]);(b=ec(c,true))&&d.addSubCommand(b);Ca(d)}else console.log("Unexpected element to ungroup:",b)};this.setSvgString=function(b){try{var c=svgedit.utilities.text2xml(b); -this.prepareSvg(c);var d=new Ga("Change Source"),n=p.nextSibling,m=g.removeChild(p);d.addSubCommand(new Oa(m,n,g));p=f.adoptNode?f.adoptNode(c.documentElement):f.importNode(c.documentElement,true);g.appendChild(p);var A=$(p);e.current_drawing_=new svgedit.draw.Drawing(p,z);var o=D().getNonce();o?aa("setnonce",o):aa("unsetnonce");A.find("image").each(function(){var F=this;Yb(F);var J=U(this);if(J.indexOf("data:")===0){var K=J.match(/svgedit_url=(.*?);/);if(K){var P=decodeURIComponent(K[1]);$(new Image).load(function(){F.setAttributeNS("http://www.w3.org/1999/xlink", -"xlink:href",P)}).attr("src",P)}}e.embedImage(J)});A.find("svg").each(function(){if(!$(this).closest("defs").length){bc(this);var F=this.parentNode;if(F.childNodes.length===1&&F.nodeName==="g"){$(F).data("gsvg",this);F.id=F.id||ya()}else pa(this)}});svgedit.browser.isGecko()&&A.find("linearGradient, radialGradient, pattern").appendTo(ib());Tb(A);gc(A[0]);svgedit.utilities.walkTreePost(p,function(F){try{nb(F)}catch(J){console.log(J)}});var l={id:"svgcontent",overflow:u.show_outside_canvas?"visible": -"hidden"},s=false;if(A.attr("viewBox")){var B=A.attr("viewBox").split(" ");l.width=B[2];l.height=B[3]}else $.each(["width","height"],function(F,J){var K=A.attr(J);K||(K="100%");if((K+"").substr(-1)==="%")s=true;else l[J]=ha(J,K)});Vb();A.children().find("a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use").each(function(){if(!this.id)this.id=ya()});if(s){var w=getStrokedBBox();l.width=w.width+w.x;l.height=w.height+w.y}if(l.width<=0)l.width=100;if(l.height<=0)l.height= -100;A.attr(l);this.contentW=l.width;this.contentH=l.height;d.addSubCommand(new Fa(p));var v=A.attr(["width","height"]);d.addSubCommand(new Qa(g,v));q=1;svgedit.transformlist.resetListMap();Ta();svgedit.path.clearData();g.appendChild(Ha.selectorParentGroup);Ca(d);aa("changed",[p])}catch(C){console.log(C);return false}return true};this.importSvgString=function(b){try{var c=svgedit.utilities.encode64(b.length+b).substr(0,32),d=false;if(Cb[c])if($(Cb[c].symbol).parents("#svgroot").length)d=true;var n= -new Ga("Import SVG");if(d)var m=Cb[c].symbol,A=Cb[c].xform;else{var o=svgedit.utilities.text2xml(b);this.prepareSvg(o);var l;l=f.adoptNode?f.adoptNode(o.documentElement):f.importNode(o.documentElement,true);bc(l);var s=ha("width",l.getAttribute("width")),B=ha("height",l.getAttribute("height")),w=l.getAttribute("viewBox"),v=w?w.split(" "):[0,0,s,B];for(b=0;b<4;++b)v[b]=+v[b];p.getAttribute("width");var C=+p.getAttribute("height");A=B>s?"scale("+C/3/v[3]+")":"scale("+C/3/v[2]+")";A="translate(0) "+ -A+" translate(0)";m=f.createElementNS(i,"symbol");var F=ib();for(svgedit.browser.isGecko()&&$(l).find("linearGradient, radialGradient, pattern").appendTo(F);l.firstChild;)m.appendChild(l.firstChild);var J=l.attributes;for(l=0;l<J.length;l++){var K=J[l];m.setAttribute(K.nodeName,K.nodeValue)}m.id=ya();Cb[c]={symbol:m,xform:A};ib().appendChild(m);n.addSubCommand(new Fa(m))}var P=f.createElementNS(i,"use");P.id=ya();Z(P,"#"+m.id);(M||D().getCurrentLayer()).appendChild(P);n.addSubCommand(new Fa(P));Ta(); -P.setAttribute("transform",A);nb(P);$(P).data("symbol",m).data("ref",m);eb([P]);Ca(n);aa("changed",[p])}catch(ca){console.log(ca);return false}return true};var Vb=e.identifyLayers=function(){$b();D().identifyLayers()};this.createLayer=function(b){var c=new Ga("Create Layer");b=D().createLayer(b);c.addSubCommand(new Fa(b));Ca(c);Ta();aa("changed",[b])};this.cloneLayer=function(b){var c=new Ga("Duplicate Layer"),d=f.createElementNS(i,"g"),n=f.createElementNS(i,"title");n.textContent=b;d.appendChild(n); -n=D().getCurrentLayer();$(n).after(d);n=n.childNodes;for(var m=0;m<n.length;m++){var A=n[m];A.localName!="title"&&d.appendChild(V(A))}Ta();Vb();c.addSubCommand(new Fa(d));Ca(c);e.setCurrentLayer(b);aa("changed",[d])};this.deleteCurrentLayer=function(){var b=D().getCurrentLayer(),c=b.nextSibling,d=b.parentNode;if(b=D().deleteCurrentLayer()){var n=new Ga("Delete Layer");n.addSubCommand(new Oa(b,c,d));Ca(n);Ta();aa("changed",[d]);return true}return false};this.setCurrentLayer=function(b){(b=D().setCurrentLayer(svgedit.utilities.toXml(b)))&& -Ta();return b};this.renameCurrentLayer=function(b){var c=D();if(c.current_layer){var d=c.current_layer;if(!e.setCurrentLayer(b)){for(var n=new Ga("Rename Layer"),m=0;m<c.getNumLayers();++m)if(c.all_layers[m][1]==d)break;var A=c.getLayerName(m);c.all_layers[m][0]=svgedit.utilities.toXml(b);var o=d.childNodes.length;for(m=0;m<o;++m){var l=d.childNodes.item(m);if(l&&l.tagName=="title"){for(;l.firstChild;)l.removeChild(l.firstChild);l.textContent=b;n.addSubCommand(new Qa(l,{"#text":A}));Ca(n);aa("changed", -[d]);return true}}}c.current_layer=d}return false};this.setCurrentLayerPosition=function(b){var c=D();if(c.current_layer&&b>=0&&b<c.getNumLayers()){for(var d=0;d<c.getNumLayers();++d)if(c.all_layers[d][1]==c.current_layer)break;if(d==c.getNumLayers())return false;if(d!=b){var n=null,m=c.current_layer.nextSibling;if(b>d){if(b<c.getNumLayers()-1)n=c.all_layers[b+1][1]}else n=c.all_layers[b][1];p.insertBefore(c.current_layer,n);Ca(new Ma(c.current_layer,m,p));Vb();e.setCurrentLayer(c.getLayerName(b)); -return true}}return false};this.setLayerVisibility=function(b,c){var d=D(),n=d.getLayerVisibility(b),m=d.setLayerVisibility(b,c);if(m)Ca(new Qa(m,{display:n?"inline":"none"},"Layer Visibility"));else return false;if(m==d.getCurrentLayer()){Ta();La.clear()}return true};this.moveSelectedToLayer=function(b){for(var c=null,d=D(),n=0;n<d.getNumLayers();++n)if(d.getLayerName(n)==b){c=d.all_layers[n][1];break}if(!c)return false;b=new Ga("Move Elements to Layer");d=I;for(n=d.length;n--;){var m=d[n];if(m){var A= -m.nextSibling,o=m.parentNode;c.appendChild(m);b.addSubCommand(new Ma(m,A,o))}}Ca(b);return true};this.mergeLayer=function(b){var c=new Ga("Merge Layer"),d=D(),n=$(d.current_layer).prev()[0];if(n){for(c.addSubCommand(new Oa(d.current_layer,d.current_layer.nextSibling,p));d.current_layer.firstChild;){var m=d.current_layer.firstChild;if(m.localName=="title"){c.addSubCommand(new Oa(m,m.nextSibling,d.current_layer));d.current_layer.removeChild(m)}else{var A=m.nextSibling;n.appendChild(m);c.addSubCommand(new Ma(m, -A,d.current_layer))}}p.removeChild(d.current_layer);if(!b){Ta();Vb();aa("changed",[p]);Ca(c)}d.current_layer=n;return c}};this.mergeAllLayers=function(){var b=new Ga("Merge all Layers"),c=D();for(c.current_layer=c.all_layers[c.getNumLayers()-1][1];$(p).children("g").length>1;)b.addSubCommand(e.mergeLayer(true));Ta();Vb();aa("changed",[p]);Ca(b)};var $b=this.leaveContext=function(){var b=Bb.length;if(b){for(var c=0;c<b;c++){var d=Bb[c],n=gb(d,"orig_opac");n!==1?d.setAttribute("opacity",n):d.removeAttribute("opacity"); -d.setAttribute("style","pointer-events: inherit")}Bb=[];Ta(true);aa("contextset",null)}M=null},mc=this.setContext=function(b){$b();if(typeof b==="string")b=ja(b);M=b;$(b).parentsUntil("#svgcontent").andSelf().siblings().each(function(){var c=this.getAttribute("opacity")||1;gb(this,"orig_opac",c);this.setAttribute("opacity",c*0.33);this.setAttribute("style","pointer-events: none");Bb.push(this)});Ta();aa("contextset",M)};this.clear=function(){La.clear();Ta();e.clearSvgContentElement();e.current_drawing_= -new svgedit.draw.Drawing(p);e.createLayer("Layer 1");e.undoMgr.resetUndoStack();Ha.initGroup();za=Ha.getRubberBandBox();aa("cleared")};this.linkControlPoints=La.linkControlPoints;this.getContentElem=function(){return p};this.getRootElem=function(){return g};this.getSelectedElems=function(){return I};var Ub=this.getResolution=function(){var b=p.getAttribute("width")/q,c=p.getAttribute("height")/q;return{w:b,h:c,zoom:q}};this.getZoom=function(){return q};this.getVersion=function(){return"svgcanvas.js ($Rev: 2082 $)"}; -this.setUiStrings=function(b){$.extend(zb,b.notification)};this.setConfig=function(b){$.extend(u,b)};this.getTitle=function(b){if(b=b||I[0]){b=$(b).data("gsvg")||$(b).data("symbol")||b;b=b.childNodes;for(var c=0;c<b.length;c++)if(b[c].nodeName=="title")return b[c].textContent;return""}};this.setGroupTitle=function(b){var c=I[0];c=$(c).data("gsvg")||c;var d=$(c).children("title"),n=new Ga("Set Label");if(b.length)if(d.length){d=d[0];n.addSubCommand(new Qa(d,{"#text":d.textContent}));d.textContent= -b}else{d=f.createElementNS(i,"title");d.textContent=b;$(c).prepend(d);n.addSubCommand(new Fa(d))}else{n.addSubCommand(new Oa(d[0],d.nextSibling,c));d.remove()}Ca(n)};this.getDocumentTitle=function(){return e.getTitle(p)};this.setDocumentTitle=function(b){for(var c=p.childNodes,d=false,n="",m=new Ga("Change Image Title"),A=0;A<c.length;A++)if(c[A].nodeName=="title"){d=c[A];n=d.textContent;break}if(!d){d=f.createElementNS(i,"title");p.insertBefore(d,p.firstChild)}if(b.length)d.textContent=b;else d.parentNode.removeChild(d); -m.addSubCommand(new Qa(d,{"#text":n}));Ca(m)};this.getEditorNS=function(b){b&&p.setAttribute("xmlns:se","http://svg-edit.googlecode.com");return"http://svg-edit.googlecode.com"};this.setResolution=function(b,c){var d=Ub(),n=d.w;d=d.h;var m;if(b=="fit"){var A=getStrokedBBox();if(A){m=new Ga("Fit Canvas to Content");var o=Lb();eb(o);var l=[],s=[];$.each(o,function(){l.push(A.x*-1);s.push(A.y*-1)});o=e.moveSelectedElements(l,s,true);m.addSubCommand(o);Ta();b=Math.round(A.width);c=Math.round(A.height)}else return false}if(b!= -n||c!=d){o=g.suspendRedraw(1E3);m||(m=new Ga("Change Image Dimensions"));b=ha("width",b);c=ha("height",c);p.setAttribute("width",b);p.setAttribute("height",c);this.contentW=b;this.contentH=c;m.addSubCommand(new Qa(p,{width:n,height:d}));p.setAttribute("viewBox",[0,0,b/q,c/q].join(" "));m.addSubCommand(new Qa(p,{viewBox:["0 0",n,d].join(" ")}));Ca(m);g.unsuspendRedraw(o);aa("changed",[p])}return true};this.getOffset=function(){return $(p).attr(["x","y"])};this.setBBoxZoom=function(b,c,d){var n=0.85, -m=function(A){if(!A)return false;var o=Math.min(Math.round(c/A.width*100*n)/100,Math.round(d/A.height*100*n)/100);e.setZoom(o);return{zoom:o,bbox:A}};if(typeof b=="object"){b=b;if(b.width==0||b.height==0){e.setZoom(b.zoom?b.zoom:q*b.factor);return{zoom:q,bbox:b}}return m(b)}switch(b){case "selection":if(!I[0])return;b=$.map(I,function(A){if(A)return A});b=getStrokedBBox(b);break;case "canvas":b=Ub();n=0.95;b={width:b.w,height:b.h,x:0,y:0};break;case "content":b=getStrokedBBox();break;case "layer":b= -getStrokedBBox(Lb(D().getCurrentLayer()));break;default:return}return m(b)};this.setZoom=function(b){var c=Ub();p.setAttribute("viewBox","0 0 "+c.w/b+" "+c.h/b);q=b;$.each(I,function(d,n){n&&Ha.requestSelector(n).resize()});La.zoomChange();pb("zoomChanged",b)};this.getMode=function(){return Ia};this.setMode=function(b){La.clear(true);fb.clear();$("#workarea").attr("class",b);cb=I[0]&&I[0].nodeName=="text"?ab:N;Ia=b};this.getColor=function(b){return cb[b]};this.setColor=function(b,c,d){N[b]=c;cb[b+ -"_paint"]={type:"solidColor"};for(var n=[],m=I.length;m--;){var A=I[m];if(A)if(A.tagName=="g")svgedit.utilities.walkTree(A,function(o){o.nodeName!="g"&&n.push(o)});else if(b=="fill")A.tagName!="polyline"&&A.tagName!="line"&&n.push(A);else n.push(A)}if(n.length>0)if(d)Nb(b,c,n);else{jb(b,c,n);aa("changed",n)}};var ib=function(){var b=p.getElementsByTagNameNS(i,"defs");if(b.length>0)b=b[0];else{b=f.createElementNS(i,"defs");p.firstChild?p.insertBefore(b,p.firstChild.nextSibling):p.appendChild(b)}return b}, -hc=this.setGradient=function(b){if(!(!cb[b+"_paint"]||cb[b+"_paint"].type=="solidColor")){var c=e[b+"Grad"],d=cc(c),n=ib();if(d)c=d;else{c=n.appendChild(f.importNode(c,true));c.id=ya()}e.setColor(b,"url(#"+c.id+")")}},cc=function(b){var c=ib();c=$(c).find("linearGradient, radialGradient");for(var d=c.length,n=["r","cx","cy","fx","fy"];d--;){var m=c[d];if(b.tagName=="linearGradient"){if(b.getAttribute("x1")!=m.getAttribute("x1")||b.getAttribute("y1")!=m.getAttribute("y1")||b.getAttribute("x2")!=m.getAttribute("x2")|| -b.getAttribute("y2")!=m.getAttribute("y2"))continue}else{var A=$(b).attr(n),o=$(m).attr(n),l=false;$.each(n,function(F,J){if(A[J]!=o[J])l=true});if(l)continue}var s=b.getElementsByTagNameNS(i,"stop"),B=m.getElementsByTagNameNS(i,"stop");if(s.length==B.length){for(var w=s.length;w--;){var v=s[w],C=B[w];if(v.getAttribute("offset")!=C.getAttribute("offset")||v.getAttribute("stop-opacity")!=C.getAttribute("stop-opacity")||v.getAttribute("stop-color")!=C.getAttribute("stop-color"))break}if(w==-1)return m}}return null}; -this.setPaint=function(b,c){var d=new $.jGraduate.Paint(c);this.setPaintOpacity(b,d.alpha/100,true);cb[b+"_paint"]=d;switch(d.type){case "solidColor":if(d.solidColor!="none")this.setColor(b,"#"+d.solidColor);else{this.setColor(b,"none");document.querySelector(b=="fill"?"#fill_color rect":"#stroke_color rect").setAttribute("fill","transparent")}break;case "linearGradient":case "radialGradient":e[b+"Grad"]=d[d.type];hc(b)}};this.getStrokeWidth=function(){return cb.stroke_width};this.setStrokeWidth= -function(b){if(b==0&&["line","path"].indexOf(Ia)>=0)e.setStrokeWidth(1);else{cb.stroke_width=b;for(var c=[],d=I.length;d--;){var n=I[d];if(n)n.tagName=="g"?svgedit.utilities.walkTree(n,function(m){m.nodeName!="g"&&c.push(m)}):c.push(n)}if(c.length>0){jb("stroke-width",b,c);aa("changed",I)}}};this.setStrokeAttr=function(b,c){N[b.replace("-","_")]=c;for(var d=[],n=I.length;n--;){var m=I[n];if(m)m.tagName=="g"?svgedit.utilities.walkTree(m,function(A){A.nodeName!="g"&&d.push(A)}):d.push(m)}if(d.length> -0){jb(b,c,d);aa("changed",I)}};this.getStyle=function(){return N};this.getOpacity=function(){return N.opacity};this.setOpacity=function(b){N.opacity=b;jb("opacity",b)};this.getFillOpacity=function(){return N.fill_opacity};this.getStrokeOpacity=function(){return N.stroke_opacity};this.setPaintOpacity=function(b,c,d){N[b+"_opacity"]=c;d?Nb(b+"-opacity",c):jb(b+"-opacity",c)};this.getBlur=function(b){var c=0;if(b)if(b.getAttribute("filter"))if(b=ja(b.id+"_blur"))c=b.firstChild.getAttribute("stdDeviation"); -return c};(function(){function b(){var m=e.undoMgr.finishUndoableChange();c.addSubCommand(m);Ca(c);d=c=null}var c=null,d=null,n=false;e.setBlurNoUndo=function(m){if(d)if(m===0){Nb("filter","");n=true}else{var A=I[0];n&&Nb("filter","url(#"+A.id+"_blur)");if(svgedit.browser.isWebkit()){A.removeAttribute("filter");A.setAttribute("filter","url(#"+A.id+"_blur)")}Nb("stdDeviation",m,[d.firstChild]);e.setBlurOffsets(d,m)}else e.setBlur(m)};e.setBlurOffsets=function(m,A){if(A>3)la(m,{x:"-50%",y:"-50%",width:"200%", -height:"200%"},100);else if(!svgedit.browser.isWebkit()){m.removeAttribute("x");m.removeAttribute("y");m.removeAttribute("width");m.removeAttribute("height")}};e.setBlur=function(m,A){if(c)b();else{var o=I[0],l=o.id;d=ja(l+"_blur");m-=0;var s=new Ga;if(d){if(m===0)d=null}else{var B=ma({element:"feGaussianBlur",attr:{"in":"SourceGraphic",stdDeviation:m}});d=ma({element:"filter",attr:{id:l+"_blur"}});d.appendChild(B);ib().appendChild(d);s.addSubCommand(new Fa(d))}B={filter:o.getAttribute("filter")}; -if(m===0){o.removeAttribute("filter");s.addSubCommand(new Qa(o,B))}else{jb("filter","url(#"+l+"_blur)");s.addSubCommand(new Qa(o,B));e.setBlurOffsets(d,m);c=s;e.undoMgr.beginUndoableChange("stdDeviation",[d?d.firstChild:null]);if(A){e.setBlurNoUndo(m);b()}}}}})();this.getBold=function(){var b=I[0];if(b!=null&&b.tagName=="text"&&I[1]==null)return b.getAttribute("font-weight")=="bold";return false};this.setBold=function(b){var c=I[0];if(c!=null&&c.tagName=="text"&&I[1]==null)jb("font-weight",b?"bold": -"normal");I[0].textContent||fb.setCursor()};this.getItalic=function(){var b=I[0];if(b!=null&&b.tagName=="text"&&I[1]==null)return b.getAttribute("font-style")=="italic";return false};this.setItalic=function(b){var c=I[0];if(c!=null&&c.tagName=="text"&&I[1]==null)jb("font-style",b?"italic":"normal");I[0].textContent||fb.setCursor()};this.getFontFamily=function(){return ab.font_family};this.setFontFamily=function(b){ab.font_family=b;jb("font-family",b);I[0]&&!I[0].textContent&&fb.setCursor()};this.setFontColor= -function(b){ab.fill=b;jb("fill",b)};this.getFontSize=function(){return ab.fill};this.getFontSize=function(){return ab.font_size};this.setFontSize=function(b){ab.font_size=b;jb("font-size",b);I[0].textContent||fb.setCursor()};this.getText=function(){var b=I[0];if(b==null)return"";return b.textContent};this.setTextContent=function(b){jb("#text",b);fb.init(b);fb.setCursor()};this.setImageURL=function(b){var c=I[0];if(c){var d=$(c).attr(["width","height"]);d=!d.width||!d.height;var n=U(c);if(n!==b)d= -true;else if(!d)return;var m=new Ga("Change Image URL");Z(c,b);m.addSubCommand(new Qa(c,{"#href":n}));d?$(new Image).load(function(){var A=$(c).attr(["width","height"]);$(c).attr({width:this.width,height:this.height});Ha.requestSelector(c).resize();m.addSubCommand(new Qa(c,A));Ca(m);aa("changed",[c])}).attr("src",b):Ca(m)}};this.setLinkURL=function(b){var c=I[0];if(c){if(c.tagName!=="a"){c=$(c).parents("a");if(c.length)c=c[0];else return}var d=U(c);if(d!==b){var n=new Ga("Change Link URL");Z(c,b); -n.addSubCommand(new Qa(c,{"#href":d}));Ca(n)}}};this.setRectRadius=function(b){var c=I[0];if(c!=null&&c.tagName=="rect"){var d=c.getAttribute("rx");if(d!=b){c.setAttribute("rx",b);c.setAttribute("ry",b);Ca(new Qa(c,{rx:d,ry:d},"Radius"));aa("changed",[c])}}};this.makeHyperlink=function(b){e.groupSelectedElements("a",b)};this.removeHyperlink=function(){e.ungroupSelectedElement()};this.setSegType=function(b){La.setSegType(b)};this.convertToPath=function(b,c){if(b==null)$.each(I,function(fa,R){R&&e.convertToPath(R)}); -else{if(!c)var d=new Ga("Convert element to Path");var n=c?{}:{fill:N.fill,"fill-opacity":N.fill_opacity,stroke:N.stroke,"stroke-width":N.stroke_width,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,opacity:N.opacity,visibility:"hidden"};$.each(["marker-start","marker-end","marker-mid","filter","clip-path"],function(){if(b.getAttribute(this))n[this]=b.getAttribute(this)});var m=ma({element:"path",attr:n}), -A=b.getAttribute("transform");A&&m.setAttribute("transform",A);var o=b.id,l=b.parentNode;b.nextSibling?l.insertBefore(m,b):l.appendChild(m);var s="",B=function(fa){$.each(fa,function(R,W){var Y=W[1];s+=W[0];for(var na=0;na<Y.length;na+=2)s+=Y[na]+","+Y[na+1]+" "})},w=1.81;switch(b.tagName){case "ellipse":case "circle":var v=$(b).attr(["rx","ry","cx","cy"]),C=v.cx,F=v.cy,J=v.rx;v=v.ry;if(b.tagName=="circle")J=v=$(b).attr("r");B([["M",[C-J,F]],["C",[C-J,F-v/w,C-J/w,F-v,C,F-v]],["C",[C+J/w,F-v,C+J,F- -v/w,C+J,F]],["C",[C+J,F+v/w,C+J/w,F+v,C,F+v]],["C",[C-J/w,F+v,C-J,F+v/w,C-J,F]],["Z",[]]]);break;case "path":s=b.getAttribute("d");break;case "line":v=$(b).attr(["x1","y1","x2","y2"]);s="M"+v.x1+","+v.y1+"L"+v.x2+","+v.y2;break;case "polyline":case "polygon":s="M"+b.getAttribute("points");break;case "rect":v=$(b).attr(["rx","ry"]);J=v.rx;v=v.ry;var K=b.getBBox();C=K.x;F=K.y;var P=K.width;K=K.height;w=4-w;!J&&!v?B([["M",[C,F]],["L",[C+P,F]],["L",[C+P,F+K]],["L",[C,F+K]],["L",[C,F]],["Z",[]]]):B([["M", -[C,F+v]],["C",[C,F+v/w,C+J/w,F,C+J,F]],["L",[C+P-J,F]],["C",[C+P-J/w,F,C+P,F+v/w,C+P,F+v]],["L",[C+P,F+K-v]],["C",[C+P,F+K-v/w,C+P-J/w,F+K,C+P-J,F+K]],["L",[C+J,F+K]],["C",[C+J/w,F+K,C,F+K-v/w,C,F+K-v]],["L",[C,F+v]],["Z",[]]]);break;default:m.parentNode.removeChild(m)}s&&m.setAttribute("d",s);if(c){La.resetOrientation(m);d=false;try{d=m.getBBox()}catch(ca){}m.parentNode.removeChild(m);return d}else{if(A){A=ia(m);qa(A)&&La.resetOrientation(m)}d.addSubCommand(new Oa(b,b.nextSibling,l));d.addSubCommand(new Fa(m)); -Ta();b.parentNode.removeChild(b);m.setAttribute("id",o);m.removeAttribute("visibility");eb([m],true);Ca(d)}}};var Nb=function(b,c,d){var n=g.suspendRedraw(1E3);Ia=="pathedit"&&La.moveNode(b,c);d=d||I;for(var m=d.length,A=["g","polyline","path"];m--;){var o=d[m];if(o!=null){Ia==="textedit"&&b!=="#text"&&o.textContent.length&&fb.toSelectMode(o);if((b==="x"||b==="y")&&A.indexOf(o.tagName)>=0){var l=getStrokedBBox([o]);e.moveSelectedElements((b==="x"?c-l.x:0)*q,(b==="y"?c-l.y:0)*q,true)}else{l=b==="#text"? -o.textContent:o.getAttribute(b);if(l==null)l="";if(l!==String(c)){if(b=="#text"){svgedit.utilities.getBBox(o);o.textContent=c;if(/rotate/.test(o.getAttribute("transform")))o=Eb(o)}else b=="#href"?Z(o,c):o.setAttribute(b,c);if(svgedit.browser.isGecko()&&o.nodeName==="text"&&/rotate/.test(o.getAttribute("transform")))if((c+"").indexOf("url")===0||["font-size","font-family","x","y"].indexOf(b)>=0&&o.textContent)o=Eb(o);I.indexOf(o)>=0&&setTimeout(function(){o.parentNode&&Ha.requestSelector(o).resize()}, -0);l=ra(o);if(l!=0&&b!="transform")for(var s=ia(o),B=s.numberOfItems;B--;)if(s.getItem(B).type==4){s.removeItem(B);var w=svgedit.utilities.getBBox(o),v=ka(w.x+w.width/2,w.y+w.height/2,ga(s).matrix);w=v.x;v=v.y;var C=g.createSVGTransform();C.setRotate(l,w,v);s.insertItemBefore(C,B);break}}}}}g.unsuspendRedraw(n)},jb=this.changeSelectedAttribute=function(b,c,d){d=d||I;e.undoMgr.beginUndoableChange(b,d);Nb(b,c,d);b=e.undoMgr.finishUndoableChange();b.isEmpty()||Ca(b)};this.deleteSelectedElements=function(){for(var b= -new Ga("Delete Elements"),c=I.length,d=[],n=0;n<c;++n){var m=I[n];if(m==null)break;var A=m.parentNode,o=m;Ha.releaseSelector(o);svgedit.path.removePath_(o.id);if(A.tagName==="a"&&A.childNodes.length===1){o=A;A=A.parentNode}var l=o.nextSibling;o=A.removeChild(o);d.push(m);I[n]=null;b.addSubCommand(new Oa(o,l,A))}b.isEmpty()||Ca(b);aa("changed",d);Ta()};this.cutSelectedElements=function(){for(var b=new Ga("Cut Elements"),c=I.length,d=[],n=0;n<c;++n){var m=I[n];if(m==null)break;var A=m.parentNode,o= -m;Ha.releaseSelector(o);svgedit.path.removePath_(o.id);var l=o.nextSibling;o=A.removeChild(o);d.push(m);I[n]=null;b.addSubCommand(new Oa(o,l,A))}b.isEmpty()||Ca(b);aa("changed",d);Ta();e.clipBoard=d};this.copySelectedElements=function(){e.clipBoard=$.merge([],I)};this.pasteElements=function(b,c,d){var n=e.clipBoard,m=n.length;if(m){for(var A=[],o=new Ga("Paste elements");m--;){var l=n[m];if(l){var s=V(l);if(!ja(l.id))s.id=l.id;A.push(s);(M||D().getCurrentLayer()).appendChild(s);o.addSubCommand(new Fa(s))}}Ib(A); -if(b!="in_place"){if(xb==null){xb.x=0;xb.y=0}var B,w;if(b){if(b==="point"){B=c;w=d}}else{B=xb.x;w=xb.y}b=getStrokedBBox(A);var v=B-(b.x+b.width/2),C=w-(b.y+b.height/2),F=[],J=[];$.each(A,function(){F.push(v);J.push(C)});B=e.moveSelectedElements(F,J,false);o.addSubCommand(B)}Ca(o);aa("changed",A)}};this.groupSelectedElements=function(b){b||(b="g");var c="";switch(b){case "a":c="Make hyperlink";var d="";if(arguments.length>1)d=arguments[1];break;default:b="g";c="Group Elements"}c=new Ga(c);var n=ma({element:b, -attr:{id:ya()}});b==="a"&&Z(n,d);c.addSubCommand(new Fa(n));for(d=I.length;d--;){var m=I[d];if(m!=null){if(m.parentNode.tagName==="a"&&m.parentNode.childNodes.length===1)m=m.parentNode;var A=m.nextSibling,o=m.parentNode;n.appendChild(m);c.addSubCommand(new Ma(m,A,o))}}c.isEmpty()||Ca(c);Ib([n],true)};var ec=this.pushGroupProperties=function(b,c){var d=b.childNodes,n=d.length,m=b.getAttribute("transform"),A=ia(b),o=ga(A).matrix,l=new Ga("Push group properties"),s=0,B=ra(b),w=$(b).attr(["filter","opacity"]), -v,C;for(s=0;s<n;s++){var F=d[s];if(F.nodeType===1){if(w.opacity!==null&&w.opacity!==1){F.getAttribute("opacity");var J=Math.round((F.getAttribute("opacity")||1)*w.opacity*100)/100;jb("opacity",J,[F])}if(w.filter){var K=J=this.getBlur(F);C||(C=this.getBlur(b));if(J)J=C-0+(J-0);else if(J===0)J=C;if(K)v=Sa(F.getAttribute("filter"));else if(v){v=V(v);ib().appendChild(v)}else v=Sa(w.filter);v.id=F.id+"_"+(v.firstChild.tagName==="feGaussianBlur"?"blur":"filter");jb("filter","url(#"+v.id+")",[F]);if(J){jb("stdDeviation", -J,[v.firstChild]);e.setBlurOffsets(v,J)}}J=ia(F);if(~F.tagName.indexOf("Gradient"))J=null;if(J)if(F.tagName!=="defs")if(A.numberOfItems){if(B&&A.numberOfItems==1){var P=A.getItem(0).matrix,ca=g.createSVGMatrix();if(K=ra(F))ca=J.getItem(0).matrix;var fa=svgedit.utilities.getBBox(F),R=ga(J).matrix,W=ka(fa.x+fa.width/2,fa.y+fa.height/2,R);fa=B+K;R=g.createSVGTransform();R.setRotate(fa,W.x,W.y);P=X(P,ca,R.matrix.inverse());K&&J.removeItem(0);if(fa)J.numberOfItems?J.insertItemBefore(R,0):J.appendItem(R); -if(P.e||P.f){K=g.createSVGTransform();K.setTranslate(P.e,P.f);J.numberOfItems?J.insertItemBefore(K,0):J.appendItem(K)}}else{K=F.getAttribute("transform");P={};P.transform=K?K:"";K=g.createSVGTransform();P=ga(J).matrix;ca=P.inverse();P=X(ca,o,P);K.setMatrix(P);J.appendItem(K)}(F=nb(F))&&l.addSubCommand(F)}}}if(m){P={};P.transform=m;b.setAttribute("transform","");b.removeAttribute("transform");l.addSubCommand(new Qa(b,P))}if(c&&!l.isEmpty())return l};this.ungroupSelectedElement=function(){var b=I[0]; -if($(b).data("gsvg")||$(b).data("symbol"))kc(b);else if(b.tagName==="use"){var c=ja(U(b).substr(1));$(b).data("symbol",c).data("ref",c);kc(b)}else{c=$(b).parents("a");if(c.length)b=c[0];if(b.tagName==="g"||b.tagName==="a"){c=new Ga("Ungroup Elements");var d=ec(b,true);d&&c.addSubCommand(d);d=b.parentNode;for(var n=b.nextSibling,m=Array(b.childNodes.length),A=0;b.firstChild;){var o=b.firstChild,l=o.nextSibling,s=o.parentNode;if(o.tagName==="title"){c.addSubCommand(new Oa(o,o.nextSibling,s));s.removeChild(o)}else{m[A++]= -o=d.insertBefore(o,n);c.addSubCommand(new Ma(o,l,s))}}Ta();n=b.nextSibling;b=d.removeChild(b);c.addSubCommand(new Oa(b,n,d));c.isEmpty()||Ca(c);eb(m)}}};this.moveToTopSelectedElement=function(){var b=I[0];if(b!=null){b=b;var c=b.parentNode,d=b.nextSibling;b=b.parentNode.appendChild(b);if(d!=b.nextSibling){Ca(new Ma(b,d,c,"top"));aa("changed",[b])}}};this.moveToBottomSelectedElement=function(){var b=I[0];if(b!=null){b=b;var c=b.parentNode,d=b.nextSibling,n=b.parentNode.firstChild;if(n.tagName=="title")n= -n.nextSibling;if(n.tagName=="defs")n=n.nextSibling;b=b.parentNode.insertBefore(b,n);if(d!=b.nextSibling){Ca(new Ma(b,d,c,"bottom"));aa("changed",[b])}}};this.moveUpDownSelected=function(b){var c=I[0];if(c){vb=[];var d,n,m=$(Rb(getStrokedBBox([c]))).toArray();b=="Down"&&m.reverse();$.each(m,function(){if(n){d=this;return false}else if(this==c)n=true});if(d){m=c.parentNode;var A=c.nextSibling;$(d)[b=="Down"?"before":"after"](c);if(A!=c.nextSibling){Ca(new Ma(c,A,m,"Move "+b));aa("changed",[c])}}}}; -this.moveSelectedElements=function(b,c,d){if(b.constructor!=Array){b/=q;c/=q}d=d||true;for(var n=new Ga("position"),m=I.length;m--;){var A=I[m];if(A!=null){var o=g.createSVGTransform(),l=ia(A);b.constructor==Array?o.setTranslate(b[m],c[m]):o.setTranslate(b,c);l.numberOfItems?l.insertItemBefore(o,0):l.appendItem(o);(o=nb(A))&&n.addSubCommand(o);Ha.requestSelector(A).resize()}}if(!n.isEmpty()){d&&Ca(n);aa("changed",I);return n}};this.cloneSelectedElements=function(b,c){for(var d=new Ga("Clone Elements"), -n=I.length,m=0;m<n;++m){var A=I[m];if(A==null)break}n=I.slice(0,m);this.clearSelection(true);for(m=n.length;m--;){A=n[m]=V(n[m]);(M||D().getCurrentLayer()).appendChild(A);d.addSubCommand(new Fa(A))}if(!d.isEmpty()){eb(n.reverse());this.moveSelectedElements(b,c,false);Ca(d)}};this.alignSelectedElements=function(b,c){var d=[],n=Number.MAX_VALUE,m=Number.MIN_VALUE,A=Number.MAX_VALUE,o=Number.MIN_VALUE,l=Number.MIN_VALUE,s=Number.MIN_VALUE,B=I.length;if(B){for(var w=0;w<B;++w){if(I[w]==null)break;d[w]= -getStrokedBBox([I[w]]);switch(c){case "smallest":if((b=="l"||b=="c"||b=="r")&&(l==Number.MIN_VALUE||l>d[w].width)||(b=="t"||b=="m"||b=="b")&&(s==Number.MIN_VALUE||s>d[w].height)){n=d[w].x;A=d[w].y;m=d[w].x+d[w].width;o=d[w].y+d[w].height;l=d[w].width;s=d[w].height}break;case "largest":if((b=="l"||b=="c"||b=="r")&&(l==Number.MIN_VALUE||l<d[w].width)||(b=="t"||b=="m"||b=="b")&&(s==Number.MIN_VALUE||s<d[w].height)){n=d[w].x;A=d[w].y;m=d[w].x+d[w].width;o=d[w].y+d[w].height;l=d[w].width;s=d[w].height}break; -default:if(d[w].x<n)n=d[w].x;if(d[w].y<A)A=d[w].y;if(d[w].x+d[w].width>m)m=d[w].x+d[w].width;if(d[w].y+d[w].height>o)o=d[w].y+d[w].height}}if(c=="page"){A=n=0;m=e.contentW;o=e.contentH}l=Array(B);s=Array(B);for(w=0;w<B;++w){if(I[w]==null)break;var v=d[w];l[w]=0;s[w]=0;switch(b){case "l":l[w]=n-v.x;break;case "c":l[w]=(n+m)/2-(v.x+v.width/2);break;case "r":l[w]=m-(v.x+v.width);break;case "t":s[w]=A-v.y;break;case "m":s[w]=(A+o)/2-(v.y+v.height/2);break;case "b":s[w]=o-(v.y+v.height)}}this.moveSelectedElements(l, -s)}};this.contentW=Ub().w;this.contentH=Ub().h;this.updateCanvas=function(b,c){g.setAttribute("width",b);g.setAttribute("height",c);var d=$("#canvasBackground")[0],n=p.getAttribute("x"),m=p.getAttribute("y"),A=b/2-this.contentW*q/2,o=c/2-this.contentH*q/2;la(p,{width:this.contentW*q,height:this.contentH*q,x:A,y:o,viewBox:"0 0 "+this.contentW+" "+this.contentH});la(d,{width:p.getAttribute("width"),height:p.getAttribute("height"),x:A,y:o});(d=ja("background_image"))&&la(d,{width:"100%",height:"100%"}); -Ha.selectorParentGroup.setAttribute("transform","translate("+A+","+o+")");return{x:A,y:o,old_x:n,old_y:m,d_x:A-n,d_y:o-m}};this.setBackground=function(b,c){var d=ja("canvasBackground"),n=$(d).find("rect")[0],m=ja("background_image");n.setAttribute("fill",b);if(c){if(!m){m=f.createElementNS(i,"image");la(m,{id:"background_image",width:"100%",height:"100%",preserveAspectRatio:"xMinYMin",style:"pointer-events:none"})}Z(m,c);d.appendChild(m)}else m&&m.parentNode.removeChild(m)};this.cycleElement=function(b){var c= -I[0],d=false,n=Lb(M||D().getCurrentLayer());if(n.length){if(c==null){b=b?n.length-1:0;d=n[b]}else for(var m=n.length;m--;)if(n[m]==c){b=b?m-1:m+1;if(b>=n.length)b=0;else if(b<0)b=n.length-1;d=n[b];break}Ib([d],true);aa("selected",I)}};this.clear();this.getPrivateMethods=function(){return{addCommandToHistory:Ca,setGradient:hc,addSvgElementFromJson:ma,assignAttributes:la,BatchCommand:Ga,call:aa,ChangeElementCommand:Qa,copyElem:V,ffClone:Eb,findDefs:ib,findDuplicateGradient:cc,getElem:ja,getId:ua,getIntersectionList:Rb, -getMouseTarget:Zb,getNextId:ya,getPathBBox:ea,getUrlFromAttr:Ra,hasMatrixTransform:qa,identifyLayers:Vb,InsertElementCommand:Fa,isIdentity:svgedit.math.isIdentity,logMatrix:tb,matrixMultiply:X,MoveElementCommand:Ma,preventClickDefault:Yb,recalculateAllSelectedDimensions:Ab,recalculateDimensions:nb,remapElement:Fb,RemoveElementCommand:Oa,removeUnusedDefElems:fc,round:Kb,runExtensions:pb,sanitizeSvg:Da,SVGEditTransformList:svgedit.transformlist.SVGTransformList,toString:toString,transformBox:svgedit.math.transformBox, -transformListToTransform:ga,transformPoint:ka,walkTree:svgedit.utilities.walkTree}}};(function(){document.addEventListener("touchstart",touchHandler,true);document.addEventListener("touchmove",touchHandler,true);document.addEventListener("touchend",touchHandler,true);document.addEventListener("touchcancel",touchHandler,true);if(!window.svgEditor)window.svgEditor=function(a){function H(D,q){var M=h.setSvgString(D)!==false;q=q||a.noop;M?q(true):a.alert(g.notification.errorLoadingSVG,function(){q(false)})}var h,i={},u=false,E={lang:"en",iconsize:"m",bkgd_color:"FFF",bkgd_url:"",img_save:"embed"}, -e={},f={canvas_expansion:1.2,dimensions:[640,480],initFill:{color:"fff",opacity:1},initStroke:{width:1.5,color:"000",opacity:1},initOpacity:1,imgPath:"images/",langPath:"locale/",extPath:"extensions/",jGraduatePath:"jgraduate/images/",extensions:["ext-markers.js","ext-eyedropper.js","ext-shapes.js","ext-grid.js"],initTool:"select",wireframe:false,colorPickerCSS:false,gridSnapping:false,gridColor:"#000",baseUnit:"px",snappingStep:10,showRulers:true,show_outside_canvas:false},g=i.uiStrings={common:{ok:"OK", -cancel:"Cancel",key_up:"Up",key_down:"Down",key_backspace:"Backspace",key_del:"Del"},layers:{layer:"Layer"},notification:{invalidAttrValGiven:"Invalid value given",noContentToFitTo:"No content to fit to",dupeLayerName:"There is already a layer named that!",enterUniqueLayerName:"Please enter a unique layer name",enterNewLayerName:"Please enter the new layer name",layerHasThatName:"Layer already has that name",QmoveElemsToLayer:'Move selected elements to layer "%s"?',QwantToClear:"Do you want to clear the drawing?\nThis will also erase your undo history!", -QwantToOpen:"Do you want to open a new file?\nThis will also erase your undo history!",QerrorsRevertToSource:"There were parsing errors in your SVG source.\nRevert back to original SVG source?",QignoreSourceChanges:"Ignore changes made to SVG source?",featNotSupported:"Feature not supported",enterNewImgURL:"Enter the new image URL",defsFailOnSave:"NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",loadingImage:"Loading image, please wait...", -saveFromBrowser:'Select "Save As..." in your browser to save this image as a %s file.',noteTheseIssues:"Also note the following issues: ",unsavedChanges:"There are unsaved changes.",enterNewLinkURL:"Enter the new hyperlink URL",errorLoadingSVG:"Error: Unable to load SVG data",URLloadFail:"Unable to load from URL",retrieving:'Retrieving "%s" ...'}};e={};var p={};i.curConfig=f;i.tool_scale=1;a.pref=function(D,q){if(q)e[D]=q;D="svg-edit-"+D;var M=location.hostname,ba=M&&M.indexOf(".")>=0,N=q!=undefined, -I=false;try{if(window.localStorage)I=localStorage}catch(ma){}try{if(window.globalStorage&&ba)I=globalStorage[M]}catch(ia){}if(I)if(N)I.setItem(D,q);else{if(I.getItem(D))return I.getItem(D)+""}else if(window.widget)if(N)widget.setPreferenceForKey(q,D);else return widget.preferenceForKey(D);else if(N){M=new Date;M.setTime(M.getTime()+31536E6);q=encodeURIComponent(q);document.cookie=D+"="+q+"; expires="+M.toUTCString()}else return(M=document.cookie.match(RegExp(D+"=([^;]+)")))?decodeURIComponent(M[1]): -""};i.setConfig=function(D){a.each(D,function(q,M){q in E&&a.pref(q,M)});a.extend(true,f,D);if(D.extensions)f.extensions=D.extensions};i.setCustomHandlers=function(D){i.ready(function(){if(D.open){a('#tool_open > input[type="file"]').remove();a("#tool_open").show();h.open=D.open}if(D.save){i.show_save_warning=false;h.bind("saved",D.save)}D.pngsave&&h.bind("exported",D.pngsave);p=D})};i.randomizeIds=function(){h.randomizeIds(arguments)};i.init=function(){function D(k,t){var G=k.id,L=G.split("_"),O= -L[0];L=L[1];t&&h.setStrokeAttr("stroke-"+O,L);ab();F("#cur_"+O,G,20);a(k).addClass("current").siblings().removeClass("current")}function q(k,t){a.pref("bkgd_color",k);a.pref("bkgd_url",t);h.setBackground(k,t)}function M(){var k=h.getHref(T);k=k.indexOf("data:")===0?"":k;a.prompt(g.notification.enterNewImgURL,k,function(t){t&&ub(t)})}function ba(){if(h.deleteCurrentLayer()){Ua();rb();a("#layerlist tr.layer").removeClass("layersel");a("#layerlist tr.layer:first").addClass("layersel")}}function N(){var k= -h.getCurrentDrawing().getCurrentLayerName()+" copy";a.prompt(g.notification.enterUniqueLayerName,k,function(t){if(t)if(h.getCurrentDrawing().hasLayer(t))a.alert(g.notification.dupeLayerName);else{h.cloneLayer(t);Ua();rb()}})}function I(k){var t=a("#layerlist tr.layersel").index(),G=h.getCurrentDrawing().getNumLayers();if(t>0||t<G-1){t+=k;h.setCurrentLayerPosition(G-t-1);rb()}}function ma(k,t){var G=document.getElementById("ruler_x_cursor"),L=document.getElementById("ruler_y_cursor"),O=document.getElementById("workarea"), -S=document.getElementById("title_show");a("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers",function(Wb){Wb.stopPropagation();G.style.left=Wb.pageX-66+O.scrollLeft+"px";L.style.top=Wb.pageY-48+O.scrollTop+"px";Wb=Wb.target.getAttribute("title");typeof Wb!="undefined"&&Wb&&S.innerHTML(Wb)});t||(t=h.getZoom());k||(k=a("#svgcanvas"));for(var da=h.getContentElem(),oa=svgedit.units.getTypeMap()[f.baseUnit],xa=0;xa<2;xa++){var Ba=xa===0,sa=Ba?"x":"y",Ya=Ba?"width":"height",Za=da.getAttribute(sa)- -0;sa=a("#ruler_"+sa+" canvas:first");$hcanv=sa.clone();sa.replaceWith($hcanv);var Q=$hcanv[0];var ob=sa=k[Ya]()*2;Q.parentNode.style[Ya]=ob+"px";var $a=0,Ka,Ea=Q.getContext("2d");Ea.fillStyle="rgb(200,0,0)";Ea.fillRect(0,0,Q.width,Q.height);$hcanv.siblings().remove();if(sa>=3E4){var Pa=parseInt(sa/3E4)+1;Ka=Array(Pa);Ka[0]=Ea;for(var ta=1;ta<Pa;ta++){Q[Ya]=3E4;var bb=Q.cloneNode(true);Q.parentNode.appendChild(bb);Ka[ta]=bb.getContext("2d")}bb[Ya]=sa%3E4;sa=3E4}Q[Ya]=sa;Ya=oa*t;var hb=50/Ya;Q=1;for(ta= -0;ta<ic.length;ta++){Q=Pa=ic[ta];if(hb<=Pa)break}hb=Q*Ya;Ea.font="normal 9px 'Lucida Grande', sans-serif";Ea.fillStyle="#777";for(var sb=Za/Ya%Q*Ya,Xb=sb-hb;sb<ob;sb+=hb){Xb+=hb;ta=Math.round(sb)+0.5;if(Ba){Ea.moveTo(ta,15);Ea.lineTo(ta,0)}else{Ea.moveTo(15,ta);Ea.lineTo(0,ta)}Pa=(Xb-Za)/Ya;if(Q>=1)ta=Math.round(Pa);else{ta=(Q+"").split(".")[1].length;ta=Pa.toFixed(ta)-0}if(ta!==0&&ta!==1E3&&ta%1E3===0)ta=ta/1E3+"K";if(Ba){Ea.fillText(ta,sb+2,8);Ea.fillStyle="#777"}else{Pa=(ta+"").split("");for(ta= -0;ta<Pa.length;ta++){Ea.fillText(Pa[ta],1,sb+9+ta*9);Ea.fillStyle="#777"}}Pa=hb/10;for(ta=1;ta<10;ta++){var Db=Math.round(sb+Pa*ta)+0.5;if(Ka&&Db>sa){$a++;Ea.stroke();if($a>=Ka.length){ta=10;sb=ob;continue}Ea=Ka[$a];sb-=3E4;Db=Math.round(sb+Pa*ta)+0.5}var pc=ta%2?12:10;if(Ba){Ea.moveTo(Db,15);Ea.lineTo(Db,pc)}else{Ea.moveTo(15,Db);Ea.lineTo(pc,Db)}}}Ea.strokeStyle="#666";Ea.stroke()}}(function(){var k=window.opener;if(k)try{var t=k.document.createEvent("Event");t.initEvent("svgEditorReady",true,true); -k.document.documentElement.dispatchEvent(t)}catch(G){}})();(function(){var k=a.deparam.querystring(true);if(!a.isEmptyObject(k)){if(k.dimensions)k.dimensions=k.dimensions.split(",");if(k.extensions)k.extensions=k.extensions.split(",");if(k.bkgd_color)k.bkgd_color="#"+k.bkgd_color;svgEditor.setConfig(k);var t=k.source,G=a.param.querystring();if(!t)if(G.indexOf("source=data:")>=0)t=G.match(/source=(data:[^&]*)/)[1];if(t)if(t.indexOf("data:")===0){t=t.replace(/ /g,"+");i.loadFromDataURI(t)}else i.loadFromString(t); -else if(G.indexOf("paramurl=")!==-1)svgEditor.loadFromURL(G.substr(9));else k.url&&svgEditor.loadFromURL(k.url)}})();var ia=function(){a.each(f.extensions,function(){var t=this;a.getScript(f.extPath+t,function(G){if(!G){G=document.createElement("script");G.src=f.extPath+t;document.querySelector("head").appendChild(G)}})});var k=[];a("#lang_select option").each(function(){k.push(this.value)});i.putLocale(null,k)};document.location.protocol==="file:"?setTimeout(ia,100):ia();a.svgIcons(f.imgPath+"svg_edit_icons.svg", -{w:24,h:24,id_match:false,no_img:!svgedit.browser.isWebkit(),fallback_path:f.imgPath,fallback:{new_image:"clear.png",save:"save.png",open:"open.png",source:"source.png",docprops:"document-properties.png",wireframe:"wireframe.png",undo:"undo.png",redo:"redo.png",select:"select.png",select_node:"select_node.png",pencil:"fhpath.png",pen:"line.png",square:"square.png",rect:"rect.png",fh_rect:"freehand-square.png",circle:"circle.png",ellipse:"ellipse.png",fh_ellipse:"freehand-circle.png",path:"path.png", -text:"text.png",image:"image.png",zoom:"zoom.png",clone:"clone.png",node_clone:"node_clone.png","delete":"delete.png",node_delete:"node_delete.png",move_top:"move_top.png",move_bottom:"move_bottom.png",to_path:"to_path.png",link_controls:"link_controls.png",reorient:"reorient.png",align_left:"align-left.png",align_center:"align-center",align_right:"align-right",align_top:"align-top",align_middle:"align-middle",align_bottom:"align-bottom",go_up:"go-up.png",go_down:"go-down.png",ok:"save.png",cancel:"cancel.png", -arrow_right:"flyouth.png",arrow_down:"dropdown.gif"},placement:{"#tool_docprops > div":"docprops","#tool_select":"select","#tool_fhpath":"pencil","#tool_line":"pen","#tool_rect,#tools_rect_show":"rect","#tool_square":"square","#tool_fhrect":"fh_rect","#tool_ellipse,#tools_ellipse_show":"ellipse","#tool_circle":"circle","#tool_fhellipse":"fh_ellipse","#tool_path":"path","#tool_text,#layer_rename":"text","#tool_image":"image","#tool_zoom":"zoom","#tool_node_clone":"node_clone","#tool_node_delete":"node_delete", -"#tool_add_subpath":"add_subpath","#tool_openclose_path":"open_path","#tool_node_link":"link_controls","#tool_alignleft, #tool_posleft":"align_left","#tool_aligncenter, #tool_poscenter":"align_center","#tool_alignright, #tool_posright":"align_right","#tool_aligntop, #tool_postop":"align_top","#tool_alignmiddle, #tool_posmiddle":"align_middle","#tool_alignbottom, #tool_posbottom":"align_bottom","#cur_position":"align","#linecap_butt,#cur_linecap":"linecap_butt","#linecap_round":"linecap_round","#linecap_square":"linecap_square", -"#linejoin_miter,#cur_linejoin":"linejoin_miter","#linejoin_round":"linejoin_round","#linejoin_bevel":"linejoin_bevel","#url_notice":"warning","#layer_up":"go_up","#layer_down":"go_down","#layer_moreopts":"context_menu","#layerlist td.layervis":"eye","#tool_source_save,#tool_docprops_save,#tool_prefs_save":"ok","#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel":"cancel","#rwidthLabel, #iwidthLabel":"width","#rheightLabel, #iheightLabel":"height","#angleLabel":"angle","#linkLabel,#tool_make_link,#tool_make_link_multi":"globe_link", -"#zoomLabel":"zoom","#blurLabel":"blur",".flyout_arrow_horiz":"arrow_right","#palette .palette_item:first, #fill_bg, #stroke_bg":"no_color"},resize:{"#logo .svg_icon":32,".flyout_arrow_horiz .svg_icon":5,".layer_button .svg_icon, #layerlist td.layervis .svg_icon":14,"#main_button .dropdown .svg_icon":9,"#fill_bg .svg_icon, #stroke_bg .svg_icon":24,".palette_item:first .svg_icon":16,".toolbar_button button .svg_icon":16,".stroke_tool div div .svg_icon":20,"#tools_bottom label .svg_icon":18,"#zoom_dropdown .svg_icon":7}, -callback:function(){a(".toolbar_button button > svg, .toolbar_button button > img").each(function(){a(this).parent().prepend(this)});var k=a("#tools_left");if(k.length!=0){k.offset();k.outerHeight()}a(".tools_flyout").each(function(){var t=a("#"+this.id+"_show"),G=t.attr("data-curopt");if(!t.children("svg, img").length){G=a(G).children().clone();if(G.length){G[0].removeAttribute("style");t.append(G)}}});svgEditor.runCallbacks();setTimeout(function(){a(".flyout_arrow_horiz:empty").each(function(){a(this).append(a.getSvgIcon("arrow_right").width(5).height(5))})}, -1)}});i.canvas=h=new a.SvgCanvas(document.getElementById("svgcanvas"),f);i.show_save_warning=false;ia=navigator.platform.indexOf("Mac")>=0;var ka=navigator.userAgent.indexOf("AppleWebKit")>=0,X=ia?"meta+":"ctrl+",qa=h.pathActions,ga=h.undoMgr,Na=svgedit.utilities,va=f.imgPath+"placeholder.svg",ha=a("#workarea"),Ra=a("#cmenu_canvas");a("#cmenu_layers");var U=null,Z=1,ea="toolbars",ra="",ja={fill:null,stroke:null};(function(){a("#dialog_container").draggable({cancel:"#dialog_content, #dialog_buttons *", -containment:"window"});var k=a("#dialog_box"),t=a("#dialog_buttons"),G=function(L,O,S,da){a("#dialog_content").html("<p>"+O.replace(/\n/g,"</p><p>")+"</p>").toggleClass("prompt",L=="prompt");t.empty();var oa=a('<input type="button" value="'+g.common.ok+'">').appendTo(t);L!="alert"&&a('<input type="button" value="'+g.common.cancel+'">').appendTo(t).click(function(){k.hide();S(false)});if(L=="prompt"){var xa=a('<input type="text">').prependTo(t);xa.val(da||"");xa.bind("keydown","return",function(){oa.click()})}L== -"process"&&oa.hide();k.show();oa.click(function(){k.hide();var Ba=L=="prompt"?xa.val():true;S&&S(Ba)}).focus();L=="prompt"&&xa.focus()};a.alert=function(L,O){G("alert",L,O)};a.confirm=function(L,O){G("confirm",L,O)};a.process_cancel=function(L,O){G("process",L,O)};a.prompt=function(L,O,S){G("prompt",L,S,O)}})();var la=function(){var k=a(".tool_button_current");if(k.length&&k[0].id!=="tool_select"){k.removeClass("tool_button_current").addClass("tool_button");a("#tool_select").addClass("tool_button_current").removeClass("tool_button"); -a("#styleoverrides").text("#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}")}h.setMode("select")},T=null,wa=false,Da=false,Ma=false,Fa=false,Oa="",Qa=a("title:first").text(),Ga=function(k,t,G){h.getResolution();a("#svgcanvas").position();if(t=h.setBBoxZoom(t,ha.width()-15,ha.height()-15)){k=t.zoom;t=t.bbox;if(k<0.0010)Ia({value:0.1});else{a("#zoom").val(k*100);G?Ob():Ob(false,{x:t.x*k+t.width*k/2,y:t.y*k+t.height*k/2});h.getMode()=="zoom"&&t.width&&la();m()}}};a("#cur_context_panel").delegate("a", -"click",function(){var k=a(this);k.attr("data-root")?h.leaveContext():h.setContext(k.text());return false});var Ca={},Ha=function(k){a.each(k,function(t,G){var L=a(t).children(),O=t+"_show",S=a(O),da=false;L.addClass("tool_button").unbind("click mousedown mouseup").each(function(Ba){var sa=G[Ba];Ca[sa.sel]=sa.fn;if(sa.isDefault)da=Ba;Ba=function(Ya){var Za=sa;if(Ya.type==="keydown"){var Q=a(Za.parent+"_show").hasClass("tool_button_current"),ob=a(Za.parent+"_show").attr("data-curopt");a.each(k[sa.parent], -function(Ka,Ea){if(Ea.sel==ob)Za=!Ya.shiftKey||!Q?Ea:k[sa.parent][Ka+1]||k[sa.parent][0]})}if(a(this).hasClass("disabled"))return false;db(O)&&Za.fn();var $a=Za.icon?a.getSvgIcon(Za.icon,true):a(Za.sel).children().eq(0).clone();$a[0].setAttribute("width",S.width());$a[0].setAttribute("height",S.height());S.children(":not(.flyout_arrow_horiz)").remove();S.append($a).attr("data-curopt",Za.sel)};a(this).mouseup(Ba);sa.key&&a(document).bind("keydown",sa.key[0]+" shift+"+sa.key[0],Ba)});if(da)S.attr("data-curopt", -G[da].sel);else S.attr("data-curopt")||S.attr("data-curopt",G[0].sel);var oa,xa=a(O).position();a(t).css({left:xa.left+34,top:xa.top+77});S.mousedown(function(Ba){a("#tools_shapelib").is(":visible")&&db(O,false);if(S.hasClass("disabled"))return false;var sa=a(t),Ya=xa.left+34,Za=sa.width()*-1,Q=sa.data("shown_popop")?200:0;oa=setTimeout(function(){S.data("isLibrary")?sa.css("left",Ya).show():sa.css("left",Za).show().animate({left:Ya},150);sa.data("shown_popop",true)},Q);Ba.preventDefault()}).mouseup(function(){clearTimeout(oa); -var Ba=a(this).attr("data-curopt");if(S.data("isLibrary")&&a(O.replace("_show","")).is(":visible"))db(O,true);else db(O)&&Ba in Ca&&Ca[Ba]()})});Pb()},Aa=function(k,t){return a("<div>",{"class":"tools_flyout",id:k}).appendTo("#svg_editor").append(t)},zb=function(){a(".tools_flyout").each(function(){var k=a("#"+this.id+"_show"),t=k.offset();k=k.outerWidth();a(this).css({left:(t.left+k)*Z,top:t.top})})},Pb=function(){a(".tools_flyout").each(function(){var k=a("#"+this.id+"_show");if(!k.data("isLibrary")){var t= -[];a(this).children().each(function(){t.push(this.title)});k[0].title=t.join(" / ")}})},gb,mb=function(k,t,G){var L=null;if(k.indexOf("url(#")===0){k=(k=h.getRefElem(k))?k.cloneNode(true):a("#"+G+"_color defs *")[0];L={alpha:t};L[k.tagName]=k}else L=k.indexOf("#")===0?{alpha:t,solidColor:k.substr(1)}:{alpha:t,solidColor:"none"};return new a.jGraduate.Paint(L)},Va=h.getResolution();if(f.baseUnit!=="px"){Va.w=svgedit.units.convertUnit(Va.w)+f.baseUnit;Va.h=svgedit.units.convertUnit(Va.h)+f.baseUnit}a(".canvas_width").val(Va.w); -a(".canvas_height").val(Va.h);a("#docprops_button").on("click",function(){o()});var ub=i.setImageURL=function(k){k||(k=va);h.setImageURL(k);a("#image_url").val(k);if(k.indexOf("data:")===0){a("#image_url").hide();a("#change_image_url").show()}else{h.embedImage(k,function(t){t?a("#url_notice").hide():a("#url_notice").show();va=k});a("#image_url").show();a("#change_image_url").hide()}},Bb=function(k){var t=Math.min(Math.max(12+k.value.length*6,50),300);a(k).width(t)},Ua=function(){var k=T;if(k!=null&& -!k.parentNode)k=null;var t=h.getCurrentDrawing().getCurrentLayerName(),G=h.getMode(),L=f.baseUnit!=="px"?f.baseUnit:null,O=G=="pathedit",S=a("#cmenu_canvas li");a("#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\t\t\t\t\t#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel").hide();a(".menu_item","#edit_menu").addClass("disabled");a(".menu_item","#object_menu").addClass("disabled");!k&&!wa&&a("#canvas_panel").show(); -if(k!=null){var da=k.nodeName,oa=h.getRotationAngle(k);a("#angle").val(Math.round(oa));oa=h.getBlur(k);a("#blur").val(oa);a("#blur_slider").slider("option","value",oa);h.addedNew&&da==="image"&&h.getHref(k).indexOf("data:")!==0&&M();if(!O&&G!="pathedit"){a("#selected_panel").show();a(".action_selected").removeClass("disabled");if(["line","circle","ellipse"].indexOf(da)>=0)a("#xy_panel").hide();else{var xa,Ba;if(["g","polyline","path"].indexOf(da)>=0){if(G=h.getStrokedBBox([k])){xa=G.x;Ba=G.y}}else{xa= -k.getAttribute("x");Ba=k.getAttribute("y")}if(L){xa=svgedit.units.convertUnit(xa);Ba=svgedit.units.convertUnit(Ba)}a("#selected_x").val(xa||0);a("#selected_y").val(Ba||0);a("#xy_panel").show()}["image","text","path","g","use"].indexOf(da)==-1&&a(".action_path_convert_selected").removeClass("disabled");da==="path"&&a(".action_path_selected").removeClass("disabled")}else{t=qa.getNodePoint();a("#tool_add_subpath").removeClass("push_button_pressed").addClass("tool_button");a("#tool_node_delete").toggleClass("disabled", -!qa.canDeleteNodes);F("#tool_openclose_path",qa.closed_subpath?"open_path":"close_path");if(t){O=a("#seg_type");if(L){t.x=svgedit.units.convertUnit(t.x);t.y=svgedit.units.convertUnit(t.y)}a("#path_node_x").val(t.x);a("#path_node_y").val(t.y);t.type?O.val(t.type).removeAttr("disabled"):O.val(4).attr("disabled","disabled")}return}L={g:[],a:[],rect:["rx","width","height"],image:["width","height"],circle:["cx","cy","r"],ellipse:["cx","cy","rx","ry"],line:["x1","y1","x2","y2"],text:[],use:[]};var sa=k.tagName; -a(k).data("gsvg")&&a("#g_panel").show();sa=="path"&&a("#path_panel").show();if(L[sa]){L=L[sa];a("#"+sa+"_panel").show();a.each(L,function(Ya,Za){var Q=k.getAttribute(Za);if(f.baseUnit!=="px"&&k[Za])Q=svgedit.units.convertUnit(k[Za].baseVal.value);a("#"+sa+"_"+Za).val(Q||0)});if(sa=="text"){a("#text_panel").css("display","inline");h.getItalic()?a("#tool_italic").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_italic").removeClass("push_button_pressed").addClass("tool_button");h.getBold()? -a("#tool_bold").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_bold").removeClass("push_button_pressed").addClass("tool_button");a("#font_family").val(k.getAttribute("font-family"));a("#font_size").val(k.getAttribute("font-size"));a("#text").val(k.textContent);h.addedNew&&setTimeout(function(){a("#text").focus().select()},100)}else if(sa=="image")ub(h.getHref(k));else if(sa==="g"||sa==="use"){a("#container_panel").show();a(".action_group_selected").removeClass("disabled");L=h.getTitle(); -da=a("#g_title")[0];da.value=L;Bb(da);sa=="use"?da.setAttribute("disabled","disabled"):da.removeAttribute("disabled")}}S[(sa==="g"?"en":"dis")+"ableContextMenuItems"]("#ungroup");S[(sa==="g"||!wa?"dis":"en")+"ableContextMenuItems"]("#group")}else if(wa){a("#multiselected_panel").show();a(".action_multi_selected").removeClass("disabled");S.enableContextMenuItems("#group").disableContextMenuItems("#ungroup")}else S.disableContextMenuItems("#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back"); -ga.getUndoStackSize()>0?a("#tool_undo").removeClass("disabled"):a("#tool_undo").addClass("disabled");ga.getRedoStackSize()>0?a("#tool_redo").removeClass("disabled"):a("#tool_redo").addClass("disabled");h.addedNew=false;if(k&&!O||wa){a("#selLayerNames").removeAttr("disabled").val(t);Ra.enableContextMenuItems("#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back")}else a("#selLayerNames").attr("disabled","disabled")};a("#text").focus(function(){});a("#text").blur(function(){});h.bind("selected", -function(k,t){var G=h.getMode();G==="select"&&la();G=G=="pathedit";T=t.length==1||t[1]==null?t[0]:null;wa=t.length>=2&&t[1]!=null;if(T!=null)if(!G){if(T!=null)switch(T.tagName){case "use":case "image":case "foreignObject":break;case "g":case "a":for(var L=null,O=T.getElementsByTagName("*"),S=0,da=O.length;S<da;S++){var oa=O[S].getAttribute("stroke-width");if(S===0)L=oa;else if(L!==oa)L=null}a("#stroke_width").val(L===null?"":L);ja.fill.update(true);ja.stroke.update(true);break;default:ja.fill.update(true); -ja.stroke.update(true);a("#stroke_width").val(T.getAttribute("stroke-width")||1);a("#stroke_style").val(T.getAttribute("stroke-dasharray")||"none");L=T.getAttribute("stroke-linejoin")||"miter";a("#linejoin_"+L).length!=0&&D(a("#linejoin_"+L)[0]);L=T.getAttribute("stroke-linecap")||"butt";a("#linecap_"+L).length!=0&&D(a("#linecap_"+L)[0])}if(T!=null){L=(T.getAttribute("opacity")||1)*100;a("#group_opacity").val(L);a("#opac_slider").slider("option","value",L);a("#elem_id").val(T.id)}ac()}a("#path_node_panel").toggle(G); -a("#tools_bottom_2,#tools_bottom_3").toggle(!G);if(G){a(".tool_button_current").removeClass("tool_button_current").addClass("tool_button");a("#tool_select").addClass("tool_button_current").removeClass("tool_button");F("#tool_select","select_node");wa=false;if(t.length)T=t[0]}else F("#tool_select","select");Ua();h.runExtensions("selectedChanged",{elems:t,selectedElement:T,multiselected:wa})});h.bind("transition",function(k,t){var G=h.getMode(),L=t[0];if(L){wa=t.length>=2&&t[1]!=null;if(!wa)switch(G){case "rotate":G= -h.getRotationAngle(L);a("#angle").val(Math.round(G));a("#tool_reorient").toggleClass("disabled",G==0)}h.runExtensions("elementTransition",{elems:t})}});h.bind("changed",function(k,t){var G=h.getMode();G==="select"&&la();for(var L=0;L<t.length;++L){var O=t[L];if(O&&O.tagName==="svg"){rb();Ob()}else if(O&&T&&T.parentNode==null)T=O}i.show_save_warning=true;Ua();if(T&&G==="select"){ja.fill.update();ja.stroke.update()}h.runExtensions("elementChanged",{elems:t})});h.bind("saved",function(k,t){i.show_save_warning= -false;t='<?xml version="1.0"?>\n'+t;var G=navigator.userAgent;if(~G.indexOf("Chrome")&&a.browser.version>=533||~G.indexOf("MSIE"))A(0,true);else{var L=k.open("data:image/svg+xml;base64,"+Na.encode64(t)),O=a.pref("save_notice_done");if(O!=="all"){var S=g.notification.saveFromBrowser.replace("%s","SVG");if(G.indexOf("Gecko/")!==-1)if(t.indexOf("<defs")!==-1){S+="\n\n"+g.notification.defsFailOnSave;a.pref("save_notice_done","all");O="all"}else a.pref("save_notice_done","part");else a.pref("save_notice_done", -"all");O!=="part"&&L.alert(S)}}});h.bind("exported",function(k,t){var G=t.issues;a("#export_canvas").length||a("<canvas>",{id:"export_canvas"}).hide().appendTo("body");var L=a("#export_canvas")[0];L.width=h.contentW;L.height=h.contentH;canvg(L,t.svg,{renderCallback:function(){var O=L.toDataURL("image/png");U.location.href=O;if(a.pref("export_notice_done")!=="all"){O=g.notification.saveFromBrowser.replace("%s","PNG");if(G.length)O+="\n\n"+g.notification.noteTheseIssues+"\n \u2022 "+G.join("\n \u2022 "); -a.pref("export_notice_done","all");U.alert(O)}}})});h.bind("zoomed",Ga);h.bind("contextset",function(k,t){var G="";if(t){var L="";G='<a href="#" data-root="y">'+h.getCurrentDrawing().getCurrentLayerName()+"</a>";a(t).parentsUntil("#svgcontent > g").andSelf().each(function(){if(this.id){L+=" > "+this.id;G+=this!==t?' > <a href="#">'+this.id+"</a>":" > "+this.id}});Oa=L}else Oa=null;a("#cur_context_panel").toggle(!!t).html(G);w()});h.bind("extension_added",function(k,t){function G(){if(gb){clearTimeout(gb); -gb=null}O||(gb=setTimeout(function(){O=true;P(e.iconsize)},50))}var L=false,O=false,S=true,da=function(){if(t.callback&&!L&&S){L=true;t.callback()}},oa=[];t.context_tools&&a.each(t.context_tools,function(Za,Q){var ob=Q.container_id?' id="'+Q.container_id+'"':"",$a=a("#"+Q.panel);$a.length||($a=a("<div>",{id:Q.panel}).appendTo("#tools_top"));switch(Q.type){case "tool_button":var Ka='<div class="tool_button">'+Q.id+"</div>",Ea=a(Ka).appendTo($a);Q.events&&a.each(Q.events,function(bb,hb){a(Ea).bind(bb, -hb)});break;case "select":Ka="<label"+ob+'><select id="'+Q.id+'">';a.each(Q.options,function(bb,hb){Ka+='<option value="'+bb+'"'+(bb==Q.defval?" selected":"")+">"+hb+"</option>"});Ka+="</select></label>";var Pa=a(Ka).appendTo($a).find("select");a.each(Q.events,function(bb,hb){a(Pa).bind(bb,hb)});break;case "button-select":Ka='<div id="'+Q.id+'" class="dropdown toolset" title="'+Q.title+'"><div id="cur_'+Q.id+'" class="icon_label"></div><button></button></div>';ob=a('<ul id="'+Q.id+'_opts"></ul>').appendTo("#option_lists"); -Q.colnum&&ob.addClass("optcols"+Q.colnum);a(Ka).appendTo($a).children();oa.push({elem:"#"+Q.id,list:"#"+Q.id+"_opts",title:Q.title,callback:Q.events.change,cur:"#cur_"+Q.id});break;case "input":Ka="<label"+ob+'><span id="'+Q.id+'_label">'+Q.label+':</span><input id="'+Q.id+'" title="'+Q.title+'" size="'+(Q.size||"4")+'" value="'+(Q.defval||"")+'" type="text"/></label>';var ta=a(Ka).appendTo($a).find("input");Q.spindata&&ta.SpinButton(Q.spindata);Q.events&&a.each(Q.events,function(bb,hb){ta.bind(bb, -hb)})}});if(t.buttons){var xa={},Ba={},sa=t.svgicons,Ya={};a.each(t.buttons,function(Za,Q){for(var ob,$a=Q.id,Ka=Za;a("#"+$a).length;)$a=Q.id+"_"+ ++Ka;if(sa){xa[$a]=Q.icon;Ka=Q.svgicon?Q.svgicon:Q.id;if(Q.type=="app_menu")Ba["#"+$a+" > div"]=Ka;else Ba["#"+$a]=Ka}else ob=Q.type=="menu"?"":a('<img src="'+Q.icon+'">');var Ea,Pa;switch(Q.type){case "mode_flyout":case "mode":Ea="tool_button";if(Q.cls)Ea+=" "+Q.cls;Pa="#tools_left";break;case "context":Ea="tool_button";Pa="#"+Q.panel;a(Pa).length||a("<div>", -{id:Q.panel}).appendTo("#tools_top");break;case "menu":Ea="menu_item tool_button";Pa="#"+(Q.after||Q.panel);break;case "app_menu":Ea="";Pa=Q.parent||"#main_menu ul";a(Pa).length||a("<div>",{id:Q.panel}).appendTo("#tools_top")}var ta=a(Q.list||Q.type=="app_menu"?"<li/>":"<div/>").attr("id",$a).attr("title",Q.title).addClass(Ea);if(!Q.includeWith&&!Q.list){if("position"in Q)a(Pa).children().eq(Q.position).before(ta);else Q.type!="menu"||!Q.after?ta.appendTo(Pa):a(Pa).after(ta);if(Q.type=="mode_flyout"){Ka= -a(ta);Ea=Ka.parent();if(!Ka.parent().hasClass("tools_flyout")){var bb=Ka[0].id.replace("tool_","tools_"),hb=Ka.clone().attr("id",bb+"_show").append(a("<div>",{"class":"flyout_arrow_horiz"}));Ka.before(hb);Ea=Aa(bb,Ka);Ea.data("isLibrary",true);hb.data("isLibrary",true)}Ba["#"+bb+"_show"]=Q.id;$a=Ya["#"+Ea[0].id]=[{sel:"#"+$a,fn:Q.events.click,icon:Q.id,isDefault:true},sb]}else if(Q.type=="app_menu"||Q.type=="menu")ta.append(Q.title)}else if(Q.list){ta.addClass("push_button");a("#"+Q.list+"_opts").append(ta); -if(Q.isDefault){a("#cur_"+Q.list).append(ta.children().clone());Ka=Q.svgicon?Q.svgicon:Q.id;Ba["#cur_"+Q.list]=Ka}}else if(Q.includeWith){Pa=Q.includeWith;Ka=a(Pa.button);Ea=Ka.parent();if(!Ka.parent().hasClass("tools_flyout")){bb=Ka[0].id.replace("tool_","tools_");hb=Ka.clone().attr("id",bb+"_show").append(a("<div>",{"class":"flyout_arrow_horiz"}));Ka.before(hb);Ea=Aa(bb,Ka)}var sb=nc.getButtonData(Pa.button);if(Pa.isDefault)Ba["#"+bb+"_show"]=Q.id;$a=Ya["#"+Ea[0].id]=[{sel:"#"+$a,fn:Q.events.click, -icon:Q.id,key:Q.key,isDefault:Q.includeWith?Q.includeWith.isDefault:0},sb];bb="position"in Pa?Pa.position:"last";sb=Ea.children().length;if(!isNaN(bb)&&bb>=0&&bb<sb)Ea.children().eq(bb).before(ta);else{Ea.append(ta);$a.reverse()}}sa||ta.append(ob);Q.list||a.each(Q.events,function(Xb,Db){if(Xb=="click")if(Q.type=="mode"){Q.includeWith?ta.bind(Xb,Db):ta.bind(Xb,function(){db(ta)&&Db()});if(Q.key){a(document).bind("keydown",Q.key,Db);Q.title&&ta.attr("title",Q.title+" ["+Q.key+"]")}}else ta.bind(Xb, -Db);else ta.bind(Xb,Db)});Ha(Ya)});a.each(oa,function(){lb(this.elem,this.list,this.callback,{seticon:true})});if(sa)S=false;a.svgIcons(sa,{w:24,h:24,id_match:false,no_img:!ka,fallback:xa,placement:Ba,callback:function(){e.iconsize&&e.iconsize!="m"&&G();S=true;da()}})}da()});h.textActions.setInputElem(a("#text")[0]);var Ja='<div class="palette_item" data-rgb="#none"></div>';a.each(["#000000","#3f3f3f","#7f7f7f","#bfbfbf","#ffffff","#ff0000","#ff7f00","#ffff00","#7fff00","#00ff00","#00ff7f","#00ffff", -"#007fff","#0000ff","#7f00ff","#ff00ff","#ff007f","#7f0000","#7f3f00","#7f7f00","#3f7f00","#007f00","#007f3f","#007f7f","#003f7f","#00007f","#3f007f","#7f007f","#7f003f","#ffaaaa","#ffd4aa","#ffffaa","#d4ffaa","#aaffaa","#aaffd4","#aaffff","#aad4ff","#aaaaff","#d4aaff","#ffaaff","#ffaad4"],function(k,t){Ja+='<div class="palette_item" style="background-color: '+t+';" data-rgb="'+t+'"></div>'});a("#palette").append(Ja);Ja="";a.each(["#FFF","#888","#000"],function(){Ja+='<div class="color_block" style="background-color:'+ -this+';"></div>'});a("#bg_blocks").append(Ja);var Wa=a("#bg_blocks div");Wa.each(function(){a(this).click(function(){Wa.removeClass("cur_background");a(this).addClass("cur_background")})});if(a.pref("bkgd_color"))q(a.pref("bkgd_color"),a.pref("bkgd_url"));else a.pref("bkgd_url")&&q(E.bkgd_color,a.pref("bkgd_url"));if(a.pref("img_save")){e.img_save=a.pref("img_save");a("#image_save_opts input").val([e.img_save])}var Ia=function(k){var t=k.value/100;if(t<0.0010)k.value=0.1;else{k=h.getZoom();Ga(window, -{width:0,height:0,x:(ha[0].scrollLeft+ha.width()/2)/k,y:(ha[0].scrollTop+ha.height()/2)/k,zoom:t},true)}},kb=function(k,t){if(t==null)t=k.value;a("#group_opacity").val(t);if(!k||!k.handle)a("#opac_slider").slider("option","value",t);h.setOpacity(t/100)},Cb=function(k,t,G){if(t==null)t=k.value;a("#blur").val(t);var L=false;if(!k||!k.handle){a("#blur_slider").slider("option","value",t);L=true}G?h.setBlurNoUndo(t):h.setBlur(t,L)},ab=function(){window.opera&&a("<p/>").hide().appendTo("body").remove()}; -a("#stroke_style").change(function(){h.setStrokeAttr("stroke-dasharray",a(this).val());ab()});a("#stroke_linejoin").change(function(){h.setStrokeAttr("stroke-linejoin",a(this).val());ab()});a("select").change(function(){a(this).blur()});var cb=false;a("#selLayerNames").change(function(){var k=this.options[this.selectedIndex].value,t=g.notification.QmoveElemsToLayer.replace("%s",k),G=function(L){if(L){cb=true;h.moveSelectedToLayer(k);h.clearSelection();rb()}};if(k)cb?G(true):a.confirm(t,G)});a("#font_family").change(function(){h.setFontFamily(this.value)}); -a("#seg_type").change(function(){h.setSegType(a(this).val())});a("#text").keyup(function(){h.setTextContent(this.value)});a("#image_url").change(function(){ub(this.value)});a("#link_url").change(function(){this.value.length?h.setLinkURL(this.value):h.removeHyperlink()});a("#g_title").change(function(){h.setGroupTitle(this.value)});a(".attr_changer").change(function(){var k=this.getAttribute("data-attr"),t=this.value;if(svgedit.units.isValidUnit(k,t,T))this.blur();else{a.alert(g.notification.invalidAttrValGiven); -this.value=T.getAttribute(k);return false}if(k!=="id")if(isNaN(t))t=h.convertToNum(k,t);else if(f.baseUnit!=="px"){var G=svgedit.units.getTypeMap();if(T[k]||h.getMode()==="pathedit"||k==="x"||k==="y")t*=G[f.baseUnit]}if(k==="id"){k=T;h.clearSelection();k.id=t;h.addToSelection([k],true)}else h.changeSelectedAttribute(k,t);this.blur()});a("#palette").mouseover(function(){var k=a('<input type="hidden">');a(this).append(k);k.focus().remove()});a(".palette_item").mousedown(function(){var k=a("#tool_stroke").hasClass("active"), -t=k?"stroke":"fill",G=a(this).attr("data-rgb"),L=null;console.log(G);if(G==="transparent"||G==="initial"||G==="#none"){G="none";L=new a.jGraduate.Paint}else L=new a.jGraduate.Paint({alpha:100,solidColor:G.substr(1)});ja[t].setPaint(L);if(k){h.setColor("stroke",G);G!="none"&&h.getStrokeOpacity()!=1&&h.setPaintOpacity("stroke",1)}else{h.setColor("fill",G);G!="none"&&h.getFillOpacity()!=1&&h.setPaintOpacity("fill",1)}ac()}).bind("contextmenu",function(k){k.preventDefault()});a("#toggle_stroke_tools").toggle(function(){a(".stroke_tool").css("display", -"table-cell");a(this).addClass("expanded");na()},function(){a(".stroke_tool").css("display","none");a(this).removeClass("expanded");na()});var db=function(k,t){if(a(k).hasClass("disabled"))return false;if(a(k).parent().hasClass("tools_flyout"))return true;var G=G||"normal";t||a(".tools_flyout").fadeOut(G);a("#styleoverrides").text("");a(".tool_button_current").removeClass("tool_button_current").addClass("tool_button");a(k).addClass("tool_button_current").removeClass("tool_button");return true};(function(){var k= -null,t=null,G=ha[0],L=false,O=false;a("#svgcanvas").bind("mousemove mouseup",function(S){if(L!==false){G.scrollLeft-=S.clientX-k;G.scrollTop-=S.clientY-t;k=S.clientX;t=S.clientY;if(S.type==="mouseup")L=false;return false}}).mousedown(function(S){if(S.button===1||O===true){L=true;k=S.clientX;t=S.clientY;return false}});a(window).mouseup(function(){L=false});a(document).bind("keydown","space",function(S){h.spaceKey=O=true;S.preventDefault()}).bind("keyup","space",function(S){S.preventDefault();h.spaceKey= -O=false}).bind("keydown","alt",function(){h.getMode()==="zoom"&&ha.addClass("out")}).bind("keyup","alt",function(){h.getMode()==="zoom"&&ha.removeClass("out")})})();var za=a(".menu"),vb=function(k){k.target.style.background="#fff";setTimeout(function(){k.target.style.background="#ddd"},50);setTimeout(function(){k.target.style.background="#fff"},150);setTimeout(function(){k.target.style.background="#ddd"},200);setTimeout(function(){k.target.style.background=""},200);setTimeout(function(){a("#menu_bar").removeClass("active")}, -220);return false};a(".menu_item").live("click",function(k){vb(k)});a("svg, body").on("click",function(k){if(!a(k.target).hasClass("menu_title")&&a("#menu_bar").hasClass("active"))if(!a(k.target).hasClass("disabled")&&a(k.target).hasClass("menu_item"))vb(k);else{a("#menu_bar").removeClass("active");a(".tools_flyout").hide();a("input").blur()}});a(".menu_title").on("click",function(){a("#menu_bar").toggleClass("active")});a(".menu_title").on("mouseover",function(){za.removeClass("open");a(this).parent().addClass("open")}); -i.addDropDown=function(k,t,G){if(a(k).length!=0){var L=a(k).find("button"),O=a(k).find("ul").attr("id",a(k)[0].id+"-list");G||a("#option_lists").append(O);var S=false;G&&a(k).addClass("dropup");O.find("li").bind("mouseup",t);a(window).mouseup(function(){if(!S){L.removeClass("down");O.hide()}S=false});L.bind("mousedown",function(){if(L.hasClass("down")){L.removeClass("down");O.hide()}else{L.addClass("down");if(!G){var da=a(k).offset();O.css({top:da.top,left:da.left-110})}O.show();S=true}}).hover(function(){S= -true}).mouseout(function(){S=false})}};var lb=function(k,t,G,L){var O=a(k);t=a(t);var S=false,da=L.dropUp;da&&a(k).addClass("dropup");t.find("li").bind("mouseup",function(){if(L.seticon){F("#cur_"+O[0].id,a(this).children());a(this).addClass("current").siblings().removeClass("current")}G.apply(this,arguments)});a(window).mouseup(function(){if(!S){O.removeClass("down");t.hide();t.css({top:0,left:0})}S=false});t.height();a(k).bind("mousedown",function(){var oa=a(k).offset();if(da){oa.top-=t.height(); -oa.left+=8}else oa.top+=a(k).height();a(t).offset(oa);if(O.hasClass("down")){O.removeClass("down");t.hide();t.css({top:0,left:0})}else{O.addClass("down");t.show();S=true;return false}}).hover(function(){S=true}).mouseout(function(){S=false});L.multiclick&&t.mousedown(function(){S=true})};i.addDropDown("#font_family_dropdown",function(){a(this).text();a("#font_family").val(a(this).text()).change()});i.addDropDown("#opacity_dropdown",function(){if(!a(this).find("div").length){var k=parseInt(a(this).text().split("%")[0]); -kb(false,k)}},false);a("#opac_slider").slider({start:function(){a("#opacity_dropdown li:not(.special)").hide()},stop:function(){a("#opacity_dropdown li").show();a(window).mouseup()},slide:function(k,t){kb(t)}});i.addDropDown("#blur_dropdown",a.noop);var xb=false;a("#blur_slider").slider({max:10,step:0.1,stop:function(k,t){xb=false;Cb(t);a("#blur_dropdown li").show();a(window).mouseup()},start:function(){xb=true},slide:function(k,t){Cb(t,null,xb)}});i.addDropDown("#zoom_dropdown",function(){var k= -a(this),t=k.attr("data-val");t?Ga(window,t):Ia({value:parseInt(k.text())})},true);lb("#stroke_linecap","#linecap_opts",function(){D(this,true)},{dropUp:true});lb("#stroke_linejoin","#linejoin_opts",function(){D(this,true)},{dropUp:true});a("div","#position_opts").each(function(){this.addEventListener("mouseup",function(){var k=this.id.replace("tool_pos","").charAt(0);h.alignSelectedElements(k,"page")})});(function(){var k,t=function(){a(k).blur()};a("#svg_editor").find("button, select, input:not(#text)").focus(function(){k= -this;ea="toolbars";ha.mousedown(t)}).blur(function(){ea="canvas";ha.unbind("mousedown",t);h.getMode()=="textedit"&&a("#text").focus()})})();var Jb=function(){if(db("#tool_select")){h.setMode("select");a("#styleoverrides").text("#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}")}},pb=function(){db("#tool_fhpath")&&h.setMode("fhpath")},Kb=function(){db("#tool_line")&&h.setMode("line")},Rb=function(){db("#tool_rect")&&h.setMode("rect")},Lb=function(){db("#tool_ellipse")&& -h.setMode("ellipse")},Sb=function(){db("#tool_image")&&h.setMode("image")},pa=function(){db("#tool_zoom")&&h.setMode("zoom")},V=function(){if(db("#tool_zoom")){c();la()}},ua=function(){db("#tool_text")&&h.setMode("text")},ya=function(){db("#tool_path")&&h.setMode("path")},aa=function(){if(T!=null||wa)h.deleteSelectedElements()},Sa=function(){if(T!=null||wa)h.cutSelectedElements()},Eb=function(){if(T!=null||wa)h.copySelectedElements()},Ab=function(){var k=h.getZoom(),t=(ha[0].scrollLeft+ha.width()/ -2)/k-h.contentW;k=(ha[0].scrollTop+ha.height()/2)/k-h.contentH;h.pasteElements("point",t,k)},wb=function(){T!=null&&h.moveToTopSelectedElement()},tb=function(){T!=null&&h.moveToBottomSelectedElement()},Fb=function(){T!=null&&h.moveUpDownSelected("Up")},Qb=function(){T!=null&&h.moveUpDownSelected("Down")},nb=function(){T!=null&&h.convertToPath()},Mb=function(){T!=null&&qa.reorient()},Ta=function(){if(T!=null||wa)a.prompt(g.notification.enterNewLinkURL,"http://",function(k){k&&h.makeHyperlink(k)})}, -eb=function(k,t){if(T!=null||wa){if(f.gridSnapping){var G=h.getZoom()*f.snappingStep;k*=G;t*=G}h.moveSelectedElements(k,t)}},Ib=function(){var k=!a("#tool_node_link").hasClass("push_button_pressed");k?a("#tool_node_link").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_node_link").removeClass("push_button_pressed").addClass("tool_button");qa.linkControlPoints(k)},Zb=function(){qa.getNodePoint()&&qa.clonePathNode()},Yb=function(){qa.getNodePoint()&&qa.deletePathNode()},fb=function(){var k= -a("#tool_add_subpath"),t=!k.hasClass("push_button_pressed");t?k.addClass("push_button_pressed").removeClass("tool_button"):k.removeClass("push_button_pressed").addClass("tool_button");qa.addSubPath(t)},La=function(){qa.opencloseSubPath()},fc=function(){h.cycleElement(1)},bc=function(){h.cycleElement(0)},Tb=function(k,t){if(!(T==null||wa)){k||(t*=-1);var G=a("#angle").val()*1+t;h.setRotationAngle(G);Ua()}},gc=function(){var k=f.dimensions;a.confirm(g.notification.QwantToClear,function(t){if(t){la(); -h.clear();h.setResolution(k[0],k[1]);Ob(true);c();rb();Ua();ja.fill.prep();ja.stroke.prep();h.runExtensions("onNewDocument")}})},kc=function(){h.setBold(!h.getBold());Ua();return false},Vb=function(){h.setItalic(!h.getItalic());Ua();return false},$b=function(){if(!p.pngsave){var k=g.notification.loadingImage;U=window.open("data:text/html;charset=utf-8,<title>"+k+"

        "+k+"

        ")}window.canvg?h.rasterExport():a.getScript("canvg/rgbcolor.js",function(){a.getScript("canvg/canvg.js",function(){h.rasterExport()})})}, -mc=function(){h.open()},Ub=function(){},ib=function(k){var t=k.prev();t.css("background","#09f");setTimeout(function(){t.css("background","")},200)},hc=function(){if(ga.getUndoStackSize()>0){window.event.type==="keydown"&&ib(a("#edit_menu"));ga.undo();rb()}},cc=function(){if(ga.getRedoStackSize()>0){window.event.type==="keydown"&&ib(a("#edit_menu"));ga.redo();rb()}},Nb=function(){if(wa)h.groupSelectedElements();else T&&h.ungroupSelectedElement()},jb=function(){window.event.type==="keydown"&&ib(a("#edit_menu")); -h.cloneSelectedElements(20,20)},ec=function(){var k=this.id.replace("tool_align","").charAt(0);h.alignSelectedElements(k,a("#align_relative_to").val())},b=function(){var k=document.querySelector("#tool_stroke rect"),t=document.querySelector("#tool_fill rect"),G=t.getAttribute("fill"),L=k.getAttribute("fill");k=parseFloat(k.getAttribute("stroke-opacity"));if(isNaN(k))k=100;t=parseFloat(t.getAttribute("fill-opacity"));if(isNaN(t))t=100;L=mb(L,k,"stroke");G=mb(G,t,"fill");ja.fill.setPaint(L,true);ja.stroke.setPaint(G, -true)},c=function(k){var t=h.getResolution();k=k?t.zoom*k:1;a("#zoom").val(k*100);h.setZoom(k);m();Ob(true)},d=function(){!a("#tool_wireframe").hasClass("push_button_pressed")?a("#tool_wireframe").addClass("push_button_pressed"):a("#tool_wireframe").removeClass("push_button_pressed");ha.toggleClass("wireframe");if(!jc){var k=a("#wireframe_rules");k.length?k.empty():a('').appendTo("head");m()}},n=function(){if(a("#tool_rulers").hasClass("push_button_pressed")){a("#tool_rulers").removeClass("push_button_pressed"); -a("#show_rulers").attr("checked",false);f.showRulers=false}else{a("#tool_rulers").addClass("push_button_pressed");a("#show_rulers").attr("checked",true);f.showRulers=true}a("#rulers").toggle(!!f.showRulers)},m=function(){if(!jc){var k="#workarea.wireframe #svgcontent * { stroke-width: "+1/h.getZoom()+"px; }";a("#wireframe_rules").text(ha.hasClass("wireframe")?k:"")}},A=function(k,t){if(!Da){Da=true;a("#save_output_btns").toggle(!!t);a("#tool_source_back").toggle(!t);var G=ra=h.getSvgString();a("#svg_source_textarea").val(G); -a("#svg_source_editor").fadeIn();s();a("#svg_source_textarea").focus()}},o=function(){if(!Ma){Ma=true;a("#image_save_opts input").val([e.img_save]);var k=h.getResolution();if(f.baseUnit!=="px"){k.w=svgedit.units.convertUnit(k.w)+f.baseUnit;k.h=svgedit.units.convertUnit(k.h)+f.baseUnit}a(".canvas_width").val(k.w);a(".canvas_height").val(k.h);a("#canvas_title").val(h.getDocumentTitle());a("#svg_docprops").show()}},l=function(){if(!Fa){Fa=true;var k=a("#bg_blocks div"),t=a.pref("bkgd_color"),G=a.pref("bkgd_url"); -k.each(function(){var L=a(this),O=L.css("background-color")==t;L.toggleClass("cur_background",O);O&&a("#canvas_bg_url").removeClass("cur_background")});t||k.eq(0).addClass("cur_background");G&&a("#canvas_bg_url").val(G);a("grid_snapping_step").attr("value",f.snappingStep);f.gridSnapping==true?a("#grid_snapping_on").attr("checked","checked"):a("#grid_snapping_on").removeAttr("checked");a("#svg_prefs").show()}},s=function(){var k=a("#svg_source_container").height()-50;a("#svg_source_textarea").css("height", -k)},B=function(){if(Da){var k=function(){h.clearSelection();fa();c();rb();w();ja.fill.prep();ja.stroke.prep()};h.setSvgString(a("#svg_source_textarea").val())?k():a.confirm(g.notification.QerrorsRevertToSource,function(t){if(!t)return false;k()});la()}},w=function(k){k=k||h.getDocumentTitle();k=Qa+(k?": "+k:"");a("title:first").text(k)},v=function(){var k=a("#canvas_width"),t=k.val(),G=a("#canvas_height"),L=G.val();if(t!="fit"&&!svgedit.units.isValidUnit("width",t)){a.alert(g.notification.invalidAttrValGiven); -k.parent().addClass("error");return false}k.parent().removeClass("error");if(L!="fit"&&!svgedit.units.isValidUnit("height",L)){a.alert(g.notification.invalidAttrValGiven);G.parent().addClass("error");return false}G.parent().removeClass("error");if(!h.setResolution(t,L)){a.alert(g.notification.noContentToFitTo);return false}e.img_save=a("#image_save_opts :checked").val();a.pref("img_save",e.img_save);Ob();R()},C=function(){var k=a("#bg_blocks div.cur_background").css("background-color")||"#FFF";q(k, -a("#canvas_bg_url").val());k=a("#lang_select").val();k!=e.lang&&i.putLocale(k);P(a("#iconsize").val());f.gridSnapping=a("#grid_snapping_on")[0].checked;f.snappingStep=a("#grid_snapping_step").val();f.showRulers=a("#show_rulers")[0].checked;a("#rulers").toggle(f.showRulers);f.showRulers&&ma();f.baseUnit=a("#base_unit").val();h.setConfig(f);Ob();W()},F=i.setIcon=function(k,t){var G=typeof t==="string"?a.getSvgIcon(t,true):t.clone();G?a(k).empty().append(G):console.log("NOTE: Icon image missing: "+t)}, -J;J=function(){var k=/^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/,t=document.getElementsByTagName("script")[0],G;for(G in t.style)if(k.test(G))return G.match(k)[0];if("WebkitOpacity"in t.style)return"Webkit";if("KhtmlOpacity"in t.style)return"Khtml";return""}();var K=function(k,t){J.toLowerCase();var G=["top","left","bottom","right"];k.each(function(){for(var L=a(this),O=L.outerWidth()*(t-1),S=L.outerHeight()*(t-1),da=0;da<4;da++){var oa=G[da],xa=L.data("orig_margin-"+oa);if(xa==null){xa=parseInt(L.css("margin-"+ -oa));L.data("orig_margin-"+oa,xa)}xa=xa*t;if(oa==="right")xa+=O;else if(oa==="bottom")xa+=S;L.css("margin-"+oa,xa)}})},P=i.setIconSize=function(k,t){if(!(k==e.size&&!t)){console.log("size",k);var G=a("#tools_top .toolset, #editor_panel > *, #history_panel > *,\t\t\t\t#main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\t\t\t\t#g_panel > *, #tool_font_size > *, .tools_flyout"),L=1;L=typeof k=="number"?k:{s:0.75,m:1,l:1.25,xl:1.5}[k];i.tool_scale=Z=L;zb();var O=G.parents(":hidden"); -O.css("visibility","hidden").show();K(G,L);O.css("visibility","visible").hide();a.pref("iconsize",k);a("#iconsize").val(k);O={"#tools_top":{left:50,height:72},"#tools_left":{width:31,top:74},"div#workarea":{left:38,top:74}};G=a("#tool_size_rules");if(G.length)G.empty();else G=a('').appendTo("head");if(k!="m"){var S="";a.each(O,function(da,oa){da="#svg_editor "+da.replace(/,/g,", #svg_editor");S+=da+"{";a.each(oa,function(xa,Ba){if(typeof Ba==="number")var sa=Ba* -L+"px";else if(Ba[k]||Ba.all)sa=Ba[k]||Ba.all;S+=xa+":"+sa+";"});S+="}"});O="-"+J.toLowerCase()+"-";S+="#tools_top .toolset, #editor_panel > *, #history_panel > *,\t\t\t\t#main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\t\t\t\t#g_panel > *, #tool_font_size > *, .tools_flyout{"+O+"transform: scale("+L+");} #svg_editor div.toolset .toolset {"+O+"transform: scale(1); margin: 1px !important;} #svg_editor .ui-slider {"+O+"transform: scale("+1/L+");}";G.text(S)}zb()}},ca=function(){a("#dialog_box").hide(); -if(!Da&&!Ma&&!Fa)Oa&&h.leaveContext();else{if(Da)ra!==a("#svg_source_textarea").val()?a.confirm(g.notification.QignoreSourceChanges,function(k){k&&fa()}):fa();else if(Ma)R();else Fa&&W();na()}},fa=function(){a("#svg_source_editor").hide();Da=false;a("#svg_source_textarea").blur()},R=function(){a("#svg_docprops").hide();a("#canvas_width,#canvas_height").removeAttr("disabled");a("#resolution")[0].selectedIndex=0;a("#image_save_opts input").val([e.img_save]);Ma=false},W=function(){a("#svg_prefs").hide(); -Fa=false},Y={width:a(window).width(),height:a(window).height()},na=a.noop,Xa;svgedit.browser.isIE()&&function(){na=function(){if(ha[0].scrollLeft===0&&ha[0].scrollTop===0){ha[0].scrollLeft=Xa.left;ha[0].scrollTop=Xa.top}};Xa={left:ha[0].scrollLeft,top:ha[0].scrollTop};a(window).resize(na);svgEditor.ready(function(){setTimeout(function(){na()},500)});ha.scroll(function(){Xa={left:ha[0].scrollLeft,top:ha[0].scrollTop}})}();a(window).resize(function(){Da&&s();a.each(Y,function(k,t){var G=a(window)[k](); -ha[0]["scroll"+(k==="width"?"Left":"Top")]-=(G-t)/2;Y[k]=G})});(function(){ha.scroll(function(){if(a("#ruler_x").length!=0)a("#ruler_x")[0].scrollLeft=ha[0].scrollLeft;if(a("#ruler_y").length!=0)a("#ruler_y")[0].scrollTop=ha[0].scrollTop})})();a("#url_notice").click(function(){a.alert(this.title)});a("#change_image_url").click(M);(function(){var k=["clear","open","save","source","delete","delete_multi","paste","clone","clone_multi","move_top","move_bottom"],t="";a.each(k,function(G,L){t+="#tool_"+ -L+(G==k.length-1?",":"")});a(t).mousedown(function(){a(this).addClass("tool_button_current")}).bind("mousedown mouseout",function(){a(this).removeClass("tool_button_current")});a("#tool_undo, #tool_redo").mousedown(function(){a(this).hasClass("disabled")||a(this).addClass("tool_button_current")}).bind("mousedown mouseout",function(){a(this).removeClass("tool_button_current")})})();if(ia&&!window.opera){ia=["tool_clear","tool_save","tool_source","tool_undo","tool_redo","tool_clone"];for(Va=ia.length;Va--;){var qb= -document.getElementById(ia[Va]);if(qb!=null){var Hb=qb.title,yb=Hb.indexOf("Ctrl+");qb.title=[Hb.substr(0,yb),"Cmd+",Hb.substr(yb+5)].join("")}}}var Gb=function(k){var t=k.attr("id")=="stroke_color"?"stroke":"fill",G=ja[t].paint,L=t=="stroke"?"Pick a Stroke Paint and Opacity":"Pick a Fill Paint and Opacity";k=k.position();a("#color_picker").draggable({cancel:".jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker",containment:"window"}).css(f.colorPickerCSS||{left:k.left,bottom:50-k.top}).jGraduate({paint:G, -window:{pickerTitle:L},images:{clientPath:f.jGraduatePath},newstop:"inverse"},function(O){G=new a.jGraduate.Paint(O);ja[t].setPaint(G);h.setPaint(t,G);a("#color_picker").hide()},function(){a("#color_picker").hide()})},ac=function(){var k=h.getColor("fill")=="none",t=h.getColor("stroke")=="none",G=["#tool_fhpath","#tool_line"],L=["#tools_rect .tool_button","#tools_ellipse .tool_button","#tool_text","#tool_path"];if(t)for(var O in G){var S=G[O];a(S).hasClass("tool_button_current")&&Jb();a(S).addClass("disabled")}else for(O in G){S= -G[O];a(S).removeClass("disabled")}if(t&&k)for(O in L){S=L[O];a(S).hasClass("tool_button_current")&&Jb();a(S).addClass("disabled")}else for(O in L){S=L[O];a(S).removeClass("disabled")}h.runExtensions("toolButtonStateUpdate",{nofill:k,nostroke:t});a(".tools_flyout").each(function(){var da=a("#"+this.id+"_show"),oa=false;a(this).children().each(function(){a(this).hasClass("disabled")||(oa=true)});da.toggleClass("disabled",!oa)});ab()};ia=function(k,t){var G=f[t==="fill"?"initFill":"initStroke"],L=(new DOMParser).parseFromString('\t\t\t\t\t',"text/xml").documentElement;L=a(k)[0].appendChild(document.importNode(L,true));L.setAttribute("width",24.5);this.rect=L.firstChild;this.defs=L.getElementsByTagName("defs")[0];this.grad=this.defs.firstChild;this.paint=new a.jGraduate.Paint({solidColor:G.color});this.type=t;this.setPaint=function(O,S){this.paint=O;var da="none",oa=O.type,xa=O.alpha/100;switch(oa){case "solidColor":da="#"+O[oa];break;case "linearGradient":case "radialGradient":this.defs.removeChild(this.grad); -this.grad=this.defs.appendChild(O[oa]);da="url(#"+(this.grad.id="gradbox_"+this.type)+")"}this.rect.setAttribute("fill",da);this.rect.setAttribute("opacity",xa);if(S){h.setColor(this.type,da,true);h.setPaintOpacity(this.type,xa,true)}};this.update=function(O){if(T){var S=this.type;switch(T.tagName){case "use":case "image":case "foreignObject":return;case "g":case "a":for(var da=null,oa=T.getElementsByTagName("*"),xa=0,Ba=oa.length;xa300)k=300-G;else if(G+k<2)k=2-G;if(k!=0){dc-=k;G=a("#layerpanel");ha.css("right",parseInt(ha.css("right"))+k);t.css("width",parseInt(t.css("width"))+k);G.css("width",parseInt(G.css("width"))+k);t=a("#ruler_x");t.css("right",parseInt(t.css("right"))+k)}}};a("#sidepanel_handle").mousedown(function(k){dc=k.pageX;a(window).mousemove(qc); -oc=false;setTimeout(function(){oc=true},20)}).mouseup(function(){lc||rc();dc=-1;lc=false});a(window).mouseup(function(){dc=-1;lc=false;a("#svg_editor").unbind("mousemove",qc)});var rc=function(k){var t=parseInt(a("#sidepanels").css("width"));k=(t>2||k?2:150)-t;t=a("#sidepanels");var G=a("#layerpanel"),L=a("#ruler_x");ha.css("right",parseInt(ha.css("right"))+k);t.css("width",parseInt(t.css("width"))+k);G.css("width",parseInt(G.css("width"))+k);L.css("right",parseInt(L.css("right"))+k)},sc=function(k){for(var t= -Array(h.getCurrentDrawing().getNumLayers()),G=0;G'+S+"":''+S+"";k.append(da);t.append('")}if(O!==undefined){O.clone();a("td.layervis",k).append(O.clone());a.resizeSvgIcons({"td.layervis .svg_icon":14})}a("#layerlist td.layername").mouseup(function(oa){a("#layerlist tr.layer").removeClass("layersel"); -a(this.parentNode).addClass("layersel");h.setCurrentLayer(this.textContent);oa.preventDefault()}).mouseover(function(){a(this).css({"font-style":"italic",color:"blue"});sc(this.textContent)}).mouseout(function(){a(this).css({"font-style":"normal",color:"black"});sc()});a("#layerlist td.layervis").click(function(){var oa=a(this.parentNode).prevAll().length;oa=a("#layerlist tr.layer:eq("+oa+") td.layername").text();var xa=a(this).hasClass("layerinvis");h.setLayerVisibility(oa,xa);xa?a(this).removeClass("layerinvis"): -a(this).addClass("layerinvis")});for(t=5-a("#layerlist tr.layer").size();t-- >0;)k.append('_')};rb();a(window).bind("load resize",function(){ha.css("line-height",ha.height()+"px")});a("#resolution").change(function(){var k=a("#canvas_width,#canvas_height");if(this.selectedIndex)if(this.value=="content")k.val("fit").attr("disabled","disabled");else{var t=this.value.split("x");a("#canvas_width").val(t[0]);a("#canvas_height").val(t[1]);k.removeAttr("disabled")}else a("#canvas_width").val()== -"fit"&&k.removeAttr("disabled").val(100)});a("input,select").attr("autocomplete","off");var nc=function(){var k=[{sel:"#tool_select",fn:Jb,evt:"click",key:["V",true]},{sel:"#tool_fhpath",fn:pb,evt:"click",key:["Q",true]},{sel:"#tool_line",fn:Kb,evt:"click",key:["L",true]},{sel:"#tool_rect",fn:Rb,evt:"click",key:["R",true],icon:"rect"},{sel:"#tool_ellipse",fn:Lb,evt:"mouseup",key:["C",true],icon:"ellipse"},{sel:"#tool_path",fn:ya,evt:"click",key:["P",true]},{sel:"#tool_text",fn:ua,evt:"click",key:["T", -true]},{sel:"#tool_image",fn:Sb,evt:"mouseup"},{sel:"#tool_zoom",fn:pa,evt:"mouseup",key:["Z",true]},{sel:"#tool_clear",fn:gc,evt:"mouseup",key:[X+"N",true]},{sel:"#tool_save",fn:function(){Da?B():h.save({images:e.img_save,round_digits:6})},evt:"mouseup",key:[X+"S",true]},{sel:"#tool_export",fn:$b,evt:"mouseup"},{sel:"#tool_open",fn:mc,evt:"mouseup"},{sel:"#tool_import",fn:Ub,evt:"mouseup"},{sel:"#tool_source",fn:A,evt:"click",key:[X+"U",true]},{sel:"#tool_wireframe",fn:d,evt:"click"},{sel:"#tool_rulers", -fn:n,evt:"click"},{sel:"#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel",fn:ca,evt:"click",key:["esc",false,false],hidekey:true},{sel:"#tool_source_save",fn:B,evt:"click"},{sel:"#tool_docprops_save",fn:v,evt:"click"},{sel:"#tool_docprops",fn:o,evt:"mouseup"},{sel:"#tool_prefs_save",fn:C,evt:"click"},{sel:"#tool_prefs_option",fn:function(){l();return false},evt:"mouseup"},{sel:"#tool_delete,#tool_delete_multi",fn:aa,evt:"click",key:["del/backspace",true]},{sel:"#tool_reorient", -fn:Mb,evt:"click"},{sel:"#tool_node_link",fn:Ib,evt:"click"},{sel:"#tool_node_clone",fn:Zb,evt:"click"},{sel:"#tool_node_delete",fn:Yb,evt:"click"},{sel:"#tool_openclose_path",fn:La,evt:"click"},{sel:"#tool_add_subpath",fn:fb,evt:"click"},{sel:"#tool_move_top",fn:wb,evt:"click",key:X+"shift+up"},{sel:"#tool_move_bottom",fn:tb,evt:"click",key:X+"shift+down"},{sel:"#tool_move_up",fn:Fb,evt:"click",key:[X+"up",true]},{sel:"#tool_move_down",fn:Qb,evt:"click",key:[X+"down",true]},{sel:"#tool_topath",fn:nb, -evt:"click"},{sel:"#tool_make_link,#tool_make_link_multi",fn:Ta,evt:"click"},{sel:"#tool_undo",fn:hc,evt:"click",key:[X+"Z",true]},{sel:"#tool_redo",fn:cc,evt:"click",key:["Y",true]},{sel:"#tool_clone,#tool_clone_multi",fn:jb,evt:"click",key:[X+"D",true]},{sel:"#tool_group",fn:Nb,evt:"click",key:[X+"G",true]},{sel:"#tool_ungroup",fn:Nb,evt:"click",key:X+"shift+G"},{sel:"#tool_unlink_use",fn:Nb,evt:"click"},{sel:"[id^=tool_align]",fn:ec,evt:"click"},{sel:"#tool_switch",fn:b,evt:"click",key:["X",true]}, -{sel:"#tool_bold",fn:kc,evt:"mousedown",key:[X+"B",true]},{sel:"#tool_italic",fn:Vb,evt:"mousedown",key:[X+"I",true]},{sel:"#copy_save_done",fn:ca,evt:"click"},{key:"ctrl+left",fn:function(){Tb(0,1)}},{key:"ctrl+right",fn:function(){Tb(1,1)}},{key:"ctrl+shift+left",fn:function(){Tb(0,5)}},{key:"ctrl+shift+right",fn:function(){Tb(1,5)}},{key:"shift+O",fn:bc},{key:"shift+P",fn:fc},{key:[X+"+",true],fn:function(){c(2)}},{key:[X+"-",true],fn:function(){c(0.5)}},{key:["up",true],fn:function(){eb(0,-1)}}, -{key:["down",true],fn:function(){eb(0,1)}},{key:["left",true],fn:function(){eb(-1,0)}},{key:["right",true],fn:function(){eb(1,0)}},{key:"shift+up",fn:function(){eb(0,-10)}},{key:"shift+down",fn:function(){eb(0,10)}},{key:"shift+left",fn:function(){eb(-10,0)}},{key:"shift+right",fn:function(){eb(10,0)}},{key:["alt+up",true],fn:function(){h.cloneSelectedElements(0,-1)}},{key:["alt+down",true],fn:function(){h.cloneSelectedElements(0,1)}},{key:["alt+left",true],fn:function(){h.cloneSelectedElements(-1, -0)}},{key:["alt+right",true],fn:function(){h.cloneSelectedElements(1,0)}},{key:["alt+shift+up",true],fn:function(){h.cloneSelectedElements(0,-10)}},{key:["alt+shift+down",true],fn:function(){h.cloneSelectedElements(0,10)}},{key:["alt+shift+left",true],fn:function(){h.cloneSelectedElements(-10,0)}},{key:["alt+shift+right",true],fn:function(){h.cloneSelectedElements(10,0)}},{key:X+"A",fn:function(){h.selectAllInCurrentLayer()}},{key:X+"z",fn:hc},{key:X+"shift+z",fn:cc},{key:X+"y",fn:cc},{key:X+"x", -fn:Sa},{key:X+"c",fn:Eb},{key:X+"v",fn:Ab}],t={"4/Shift+4":"#tools_rect_show","5/Shift+5":"#tools_ellipse_show"};return{setAll:function(){var G={};a.each(k,function(L,O){if(O.sel){var S=a(O.sel);if(S.length==0)return true;if(O.evt){if(svgedit.browser.isTouch()&&O.evt==="click")O.evt="mousedown";S[O.evt](O.fn)}if(O.parent&&a(O.parent+"_show").length!=0){var da=a(O.parent);da.length||(da=Aa(O.parent.substr(1)));da.append(S);a.isArray(G[O.parent])||(G[O.parent]=[]);G[O.parent].push(O)}}if(O.key){var oa= -O.fn,xa=false;if(a.isArray(O.key)){da=O.key[0];if(O.key.length>1)xa=O.key[1]}else da=O.key;da+="";svgedit.browser.isMac&&da.indexOf("+")!=-1&&da.split("+")[0]=="ctrl"&&da.replace("ctrl","cmd");a.each(da.split("/"),function(sa,Ya){a(document).bind("keydown",Ya,function(Za){oa();xa&&Za.preventDefault();return false})});if(O.sel&&!O.hidekey&&S.attr("title")){var Ba=S.attr("title").split("[")[0]+" ("+da+")";t[da]=O.sel;S.parents("#main_menu").length||S.attr("title",Ba)}}});Ha(G);a(".attr_changer, #image_url").bind("keydown", -"return",function(L){a(this).change();L.preventDefault()});a(window).bind("keydown","tab",function(L){if(ea==="canvas"){L.preventDefault();fc()}}).bind("keydown","shift+tab",function(L){if(ea==="canvas"){L.preventDefault();bc()}});a("#tool_zoom").dblclick(V)},setTitles:function(){a.each(t,function(G,L){var O=a(L).parents("#main_menu").length;a(L).each(function(){var S=O?a(this).text().split(" [")[0]:this.title.split(" [")[0],da="";a.each(G.split("/"),function(oa,xa){var Ba=xa.split("+"),sa="";if(Ba.length> -1){sa=Ba[0]+"+";xa=Ba[1]}da+=(oa?"/":"")+sa+(g["key_"+xa]||xa)});if(O)this.lastChild.textContent=S+" ["+da+"]";else this.title=S+" ["+da+"]"})})},getButtonData:function(G){var L;a.each(k,function(O,S){if(S.sel===G)L=S});return L}}}();nc.setAll();i.ready(function(){var k=f.initTool,t=a("#tools_left, #svg_editor .tools_flyout"),G=t.find("#tool_"+k);k=t.find("#"+k);(G.length?G:k.length?k:a("#tool_select")).click().mouseup();f.wireframe&&a("#tool_wireframe").click();f.showlayers&&rc();a("#rulers").toggle(!!f.showRulers); -if(f.showRulers)a("#show_rulers")[0].checked=true;if(f.gridSnapping)a("#grid_snapping_on")[0].checked=true;f.baseUnit&&a("#base_unit").val(f.baseUnit);f.snappingStep&&a("#grid_snapping_step").val(f.snappingStep)});a("#rect_rx").SpinButton({min:0,max:1E3,step:1,callback:function(k){h.setRectRadius(k.value)}});a("#stroke_width").SpinButton({min:0,max:99,step:1,smallStep:0.1,callback:function(k){var t=k.value;if(t==0&&T&&["line","polyline"].indexOf(T.nodeName)>=0)t=k.value=1;h.setStrokeWidth(t)}});a("#angle").SpinButton({min:-180, -max:180,step:5,callback:function(k){h.setRotationAngle(k.value);a("#tool_reorient").toggleClass("disabled",k.value==0)}});a("#font_size").SpinButton({step:1,min:0.0010,stepfunc:function(k,t){var G=k.value-0,L=G+t,O=L>=G;if(t===0)return G;return G>=24?O?Math.round(G*1.1):Math.round(G/1.1):G<=1?O?G*2:G/2:L},callback:function(k){h.setFontSize(k.value)}});a("#group_opacity").SpinButton({step:5,min:0,max:100,callback:kb});a("#blur").SpinButton({step:0.1,min:0,max:10,callback:Cb});a("#zoom").SpinButton({min:0.0010, -max:1E4,step:50,stepfunc:function(k,t){var G=k.value-0;if(G===0)return 100;var L=G+t;if(t===0)return G;return G>=100?L:L>=G?G*2:G/2},callback:Ia}).val(h.getZoom()*100);a("#workarea").contextMenu({menu:"cmenu_canvas",inSpeed:0},function(k){switch(k){case "delete":aa();break;case "cut":Sa();break;case "copy":Eb();break;case "paste":h.pasteElements();break;case "paste_in_place":h.pasteElements("in_place");break;case "group":h.groupSelectedElements();break;case "ungroup":h.ungroupSelectedElement();break; -case "move_front":wb();break;case "move_up":T!=null&&h.moveUpDownSelected("Up");break;case "move_down":T!=null&&h.moveUpDownSelected("Down");break;case "move_back":tb();break;default:svgedit.contextmenu&&svgedit.contextmenu.hasCustomHandler(k)&&svgedit.contextmenu.getCustomHandler(k).call()}h.clipBoard.length&&Ra.enableContextMenuItems("#paste,#paste_in_place")});ia=function(k){switch(k){case "dupe":N();break;case "delete":ba();break;case "merge_down":if(a("#layerlist tr.layersel").index()!=h.getCurrentDrawing().getNumLayers()- -1){h.mergeLayer();Ua();rb()}break;case "merge_all":h.mergeAllLayers();Ua();rb()}};a("#layerlist").contextMenu({menu:"cmenu_layers",inSpeed:0},ia);a("#layer_moreopts").contextMenu({menu:"cmenu_layers",inSpeed:0,allowLeft:true},ia);a(".contextMenu li").mousedown(function(k){k.preventDefault()});a("#cmenu_canvas li").disableContextMenu();Ra.enableContextMenuItems("#delete,#cut,#copy");window.onbeforeunload=function(){if(ga.getUndoStackSize()===0)i.show_save_warning=false;if(!f.no_save_warning&&i.show_save_warning)return g.notification.unsavedChanges}; -i.openPrep=function(k){a("#main_menu").hide();ga.getUndoStackSize()===0?k(true):a.confirm(g.notification.QwantToOpen,k)};if(window.FileReader){ia=a('').change(function(){var k=this;i.openPrep(function(t){if(t){h.clear();if(k.files.length==1){t=new FileReader;t.onloadend=function(G){H(G.target.result);Ob()};t.readAsText(k.files[0])}}})});a("#tool_open").show().prepend(ia);ia=a('').change(function(){a("#main_menu").hide();if(this.files.length==1){var k=new FileReader; -k.onloadend=function(t){h.importSvgString(t.target.result,true);Ob()};k.readAsText(this.files[0])}});a("#tool_import").show().prepend(ia)}var Ob=i.updateCanvas=function(k,t){var G=ha.width(),L=ha.height(),O=G,S=L,da=h.getZoom(),oa=a("#svgcanvas"),xa={x:ha[0].scrollLeft+O/2,y:ha[0].scrollTop+S/2},Ba=f.canvas_expansion;G=Math.max(O,h.contentW*da*Ba);L=Math.max(S,h.contentH*da*Ba);G==O&&L==S?ha.css("overflow","hidden"):ha.css("overflow","scroll");Ba=oa.height()/2;var sa=oa.width()/2;oa.width(G).height(L); -var Ya=L/2,Za=G/2,Q=h.updateCanvas(G,L),ob=Za/sa;G=G/2-O/2;L=L/2-S/2;if(t){t.x+=Q.x;t.y+=Q.y}else t={x:Za+(xa.x-sa)*ob,y:Ya+(xa.y-Ba)*ob};if(k)if(h.contentW>ha.width()){ha[0].scrollLeft=Q.x-10;ha[0].scrollTop=Q.y-10}else{ha[0].scrollLeft=G;ha[0].scrollTop=L}else{ha[0].scrollLeft=t.x-O/2;ha[0].scrollTop=t.y-S/2}if(f.showRulers){ma(oa,da);ha.scroll()}},ic=[];for(Va=0.1;Va<1E5;Va*=10){ic.push(1*Va);ic.push(2*Va);ic.push(5*Va)}Ob(true);try{var tc=function(k){if(window.JSON&&JSON.stringify)return JSON.stringify(k); -var t=arguments.callee;if(typeof k=="boolean"||typeof k=="number")return k+"";else if(typeof k=="string")return'"'+k.replace(/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,function(O){return"\\u"+("0000"+O.charCodeAt(0).toString(16)).slice(-4)})+'"';else if(k.length){for(var G=0;G");var h=H.shortcut||"";$("#cmenu_canvas").append("
      • "+H.label+""+h+"
      • ")}});svgedit.contextmenu.resetCustomMenus=function(){a.contextMenuExtensions= -{}};svgedit.contextmenu.add=function(H){if(H&&H.id&&H.label&&H.action&&typeof H.action=="function")if(H.id in a.contextMenuExtensions)console.error('Cannot add extension "'+H.id+'", an extension by that name already exists"');else{console.log("Registed contextmenu item: {id:"+H.id+", label:"+H.label+"}");a.contextMenuExtensions[H.id]=H}else console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function")};svgedit.contextmenu.hasCustomHandler= -function(H){return a.contextMenuExtensions[H]&&true};svgedit.contextmenu.getCustomHandler=function(H){return a.contextMenuExtensions[H].action}})();var svgEditor=function(a,H){function h(u,E,e){var f=a("#svg_editor").parent(),g;for(g in E){var p=E[g];p||console.log(g);if(e)g="#"+g;if(f.find(g).length){var z=f.find(g)[0];switch(u){case "content":for(var D=0;D elements. Each element should contain the markup of an SVG -icon. The element has an ID that should -correspond with the ID of the HTML element used on the page that should contain -or optionally be replaced by the icon. Additionally, one empty element should be -added at the end with id "svg_eof". - -2. Optionally create fallback raster images for each SVG icon. - -3. Include the jQuery and the SVG Icon Loader scripts on your page. - -4. Run $.svgIcons() when the document is ready: - -$.svgIcons( file [string], options [object literal]); - -File is the location of a local SVG or SVGz file. - -All options are optional and can include: - -- 'w (number)': The icon widths - -- 'h (number)': The icon heights - -- 'fallback (object literal)': List of raster images with each - key being the SVG icon ID to replace, and the value the image file name. - -- 'fallback_path (string)': The path to use for all images - listed under "fallback" - -- 'replace (boolean)': If set to true, HTML elements will be replaced by, - rather than include the SVG icon. - -- 'placement (object literal)': List with selectors for keys and SVG icon ids - as values. This provides a custom method of adding icons. - -- 'resize (object literal)': List with selectors for keys and numbers - as values. This allows an easy way to resize specific icons. - -- 'callback (function)': A function to call when all icons have been loaded. - Includes an object literal as its argument with as keys all icon IDs and the - icon as a jQuery object as its value. - -- 'id_match (boolean)': Automatically attempt to match SVG icon ids with - corresponding HTML id (default: true) - -- 'no_img (boolean)': Prevent attempting to convert the icon into an - element (may be faster, help for browser consistency) - -- 'svgz (boolean)': Indicate that the file is an SVGZ file, and thus not to - parse as XML. SVGZ files add compression benefits, but getting data from - them fails in Firefox 2 and older. - -5. To access an icon at a later point without using the callback, use this: - $.getSvgIcon(id (string)); - -This will return the icon (as jQuery object) with a given ID. - -6. To resize icons at a later point without using the callback, use this: - $.resizeSvgIcons(resizeOptions) (use the same way as the "resize" parameter) - - -Example usage #1: - -$(function() { - $.svgIcons('my_icon_set.svg'); // The SVG file that contains all icons - // No options have been set, so all icons will automatically be inserted - // into HTML elements that match the same IDs. -}); - -Example usage #2: - -$(function() { - $.svgIcons('my_icon_set.svg', { // The SVG file that contains all icons - callback: function(icons) { // Custom callback function that sets click - // events for each icon - $.each(icons, function(id, icon) { - icon.click(function() { - alert('You clicked on the icon with id ' + id); - }); - }); - } - }); //The SVG file that contains all icons -}); - -Example usage #3: - -$(function() { - $.svgIcons('my_icon_set.svgz', { // The SVGZ file that contains all icons - w: 32, // All icons will be 32px wide - h: 32, // All icons will be 32px high - fallback_path: 'icons/', // All fallback files can be found here - fallback: { - '#open_icon': 'open.png', // The "open.png" will be appended to the - // HTML element with ID "open_icon" - '#close_icon': 'close.png', - '#save_icon': 'save.png' - }, - placement: {'.open_icon','open'}, // The "open" icon will be added - // to all elements with class "open_icon" - resize: function() { - '#save_icon .svg_icon': 64 // The "save" icon will be resized to 64 x 64px - }, - - callback: function(icons) { // Sets background color for "close" icon - icons['close'].css('background','red'); - }, - - svgz: true // Indicates that an SVGZ file is being used - - }) -}); - -*/ - - -(function($) { - var svg_icons = {}, fixIDs; - - $.svgIcons = function(file, opts) { - var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - icon_w = opts.w?opts.w : 24, - icon_h = opts.h?opts.h : 24, - elems, svgdoc, testImg, - icons_made = false, data_loaded = false, load_attempts = 0, - ua = navigator.userAgent, isOpera = !!window.opera, isSafari = (ua.indexOf('Safari/') > -1 && ua.indexOf('Chrome/')==-1), - data_pre = 'data:image/svg+xml;charset=utf-8;base64,'; - - if(opts.svgz) { - var data_el = $('').appendTo('body').hide(); - try { - svgdoc = data_el[0].contentDocument; - data_el.load(getIcons); - getIcons(0, true); // Opera will not run "load" event if file is already cached - } catch(err1) { - useFallback(); - } - } else { - var parser = new DOMParser(); - $.ajax({ - url: file, - dataType: 'string', - success: function(data) { - if(!data) { - $(useFallback); - return; - } - svgdoc = parser.parseFromString(data, "text/xml"); - $(function() { - getIcons('ajax'); - }); - }, - error: function(err) { - // TODO: Fix Opera widget icon bug - if(window.opera) { - $(function() { - useFallback(); - }); - } else { - if(err.responseText) { - svgdoc = parser.parseFromString(err.responseText, "text/xml"); - - if(!svgdoc.childNodes.length) { - $(useFallback); - } - $(function() { - getIcons('ajax'); - }); - } else { - $(useFallback); - } - } - } - }); - } - - function getIcons(evt, no_wait) { - if(evt !== 'ajax') { - if(data_loaded) return; - // Webkit sometimes says svgdoc is undefined, other times - // it fails to load all nodes. Thus we must make sure the "eof" - // element is loaded. - svgdoc = data_el[0].contentDocument; // Needed again for Webkit - var isReady = (svgdoc && svgdoc.getElementById('svg_eof')); - if(!isReady && !(no_wait && isReady)) { - load_attempts++; - if(load_attempts < 50) { - setTimeout(getIcons, 20); - } else { - useFallback(); - data_loaded = true; - } - return; - } - data_loaded = true; - } - - elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent'); - - if(!opts.no_img) { - var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; - - testImg = $(new Image()).attr({ - src: testSrc, - width: 0, - height: 0 - }).appendTo('body') - .load(function () { - // Safari 4 crashes, Opera and Chrome don't - makeIcons(true); - }).error(function () { - makeIcons(); - }); - } else { - setTimeout(function() { - if(!icons_made) makeIcons(); - },500); - } - } - - var setIcon = function(target, icon, id, setID) { - if(isOpera) icon.css('visibility','hidden'); - if(opts.replace) { - if(setID) icon.attr('id',id); - var cl = target.attr('class'); - if(cl) icon.attr('class','svg_icon '+cl); - target.replaceWith(icon); - } else { - - target.append(icon); - } - if(isOpera) { - setTimeout(function() { - icon.removeAttr('style'); - },1); - } - } - - var addIcon = function(icon, id) { - if(opts.id_match === undefined || opts.id_match !== false) { - setIcon(holder, icon, id, true); - } - svg_icons[id] = icon; - } - - function makeIcons(toImage, fallback) { - if(icons_made) return; - if(opts.no_img) toImage = false; - var holder; - - if(toImage) { - var temp_holder = $(document.createElement('div')); - temp_holder.hide().appendTo('body'); - } - if(fallback) { - var path = opts.fallback_path?opts.fallback_path:''; - $.each(fallback, function(id, imgsrc) { - holder = $('#' + id); - var icon = $(new Image()) - .attr({ - 'class':'svg_icon', - src: path + imgsrc, - 'width': icon_w, - 'height': icon_h, - 'alt': 'icon' - }); - - addIcon(icon, id); - }); - } else { - var len = elems.length; - for(var i = 0; i < len; i++) { - var elem = elems[i]; - var id = elem.id; - if(id === 'svg_eof') break; - holder = $('#' + id); - var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; - var svgroot = document.createElementNS(svgns, "svg"); - svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' ')); - // Make flexible by converting width/height to viewBox - var w = svg.getAttribute('width'); - var h = svg.getAttribute('height'); - svg.removeAttribute('width'); - svg.removeAttribute('height'); - - var vb = svg.getAttribute('viewBox'); - if(!vb) { - svg.setAttribute('viewBox', [0,0,w,h].join(' ')); - } - - // Not using jQuery to be a bit faster - svgroot.setAttribute('xmlns', svgns); - svgroot.setAttribute('width', icon_w); - svgroot.setAttribute('height', icon_h); - svgroot.setAttribute("xmlns:xlink", xlinkns); - svgroot.setAttribute("class", 'svg_icon'); - - // Without cloning, Firefox will make another GET request. - // With cloning, causes issue in Opera/Win/Non-EN - if(!isOpera) svg = svg.cloneNode(true); - - svgroot.appendChild(svg); - - if(toImage) { - // Without cloning, Safari will crash - // With cloning, causes issue in Opera/Win/Non-EN - var svgcontent = isOpera?svgroot:svgroot.cloneNode(true); - temp_holder.empty().append(svgroot); - var str = data_pre + encode64(temp_holder.html()); - var icon = $(new Image()) - .attr({'class':'svg_icon', src:str}); - } else { - var icon = fixIDs($(svgroot), i); - } - addIcon(icon, id); - } - - } - - if(opts.placement) { - $.each(opts.placement, function(sel, id) { - if(!svg_icons[id]) return; - $(sel).each(function(i) { - var copy = svg_icons[id].clone(); - if(i > 0 && !toImage) copy = fixIDs(copy, i, true); - setIcon($(this), copy, id); - }) - }); - } - if(!fallback) { - if(toImage) temp_holder.remove(); - if(data_el) data_el.remove(); - if(testImg) testImg.remove(); - } - if(opts.resize) $.resizeSvgIcons(opts.resize); - icons_made = true; - - if(opts.callback) opts.callback(svg_icons); - } - - fixIDs = function(svg_el, svg_num, force) { - var defs = svg_el.find('defs'); - if(!defs.length) return svg_el; - - if(isOpera) { - var id_elems = defs.find('*').filter(function() { - return !!this.id; - }); - } else { - var id_elems = defs.find('[id]'); - } - - var all_elems = svg_el[0].getElementsByTagName('*'), len = all_elems.length; - - id_elems.each(function(i) { - var id = this.id; - var no_dupes = ($(svgdoc).find('#' + id).length <= 1); - if(isOpera) no_dupes = false; // Opera didn't clone svg_el, so not reliable - // if(!force && no_dupes) return; - var new_id = 'x' + id + svg_num + i; - this.id = new_id; - - var old_val = 'url(#' + id + ')'; - var new_val = 'url(#' + new_id + ')'; - - // Selector method, possibly faster but fails in Opera / jQuery 1.4.3 -// svg_el.find('[fill="url(#' + id + ')"]').each(function() { -// this.setAttribute('fill', 'url(#' + new_id + ')'); -// }).end().find('[stroke="url(#' + id + ')"]').each(function() { -// this.setAttribute('stroke', 'url(#' + new_id + ')'); -// }).end().find('use').each(function() { -// if(this.getAttribute('xlink:href') == '#' + id) { -// this.setAttributeNS(xlinkns,'href','#' + new_id); -// } -// }).end().find('[filter="url(#' + id + ')"]').each(function() { -// this.setAttribute('filter', 'url(#' + new_id + ')'); -// }); - - for(var i = 0; i < len; i++) { - var elem = all_elems[i]; - if(elem.getAttribute('fill') === old_val) { - elem.setAttribute('fill', new_val); - } - if(elem.getAttribute('stroke') === old_val) { - elem.setAttribute('stroke', new_val); - } - if(elem.getAttribute('filter') === old_val) { - elem.setAttribute('filter', new_val); - } - } - }); - return svg_el; - } - - function useFallback() { - if(file.indexOf('.svgz') != -1) { - var reg_file = file.replace('.svgz','.svg'); - if(window.console) { - console.log('.svgz failed, trying with .svg'); - } - $.svgIcons(reg_file, opts); - } else if(opts.fallback) { - makeIcons(false, opts.fallback); - } - } - - function encode64(input) { - // base64 strings are 4/3 larger than the original string - if(window.btoa) return window.btoa(input); - var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0, p = 0; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = _keyStr.charAt(enc1); - output[p++] = _keyStr.charAt(enc2); - output[p++] = _keyStr.charAt(enc3); - output[p++] = _keyStr.charAt(enc4); - } while (i < input.length); - - return output.join(''); - } - } - - $.getSvgIcon = function(id, uniqueClone) { - var icon = svg_icons[id]; - if(uniqueClone && icon) { - icon = fixIDs(icon, 0, true).clone(true); - } - return icon; - } - - $.resizeSvgIcons = function(obj) { - // FF2 and older don't detect .svg_icon, so we change it detect svg elems instead - var change_sel = !$('.svg_icon:first').length; - $.each(obj, function(sel, size) { - var arr = $.isArray(size); - var w = arr?size[0]:size, - h = arr?size[1]:size; - if(change_sel) { - sel = sel.replace(/\.svg_icon/g,'svg'); - } - $(sel).each(function() { - this.setAttribute('width', w); - this.setAttribute('height', h); - if(window.opera && window.widget) { - this.parentNode.style.width = w + 'px'; - this.parentNode.style.height = h + 'px'; - } - }); - }); - } - -})(jQuery); \ No newline at end of file diff --git a/build/opera/editor/svgtransformlist.js b/build/opera/editor/svgtransformlist.js deleted file mode 100644 index 5c291ca..0000000 --- a/build/opera/editor/svgtransformlist.js +++ /dev/null @@ -1,291 +0,0 @@ -/** - * SVGTransformList - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) browser.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.transformlist) { - svgedit.transformlist = {}; -} - -var svgroot = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - -// Helper function. -function transformToString(xform) { - var m = xform.matrix, - text = ""; - switch(xform.type) { - case 1: // MATRIX - text = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - break; - case 2: // TRANSLATE - text = "translate(" + m.e + "," + m.f + ")"; - break; - case 3: // SCALE - if (m.a == m.d) text = "scale(" + m.a + ")"; - else text = "scale(" + m.a + "," + m.d + ")"; - break; - case 4: // ROTATE - var cx = 0, cy = 0; - // this prevents divide by zero - if (xform.angle != 0) { - var K = 1 - m.a; - cy = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b ); - cx = ( m.e - m.b * cy ) / K; - } - text = "rotate(" + xform.angle + " " + cx + "," + cy + ")"; - break; - } - return text; -}; - - -/** - * Map of SVGTransformList objects. - */ -var listMap_ = {}; - - -// ************************************************************************************** -// SVGTransformList implementation for Webkit -// These methods do not currently raise any exceptions. -// These methods also do not check that transforms are being inserted. This is basically -// implementing as much of SVGTransformList that we need to get the job done. -// -// interface SVGEditTransformList { -// attribute unsigned long numberOfItems; -// void clear ( ) -// SVGTransform initialize ( in SVGTransform newItem ) -// SVGTransform getItem ( in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform insertItemBefore ( in SVGTransform newItem, in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform replaceItem ( in SVGTransform newItem, in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform removeItem ( in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform appendItem ( in SVGTransform newItem ) -// NOT IMPLEMENTED: SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix ); -// NOT IMPLEMENTED: SVGTransform consolidate ( ); -// } -// ************************************************************************************** -svgedit.transformlist.SVGTransformList = function(elem) { - this._elem = elem || null; - this._xforms = []; - // TODO: how do we capture the undo-ability in the changed transform list? - this._update = function() { - var tstr = ""; - var concatMatrix = svgroot.createSVGMatrix(); - for (var i = 0; i < this.numberOfItems; ++i) { - var xform = this._list.getItem(i); - tstr += transformToString(xform) + " "; - } - this._elem.setAttribute("transform", tstr); - }; - this._list = this; - this._init = function() { - // Transform attribute parser - var str = this._elem.getAttribute("transform"); - if(!str) return; - - // TODO: Add skew support in future - var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; - var arr = []; - var m = true; - while(m) { - m = str.match(re); - str = str.replace(re,''); - if(m && m[1]) { - var x = m[1]; - var bits = x.split(/\s*\(/); - var name = bits[0]; - var val_bits = bits[1].match(/\s*(.*?)\s*\)/); - val_bits[1] = val_bits[1].replace(/(\d)-/g, "$1 -"); - var val_arr = val_bits[1].split(/[, ]+/); - var letters = 'abcdef'.split(''); - var mtx = svgroot.createSVGMatrix(); - $.each(val_arr, function(i, item) { - val_arr[i] = parseFloat(item); - if(name == 'matrix') { - mtx[letters[i]] = val_arr[i]; - } - }); - var xform = svgroot.createSVGTransform(); - var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1); - var values = name=='matrix'?[mtx]:val_arr; - - if (name == 'scale' && values.length == 1) { - values.push(values[0]); - } else if (name == 'translate' && values.length == 1) { - values.push(0); - } else if (name == 'rotate' && values.length == 1) { - values.push(0); - values.push(0); - } - xform[fname].apply(xform, values); - this._list.appendItem(xform); - } - } - }; - this._removeFromOtherLists = function(item) { - if (item) { - // Check if this transform is already in a transformlist, and - // remove it if so. - var found = false; - for (var id in listMap_) { - var tl = listMap_[id]; - for (var i = 0, len = tl._xforms.length; i < len; ++i) { - if(tl._xforms[i] == item) { - found = true; - tl.removeItem(i); - break; - } - } - if (found) { - break; - } - } - } - }; - - this.numberOfItems = 0; - this.clear = function() { - this.numberOfItems = 0; - this._xforms = []; - }; - - this.initialize = function(newItem) { - this.numberOfItems = 1; - this._removeFromOtherLists(newItem); - this._xforms = [newItem]; - }; - - this.getItem = function(index) { - if (index < this.numberOfItems && index >= 0) { - return this._xforms[index]; - } - throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR - }; - - this.insertItemBefore = function(newItem, index) { - var retValue = null; - if (index >= 0) { - if (index < this.numberOfItems) { - this._removeFromOtherLists(newItem); - var newxforms = new Array(this.numberOfItems + 1); - // TODO: use array copying and slicing - for ( var i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - newxforms[i] = newItem; - for ( var j = i+1; i < this.numberOfItems; ++j, ++i) { - newxforms[j] = this._xforms[i]; - } - this.numberOfItems++; - this._xforms = newxforms; - retValue = newItem; - this._list._update(); - } - else { - retValue = this._list.appendItem(newItem); - } - } - return retValue; - }; - - this.replaceItem = function(newItem, index) { - var retValue = null; - if (index < this.numberOfItems && index >= 0) { - this._removeFromOtherLists(newItem); - this._xforms[index] = newItem; - retValue = newItem; - this._list._update(); - } - return retValue; - }; - - this.removeItem = function(index) { - if (index < this.numberOfItems && index >= 0) { - var retValue = this._xforms[index]; - var newxforms = new Array(this.numberOfItems - 1); - for (var i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - for (var j = i; j < this.numberOfItems-1; ++j, ++i) { - newxforms[j] = this._xforms[i+1]; - } - this.numberOfItems--; - this._xforms = newxforms; - this._list._update(); - return retValue; - } else { - throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR - } - }; - - this.appendItem = function(newItem) { - this._removeFromOtherLists(newItem); - this._xforms.push(newItem); - this.numberOfItems++; - this._list._update(); - return newItem; - }; -}; - - -svgedit.transformlist.resetListMap = function() { - listMap_ = {}; -}; - -/** - * Removes transforms of the given element from the map. - * Parameters: - * elem - a DOM Element - */ -svgedit.transformlist.removeElementFromListMap = function(elem) { - if (elem.id && listMap_[elem.id]) { - delete listMap_[elem.id]; - } -}; - -// Function: getTransformList -// Returns an object that behaves like a SVGTransformList for the given DOM element -// -// Parameters: -// elem - DOM element to get a transformlist from -svgedit.transformlist.getTransformList = function(elem) { - if (!svgedit.browser.supportsNativeTransformLists()) { - var id = elem.id; - if(!id) { - // Get unique ID for temporary element - id = 'temp'; - } - var t = listMap_[id]; - if (!t || id == 'temp') { - listMap_[id] = new svgedit.transformlist.SVGTransformList(elem); - listMap_[id]._init(); - t = listMap_[id]; - } - return t; - } - else if (elem.transform) { - return elem.transform.baseVal; - } - else if (elem.gradientTransform) { - return elem.gradientTransform.baseVal; - } - else if (elem.patternTransform) { - return elem.patternTransform.baseVal; - } - - return null; -}; - - -})(); \ No newline at end of file diff --git a/build/opera/editor/svgutils.js b/build/opera/editor/svgutils.js deleted file mode 100644 index a3a6b49..0000000 --- a/build/opera/editor/svgutils.js +++ /dev/null @@ -1,648 +0,0 @@ -/** - * Package: svgedit.utilities - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.utilities) { - svgedit.utilities = {}; -} - -// Constants - -// String used to encode base64. -var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -var SVGNS = 'http://www.w3.org/2000/svg'; -var XLINKNS = 'http://www.w3.org/1999/xlink'; -var XMLNS = "http://www.w3.org/XML/1998/namespace"; - -// Much faster than running getBBox() every time -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); -//var hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath'; - -var editorContext_ = null; -var domdoc_ = null; -var domcontainer_ = null; -var svgroot_ = null; - -svgedit.utilities.init = function(editorContext) { - editorContext_ = editorContext; - domdoc_ = editorContext.getDOMDocument(); - domcontainer_ = editorContext.getDOMContainer(); - svgroot_ = editorContext.getSVGRoot(); -}; - -// Function: svgedit.utilities.toXml -// Converts characters in a string to XML-friendly entities. -// -// Example: "&" becomes "&" -// -// Parameters: -// str - The string to be converted -// -// Returns: -// The converted string -svgedit.utilities.toXml = function(str) { - return $('

        ').text(str).html(); -}; - -// Function: svgedit.utilities.fromXml -// Converts XML entities in a string to single characters. -// Example: "&" becomes "&" -// -// Parameters: -// str - The string to be converted -// -// Returns: -// The converted string -svgedit.utilities.fromXml = function(str) { - return $('

        ').html(str).text(); -}; - -// This code was written by Tyler Akins and has been placed in the -// public domain. It would be nice if you left this header intact. -// Base64 code from Tyler Akins -- http://rumkin.com - -// schiller: Removed string concatenation in favour of Array.join() optimization, -// also precalculate the size of the array needed. - -// Function: svgedit.utilities.encode64 -// Converts a string to base64 -svgedit.utilities.encode64 = function(input) { - // base64 strings are 4/3 larger than the original string -// input = svgedit.utilities.encodeUTF8(input); // convert non-ASCII characters - input = svgedit.utilities.convertToXMLReferences(input); - if(window.btoa) return window.btoa(input); // Use native if available - var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0, p = 0; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = KEYSTR.charAt(enc1); - output[p++] = KEYSTR.charAt(enc2); - output[p++] = KEYSTR.charAt(enc3); - output[p++] = KEYSTR.charAt(enc4); - } while (i < input.length); - - return output.join(''); -}; - -// Function: svgedit.utilities.decode64 -// Converts a string from base64 -svgedit.utilities.decode64 = function(input) { - if(window.atob) return window.atob(input); - var output = ""; - var chr1, chr2, chr3 = ""; - var enc1, enc2, enc3, enc4 = ""; - var i = 0; - - // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - do { - enc1 = KEYSTR.indexOf(input.charAt(i++)); - enc2 = KEYSTR.indexOf(input.charAt(i++)); - enc3 = KEYSTR.indexOf(input.charAt(i++)); - enc4 = KEYSTR.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - chr1 = chr2 = chr3 = ""; - enc1 = enc2 = enc3 = enc4 = ""; - - } while (i < input.length); - return unescape(output); -}; - -// Currently not being used, so commented out for now -// based on http://phpjs.org/functions/utf8_encode:577 -// codedread:does not seem to work with webkit-based browsers on OSX -// "encodeUTF8": function(input) { -// //return unescape(encodeURIComponent(input)); //may or may not work -// var output = ''; -// for (var n = 0; n < input.length; n++){ -// var c = input.charCodeAt(n); -// if (c < 128) { -// output += input[n]; -// } -// else if (c > 127) { -// if (c < 2048){ -// output += String.fromCharCode((c >> 6) | 192); -// } -// else { -// output += String.fromCharCode((c >> 12) | 224) + String.fromCharCode((c >> 6) & 63 | 128); -// } -// output += String.fromCharCode((c & 63) | 128); -// } -// } -// return output; -// }, - -// Function: svgedit.utilities.convertToXMLReferences -// Converts a string to use XML references -svgedit.utilities.convertToXMLReferences = function(input) { - var output = ''; - for (var n = 0; n < input.length; n++){ - var c = input.charCodeAt(n); - if (c < 128) { - output += input[n]; - } else if(c > 127) { - output += ("&#" + c + ";"); - } - } - return output; -}; - -// Function: svgedit.utilities.text2xml -// Cross-browser compatible method of converting a string to an XML tree -// found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f -svgedit.utilities.text2xml = function(sXML) { - if(sXML.indexOf('= 0) { - sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns'); - } - - var out; - try{ - var dXML = (window.DOMParser)?new DOMParser():new ActiveXObject("Microsoft.XMLDOM"); - dXML.async = false; - } catch(e){ - throw new Error("XML Parser could not be instantiated"); - }; - try{ - if(dXML.loadXML) out = (dXML.loadXML(sXML))?dXML:false; - else out = dXML.parseFromString(sXML, "text/xml"); - } - catch(e){ throw new Error("Error parsing XML string"); }; - return out; -}; - -// Function: svgedit.utilities.bboxToObj -// Converts a SVGRect into an object. -// -// Parameters: -// bbox - a SVGRect -// -// Returns: -// An object with properties names x, y, width, height. -svgedit.utilities.bboxToObj = function(bbox) { - return { - x: bbox.x, - y: bbox.y, - width: bbox.width, - height: bbox.height - } -}; - -// Function: svgedit.utilities.walkTree -// Walks the tree and executes the callback on each element in a top-down fashion -// -// Parameters: -// elem - DOM element to traverse -// cbFn - Callback function to run on each element -svgedit.utilities.walkTree = function(elem, cbFn){ - if (elem && elem.nodeType == 1) { - cbFn(elem); - var i = elem.childNodes.length; - while (i--) { - svgedit.utilities.walkTree(elem.childNodes.item(i), cbFn); - } - } -}; - -// Function: svgedit.utilities.walkTreePost -// Walks the tree and executes the callback on each element in a depth-first fashion -// TODO: FIXME: Shouldn't this be calling walkTreePost? -// -// Parameters: -// elem - DOM element to traverse -// cbFn - Callback function to run on each element -svgedit.utilities.walkTreePost = function(elem, cbFn) { - if (elem && elem.nodeType == 1) { - var i = elem.childNodes.length; - while (i--) { - svgedit.utilities.walkTree(elem.childNodes.item(i), cbFn); - } - cbFn(elem); - } -}; - -// Function: svgedit.utilities.getUrlFromAttr -// Extracts the URL from the url(...) syntax of some attributes. -// Three variants: -// * -// * -// * -// -// Parameters: -// attrVal - The attribute value as a string -// -// Returns: -// String with just the URL, like someFile.svg#foo -svgedit.utilities.getUrlFromAttr = function(attrVal) { - if (attrVal) { - // url("#somegrad") - if (attrVal.indexOf('url("') === 0) { - return attrVal.substring(5,attrVal.indexOf('"',6)); - } - // url('#somegrad') - else if (attrVal.indexOf("url('") === 0) { - return attrVal.substring(5,attrVal.indexOf("'",6)); - } - else if (attrVal.indexOf("url(") === 0) { - return attrVal.substring(4,attrVal.indexOf(')')); - } - } - return null; -}; - -// Function: svgedit.utilities.getHref -// Returns the given element's xlink:href value -svgedit.utilities.getHref = function(elem) { - return elem.getAttributeNS(XLINKNS, "href"); -} - -// Function: svgedit.utilities.setHref -// Sets the given element's xlink:href value -svgedit.utilities.setHref = function(elem, val) { - elem.setAttributeNS(XLINKNS, "xlink:href", val); -} - -// Function: findDefs -// Parameters: -// svgElement - The element. -// -// Returns: -// The document's element, create it first if necessary -svgedit.utilities.findDefs = function(svgElement) { - var svgElement = editorContext_.getSVGContent().documentElement; - var defs = svgElement.getElementsByTagNameNS(SVGNS, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - // first child is a comment, so call nextSibling - defs = svgElement.insertBefore( svgElement.ownerDocument.createElementNS(SVGNS, "defs" ), svgElement.firstChild.nextSibling); - } - return defs; -}; - -// TODO(codedread): Consider moving the next to functions to bbox.js - -// Function: svgedit.utilities.getPathBBox -// Get correct BBox for a path in Webkit -// Converted from code found here: -// http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html -// -// Parameters: -// path - The path DOM element to get the BBox for -// -// Returns: -// A BBox-like object -svgedit.utilities.getPathBBox = function(path) { - var seglist = path.pathSegList; - var tot = seglist.numberOfItems; - - var bounds = [[], []]; - var start = seglist.getItem(0); - var P0 = [start.x, start.y]; - - for(var i=0; i < tot; i++) { - var seg = seglist.getItem(i); - - if(typeof seg.x == 'undefined') continue; - - // Add actual points to limits - bounds[0].push(P0[0]); - bounds[1].push(P0[1]); - - if(seg.x1) { - var P1 = [seg.x1, seg.y1], - P2 = [seg.x2, seg.y2], - P3 = [seg.x, seg.y]; - - for(var j=0; j < 2; j++) { - - var calc = function(t) { - return Math.pow(1-t,3) * P0[j] - + 3 * Math.pow(1-t,2) * t * P1[j] - + 3 * (1-t) * Math.pow(t,2) * P2[j] - + Math.pow(t,3) * P3[j]; - }; - - var b = 6 * P0[j] - 12 * P1[j] + 6 * P2[j]; - var a = -3 * P0[j] + 9 * P1[j] - 9 * P2[j] + 3 * P3[j]; - var c = 3 * P1[j] - 3 * P0[j]; - - if(a == 0) { - if(b == 0) { - continue; - } - var t = -c / b; - if(0 < t && t < 1) { - bounds[j].push(calc(t)); - } - continue; - } - - var b2ac = Math.pow(b,2) - 4 * c * a; - if(b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac))/(2 * a); - if(0 < t1 && t1 < 1) bounds[j].push(calc(t1)); - var t2 = (-b - Math.sqrt(b2ac))/(2 * a); - if(0 < t2 && t2 < 1) bounds[j].push(calc(t2)); - } - P0 = P3; - } else { - bounds[0].push(seg.x); - bounds[1].push(seg.y); - } - } - - var x = Math.min.apply(null, bounds[0]); - var w = Math.max.apply(null, bounds[0]) - x; - var y = Math.min.apply(null, bounds[1]); - var h = Math.max.apply(null, bounds[1]) - y; - return { - 'x': x, - 'y': y, - 'width': w, - 'height': h - }; -}; - -// Function: groupBBFix -// Get the given/selected element's bounding box object, checking for -// horizontal/vertical lines (see issue 717) -// Note that performance is currently terrible, so some way to improve would -// be great. -// -// Parameters: -// selected - Container or DOM element -function groupBBFix(selected) { - if(svgedit.browser.supportsHVLineContainerBBox()) { - try { return selected.getBBox();} catch(e){} - } - var ref = $.data(selected, 'ref'); - var matched = null; - - if(ref) { - var copy = $(ref).children().clone().attr('visibility', 'hidden'); - $(svgroot_).append(copy); - matched = copy.filter('line, path'); - } else { - matched = $(selected).find('line, path'); - } - - var issue = false; - if(matched.length) { - matched.each(function() { - var bb = this.getBBox(); - if(!bb.width || !bb.height) { - issue = true; - } - }); - if(issue) { - var elems = ref ? copy : $(selected).children(); - ret = getStrokedBBox(elems); - } else { - ret = selected.getBBox(); - } - } else { - ret = selected.getBBox(); - } - if(ref) { - copy.remove(); - } - return ret; -} - -// Function: svgedit.utilities.getBBox -// Get the given/selected element's bounding box object, convert it to be more -// usable when necessary -// -// Parameters: -// elem - Optional DOM element to get the BBox for -svgedit.utilities.getBBox = function(elem) { - var selected = elem || editorContext_.geSelectedElements()[0]; - if (elem.nodeType != 1) return null; - var ret = null; - var elname = selected.nodeName; - - switch ( elname ) { - case 'text': - if(selected.textContent === '') { - selected.textContent = 'a'; // Some character needed for the selector to use. - ret = selected.getBBox(); - selected.textContent = ''; - } else { - try { ret = selected.getBBox();} catch(e){} - } - break; - case 'path': - if(!svgedit.browser.supportsPathBBox()) { - ret = svgedit.utilities.getPathBBox(selected); - } else { - try { ret = selected.getBBox();} catch(e){} - } - break; - case 'g': - case 'a': - ret = groupBBFix(selected); - break; - default: - - if(elname === 'use') { - ret = groupBBFix(selected, true); - } - - if(elname === 'use') { - if(!ret) ret = selected.getBBox(); - if(!svgedit.browser.isWebkit()) { - var bb = {}; - bb.width = ret.width; - bb.height = ret.height; - bb.x = ret.x + parseFloat(selected.getAttribute('x')||0); - bb.y = ret.y + parseFloat(selected.getAttribute('y')||0); - ret = bb; - } - } else if(~visElems_arr.indexOf(elname)) { - try { ret = selected.getBBox();} - 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; - } - } - } - } - - if(ret) { - ret = svgedit.utilities.bboxToObj(ret); - } - - // get the bounding box from the DOM (which is in that element's coordinate system) - return ret; -}; - -// Function: svgedit.utilities.getRotationAngle -// Get the rotation angle of the given/selected DOM element -// -// Parameters: -// elem - Optional DOM element to get the angle for -// to_rad - Boolean that when true returns the value in radians rather than degrees -// -// Returns: -// Float with the angle in degrees or radians -svgedit.utilities.getRotationAngle = function(elem, to_rad) { - var selected = elem || editorContext_.getSelectedElements()[0]; - // find the rotation transform (if any) and set it - var tlist = svgedit.transformlist.getTransformList(selected); - if(!tlist) return 0; // elements have no tlist - var N = tlist.numberOfItems; - for (var i = 0; i < N; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - return to_rad ? xform.angle * Math.PI / 180.0 : xform.angle; - } - } - return 0.0; -}; - -// Function: getElem -// Get a DOM element by ID within the SVG root element. -// -// Parameters: -// id - String with the element's new ID -if (svgedit.browser.supportsSelectors()) { - svgedit.utilities.getElem = function(id) { - // querySelector lookup - return svgroot_.querySelector('#'+id); - }; -} else if (svgedit.browser.supportsXpath()) { - svgedit.utilities.getElem = function(id) { - // xpath lookup - return domdoc_.evaluate( - 'svg:svg[@id="svgroot"]//svg:*[@id="'+id+'"]', - domcontainer_, - function() { return "http://www.w3.org/2000/svg"; }, - 9, - null).singleNodeValue; - }; -} else { - svgedit.utilities.getElem = function(id) { - // jQuery lookup: twice as slow as xpath in FF - return $(svgroot_).find('[id=' + id + ']')[0]; - }; -} - -// Function: assignAttributes -// Assigns multiple attributes to an element. -// -// Parameters: -// node - DOM element to apply new attribute values to -// attrs - Object with attribute keys/values -// suspendLength - Optional integer of milliseconds to suspend redraw -// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr -svgedit.utilities.assignAttributes = function(node, attrs, suspendLength, unitCheck) { - if(!suspendLength) suspendLength = 0; - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!svgedit.browser.isOpera()) svgroot_.suspendRedraw(suspendLength); - - for (var i in attrs) { - var ns = (i.substr(0,4) === "xml:" ? XMLNS : - i.substr(0,6) === "xlink:" ? XLINKNS : null); - - if(ns) { - node.setAttributeNS(ns, i, attrs[i]); - } else if(!unitCheck) { - node.setAttribute(i, attrs[i]); - } else { - svgedit.units.setUnitAttr(node, i, attrs[i]); - } - - } - - if (!svgedit.browser.isOpera()) svgroot_.unsuspendRedraw(handle); -}; - -// Function: cleanupElement -// Remove unneeded (default) attributes, makes resulting SVG smaller -// -// Parameters: -// element - DOM element to clean up -svgedit.utilities.cleanupElement = function(element) { - var handle = svgroot_.suspendRedraw(60); - var defaults = { - 'fill-opacity':1, - 'stop-opacity':1, - 'opacity':1, - 'stroke':'none', - 'stroke-dasharray':'none', - 'stroke-linejoin':'miter', - 'stroke-linecap':'butt', - 'stroke-opacity':1, - 'stroke-width':1, - 'rx':0, - 'ry':0 - } - - for(var attr in defaults) { - var val = defaults[attr]; - if(element.getAttribute(attr) == val) { - element.removeAttribute(attr); - } - } - - svgroot_.unsuspendRedraw(handle); -}; - - -})(); diff --git a/build/opera/editor/touch.js b/build/opera/editor/touch.js deleted file mode 100644 index 7db1544..0000000 --- a/build/opera/editor/touch.js +++ /dev/null @@ -1,28 +0,0 @@ -function touchHandler(event) -{ - - var touches = event.changedTouches, - first = touches[0], - type = ""; - switch(event.type) - { - case "touchstart": type="mousedown"; break; - case "touchmove": type="mousemove"; break; - case "touchend": type="mouseup"; break; - default: return; - } - - //initMouseEvent(type, canBubble, cancelable, view, clickCount, - // screenX, screenY, clientX, clientY, ctrlKey, - // altKey, shiftKey, metaKey, button, relatedTarget); - - var simulatedEvent = document.createEvent("MouseEvent"); - simulatedEvent.initMouseEvent(type, true, true, window, 1, - first.screenX, first.screenY, - first.clientX, first.clientY, false, - false, false, false, 0/*left*/, null); - if(touches.length < 2) { - first.target.dispatchEvent(simulatedEvent); - event.preventDefault(); - } -} diff --git a/build/opera/editor/units.js b/build/opera/editor/units.js deleted file mode 100644 index f2b30e7..0000000 --- a/build/opera/editor/units.js +++ /dev/null @@ -1,281 +0,0 @@ -/** - * Package: svgedit.units - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.units) { - svgedit.units = {}; -} - -var w_attrs = ['x', 'x1', 'cx', 'rx', 'width']; -var h_attrs = ['y', 'y1', 'cy', 'ry', 'height']; -var unit_attrs = $.merge(['r','radius'], w_attrs); - -var unitNumMap = { - '%': 2, - 'em': 3, - 'ex': 4, - 'px': 5, - 'cm': 6, - 'mm': 7, - 'in': 8, - 'pt': 9, - 'pc': 10 -}; - -$.merge(unit_attrs, h_attrs); - -// Container of elements. -var elementContainer_; - -/** - * Stores mapping of unit type to user coordinates. - */ -var typeMap_ = {px: 1}; - -/** - * ElementContainer interface - * - * function getBaseUnit() - returns a string of the base unit type of the container ("em") - * function getElement() - returns an element in the container given an id - * function getHeight() - returns the container's height - * function getWidth() - returns the container's width - * function getRoundDigits() - returns the number of digits number should be rounded to - */ - -/** - * Function: svgedit.units.init() - * Initializes this module. - * - * Parameters: - * elementContainer - an object implementing the ElementContainer interface. - */ -svgedit.units.init = function(elementContainer) { - elementContainer_ = elementContainer; - - var svgns = 'http://www.w3.org/2000/svg'; - - // Get correct em/ex values by creating a temporary SVG. - var svg = document.createElementNS(svgns, 'svg'); - document.body.appendChild(svg); - var rect = document.createElementNS(svgns,'rect'); - rect.setAttribute('width',"1em"); - rect.setAttribute('height',"1ex"); - rect.setAttribute('x',"1in"); - svg.appendChild(rect); - var bb = rect.getBBox(); - document.body.removeChild(svg); - - var inch = bb.x; - typeMap_['em'] = bb.width; - typeMap_['ex'] = bb.height; - typeMap_['in'] = inch; - typeMap_['cm'] = inch / 2.54; - typeMap_['mm'] = inch / 25.4; - typeMap_['pt'] = inch / 72; - typeMap_['pc'] = inch / 6; - typeMap_['%'] = 0; -}; - -// Group: Unit conversion functions - -// Function: svgedit.units.getTypeMap -// Returns the unit object with values for each unit -svgedit.units.getTypeMap = function() { - return typeMap_; -}; - -// Function: svgedit.units.shortFloat -// Rounds a given value to a float with number of digits defined in save_options -// -// Parameters: -// val - The value as a String, Number or Array of two numbers to be rounded -// -// Returns: -// If a string/number was given, returns a Float. If an array, return a string -// with comma-seperated floats -svgedit.units.shortFloat = function(val) { - var digits = elementContainer_.getRoundDigits(); - if(!isNaN(val)) { - // Note that + converts to Number - return +((+val).toFixed(digits)); - } else if($.isArray(val)) { - return svgedit.units.shortFloat(val[0]) + ',' + svgedit.units.shortFloat(val[1]); - } - return parseFloat(val).toFixed(digits) - 0; -}; - -// Function: svgedit.units.convertUnit -// Converts the number to given unit or baseUnit -svgedit.units.convertUnit = function(val, unit) { - unit = unit || elementContainer_.getBaseUnit(); -// baseVal.convertToSpecifiedUnits(unitNumMap[unit]); -// var val = baseVal.valueInSpecifiedUnits; -// baseVal.convertToSpecifiedUnits(1); - return svgedit.unit.shortFloat(val / typeMap_[unit]); -}; - -// Function: svgedit.units.setUnitAttr -// Sets an element's attribute based on the unit in its current value. -// -// Parameters: -// elem - DOM element to be changed -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to convert -svgedit.units.setUnitAttr = function(elem, attr, val) { - if(!isNaN(val)) { - // New value is a number, so check currently used unit - var old_val = elem.getAttribute(attr); - - // Enable this for alternate mode -// if(old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) { -// // Old value was a number, so get unit, then convert -// var unit; -// if(old_val.substr(-1) === '%') { -// var res = getResolution(); -// unit = '%'; -// val *= 100; -// if(w_attrs.indexOf(attr) >= 0) { -// val = val / res.w; -// } else if(h_attrs.indexOf(attr) >= 0) { -// val = val / res.h; -// } else { -// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2); -// } -// } else { -// if(elementContainer_.getBaseUnit() !== 'px') { -// unit = elementContainer_.getBaseUnit(); -// } else { -// unit = old_val.substr(-2); -// } -// val = val / typeMap_[unit]; -// } -// -// val += unit; -// } - } - elem.setAttribute(attr, val); -}; - -var attrsToConvert = { - "line": ['x1', 'x2', 'y1', 'y2'], - "circle": ['cx', 'cy', 'r'], - "ellipse": ['cx', 'cy', 'rx', 'ry'], - "foreignObject": ['x', 'y', 'width', 'height'], - "rect": ['x', 'y', 'width', 'height'], - "image": ['x', 'y', 'width', 'height'], - "use": ['x', 'y', 'width', 'height'], - "text": ['x', 'y'] -}; - -// Function: svgedit.units.convertAttrs -// Converts all applicable attributes to the configured baseUnit -// -// Parameters: -// element - a DOM element whose attributes should be converted -svgedit.units.convertAttrs = function(element) { - var elName = element.tagName; - var unit = elementContainer_.getBaseUnit(); - var attrs = attrsToConvert[elName]; - if(!attrs) return; - var len = attrs.length - for(var i = 0; i < len; i++) { - var attr = attrs[i]; - var cur = element.getAttribute(attr); - if(cur) { - if(!isNaN(cur)) { - element.setAttribute(attr, (cur / typeMap_[unit]) + unit); - } else { - // Convert existing? - } - } - } -}; - -// Function: svgedit.units.convertToNum -// Converts given values to numbers. Attributes must be supplied in -// case a percentage is given -// -// Parameters: -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to convert -svgedit.units.convertToNum = function(attr, val) { - // Return a number if that's what it already is - if(!isNaN(val)) return val-0; - - if(val.substr(-1) === '%') { - // Deal with percentage, depends on attribute - var num = val.substr(0, val.length-1)/100; - var width = elementContainer_.getWidth(); - var height = elementContainer_.getHeight(); - - if(w_attrs.indexOf(attr) >= 0) { - return num * width; - } else if(h_attrs.indexOf(attr) >= 0) { - return num * height; - } else { - return num * Math.sqrt((width*width) + (height*height))/Math.sqrt(2); - } - } else { - var unit = val.substr(-2); - var num = val.substr(0, val.length-2); - // Note that this multiplication turns the string into a number - return num * typeMap_[unit]; - } -}; - -// Function: svgedit.units.isValidUnit -// Check if an attribute's value is in a valid format -// -// Parameters: -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to check -svgedit.units.isValidUnit = function(attr, val, selectedElement) { - var valid = false; - if(unit_attrs.indexOf(attr) >= 0) { - // True if it's just a number - if(!isNaN(val)) { - valid = true; - } else { - // Not a number, check if it has a valid unit - val = val.toLowerCase(); - $.each(typeMap_, function(unit) { - if(valid) return; - var re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - if(re.test(val)) valid = true; - }); - } - } else if (attr == "id") { - // if we're trying to change the id, make sure it's not already present in the doc - // and the id value is valid. - - var result = false; - // because getElem() can throw an exception in the case of an invalid id - // (according to http://www.w3.org/TR/xml-id/ IDs must be a NCName) - // we wrap it in an exception and only return true if the ID was valid and - // not already present - try { - var elem = elementContainer_.getElement(val); - result = (elem == null || elem === selectedElement); - } catch(e) {} - return result; - } else { - valid = true; - } - - return valid; -}; - - -})(); \ No newline at end of file diff --git a/build/opera/handlers.js b/build/opera/handlers.js deleted file mode 100644 index bb1d138..0000000 --- a/build/opera/handlers.js +++ /dev/null @@ -1,62 +0,0 @@ -// Note: This JavaScript file must be included as the last script on the main HTML editor page to override the open/save handlers -$(function() { - if(window.opera && window.opera.io && window.opera.io.filesystem) { - svgCanvas.setCustomHandlers({ - 'open':function() { - try { - window.opera.io.filesystem.browseForFile( - new Date().getTime(), /* mountpoint name */ - "", /* default location */ - function(file) { - try { - if (file) { - fstream = file.open(file, "r"); - var output = ""; - while (!fstream.eof) { - output += fstream.readLine(); - } - - svgCanvas.setSvgString(output); /* 'this' is bound to the filestream object here */ - } - } - catch(e) { - console.log("Reading file failed."); - } - }, - false, /* not persistent */ - false, /* no multiple selections */ - "*.svg" /* file extension filter */ - ); - } - catch(e) { - console.log("Open file failed."); - } - - }, - 'save':function(window, svg) { - try { - window.opera.io.filesystem.browseForSave( - new Date().getTime(), /* mountpoint name */ - "", /* default location */ - function(file) { - try { - if (file) { - var fstream = file.open(file, "w"); - fstream.write(svg, "UTF-8"); - fstream.close(); - } - } - catch(e) { - console.log("Write to file failed."); - } - }, - false /* not persistent */ - ); - } - catch(e) { - console.log("Save file failed."); - } - } - }); - } -}); \ No newline at end of file diff --git a/build/opera/index.html b/build/opera/index.html deleted file mode 100644 index f439312..0000000 --- a/build/opera/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - SVG Edit - - - - - - Failed to load for some reason. - - - diff --git a/build/opera/style.css b/build/opera/style.css deleted file mode 100644 index b4e8ae6..0000000 --- a/build/opera/style.css +++ /dev/null @@ -1,2 +0,0 @@ -body { margin: 0px; padding: 0px; } -#container { width: 100%; height: 100%; border: none; } diff --git a/build/svg-edit-2.6-src.tar.gz b/build/svg-edit-2.6-src.tar.gz deleted file mode 100644 index fdb8f0e..0000000 Binary files a/build/svg-edit-2.6-src.tar.gz and /dev/null differ diff --git a/build/svg-edit-2.6-src/.DS_Store b/build/svg-edit-2.6-src/.DS_Store deleted file mode 100644 index 7102efb..0000000 Binary files a/build/svg-edit-2.6-src/.DS_Store and /dev/null differ diff --git a/build/svg-edit-2.6-src/AUTHORS b/build/svg-edit-2.6-src/AUTHORS deleted file mode 100644 index 2e0fe8d..0000000 --- a/build/svg-edit-2.6-src/AUTHORS +++ /dev/null @@ -1,22 +0,0 @@ -Narendra Sisodiya -Pavol Rusnak -Jeff Schiller -Vidar Hokstad -Alexis Deveria - -Translation credits: - -ar: Tarik Belaam (العربية) -cs: Jan Ptacek (Čeština) -de: Reimar Bauer (Deutsch) -es: Alicia Puerto (Español) -fa: Payman Delshad (فارسی) -fr: wormsxulla (Français) -fy: Wander Nauta (Frysk) -hi: Tavish Naruka (हिन्दी) -ja: Dong (日本語) -nl: Jaap Blom (Nederlands) -ro: Christian Tzurcanu (Româneşte) -ru: Laurent Dufloux (Русский) -sk: Pavol Rusnak (Slovenčina) -zh-TW: 黃瀚生 (Han Sheng Huang) (台灣正體) diff --git a/build/svg-edit-2.6-src/CHANGES b/build/svg-edit-2.6-src/CHANGES deleted file mode 100644 index 9abfcef..0000000 --- a/build/svg-edit-2.6-src/CHANGES +++ /dev/null @@ -1,97 +0,0 @@ -2.5 - June 15, 2010 -------------------- -* Open Local Files (Firefox 3.6+ only) -* Import SVG into Drawing (Firefox 3.6+ only) -* Ability to create extensions/plugins -* Main menu and overal interface improvements -* Create and select elements outside the canvas -* Base support for the svg:use element -* Add/Edit Sub-paths -* Multiple path segment selection -* Radial Gradient support -* Connector lines -* Arrows & Markers -* Smoother freehand paths -* Foreign markup support (ForeignObject?/MathML) -* Configurable options -* File-loading options -* Eye-dropper tool (copy element style) -* Stroke linejoin and linecap options -* Export to PNG -* Blur tool -* Page-align single elements -* Inline text editing -* Line draw snapping with Shift key - -2.4 - January 11, 2010 ----------------------- -* Zoom -* Layers -* UI Localization -* Wireframe Mode -* Resizable UI (SVG icons) -* Set background color and/or image (for tracing) -* Convert Shapes to Paths -* X, Y coordinates for all elements -* Draggable Dialog boxes -* Select Non-Adjacent Elements -* Fixed-ratio resize -* Automatic Tool Switching -* Raster Images -* Group elements -* Add/Remove path nodes -* Curved Paths -* Floating point values for all attributes -* Text fields for all attributes -* Title element - -2.3 - September 08, 2009 ------------------------- -* Align Objects -* Rotate Objects -* Clone Objects -* Select Next/Prev Object -* Edit SVG Source -* Gradient picking -* Polygon Mode (Path Editing, Phase 1) - -2.2 - July 08, 2009 -------------------- -* Multiselect Mode -* Undo/Redo Actions -* Resize Elements -* Contextual tools for rect, circle, ellipse, line, text elements -* Some updated button images -* Stretched the UI to fit the browser window -* Resizing of the SVG canvas -* Upgraded to jPicker 1.0.8 - -2.1 - June 17, 2009 -------------------- -* tooltips added to all UI elements -* fix flyout menus -* ask before clearing the drawing (suggested by martin.vidner) -* control group, fill and stroke opacity -* fix flyouts when using color picker -* change license from GPLv2 to Apache License v2.0 -* replaced Farbtastic with jPicker, because of the license issues -* removed dependency on svgcanvas.svg, now created in JavaScript -* added Select tool -* using jQuery hosted by Google instead of local version -* allow dragging of elements -* save SVG file to separate tab -* create and edit text elements -* context panel tools -* change rect radius, font-family, font-size -* added keystroke shortcuts for all tools -* move to top/bottom - -2.0 - June 03, 2009 -------------------- -* rewritten SVG-edit, so now it uses OOP -* draw ellipse, square -* created HTML interface similar to Inkscape - -1.0 - February 06, 2009 -------------------- -* SVG-Edit released diff --git a/build/svg-edit-2.6-src/LICENSE b/build/svg-edit-2.6-src/LICENSE deleted file mode 100644 index b98ac70..0000000 --- a/build/svg-edit-2.6-src/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2009-2011 by SVG-edit authors (see AUTHORS file) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/build/svg-edit-2.6-src/Makefile b/build/svg-edit-2.6-src/Makefile deleted file mode 100644 index a528cf8..0000000 --- a/build/svg-edit-2.6-src/Makefile +++ /dev/null @@ -1,101 +0,0 @@ -NAME=svg-edit -VERSION=2.6 -PACKAGE=$(NAME)-$(VERSION) -MAKEDOCS=naturaldocs/NaturalDocs -CLOSURE=build/tools/closure-compiler.jar -ZIP=zip - -# All files that will be compiled by the Closure compiler. - -JS_FILES=\ - contextmenu/jquery.contextmenu.js \ - browser.js \ - svgtransformlist.js \ - math.js \ - units.js \ - svgutils.js \ - sanitize.js \ - history.js \ - select.js \ - draw.js \ - path.js \ - svgcanvas.js \ - svg-editor.js \ - contextmenu.js \ - locale/locale.js \ - touch.js - -JS_INPUT_FILES=$(addprefix editor/, $(JS_FILES)) -JS_BUILD_FILES=$(addprefix build/$(PACKAGE)/, $(JS_FILES)) -CLOSURE_JS_ARGS=$(addprefix --js , $(JS_INPUT_FILES)) -COMPILED_JS=editor/svgedit.compiled.js - -all: release firefox opera - -# The build directory relies on the JS being compiled. -build/$(PACKAGE): $(COMPILED_JS) - rm -rf config - mkdir config - if [ -x $(MAKEDOCS) ] ; then $(MAKEDOCS) -i editor/ -o html docs/ -p config/ -oft -r ; fi - - # Make build directory and copy all editor contents into it - mkdir -p build/$(PACKAGE) - cp -r editor/* build/$(PACKAGE) - - # Remove all hidden .svn directories - -find build/$(PACKAGE) -name .svn -type d | xargs rm -rf {} \; - -find build/$(PACKAGE) -name .git -type d | xargs rm -rf {} \; - - # Create the release version of the main HTML file. - build/tools/ship.py --i=editor/svg-editor.html --on=svg_edit_release > build/$(PACKAGE)/svg-editor.html - -# NOTE: Some files are not ready for the Closure compiler: (jquery) -# NOTE: Our code safely compiles under SIMPLE_OPTIMIZATIONS -# NOTE: Our code is *not* ready for ADVANCED_OPTIMIZATIONS -# NOTE: WHITESPACE_ONLY and --formatting PRETTY_PRINT is helpful for debugging. -$(COMPILED_JS): - java -jar $(CLOSURE) \ - --compilation_level SIMPLE_OPTIMIZATIONS \ - $(CLOSURE_JS_ARGS) \ - --js_output_file $(COMPILED_JS) - -compile: $(COMPILED_JS) - -release: build/$(PACKAGE) - cd build ; $(ZIP) $(PACKAGE).zip -r $(PACKAGE) ; cd .. - tar -z -c -f build/$(PACKAGE)-src.tar.gz \ - --exclude='\.svn' \ - --exclude='\.git' \ - --exclude='build/*' \ - . - -firefox: build/$(PACKAGE) - mkdir -p build/firefox/content/editor - cp -r firefox-extension/* build/firefox - rm -rf build/firefox/content/.svn - rm -rf build/firefox/content/.git - cp -r build/$(PACKAGE)/* build/firefox/content/editor - rm -f build/firefox/content/editor/embedapi.js - cd build/firefox ; $(ZIP) ../$(PACKAGE).xpi -r * ; cd ../.. - -opera: build/$(PACKAGE) - mkdir -p build/opera/editor - cp opera-widget/* build/opera - cp -r build/$(PACKAGE)/* build/opera/editor - cd build/opera ; $(ZIP) ../$(PACKAGE).wgt -r * ; cd ../.. - -chrome: - mkdir -p build/svgedit_app - cp -a chrome-app/* build/svgedit_app - cd build ; $(ZIP) -r $(PACKAGE)-crx.zip svgedit_app ; rm -rf svgedit_app; cd .. - -clean: - rm -rf config - rm -rf build/$(PACKAGE) - rm -rf build/firefox - rm -rf build/opera - rm -rf build/$(PACKAGE).zip - rm -rf build/$(PACKAGE)-src.tar.gz - rm -rf build/$(PACKAGE).xpi - rm -rf build/$(PACKAGE).wgt - rm -rf $(COMPILED_JS) diff --git a/build/svg-edit-2.6-src/README b/build/svg-edit-2.6-src/README deleted file mode 100644 index f8fe943..0000000 --- a/build/svg-edit-2.6-src/README +++ /dev/null @@ -1,21 +0,0 @@ -SVG-edit, a web based SVG editor - -http://code.google.com/p/svg-edit/ - -see AUTHORS file for authors - ------ - -SVG-edit contains code from these projects: - -jQuery JavaScript Library v1.3.2 -http://jquery.com/ -Copyright (c) 2009 John Resig - -jQuery js-Hotkeys -http://code.google.com/p/js-hotkeys/ -Copyright (c) 2008 Tzury Bar Yochay - -jPicker -http://www.digitalmagicpro.com/jPicker/ -Copyright (c) 2009 Christopher T. Tillman diff --git a/build/svg-edit-2.6-src/chrome-app/icon_128.png b/build/svg-edit-2.6-src/chrome-app/icon_128.png deleted file mode 100644 index 964027f..0000000 Binary files a/build/svg-edit-2.6-src/chrome-app/icon_128.png and /dev/null differ diff --git a/build/svg-edit-2.6-src/chrome-app/manifest.json b/build/svg-edit-2.6-src/chrome-app/manifest.json deleted file mode 100644 index 80dba56..0000000 --- a/build/svg-edit-2.6-src/chrome-app/manifest.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "SVG-edit", - "description": "A fast, web-based, Javascript-driven SVG editor that works in any modern browser", - "version": "2.6", - "app": { - "urls": [ - "*://svg-edit.googlecode.com/svn/tags/stable/" - ], - "launch": { - "web_url": "http://svg-edit.googlecode.com/svn/tags/stable/editor/svg-editor.html" - } - }, - "icons": { - "128": "icon_128.png" - }, - "permissions": [ - "unlimitedStorage", - "notifications" - ] -} diff --git a/build/svg-edit-2.6-src/clipart/moon.svg b/build/svg-edit-2.6-src/clipart/moon.svg deleted file mode 100644 index 179fa66..0000000 --- a/build/svg-edit-2.6-src/clipart/moon.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - Layer 1 - - - - - - - - - diff --git a/build/svg-edit-2.6-src/clipart/star.svg b/build/svg-edit-2.6-src/clipart/star.svg deleted file mode 100644 index 62bb89a..0000000 --- a/build/svg-edit-2.6-src/clipart/star.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/build/svg-edit-2.6-src/clipart/sun.svg b/build/svg-edit-2.6-src/clipart/sun.svg deleted file mode 100644 index df2f5b7..0000000 --- a/build/svg-edit-2.6-src/clipart/sun.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -image/svg+xml diff --git a/build/svg-edit-2.6-src/docs/files/svgcanvas-js.html b/build/svg-edit-2.6-src/docs/files/svgcanvas-js.html deleted file mode 100644 index 6f1b0b3..0000000 --- a/build/svg-edit-2.6-src/docs/files/svgcanvas-js.html +++ /dev/null @@ -1,426 +0,0 @@ - - -SvgCanvas - - - - - - - - - -

        SvgCanvas

        The main SvgCanvas class that manages all SVG-related functions

        Parameters

        containerThe container HTML element that should hold the SVG root element
        configAn object that contains configuration data
        Summary
        SvgCanvasThe main SvgCanvas class that manages all SVG-related functions
        Utils.toXmlConverts characters in a string to XML-friendly entities.
        Utils.fromXmlConverts XML entities in a string to single characters.
        Utils.encode64Converts a string to base64
        Utils.decode64Converts a string from base64
        Utils.convertToXMLReferencesConverts a string to use XML references
        rectsIntersectCheck if two rectangles (BBoxes objects) intersect each other
        snapToAngleReturns a 45 degree angle coordinate associated with the two given coordinates
        text2xmlCross-browser compatible method of converting a string to an XML tree found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f
        Unit conversion functions
        convertToNumConverts given values to numbers.
        setUnitAttrSets an element’s attribute based on the unit in its current value.
        isValidUnitCheck if an attribute’s value is in a valid format
        Undo/Redo history management
        ChangeElementCommandHistory command to make a change to an element.
        ChangeElementCommand.applyPerforms the stored change action
        ChangeElementCommand.unapplyReverses the stored change action
        ChangeElementCommand.elementsReturns array with element associated with this command
        InsertElementCommandHistory command for an element that was added to the DOM
        InsertElementCommand.applyRe-Inserts the new element
        InsertElementCommand.unapplyRemoves the element
        InsertElementCommand.elementsReturns array with element associated with this command
        RemoveElementCommandHistory command for an element removed from the DOM
        RemoveElementCommand.applyRe-removes the new element
        RemoveElementCommand.unapplyRe-adds the new element
        RemoveElementCommand.elementsReturns array with element associated with this command
        MoveElementCommandHistory command for an element that had its DOM position changed
        MoveElementCommand.unapplyRe-positions the element
        MoveElementCommand.unapplyPositions the element back to its original location
        MoveElementCommand.elementsReturns array with element associated with this command
        BatchCommandHistory command that can contain/execute multiple other commands
        BatchCommand.applyRuns “apply” on all subcommands
        BatchCommand.unapplyRuns “unapply” on all subcommands
        BatchCommand.elementsIterate through all our subcommands and returns all the elements we are changing
        BatchCommand.addSubCommandAdds a given command to the history stack
        BatchCommand.isEmptyReturns a boolean indicating whether or not the batch command is empty
        resetUndoStackResets the undo stack, effectively clearing the undo/redo history
        undoMgr.getUndoStackSizeInteger with the current size of the undo history stack
        undoMgr.getRedoStackSizeInteger with the current size of the redo history stack
        undoMgr.getNextUndoCommandTextString associated with the next undo command
        undoMgr.getNextRedoCommandTextString associated with the next redo command
        undoMgr.undoPerforms an undo step
        undoMgr.redoPerforms a redo step
        addCommandToHistoryAdds a command object to the undo history stack
        beginUndoableChangeThis function tells the canvas to remember the old values of the attrName attribute for each element sent in.
        finishUndoableChangeThis function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
        SelectorPrivate class for DOM element selection boxes
        Functions
        Selector.resetUsed to reset the id and element that the selector is attached to
        Selector.showGripsShow the resize grips of this selector
        Selector.updateGripCursorsUpdates cursors for corner grips on rotation so arrows point the right way
        Selector.resizeUpdates the selector to match the element’s size
        SelectorManagerPublic class to manage all selector objects (selection boxes)
        SelectorManager.initGroupResets the parent selector group element
        SelectorManager.requestSelectorReturns the selector based on the given element
        SelectorManager.releaseSelectorRemoves the selector of the given element (hides selection box)
        SelectorManager.getRubberBandBoxReturns the rubberBandBox DOM element.
        Helper functions
        walkTreeWalks the tree and executes the callback on each element in a top-down fashion
        walkTreePostWalks the tree and executes the callback on each element in a depth-first fashion
        assignAttributesAssigns multiple attributes to an element.
        cleanupElementRemove unneeded (default) attributes, makes resulting SVG smaller
        addSvgElementFromJsonCreate a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
        addExtensionAdd an extension to the editor
        shortFloatRounds a given value to a float with number of digits defined in save_options
        getStrokedBBoxGet the bounding box for one or more stroked and/or transformed elements
        getVisibleElementsGet all elements that have a BBox (excludes <defs>, <title>, etc).
        copyElemCreate a clone of an element, updating its ID and its children’s IDs when needed
        getElemGet a DOM element by ID within the SVG root element.
        getIdReturns the last created DOM element ID string
        getNextIdCreates and returns a unique ID string for a DOM element
        bindAttaches a callback function to an event
        setIdPrefixChanges the ID prefix to the given value
        sanitizeSvgSanitizes the input node and its children It only keeps what is allowed from our whitelist defined above
        getUrlFromAttrExtracts the URL from the url(...)
        getBBoxGet the given/selected element’s bounding box object, convert it to be more usable when necessary
        ffCloneHack for Firefox bugs where text element features aren’t updated.
        getPathBBoxGet correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
        Element Transforms
        getRotationAngleGet the rotation angle of the given/selected DOM element
        setRotationAngleRemoves any old rotations if present, prepends a new rotation at the transformed center
        getTransformListReturns an object that behaves like a SVGTransformList for the given DOM element
        recalculateAllSelectedDimensionsRuns recalculateDimensions on the selected elements, adding the changes to a single batch command
        remapElementApplies coordinate changes to an element based on the given matrix
        recalculateDimensionsDecides the course of action based on the element’s transform list
        transformPointA (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)
        isIdentityHelper function to check if the matrix performs no actual transform (i.e.
        matrixMultiplyThis function tries to return a SVGMatrix that is the multiplication m1*m2.
        transformListToTransformThis returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments
        hasMatrixTransformSee if the given transformlist includes a non-indentity matrix transform
        getMatrixGet the matrix object for a given element
        transformBoxTransforms a rectangle based on the given matrix
        Selection
        clearSelectionClears the selection.
        addToSelectionAdds a list of elements to the selection.
        removeFromSelectionRemoves elements from the selection.
        selectAllInCurrentLayerClears the selection, then adds all elements in the current layer to the selection.
        smoothControlPointsTakes three points and creates a smoother line based on them
        getMouseTargetGets the desired element from a mouse event
        preventClickDefaultPrevents default browser click behaviour on the given element
        Text edit functionsFunctions relating to editing text elements
        Path edit functionsFunctions relating to editing path elements
        Serialization
        removeUnusedDefElemsLooks at DOM elements inside the <defs> to see if they are referred to, removes them from the DOM if they are not.
        svgCanvasToStringMain function to set up the SVG content for output
        svgToStringSub function ran on each SVG element to convert it to a string as desired
        embedImageConverts a given image file to a data URL when possible, then runs a given callback
        saveSerializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.
        rasterExportGenerates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found
        getSvgStringReturns the current drawing as raw SVG XML text.
        setSvgStringThis function sets the current drawing as the input SVG XML.
        importSvgStringThis function imports the input SVG XML into the current layer in the drawing
        Layers
        identifyLayersUpdates layer system
        createLayerCreates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
        deleteCurrentLayerDeletes the current layer from the drawing and then clears the selection.
        getNumLayersReturns the number of layers in the current drawing.
        getLayerReturns the name of the ith layer.
        getCurrentLayerReturns the name of the currently selected layer.
        setCurrentLayerSets the current layer.
        renameCurrentLayerRenames the current layer.
        setCurrentLayerPositionChanges the position of the current layer to the new value.
        getLayerVisibilityReturns whether the layer is visible.
        setLayerVisibilitySets the visibility of the layer.
        moveSelectedToLayerMoves the selected elements to layername.
        getLayerOpacityReturns the opacity of the given layer.
        setLayerOpacitySets the opacity of the given layer.
        Document functions
        clearClears the current document.
        linkControlPointsAlias function
        getContentElemReturns the content DOM element
        getRootElemReturns the root DOM element
        getSelectedElemsReturns the array with selected DOM elements
        getResolutionReturns the current dimensions and zoom level in an object
        getZoomReturns the current zoom level
        getVersionReturns a string which describes the revision number of SvgCanvas.
        setUiStringsUpdate interface strings with given values
        setConfigUpdate configuration options with given values
        getDocumentTitleReturns the current document title or an empty string if not found
        setDocumentTitleAdds/updates a title element for the document with the given name.
        getEditorNSReturns the editor’s namespace URL, optionally adds it to root element
        setResolutionChanges the document’s dimensions to the given size
        getOffsetReturns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.
        setBBoxZoomSets the zoom level on the canvas-side based on the given value
        setZoomSets the zoom to the given level
        getModeReturns the current editor mode string
        setModeSets the editor’s mode to the given string
        Element Styling
        getColorReturns the current fill/stroke option
        setColorChange the current stroke/fill color/gradient value
        findDefsReturn the document’s <defs> element, create it first if necessary
        setGradientApply the current gradient to selected element’s fill or stroke
        findDuplicateGradientCheck if exact gradient already exists
        setPaintSet a color/gradient to a fill/stroke
        getStrokeWidthReturns the current stroke-width value
        setStrokeWidthSets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead
        setStrokeAttrSet the given stroke-related attribute the given value for selected elements
        getOpacityReturns the current opacity
        setOpacitySets the given opacity to the current selected elements
        getOpacityReturns the current fill opacity
        getStrokeOpacityReturns the current stroke opacity
        setPaintOpacitySets the current fill/stroke opacity
        getBlurGets the stdDeviation blur value of the given element
        setBlurNoUndoSets the stdDeviation blur value on the selected element without being undoable
        setBlurOffsetsSets the x, y, with, height values of the filter element in order to make the blur not be clipped.
        setBlurAdds/updates the blur filter to the selected element
        getBoldCheck whether selected element is bold or not
        setBoldMake the selected element bold or normal
        getItalicCheck whether selected element is italic or not
        setItalicMake the selected element italic or normal
        getFontFamilyReturns the current font family
        setFontFamilySet the new font family
        getFontSizeReturns the current font size
        setFontSizeApplies the given font size to the selected element
        getTextReturns the current text (textContent) of the selected element
        setTextContentUpdates the text element with the given string
        setImageURLSets the new image URL for the selected image element.
        setRectRadiusSets the rx & ry values to the selected rect element to change its corner radius
        Element manipulation
        setSegTypeSets the new segment type to the selected segment(s).
        convertToPathConvert selected element to a path, or get the BBox of an element-as-path
        changeSelectedAttributeNoUndoThis function makes the changes to the elements.
        changeSelectedAttributeChange the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
        deleteSelectedElementsRemoves all selected elements from the DOM and adds the change to the history stack
        groupSelectedElementsWraps all the selected elements in a group (g) element
        ungroupSelectedElementUnwraps all the elements in a selected group (g) element.
        moveToTopSelectedElementRepositions the selected element to the bottom in the DOM to appear on top of other elements
        moveToBottomSelectedElementRepositions the selected element to the top in the DOM to appear under other elements
        moveSelectedElementsMoves selected elements on the X/Y axis
        cloneSelectedElementsCreate deep DOM copies (clones) of all selected elements and move them slightly from their originals
        alignSelectedElementsAligns selected elements
        Additional editor tools
        updateCanvasUpdates the editor canvas width/height/position after a zoom has occurred
        setBackgroundSet the background of the editor (NOT the actual document)
        cycleElementSelect the next/previous element within the current layer
        - -

        Utils.toXml

        Converts characters in a string to XML-friendly entities.

        Example: “&” becomes “&amp;”

        Parameters

        strThe string to be converted

        Returns

        The converted string

        - -

        Utils.fromXml

        Converts XML entities in a string to single characters.  Example: “&amp;” becomes “&”

        Parameters

        strThe string to be converted

        Returns

        The converted string

        - -

        Utils.encode64

        Converts a string to base64

        - -

        Utils.decode64

        Converts a string from base64

        - -

        Utils.convertToXMLReferences

        Converts a string to use XML references

        - -

        rectsIntersect

        "rectsIntersect": function(r1,
        r2)

        Check if two rectangles (BBoxes objects) intersect each other

        Paramaters

        r1The first BBox-like object
        r2The second BBox-like object

        Returns

        Boolean that’s true if rectangles intersect

        - -

        snapToAngle

        "snapToAngle": function(x1,
        y1,
        x2,
        y2)

        Returns a 45 degree angle coordinate associated with the two given coordinates

        Parameters

        x1First coordinate’s x value
        x2Second coordinate’s x value
        y1First coordinate’s y value
        y2Second coordinate’s y value

        Returns

        Object with the following values: x - The angle-snapped x value y - The angle-snapped y value snapangle - The angle at which to snap

        - -

        text2xml

        "text2xml": function(sXML)

        Cross-browser compatible method of converting a string to an XML tree found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f

        - -

        Unit conversion functions

        - -

        convertToNum

        convertToNum = function(attr,
        val)

        Converts given values to numbers.  Attributes must be supplied in case a percentage is given

        Parameters

        attrString with the name of the attribute associated with the value
        valString with the attribute value to convert
        - -

        setUnitAttr

        setUnitAttr = function(elem,
        attr,
        val)

        Sets an element’s attribute based on the unit in its current value.

        Parameters

        elemDOM element to be changed
        attrString with the name of the attribute associated with the value
        valString with the attribute value to convert
        - -

        isValidUnit

        canvas.isValidUnit = function(attr,
        val)

        Check if an attribute’s value is in a valid format

        Parameters

        attrString with the name of the attribute associated with the value
        valString with the attribute value to check
        - -

        Undo/Redo history management

        - -

        ChangeElementCommand

        var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
        attrs,
        text)

        History command to make a change to an element.  Usually an attribute change, but can also be textcontent.

        Parameters

        elemThe DOM element that was changed
        attrsAn object with the attributes to be changed and the values they had before the change
        textAn optional string visible to user related to this change
        - -

        ChangeElementCommand.apply

        Performs the stored change action

        - -

        ChangeElementCommand.unapply

        Reverses the stored change action

        - -

        ChangeElementCommand.elements

        Returns array with element associated with this command

        - -

        InsertElementCommand

        var InsertElementCommand = this.undoCmd.insertElement = function(elem,
        text)

        History command for an element that was added to the DOM

        Parameters

        elemThe newly added DOM element
        textAn optional string visible to user related to this change
        - -

        InsertElementCommand.apply

        Re-Inserts the new element

        - -

        InsertElementCommand.unapply

        Removes the element

        - -

        InsertElementCommand.elements

        Returns array with element associated with this command

        - -

        RemoveElementCommand

        var RemoveElementCommand = this.undoCmd.removeElement = function(elem,
        parent,
        text)

        History command for an element removed from the DOM

        Parameters

        elemThe removed DOM element
        parentThe DOM element’s parent
        textAn optional string visible to user related to this change
        - -

        RemoveElementCommand.apply

        Re-removes the new element

        - -

        RemoveElementCommand.unapply

        Re-adds the new element

        - -

        RemoveElementCommand.elements

        Returns array with element associated with this command

        - -

        MoveElementCommand

        var MoveElementCommand = this.undoCmd.moveElement = function(elem,
        oldNextSibling,
        oldParent,
        text)

        History command for an element that had its DOM position changed

        Parameters

        elemThe DOM element that was moved
        oldNextSiblingThe element’s next sibling before it was moved
        oldParentThe element’s parent before it was moved
        textAn optional string visible to user related to this change
        - -

        MoveElementCommand.unapply

        Re-positions the element

        - -

        MoveElementCommand.unapply

        Positions the element back to its original location

        - -

        MoveElementCommand.elements

        Returns array with element associated with this command

        - -

        BatchCommand

        var BatchCommand = this.undoCmd.batch = function(text)

        History command that can contain/execute multiple other commands

        Parameters

        textAn optional string visible to user related to this change
        - -

        BatchCommand.apply

        Runs “apply” on all subcommands

        - -

        BatchCommand.unapply

        Runs “unapply” on all subcommands

        - -

        BatchCommand.elements

        Iterate through all our subcommands and returns all the elements we are changing

        - -

        BatchCommand.addSubCommand

        Adds a given command to the history stack

        Parameters

        cmdThe undo command object to add
        - -

        BatchCommand.isEmpty

        Returns a boolean indicating whether or not the batch command is empty

        - -

        resetUndoStack

        resetUndoStack = function()

        Resets the undo stack, effectively clearing the undo/redo history

        - -

        undoMgr.getUndoStackSize

        Returns

        Integer with the current size of the undo history stack

        - -

        undoMgr.getRedoStackSize

        Returns

        Integer with the current size of the redo history stack

        - -

        undoMgr.getNextUndoCommandText

        Returns

        String associated with the next undo command

        - -

        undoMgr.getNextRedoCommandText

        Returns

        String associated with the next redo command

        - -

        undoMgr.undo

        Performs an undo step

        - -

        undoMgr.redo

        Performs a redo step

        - -

        addCommandToHistory

        addCommandToHistory = c.undoCmd.add = function(cmd)

        Adds a command object to the undo history stack

        Parameters

        cmdThe command object to add
        - -

        beginUndoableChange

        c.beginUndoableChange = function(attrName,
        elems)

        This function tells the canvas to remember the old values of the attrName attribute for each element sent in.  The elements and values are stored on a stack, so the next call to finishUndoableChange() will pop the elements and old values off the stack, gets the current values from the DOM and uses all of these to construct the undo-able command.

        Parameters

        attrNameThe name of the attribute being changed
        elemsArray of DOM elements being changed
        - -

        finishUndoableChange

        c.finishUndoableChange = function()

        This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.  The command can then be added to the command history

        Returns

        Batch command object with resulting changes

        - -

        Selector

        Private class for DOM element selection boxes

        Parameters

        idinteger to internally indentify the selector
        elemDOM element associated with this selector
        Summary
        Functions
        Selector.resetUsed to reset the id and element that the selector is attached to
        Selector.showGripsShow the resize grips of this selector
        Selector.updateGripCursorsUpdates cursors for corner grips on rotation so arrows point the right way
        Selector.resizeUpdates the selector to match the element’s size
        - -

        Functions

        - -

        Selector.reset

        Used to reset the id and element that the selector is attached to

        Parameters

        eDOM element associated with this selector
        - -

        Selector.showGrips

        Show the resize grips of this selector

        Parameters

        showboolean indicating whether grips should be shown or not
        - -

        Selector.updateGripCursors

        Updates cursors for corner grips on rotation so arrows point the right way

        Parameters

        angleFloat indicating current rotation angle in degrees
        - -

        Selector.resize

        Updates the selector to match the element’s size

        - -

        SelectorManager

        Public class to manage all selector objects (selection boxes)

        Summary
        SelectorManager.initGroupResets the parent selector group element
        SelectorManager.requestSelectorReturns the selector based on the given element
        SelectorManager.releaseSelectorRemoves the selector of the given element (hides selection box)
        SelectorManager.getRubberBandBoxReturns the rubberBandBox DOM element.
        Helper functions
        walkTreeWalks the tree and executes the callback on each element in a top-down fashion
        walkTreePostWalks the tree and executes the callback on each element in a depth-first fashion
        assignAttributesAssigns multiple attributes to an element.
        cleanupElementRemove unneeded (default) attributes, makes resulting SVG smaller
        addSvgElementFromJsonCreate a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
        addExtensionAdd an extension to the editor
        shortFloatRounds a given value to a float with number of digits defined in save_options
        getStrokedBBoxGet the bounding box for one or more stroked and/or transformed elements
        getVisibleElementsGet all elements that have a BBox (excludes <defs>, <title>, etc).
        copyElemCreate a clone of an element, updating its ID and its children’s IDs when needed
        getElemGet a DOM element by ID within the SVG root element.
        getIdReturns the last created DOM element ID string
        getNextIdCreates and returns a unique ID string for a DOM element
        bindAttaches a callback function to an event
        setIdPrefixChanges the ID prefix to the given value
        sanitizeSvgSanitizes the input node and its children It only keeps what is allowed from our whitelist defined above
        getUrlFromAttrExtracts the URL from the url(...)
        getBBoxGet the given/selected element’s bounding box object, convert it to be more usable when necessary
        ffCloneHack for Firefox bugs where text element features aren’t updated.
        getPathBBoxGet correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
        Element Transforms
        getRotationAngleGet the rotation angle of the given/selected DOM element
        setRotationAngleRemoves any old rotations if present, prepends a new rotation at the transformed center
        getTransformListReturns an object that behaves like a SVGTransformList for the given DOM element
        recalculateAllSelectedDimensionsRuns recalculateDimensions on the selected elements, adding the changes to a single batch command
        remapElementApplies coordinate changes to an element based on the given matrix
        recalculateDimensionsDecides the course of action based on the element’s transform list
        transformPointA (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)
        isIdentityHelper function to check if the matrix performs no actual transform (i.e.
        matrixMultiplyThis function tries to return a SVGMatrix that is the multiplication m1*m2.
        transformListToTransformThis returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments
        hasMatrixTransformSee if the given transformlist includes a non-indentity matrix transform
        getMatrixGet the matrix object for a given element
        transformBoxTransforms a rectangle based on the given matrix
        Selection
        clearSelectionClears the selection.
        addToSelectionAdds a list of elements to the selection.
        removeFromSelectionRemoves elements from the selection.
        selectAllInCurrentLayerClears the selection, then adds all elements in the current layer to the selection.
        smoothControlPointsTakes three points and creates a smoother line based on them
        getMouseTargetGets the desired element from a mouse event
        preventClickDefaultPrevents default browser click behaviour on the given element
        Text edit functionsFunctions relating to editing text elements
        Path edit functionsFunctions relating to editing path elements
        Serialization
        removeUnusedDefElemsLooks at DOM elements inside the <defs> to see if they are referred to, removes them from the DOM if they are not.
        svgCanvasToStringMain function to set up the SVG content for output
        svgToStringSub function ran on each SVG element to convert it to a string as desired
        embedImageConverts a given image file to a data URL when possible, then runs a given callback
        saveSerializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.
        rasterExportGenerates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found
        getSvgStringReturns the current drawing as raw SVG XML text.
        setSvgStringThis function sets the current drawing as the input SVG XML.
        importSvgStringThis function imports the input SVG XML into the current layer in the drawing
        Layers
        identifyLayersUpdates layer system
        createLayerCreates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
        deleteCurrentLayerDeletes the current layer from the drawing and then clears the selection.
        getNumLayersReturns the number of layers in the current drawing.
        getLayerReturns the name of the ith layer.
        getCurrentLayerReturns the name of the currently selected layer.
        setCurrentLayerSets the current layer.
        renameCurrentLayerRenames the current layer.
        setCurrentLayerPositionChanges the position of the current layer to the new value.
        getLayerVisibilityReturns whether the layer is visible.
        setLayerVisibilitySets the visibility of the layer.
        moveSelectedToLayerMoves the selected elements to layername.
        getLayerOpacityReturns the opacity of the given layer.
        setLayerOpacitySets the opacity of the given layer.
        Document functions
        clearClears the current document.
        linkControlPointsAlias function
        getContentElemReturns the content DOM element
        getRootElemReturns the root DOM element
        getSelectedElemsReturns the array with selected DOM elements
        getResolutionReturns the current dimensions and zoom level in an object
        getZoomReturns the current zoom level
        getVersionReturns a string which describes the revision number of SvgCanvas.
        setUiStringsUpdate interface strings with given values
        setConfigUpdate configuration options with given values
        getDocumentTitleReturns the current document title or an empty string if not found
        setDocumentTitleAdds/updates a title element for the document with the given name.
        getEditorNSReturns the editor’s namespace URL, optionally adds it to root element
        setResolutionChanges the document’s dimensions to the given size
        getOffsetReturns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.
        setBBoxZoomSets the zoom level on the canvas-side based on the given value
        setZoomSets the zoom to the given level
        getModeReturns the current editor mode string
        setModeSets the editor’s mode to the given string
        Element Styling
        getColorReturns the current fill/stroke option
        setColorChange the current stroke/fill color/gradient value
        findDefsReturn the document’s <defs> element, create it first if necessary
        setGradientApply the current gradient to selected element’s fill or stroke
        findDuplicateGradientCheck if exact gradient already exists
        setPaintSet a color/gradient to a fill/stroke
        getStrokeWidthReturns the current stroke-width value
        setStrokeWidthSets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead
        setStrokeAttrSet the given stroke-related attribute the given value for selected elements
        getOpacityReturns the current opacity
        setOpacitySets the given opacity to the current selected elements
        getOpacityReturns the current fill opacity
        getStrokeOpacityReturns the current stroke opacity
        setPaintOpacitySets the current fill/stroke opacity
        getBlurGets the stdDeviation blur value of the given element
        setBlurNoUndoSets the stdDeviation blur value on the selected element without being undoable
        setBlurOffsetsSets the x, y, with, height values of the filter element in order to make the blur not be clipped.
        setBlurAdds/updates the blur filter to the selected element
        getBoldCheck whether selected element is bold or not
        setBoldMake the selected element bold or normal
        getItalicCheck whether selected element is italic or not
        setItalicMake the selected element italic or normal
        getFontFamilyReturns the current font family
        setFontFamilySet the new font family
        getFontSizeReturns the current font size
        setFontSizeApplies the given font size to the selected element
        getTextReturns the current text (textContent) of the selected element
        setTextContentUpdates the text element with the given string
        setImageURLSets the new image URL for the selected image element.
        setRectRadiusSets the rx & ry values to the selected rect element to change its corner radius
        Element manipulation
        setSegTypeSets the new segment type to the selected segment(s).
        convertToPathConvert selected element to a path, or get the BBox of an element-as-path
        changeSelectedAttributeNoUndoThis function makes the changes to the elements.
        changeSelectedAttributeChange the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
        deleteSelectedElementsRemoves all selected elements from the DOM and adds the change to the history stack
        groupSelectedElementsWraps all the selected elements in a group (g) element
        ungroupSelectedElementUnwraps all the elements in a selected group (g) element.
        moveToTopSelectedElementRepositions the selected element to the bottom in the DOM to appear on top of other elements
        moveToBottomSelectedElementRepositions the selected element to the top in the DOM to appear under other elements
        moveSelectedElementsMoves selected elements on the X/Y axis
        cloneSelectedElementsCreate deep DOM copies (clones) of all selected elements and move them slightly from their originals
        alignSelectedElementsAligns selected elements
        Additional editor tools
        updateCanvasUpdates the editor canvas width/height/position after a zoom has occurred
        setBackgroundSet the background of the editor (NOT the actual document)
        cycleElementSelect the next/previous element within the current layer
        - -

        SelectorManager.initGroup

        Resets the parent selector group element

        - -

        SelectorManager.requestSelector

        Returns the selector based on the given element

        Parameters

        elemDOM element to get the selector for
        - -

        SelectorManager.releaseSelector

        Removes the selector of the given element (hides selection box)

        Parameters

        elemDOM element to remove the selector for
        - -

        SelectorManager.getRubberBandBox

        Returns the rubberBandBox DOM element.  This is the rectangle drawn by the user for selecting/zooming

        - -

        Helper functions

        - -

        walkTree

        function walkTree(elem,
        cbFn)

        Walks the tree and executes the callback on each element in a top-down fashion

        Parameters

        elemDOM element to traverse
        cbFnCallback function to run on each element
        - -

        walkTreePost

        function walkTreePost(elem,
        cbFn)

        Walks the tree and executes the callback on each element in a depth-first fashion

        Parameters

        elemDOM element to traverse
        cbFnCallback function to run on each element
        - -

        assignAttributes

        var assignAttributes = this.assignAttributes = function(node,
        attrs,
        suspendLength,
        unitCheck)

        Assigns multiple attributes to an element.

        Parameters

        nodeDOM element to apply new attribute values to
        attrsObject with attribute keys/values
        suspendLengthOptional integer of milliseconds to suspend redraw
        unitCheckBoolean to indicate the need to use setUnitAttr
        - -

        cleanupElement

        var cleanupElement = this.cleanupElement = function(element)

        Remove unneeded (default) attributes, makes resulting SVG smaller

        Parameters

        elementDOM element to clean up
        - -

        addSvgElementFromJson

        var addSvgElementFromJson = this.addSvgElementFromJson = function(data)

        Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned

        Parameters

        dataObject with the following keys/values:
        • element - DOM element to create
        • attr - Object with attributes/values to assign to the new element
        • curStyles - Boolean indicating that current style attributes should be applied first

        Returns: The new element

        - -

        addExtension

        this.addExtension = function(name,
        ext_func)

        Add an extension to the editor

        Parameters

        nameString with the ID of the extension
        ext_funcFunction supplied by the extension with its data
        - -

        shortFloat

        var shortFloat = function(val)

        Rounds a given value to a float with number of digits defined in save_options

        Parameters

        valThe value as a String, Number or Array of two numbers to be rounded

        Returns

        If a string/number was given, returns a Float.  If an array, return a string with comma-seperated floats

        - -

        getStrokedBBox

        var getStrokedBBox = this.getStrokedBBox = function(elems)

        Get the bounding box for one or more stroked and/or transformed elements

        Parameters

        elemsArray with DOM elements to check

        Returns

        A single bounding box object

        - -

        getVisibleElements

        var getVisibleElements = this.getVisibleElements = function(parent,
        includeBBox)

        Get all elements that have a BBox (excludes <defs>, <title>, etc).  Note that 0-opacity, off-screen etc elements are still considered “visible” for this function

        Parameters

        parentThe parent DOM element to search within
        includeBBoxBoolean to indicate that an object should return with the element and its bbox

        Returns

        An array with all “visible” elements, or if includeBBox is true, an array with objects that include:

        • elem - The element
        • bbox - The element’s BBox as retrieved from getStrokedBBox
        - -

        copyElem

        var copyElem = function(el)

        Create a clone of an element, updating its ID and its children’s IDs when needed

        Parameters

        elDOM element to clone

        Returns: The cloned element

        - -

        getElem

        function getElem(id)

        Get a DOM element by ID within the SVG root element.

        Parameters

        idString with the element’s new ID
        - -

        getId

        getId = c.getId = function()

        Returns the last created DOM element ID string

        - -

        getNextId

        getNextId = c.getNextId = function()

        Creates and returns a unique ID string for a DOM element

        - -

        bind

        c.bind = function(event,
        f)

        Attaches a callback function to an event

        Parameters

        eventString indicating the name of the event
        fThe callback function to bind to the event

        Return

        The previous event

        - -

        setIdPrefix

        c.setIdPrefix = function(p)

        Changes the ID prefix to the given value

        Parameters

        pString with the new prefix
        - -

        sanitizeSvg

        var sanitizeSvg = this.sanitizeSvg = function(node)

        Sanitizes the input node and its children It only keeps what is allowed from our whitelist defined above

        Parameters

        nodeThe DOM element to be checked, will also check its children
        - -

        getUrlFromAttr

        var getUrlFromAttr = this.getUrlFromAttr = function(attrVal)

        Extracts the URL from the url(...) syntax of some attributes.  Three variants:

        • <circle fill=”url(someFile.svg#foo)” />
        • <circle fill=”url(‘someFile.svg#foo’)” />
        • <circle fill=’url(“someFile.svg#foo”)’ />

        Parameters

        attrValThe attribute value as a string

        Returns

        String with just the URL, like someFile.svg#foo

        - -

        getBBox

        var getBBox = this.getBBox = function(elem)

        Get the given/selected element’s bounding box object, convert it to be more usable when necessary

        Parameters

        elemOptional DOM element to get the BBox for
        - -

        ffClone

        var ffClone = function(elem)

        Hack for Firefox bugs where text element features aren’t updated.  This function clones the element and re-selects it TODO: Test for this bug on load and add it to “support” object instead of browser sniffing

        Parameters

        elemThe (text) DOM element to clone
        - -

        getPathBBox

        var getPathBBox = function(path)

        Get correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html

        Parameters

        pathThe path DOM element to get the BBox for

        Returns

        A BBox-like object

        - -

        Element Transforms

        - -

        getRotationAngle

        var getRotationAngle = this.getRotationAngle = function(elem,
        to_rad)

        Get the rotation angle of the given/selected DOM element

        Parameters

        elemOptional DOM element to get the angle for
        to_radBoolean that when true returns the value in radians rather than degrees

        Returns

        Float with the angle in degrees or radians

        - -

        setRotationAngle

        this.setRotationAngle = function(val,
        preventUndo)

        Removes any old rotations if present, prepends a new rotation at the transformed center

        Parameters

        valThe new rotation angle in degrees
        preventUndoBoolean indicating whether the action should be undoable or not
        - -

        getTransformList

        var getTransformList = this.getTransformList = function(elem)

        Returns an object that behaves like a SVGTransformList for the given DOM element

        Parameters

        elemDOM element to get a transformlist from
        - -

        recalculateAllSelectedDimensions

        var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function()

        Runs recalculateDimensions on the selected elements, adding the changes to a single batch command

        - -

        remapElement

        var remapElement = this.remapElement = function(selected,
        changes,
        m)

        Applies coordinate changes to an element based on the given matrix

        Parameters

        selectedDOM element to be changed
        changesObject with changes to be remapped
        mMatrix object to use for remapping coordinates
        - -

        recalculateDimensions

        var recalculateDimensions = this.recalculateDimensions = function(selected)

        Decides the course of action based on the element’s transform list

        Parameters

        selectedThe DOM element to recalculate

        Returns

        Undo command object with the resulting change

        - -

        transformPoint

        var transformPoint = function(x,
        y,
        m)

        A (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)

        Parameters

        xFloat representing the x coordinate
        yFloat representing the y coordinate
        mMatrix object to transform the point with Returns a x,y object representing the transformed point
        - -

        isIdentity

        var isIdentity = function(m)

        Helper function to check if the matrix performs no actual transform (i.e. exists for identity purposes)

        Parameters

        mThe matrix object to check

        Returns

        Boolean indicating whether or not the matrix is 1,0,0,1,0,0

        - -

        matrixMultiply

        var matrixMultiply = this.matrixMultiply = function()

        This function tries to return a SVGMatrix that is the multiplication m1*m2.  We also round to zero when it’s near zero

        Parameters

        = 2 Matrix objects to multiply

        Returns

        The matrix object resulting from the calculation

        - -

        transformListToTransform

        var transformListToTransform = this.transformListToTransform = function(tlist,
        min,
        max)

        This returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments

        Parameters

        tlistThe transformlist object
        minOptional integer indicating start transform position
        maxOptional integer indicating end transform position

        Returns

        A single matrix transform object

        - -

        hasMatrixTransform

        var hasMatrixTransform = this.hasMatrixTransform = function(tlist)

        See if the given transformlist includes a non-indentity matrix transform

        Parameters

        tlistThe transformlist to check

        Returns

        Boolean on whether or not a matrix transform was found

        - -

        getMatrix

        var getMatrix = function(elem)

        Get the matrix object for a given element

        Parameters

        elemThe DOM element to check

        Returns

        The matrix object associated with the element’s transformlist

        - -

        transformBox

        var transformBox = this.transformBox = function(l,
        t,
        w,
        h,
        m)

        Transforms a rectangle based on the given matrix

        Parameters

        lFloat with the box’s left coordinate
        tFloat with the box’s top coordinate
        wFloat with the box width
        hFloat with the box height
        mMatrix object to transform the box by

        Returns

        An object with the following values:

        • tl - The top left coordinate (x,y object)
        • tr - The top right coordinate (x,y object)
        • bl - The bottom left coordinate (x,y object)
        • br - The bottom right coordinate (x,y object)
        • aabox - Object with the following values:
        • Float with the axis-aligned x coordinate
        • Float with the axis-aligned y coordinate
        • Float with the axis-aligned width coordinate
        • Float with the axis-aligned height coordinate
        - -

        Selection

        - -

        clearSelection

        var clearSelection = this.clearSelection = function(noCall)

        Clears the selection.  The ‘selected’ handler is then called.  Parameters: noCall - Optional boolean that when true does not call the “selected” handler

        - -

        addToSelection

        var addToSelection = this.addToSelection = function(elemsToAdd,
        showGrips)

        Adds a list of elements to the selection.  The ‘selected’ handler is then called.

        Parameters

        elemsToAddan array of DOM elements to add to the selection
        showGripsa boolean flag indicating whether the resize grips should be shown
        - -

        removeFromSelection

        var removeFromSelection = this.removeFromSelection = function(elemsToRemove)

        Removes elements from the selection.

        Parameters

        elemsToRemovean array of elements to remove from selection
        - -

        selectAllInCurrentLayer

        this.selectAllInCurrentLayer = function()

        Clears the selection, then adds all elements in the current layer to the selection.  This function then fires the selected event.

        - -

        smoothControlPoints

        var smoothControlPoints = this.smoothControlPoints = function(ct1,
        ct2,
        pt)

        Takes three points and creates a smoother line based on them

        Parameters

        ct1Object with x and y values (first control point)
        ct2Object with x and y values (second control point)
        ptObject with x and y values (third point)

        Returns

        Array of two “smoothed” point objects

        - -

        getMouseTarget

        var getMouseTarget = this.getMouseTarget = function(evt)

        Gets the desired element from a mouse event

        Parameters

        evtEvent object from the mouse event

        Returns

        DOM element we want

        - -

        preventClickDefault

        var preventClickDefault = function(img)

        Prevents default browser click behaviour on the given element

        Parameters

        imgThe DOM element to prevent the cilck on
        - -

        Text edit functions

        Functions relating to editing text elements

        - -

        Path edit functions

        Functions relating to editing path elements

        - -

        Serialization

        - -

        removeUnusedDefElems

        var removeUnusedDefElems = this.removeUnusedDefElems = function()

        Looks at DOM elements inside the <defs> to see if they are referred to, removes them from the DOM if they are not.

        Returns

        The amount of elements that were removed

        - -

        svgCanvasToString

        var svgCanvasToString = this.svgCanvasToString = function()

        Main function to set up the SVG content for output

        Returns

        String containing the SVG image for output

        - -

        svgToString

        var svgToString = this.svgToString = function(elem,
        indent)

        Sub function ran on each SVG element to convert it to a string as desired

        Parameters

        elemThe SVG element to convert
        indentInteger with the amount of spaces to indent this tag

        Returns

        String with the given element as an SVG tag

        - -

        embedImage

        this.embedImage = function(val,
        callback)

        Converts a given image file to a data URL when possible, then runs a given callback

        Parameters

        valString with the path/URL of the image
        callbackOptional function to run when image data is found, supplies the result (data URL or false) as first parameter.
        - -

        save

        this.save = function(opts)

        Serializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.  This function also includes the XML prolog.  Clients of the SvgCanvas bind their save function to the ‘saved’ event.

        Returns

        Nothing

        - -

        rasterExport

        this.rasterExport = function()

        Generates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found

        - -

        getSvgString

        this.getSvgString = function()

        Returns the current drawing as raw SVG XML text.

        Returns

        The current drawing as raw SVG XML text.

        - -

        setSvgString

        this.setSvgString = function(xmlString)

        This function sets the current drawing as the input SVG XML.

        Parameters

        xmlStringThe SVG as XML text.

        Returns

        This function returns false if the set was unsuccessful, true otherwise.

        - -

        importSvgString

        this.importSvgString = function(xmlString)

        This function imports the input SVG XML into the current layer in the drawing

        Parameters

        xmlStringThe SVG as XML text.

        Returns

        This function returns false if the import was unsuccessful, true otherwise.  TODO:

        • properly handle if namespace is introduced by imported content (must add to svgcontent and update all prefixes in the imported node)
        • properly handle recalculating dimensions, recalculateDimensions() doesn’t handle 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
        - -

        Layers

        - -

        identifyLayers

        var identifyLayers = function()

        Updates layer system

        - -

        createLayer

        this.createLayer = function(name)

        Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.  This is an undoable action.

        Parameters

        nameThe given name
        - -

        deleteCurrentLayer

        this.deleteCurrentLayer = function()

        Deletes the current layer from the drawing and then clears the selection.  This function then calls the ‘changed’ handler.  This is an undoable action.

        - -

        getNumLayers

        this.getNumLayers = function()

        Returns the number of layers in the current drawing.

        Returns

        The number of layers in the current drawing.

        - -

        getLayer

        this.getLayer = function(i)

        Returns the name of the ith layer.  If the index is out of range, an empty string is returned.

        Parameters

        ithe zero-based index of the layer you are querying.

        Returns

        The name of the ith layer

        - -

        getCurrentLayer

        this.getCurrentLayer = function()

        Returns the name of the currently selected layer.  If an error occurs, an empty string is returned.

        Returns

        The name of the currently active layer.

        - -

        setCurrentLayer

        this.setCurrentLayer = function(name)

        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 undo-able action.

        Parameters

        namethe name of the layer you want to switch to.

        Returns

        true if the current layer was switched, otherwise false

        - -

        renameCurrentLayer

        this.renameCurrentLayer = function(newname)

        Renames the current layer.  If the layer name is not valid (i.e. unique), then this function does nothing and returns false, otherwise it returns true.  This is an undo-able action.

        Parameters

        newnamethe new name you want to give the current layer.  This name must be unique among all layer names.

        Returns

        true if the rename succeeded, false otherwise.

        - -

        setCurrentLayerPosition

        this.setCurrentLayerPosition = function(newpos)

        Changes the position of the current layer to the new value.  If the new index is not valid, this function does nothing and returns false, otherwise it returns true.  This is an undo-able action.

        Parameters

        newposThe zero-based index of the new position of the layer.  This should be between
        0 and (number of layers1)

        Returns

        true if the current layer position was changed, false otherwise.

        - -

        getLayerVisibility

        this.getLayerVisibility = function(layername)

        Returns whether the layer is visible.  If the layer name is not valid, then this function returns false.

        Parameters

        layernamethe name of the layer which you want to query.

        Returns

        The visibility state of the layer, or false if the layer name was invalid.

        - -

        setLayerVisibility

        this.setLayerVisibility = function(layername,
        bVisible)

        Sets the visibility of the layer.  If the layer name is not valid, this function return false, otherwise it returns true.  This is an undo-able action.

        Parameters

        layernamethe name of the layer to change the visibility
        bVisibletrue/false, whether the layer should be visible

        Returns

        true if the layer’s visibility was set, false otherwise

        - -

        moveSelectedToLayer

        this.moveSelectedToLayer = function(layername)

        Moves the selected elements to layername.  If the name is not a valid layer name, then false is returned.  Otherwise it returns true.  This is an undo-able action.

        Parameters

        layernamethe name of the layer you want to which you want to move the selected elements

        Returns

        true if the selected elements were moved to the layer, false otherwise.

        - -

        getLayerOpacity

        this.getLayerOpacity = function(layername)

        Returns the opacity of the given layer.  If the input name is not a layer, null is returned.

        Parameters

        layernamename of the layer on which to get the opacity

        Returns

        The opacity value of the given layer.  This will be a value between 0.0 and 1.0, or null if layername is not a valid layer

        - -

        setLayerOpacity

        this.setLayerOpacity = function(layername,
        opacity)

        Sets the opacity of the given layer.  If the input name is not a layer, nothing happens.  This is not an undo-able action.  NOTE: this function exists solely to apply a highlighting/de-emphasis effect to a layer, when it is possible for a user to affect the opacity of a layer, we will need to allow this function to produce an undo-able action.  If opacity is not a value between 0.0 and 1.0, then nothing happens.

        Parameters

        layernamename of the layer on which to set the opacity
        opacitya float value in the range 0.0-1.0
        - -

        Document functions

        - -

        clear

        this.clear = function()

        Clears the current document.  This is not an undoable action.

        - -

        linkControlPoints

        Alias function

        - -

        getContentElem

        this.getContentElem = function()

        Returns the content DOM element

        - -

        getRootElem

        this.getRootElem = function()

        Returns the root DOM element

        - -

        getSelectedElems

        this.getSelectedElems = function()

        Returns the array with selected DOM elements

        - -

        getResolution

        var getResolution = this.getResolution = function()

        Returns the current dimensions and zoom level in an object

        - -

        getZoom

        this.getZoom = function()

        Returns the current zoom level

        - -

        getVersion

        this.getVersion = function()

        Returns a string which describes the revision number of SvgCanvas.

        - -

        setUiStrings

        this.setUiStrings = function(strs)

        Update interface strings with given values

        Parameters

        strsObject with strings (see uiStrings for examples)
        - -

        setConfig

        this.setConfig = function(opts)

        Update configuration options with given values

        Parameters

        optsObject with options (see curConfig for examples)
        - -

        getDocumentTitle

        this.getDocumentTitle = function()

        Returns the current document title or an empty string if not found

        - -

        setDocumentTitle

        this.setDocumentTitle = function(newtitle)

        Adds/updates a title element for the document with the given name.  This is an undoable action

        Parameters

        newtitleString with the new title
        - -

        getEditorNS

        this.getEditorNS = function(add)

        Returns the editor’s namespace URL, optionally adds it to root element

        Parameters

        addBoolean to indicate whether or not to add the namespace value
        - -

        setResolution

        this.setResolution = function(x,
        y)

        Changes the document’s dimensions to the given size

        Parameters

        xNumber with the width of the new dimensions in user units.  Can also be the string “fit” to indicate “fit to content”
        yNumber with the height of the new dimensions in user units.

        Returns

        Boolean to indicate if resolution change was succesful.  It will fail on “fit to content” option with no content to fit to.

        - -

        getOffset

        this.getOffset = function()

        Returns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.

        - -

        setBBoxZoom

        this.setBBoxZoom = function(val,
        editor_w,
        editor_h)

        Sets the zoom level on the canvas-side based on the given value

        Parameters

        valBounding box object to zoom to or string indicating zoom option
        editor_wInteger with the editor’s workarea box’s width
        editor_hInteger with the editor’s workarea box’s height
        - -

        setZoom

        this.setZoom = function(zoomlevel)

        Sets the zoom to the given level

        Parameters

        zoomlevelFloat indicating the zoom level to change to
        - -

        getMode

        this.getMode = function()

        Returns the current editor mode string

        - -

        setMode

        this.setMode = function(name)

        Sets the editor’s mode to the given string

        Parameters

        nameString with the new mode to change to
        - -

        Element Styling

        - -

        getColor

        this.getColor = function(type)

        Returns the current fill/stroke option

        - -

        setColor

        this.setColor = function(type,
        val,
        preventUndo)

        Change the current stroke/fill color/gradient value

        Parameters

        typeString indicating fill or stroke
        valThe value to set the stroke attribute to
        preventUndoBoolean indicating whether or not this should be and undoable option
        - -

        findDefs

        var findDefs = function()

        Return the document’s <defs> element, create it first if necessary

        - -

        setGradient

        var setGradient = this.setGradient = function(type)

        Apply the current gradient to selected element’s fill or stroke

        Parameters type - String indicating “fill” or “stroke” to apply to an element

        - -

        findDuplicateGradient

        var findDuplicateGradient = function(grad)

        Check if exact gradient already exists

        Parameters

        gradThe gradient DOM element to compare to others

        Returns

        The existing gradient if found, null if not

        - -

        setPaint

        this.setPaint = function(type,
        paint)

        Set a color/gradient to a fill/stroke

        Parameters

        typeString with “fill” or “stroke”
        paintThe jGraduate paint object to apply
        - -

        getStrokeWidth

        this.getStrokeWidth = function()

        Returns the current stroke-width value

        - -

        setStrokeWidth

        this.setStrokeWidth = function(val)

        Sets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead

        Parameters

        valA Float indicating the new stroke width value
        - -

        setStrokeAttr

        this.setStrokeAttr = function(attr,
        val)

        Set the given stroke-related attribute the given value for selected elements

        Parameters

        attrString with the attribute name
        valString or number with the attribute value
        - -

        getOpacity

        this.getOpacity = function()

        Returns the current opacity

        - -

        setOpacity

        this.setOpacity = function(val)

        Sets the given opacity to the current selected elements

        - -

        getOpacity

        Returns the current fill opacity

        - -

        getStrokeOpacity

        this.getStrokeOpacity = function()

        Returns the current stroke opacity

        - -

        setPaintOpacity

        this.setPaintOpacity = function(type,
        val,
        preventUndo)

        Sets the current fill/stroke opacity

        Parameters

        typeString with “fill” or “stroke”
        valFloat with the new opacity value
        preventUndoBoolean indicating whether or not this should be an undoable action
        - -

        getBlur

        this.getBlur = function(elem)

        Gets the stdDeviation blur value of the given element

        Parameters

        elemThe element to check the blur value for
        - -

        setBlurNoUndo

        canvas.setBlurNoUndo = function(val)

        Sets the stdDeviation blur value on the selected element without being undoable

        Parameters

        valThe new stdDeviation value
        - -

        setBlurOffsets

        canvas.setBlurOffsets = function(filter,
        stdDev)

        Sets the x, y, with, height values of the filter element in order to make the blur not be clipped.  Removes them if not neeeded

        Parameters

        filterThe filter DOM element to update
        stdDevThe standard deviation value on which to base the offset size
        - -

        setBlur

        canvas.setBlur = function(val,
        complete)

        Adds/updates the blur filter to the selected element

        Parameters

        valFloat with the new stdDeviation blur value
        completeBoolean indicating whether or not the action should be completed (to add to the undo manager)
        - -

        getBold

        this.getBold = function()

        Check whether selected element is bold or not

        Returns

        Boolean indicating whether or not element is bold

        - -

        setBold

        this.setBold = function(b)

        Make the selected element bold or normal

        Parameters

        bBoolean indicating bold (true) or normal (false)
        - -

        getItalic

        this.getItalic = function()

        Check whether selected element is italic or not

        Returns

        Boolean indicating whether or not element is italic

        - -

        setItalic

        this.setItalic = function(i)

        Make the selected element italic or normal

        Parameters

        bBoolean indicating italic (true) or normal (false)
        - -

        getFontFamily

        this.getFontFamily = function()

        Returns the current font family

        - -

        setFontFamily

        this.setFontFamily = function(val)

        Set the new font family

        Parameters

        valString with the new font family
        - -

        getFontSize

        this.getFontSize = function()

        Returns the current font size

        - -

        setFontSize

        this.setFontSize = function(val)

        Applies the given font size to the selected element

        Parameters

        valFloat with the new font size
        - -

        getText

        this.getText = function()

        Returns the current text (textContent) of the selected element

        - -

        setTextContent

        this.setTextContent = function(val)

        Updates the text element with the given string

        Parameters

        valString with the new text
        - -

        setImageURL

        this.setImageURL = function(val)

        Sets the new image URL for the selected image element.  Updates its size if a new URL is given

        Parameters

        valString with the image URL/path
        - -

        setRectRadius

        this.setRectRadius = function(val)

        Sets the rx & ry values to the selected rect element to change its corner radius

        Parameters

        valThe new radius
        - -

        Element manipulation

        - -

        setSegType

        this.setSegType = function(new_type)

        Sets the new segment type to the selected segment(s).

        Parameters

        new_typeInteger with the new segment type See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list
        - -

        convertToPath

        this.convertToPath = function(elem,
        getBBox)

        Convert selected element to a path, or get the BBox of an element-as-path

        Parameters

        elemThe DOM element to be converted
        getBBoxBoolean on whether or not to only return the path’s BBox

        Returns

        If the getBBox flag is true, the resulting path’s bounding box object.  Otherwise the resulting path element is returned.

        - -

        changeSelectedAttributeNoUndo

        var changeSelectedAttributeNoUndo = function(attr,
        newValue,
        elems)

        This function makes the changes to the elements.  It does not add the change to the history stack.

        Parameters

        attrString with the attribute name
        newValueString or number with the new attribute value
        elemsThe DOM elements to apply the change to
        - -

        changeSelectedAttribute

        var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
        val,
        elems)

        Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.  If you want to change only a subset of selectedElements, then send the subset to this function in the elems argument.

        Parameters

        attrString with the attribute name
        newValueString or number with the new attribute value
        elemsThe DOM elements to apply the change to
        - -

        deleteSelectedElements

        this.deleteSelectedElements = function()

        Removes all selected elements from the DOM and adds the change to the history stack

        - -

        groupSelectedElements

        this.groupSelectedElements = function()

        Wraps all the selected elements in a group (g) element

        - -

        ungroupSelectedElement

        this.ungroupSelectedElement = function()

        Unwraps all the elements in a selected group (g) element.  This requires significant recalculations to apply group’s transforms, etc to its children

        - -

        moveToTopSelectedElement

        this.moveToTopSelectedElement = function()

        Repositions the selected element to the bottom in the DOM to appear on top of other elements

        - -

        moveToBottomSelectedElement

        this.moveToBottomSelectedElement = function()

        Repositions the selected element to the top in the DOM to appear under other elements

        - -

        moveSelectedElements

        this.moveSelectedElements = function(dx,
        dy,
        undoable)

        Moves selected elements on the X/Y axis

        Parameters

        dxFloat with the distance to move on the x-axis
        dyFloat with the distance to move on the y-axis
        undoableBoolean indicating whether or not the action should be undoable

        Returns

        Batch command for the move

        - -

        cloneSelectedElements

        this.cloneSelectedElements = function()

        Create deep DOM copies (clones) of all selected elements and move them slightly from their originals

        - -

        alignSelectedElements

        this.alignSelectedElements = function(type,
        relative_to)

        Aligns selected elements

        Parameters

        typeString with single character indicating the alignment type
        relative_toString that must be one of the following: “selected”, “largest”, “smallest”, “page”
        - -

        Additional editor tools

        - -

        updateCanvas

        this.updateCanvas = function(w,
        h)

        Updates the editor canvas width/height/position after a zoom has occurred

        Parameters

        wFloat with the new width
        hFloat with the new height

        Returns

        Object with the following values:

        • x - The canvas’ new x coordinate
        • y - The canvas’ new y coordinate
        • old_x - The canvas’ old x coordinate
        • old_y - The canvas’ old y coordinate
        • d_x - The x position difference
        • d_y - The y position difference
        - -

        setBackground

        this.setBackground = function(color,
        url)

        Set the background of the editor (NOT the actual document)

        Parameters

        colorString with fill color to apply
        urlURL or path to image to use
        - -

        cycleElement

        this.cycleElement = function(next)

        Select the next/previous element within the current layer

        Parameters

        nextBoolean where true = next and false = previous element
        - -
        - - - - - - - - - - -
        "rectsIntersect": function(r1,
        r2)
        Check if two rectangles (BBoxes objects) intersect each other
        "snapToAngle": function(x1,
        y1,
        x2,
        y2)
        Returns a 45 degree angle coordinate associated with the two given coordinates
        "text2xml": function(sXML)
        Cross-browser compatible method of converting a string to an XML tree found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f
        convertToNum = function(attr,
        val)
        Converts given values to numbers.
        setUnitAttr = function(elem,
        attr,
        val)
        Sets an element’s attribute based on the unit in its current value.
        canvas.isValidUnit = function(attr,
        val)
        Check if an attribute’s value is in a valid format
        var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
        attrs,
        text)
        History command to make a change to an element.
        var InsertElementCommand = this.undoCmd.insertElement = function(elem,
        text)
        History command for an element that was added to the DOM
        var RemoveElementCommand = this.undoCmd.removeElement = function(elem,
        parent,
        text)
        History command for an element removed from the DOM
        var MoveElementCommand = this.undoCmd.moveElement = function(elem,
        oldNextSibling,
        oldParent,
        text)
        History command for an element that had its DOM position changed
        var BatchCommand = this.undoCmd.batch = function(text)
        History command that can contain/execute multiple other commands
        resetUndoStack = function()
        Resets the undo stack, effectively clearing the undo/redo history
        addCommandToHistory = c.undoCmd.add = function(cmd)
        Adds a command object to the undo history stack
        c.beginUndoableChange = function(attrName,
        elems)
        This function tells the canvas to remember the old values of the attrName attribute for each element sent in.
        c.finishUndoableChange = function()
        This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
        function walkTree(elem,
        cbFn)
        Walks the tree and executes the callback on each element in a top-down fashion
        function walkTreePost(elem,
        cbFn)
        Walks the tree and executes the callback on each element in a depth-first fashion
        var assignAttributes = this.assignAttributes = function(node,
        attrs,
        suspendLength,
        unitCheck)
        Assigns multiple attributes to an element.
        var cleanupElement = this.cleanupElement = function(element)
        Remove unneeded (default) attributes, makes resulting SVG smaller
        var addSvgElementFromJson = this.addSvgElementFromJson = function(data)
        Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
        this.addExtension = function(name,
        ext_func)
        Add an extension to the editor
        var shortFloat = function(val)
        Rounds a given value to a float with number of digits defined in save_options
        var getStrokedBBox = this.getStrokedBBox = function(elems)
        Get the bounding box for one or more stroked and/or transformed elements
        var getVisibleElements = this.getVisibleElements = function(parent,
        includeBBox)
        Get all elements that have a BBox (excludes defs, title, etc).
        var copyElem = function(el)
        Create a clone of an element, updating its ID and its children’s IDs when needed
        function getElem(id)
        Get a DOM element by ID within the SVG root element.
        getId = c.getId = function()
        Returns the last created DOM element ID string
        getNextId = c.getNextId = function()
        Creates and returns a unique ID string for a DOM element
        c.bind = function(event,
        f)
        Attaches a callback function to an event
        c.setIdPrefix = function(p)
        Changes the ID prefix to the given value
        var sanitizeSvg = this.sanitizeSvg = function(node)
        Sanitizes the input node and its children It only keeps what is allowed from our whitelist defined above
        var getUrlFromAttr = this.getUrlFromAttr = function(attrVal)
        Extracts the URL from the url(...)
        var getBBox = this.getBBox = function(elem)
        Get the given/selected element’s bounding box object, convert it to be more usable when necessary
        var ffClone = function(elem)
        Hack for Firefox bugs where text element features aren’t updated.
        var getPathBBox = function(path)
        Get correct BBox for a path in Webkit Converted from code found here: http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html
        var getRotationAngle = this.getRotationAngle = function(elem,
        to_rad)
        Get the rotation angle of the given/selected DOM element
        this.setRotationAngle = function(val,
        preventUndo)
        Removes any old rotations if present, prepends a new rotation at the transformed center
        var getTransformList = this.getTransformList = function(elem)
        Returns an object that behaves like a SVGTransformList for the given DOM element
        var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function()
        Runs recalculateDimensions on the selected elements, adding the changes to a single batch command
        var remapElement = this.remapElement = function(selected,
        changes,
        m)
        Applies coordinate changes to an element based on the given matrix
        var recalculateDimensions = this.recalculateDimensions = function(selected)
        Decides the course of action based on the element’s transform list
        var transformPoint = function(x,
        y,
        m)
        A (hopefully) quicker function to transform a point by a matrix (this function avoids any DOM calls and just does the math)
        var isIdentity = function(m)
        Helper function to check if the matrix performs no actual transform (i.e.
        var matrixMultiply = this.matrixMultiply = function()
        This function tries to return a SVGMatrix that is the multiplication m1*m2.
        var transformListToTransform = this.transformListToTransform = function(tlist,
        min,
        max)
        This returns a single matrix Transform for a given Transform List (this is the equivalent of SVGTransformList.consolidate() but unlike that method, this one does not modify the actual SVGTransformList) This function is very liberal with its min,max arguments
        var hasMatrixTransform = this.hasMatrixTransform = function(tlist)
        See if the given transformlist includes a non-indentity matrix transform
        var getMatrix = function(elem)
        Get the matrix object for a given element
        var transformBox = this.transformBox = function(l,
        t,
        w,
        h,
        m)
        Transforms a rectangle based on the given matrix
        var clearSelection = this.clearSelection = function(noCall)
        Clears the selection.
        var addToSelection = this.addToSelection = function(elemsToAdd,
        showGrips)
        Adds a list of elements to the selection.
        var removeFromSelection = this.removeFromSelection = function(elemsToRemove)
        Removes elements from the selection.
        this.selectAllInCurrentLayer = function()
        Clears the selection, then adds all elements in the current layer to the selection.
        var smoothControlPoints = this.smoothControlPoints = function(ct1,
        ct2,
        pt)
        Takes three points and creates a smoother line based on them
        var getMouseTarget = this.getMouseTarget = function(evt)
        Gets the desired element from a mouse event
        var preventClickDefault = function(img)
        Prevents default browser click behaviour on the given element
        var removeUnusedDefElems = this.removeUnusedDefElems = function()
        Looks at DOM elements inside the defs to see if they are referred to, removes them from the DOM if they are not.
        var svgCanvasToString = this.svgCanvasToString = function()
        Main function to set up the SVG content for output
        var svgToString = this.svgToString = function(elem,
        indent)
        Sub function ran on each SVG element to convert it to a string as desired
        this.embedImage = function(val,
        callback)
        Converts a given image file to a data URL when possible, then runs a given callback
        this.save = function(opts)
        Serializes the current drawing into SVG XML text and returns it to the ‘saved’ handler.
        this.rasterExport = function()
        Generates a PNG Data URL based on the current image, then calls “exported” with an object including the string and any issues found
        this.getSvgString = function()
        Returns the current drawing as raw SVG XML text.
        this.setSvgString = function(xmlString)
        This function sets the current drawing as the input SVG XML.
        this.importSvgString = function(xmlString)
        This function imports the input SVG XML into the current layer in the drawing
        var identifyLayers = function()
        Updates layer system
        this.createLayer = function(name)
        Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
        this.deleteCurrentLayer = function()
        Deletes the current layer from the drawing and then clears the selection.
        this.getNumLayers = function()
        Returns the number of layers in the current drawing.
        this.getLayer = function(i)
        Returns the name of the ith layer.
        this.getCurrentLayer = function()
        Returns the name of the currently selected layer.
        this.setCurrentLayer = function(name)
        Sets the current layer.
        this.renameCurrentLayer = function(newname)
        Renames the current layer.
        this.setCurrentLayerPosition = function(newpos)
        Changes the position of the current layer to the new value.
        this.getLayerVisibility = function(layername)
        Returns whether the layer is visible.
        this.setLayerVisibility = function(layername,
        bVisible)
        Sets the visibility of the layer.
        this.moveSelectedToLayer = function(layername)
        Moves the selected elements to layername.
        this.getLayerOpacity = function(layername)
        Returns the opacity of the given layer.
        this.setLayerOpacity = function(layername,
        opacity)
        Sets the opacity of the given layer.
        this.clear = function()
        Clears the current document.
        this.getContentElem = function()
        Returns the content DOM element
        this.getRootElem = function()
        Returns the root DOM element
        this.getSelectedElems = function()
        Returns the array with selected DOM elements
        var getResolution = this.getResolution = function()
        Returns the current dimensions and zoom level in an object
        this.getZoom = function()
        Returns the current zoom level
        this.getVersion = function()
        Returns a string which describes the revision number of SvgCanvas.
        this.setUiStrings = function(strs)
        Update interface strings with given values
        this.setConfig = function(opts)
        Update configuration options with given values
        this.getDocumentTitle = function()
        Returns the current document title or an empty string if not found
        this.setDocumentTitle = function(newtitle)
        Adds/updates a title element for the document with the given name.
        this.getEditorNS = function(add)
        Returns the editor’s namespace URL, optionally adds it to root element
        this.setResolution = function(x,
        y)
        Changes the document’s dimensions to the given size
        this.getOffset = function()
        Returns an object with x, y values indicating the svgcontent element’s position in the editor’s canvas.
        this.setBBoxZoom = function(val,
        editor_w,
        editor_h)
        Sets the zoom level on the canvas-side based on the given value
        this.setZoom = function(zoomlevel)
        Sets the zoom to the given level
        this.getMode = function()
        Returns the current editor mode string
        this.setMode = function(name)
        Sets the editor’s mode to the given string
        this.getColor = function(type)
        Returns the current fill/stroke option
        this.setColor = function(type,
        val,
        preventUndo)
        Change the current stroke/fill color/gradient value
        var findDefs = function()
        Return the document’s defs element, create it first if necessary
        var setGradient = this.setGradient = function(type)
        Apply the current gradient to selected element’s fill or stroke
        var findDuplicateGradient = function(grad)
        Check if exact gradient already exists
        this.setPaint = function(type,
        paint)
        Set a color/gradient to a fill/stroke
        this.getStrokeWidth = function()
        Returns the current stroke-width value
        this.setStrokeWidth = function(val)
        Sets the stroke width for the current selected elements When attempting to set a line’s width to 0, this changes it to 1 instead
        this.setStrokeAttr = function(attr,
        val)
        Set the given stroke-related attribute the given value for selected elements
        this.getOpacity = function()
        Returns the current opacity
        this.setOpacity = function(val)
        Sets the given opacity to the current selected elements
        this.getStrokeOpacity = function()
        Returns the current stroke opacity
        this.setPaintOpacity = function(type,
        val,
        preventUndo)
        Sets the current fill/stroke opacity
        this.getBlur = function(elem)
        Gets the stdDeviation blur value of the given element
        canvas.setBlurNoUndo = function(val)
        Sets the stdDeviation blur value on the selected element without being undoable
        canvas.setBlurOffsets = function(filter,
        stdDev)
        Sets the x, y, with, height values of the filter element in order to make the blur not be clipped.
        canvas.setBlur = function(val,
        complete)
        Adds/updates the blur filter to the selected element
        this.getBold = function()
        Check whether selected element is bold or not
        this.setBold = function(b)
        Make the selected element bold or normal
        this.getItalic = function()
        Check whether selected element is italic or not
        this.setItalic = function(i)
        Make the selected element italic or normal
        this.getFontFamily = function()
        Returns the current font family
        this.setFontFamily = function(val)
        Set the new font family
        this.getFontSize = function()
        Returns the current font size
        this.setFontSize = function(val)
        Applies the given font size to the selected element
        this.getText = function()
        Returns the current text (textContent) of the selected element
        this.setTextContent = function(val)
        Updates the text element with the given string
        this.setImageURL = function(val)
        Sets the new image URL for the selected image element.
        this.setRectRadius = function(val)
        Sets the rx & ry values to the selected rect element to change its corner radius
        this.setSegType = function(new_type)
        Sets the new segment type to the selected segment(s).
        this.convertToPath = function(elem,
        getBBox)
        Convert selected element to a path, or get the BBox of an element-as-path
        var changeSelectedAttributeNoUndo = function(attr,
        newValue,
        elems)
        This function makes the changes to the elements.
        var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
        val,
        elems)
        Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
        this.deleteSelectedElements = function()
        Removes all selected elements from the DOM and adds the change to the history stack
        this.groupSelectedElements = function()
        Wraps all the selected elements in a group (g) element
        this.ungroupSelectedElement = function()
        Unwraps all the elements in a selected group (g) element.
        this.moveToTopSelectedElement = function()
        Repositions the selected element to the bottom in the DOM to appear on top of other elements
        this.moveToBottomSelectedElement = function()
        Repositions the selected element to the top in the DOM to appear under other elements
        this.moveSelectedElements = function(dx,
        dy,
        undoable)
        Moves selected elements on the X/Y axis
        this.cloneSelectedElements = function()
        Create deep DOM copies (clones) of all selected elements and move them slightly from their originals
        this.alignSelectedElements = function(type,
        relative_to)
        Aligns selected elements
        this.updateCanvas = function(w,
        h)
        Updates the editor canvas width/height/position after a zoom has occurred
        this.setBackground = function(color,
        url)
        Set the background of the editor (NOT the actual document)
        this.cycleElement = function(next)
        Select the next/previous element within the current layer
        - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/index.html b/build/svg-edit-2.6-src/docs/index.html deleted file mode 100644 index 635c317..0000000 --- a/build/svg-edit-2.6-src/docs/index.html +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/index/Files.html b/build/svg-edit-2.6-src/docs/index/Files.html deleted file mode 100644 index 9ebbb55..0000000 --- a/build/svg-edit-2.6-src/docs/index/Files.html +++ /dev/null @@ -1,37 +0,0 @@ - - -File Index - - - - - - - - - -
        File Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        M
         my_svgcanvas.js
        S
         svgcanvas-latest copy.js
         svgcanvas-mine.js
         svgcanvas-textanchor-experiment.js
         svgcanvas.js
         svgcanvas_subpaths.js
         svgcanvas_temp.js
        - - - - - - - -
        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/index/Functions.html b/build/svg-edit-2.6-src/docs/index/Functions.html deleted file mode 100644 index 9c282c2..0000000 --- a/build/svg-edit-2.6-src/docs/index/Functions.html +++ /dev/null @@ -1,53 +0,0 @@ - - -Function Index - - - - - - - - - -
        Function Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        A
         addCommandToHistory, SvgCanvas
         addExtension, SelectorManager
         addSubCommand, SvgCanvas.BatchCommand
         addSvgElementFromJson, SelectorManager
         addToSelection, SelectorManager
         alignSelectedElements, SelectorManager
         apply
         assignAttributes, SelectorManager
        B
         BatchCommand, SvgCanvas
         beginUndoableChange, SvgCanvas
         bind, SelectorManager
        C
         ChangeElementCommand, SvgCanvas
         changeSelectedAttribute, SelectorManager
         changeSelectedAttributeNoUndo, SelectorManager
         cleanupElement, SelectorManager
         clear, SelectorManager
         clearSelection, SelectorManager
         cloneSelectedElements, SelectorManager
         convertToNum, SvgCanvas
         convertToPath, SelectorManager
         convertToXMLReferences, SvgCanvas.Utils
         copyElem, SelectorManager
         createLayer, SelectorManager
         cycleElement, SelectorManager
        D
         decode64, SvgCanvas.Utils
         deleteCurrentLayer, SelectorManager
         deleteSelectedElements, SelectorManager
        E
         elements
         embedImage, SelectorManager
         encode64, SvgCanvas.Utils
        F
         ffClone, SelectorManager
         findDefs, SelectorManager
         findDuplicateGradient, SelectorManager
         finishUndoableChange, SvgCanvas
         fromXml, SvgCanvas.Utils
        - -
        addCommandToHistory = c.undoCmd.add = function(cmd)
        Adds a command object to the undo history stack
        this.addExtension = function(name,
        ext_func)
        Add an extension to the editor
        Adds a given command to the history stack
        var addSvgElementFromJson = this.addSvgElementFromJson = function(data)
        Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
        var addToSelection = this.addToSelection = function(elemsToAdd,
        showGrips)
        Adds a list of elements to the selection.
        this.alignSelectedElements = function(type,
        relative_to)
        Aligns selected elements
        Runs “apply” on all subcommands
        Performs the stored change action
        Re-Inserts the new element
        Re-removes the new element
        var assignAttributes = this.assignAttributes = function(node,
        attrs,
        suspendLength,
        unitCheck)
        Assigns multiple attributes to an element.
        - - - -
        var BatchCommand = this.undoCmd.batch = function(text)
        History command that can contain/execute multiple other commands
        c.beginUndoableChange = function(attrName,
        elems)
        This function tells the canvas to remember the old values of the attrName attribute for each element sent in.
        c.bind = function(event,
        f)
        Attaches a callback function to an event
        - - - -
        var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
        attrs,
        text)
        History command to make a change to an element.
        var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
        val,
        elems)
        Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
        var changeSelectedAttributeNoUndo = function(attr,
        newValue,
        elems)
        This function makes the changes to the elements.
        var cleanupElement = this.cleanupElement = function(element)
        Remove unneeded (default) attributes, makes resulting SVG smaller
        this.clear = function()
        Clears the current document.
        var clearSelection = this.clearSelection = function(noCall)
        Clears the selection.
        this.cloneSelectedElements = function()
        Create deep DOM copies (clones) of all selected elements and move them slightly from their originals
        convertToNum = function(attr,
        val)
        Converts given values to numbers.
        this.convertToPath = function(elem,
        getBBox)
        Convert selected element to a path, or get the BBox of an element-as-path
        Converts a string to use XML references
        var copyElem = function(el)
        Create a clone of an element, updating its ID and its children’s IDs when needed
        this.createLayer = function(name)
        Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
        this.cycleElement = function(next)
        Select the next/previous element within the current layer
        - - - -
        Converts a string from base64
        this.deleteCurrentLayer = function()
        Deletes the current layer from the drawing and then clears the selection.
        this.deleteSelectedElements = function()
        Removes all selected elements from the DOM and adds the change to the history stack
        - - - -
        Iterate through all our subcommands and returns all the elements we are changing
        Returns array with element associated with this command
        Returns array with element associated with this command
        Returns array with element associated with this command
        Returns array with element associated with this command
        this.embedImage = function(val,
        callback)
        Converts a given image file to a data URL when possible, then runs a given callback
        Converts a string to base64
        - - - -
        var ffClone = function(elem)
        Hack for Firefox bugs where text element features aren’t updated.
        var findDefs = function()
        Return the document’s defs element, create it first if necessary
        var findDuplicateGradient = function(grad)
        Check if exact gradient already exists
        c.finishUndoableChange = function()
        This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
        Converts XML entities in a string to single characters.
        - -
        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/index/General.html b/build/svg-edit-2.6-src/docs/index/General.html deleted file mode 100644 index 69d5a0b..0000000 --- a/build/svg-edit-2.6-src/docs/index/General.html +++ /dev/null @@ -1,53 +0,0 @@ - - -Index - - - - - - - - - -
        Index
        $#! · 0-9 · A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z
        A
         addCommandToHistory, SvgCanvas
         addExtension, SelectorManager
         Additional editor tools, SelectorManager
         addSubCommand, SvgCanvas.BatchCommand
         addSvgElementFromJson, SelectorManager
         addToSelection, SelectorManager
         alignSelectedElements, SelectorManager
         apply
         assignAttributes, SelectorManager
        B
         BatchCommand, SvgCanvas
         beginUndoableChange, SvgCanvas
         bind, SelectorManager
        C
         ChangeElementCommand, SvgCanvas
         changeSelectedAttribute, SelectorManager
         changeSelectedAttributeNoUndo, SelectorManager
         cleanupElement, SelectorManager
         clear, SelectorManager
         clearSelection, SelectorManager
         cloneSelectedElements, SelectorManager
         convertToNum, SvgCanvas
         convertToPath, SelectorManager
         convertToXMLReferences, SvgCanvas.Utils
         copyElem, SelectorManager
         createLayer, SelectorManager
         cycleElement, SelectorManager
        D
         decode64, SvgCanvas.Utils
         deleteCurrentLayer, SelectorManager
         deleteSelectedElements, SelectorManager
         Document functions, SelectorManager
        E
         Element manipulation, SelectorManager
         Element Styling, SelectorManager
         Element Transforms, SelectorManager
         elements
         embedImage, SelectorManager
         encode64, SvgCanvas.Utils
        F
         ffClone, SelectorManager
         findDefs, SelectorManager
         findDuplicateGradient, SelectorManager
         finishUndoableChange, SvgCanvas
         fromXml, SvgCanvas.Utils
         Functions, Selector
        - -
        addCommandToHistory = c.undoCmd.add = function(cmd)
        Adds a command object to the undo history stack
        this.addExtension = function(name,
        ext_func)
        Add an extension to the editor
        Adds a given command to the history stack
        var addSvgElementFromJson = this.addSvgElementFromJson = function(data)
        Create a new SVG element based on the given object keys/values and add it to the current layer The element will be ran through cleanupElement before being returned
        var addToSelection = this.addToSelection = function(elemsToAdd,
        showGrips)
        Adds a list of elements to the selection.
        this.alignSelectedElements = function(type,
        relative_to)
        Aligns selected elements
        Runs “apply” on all subcommands
        Performs the stored change action
        Re-Inserts the new element
        Re-removes the new element
        var assignAttributes = this.assignAttributes = function(node,
        attrs,
        suspendLength,
        unitCheck)
        Assigns multiple attributes to an element.
        - - - -
        var BatchCommand = this.undoCmd.batch = function(text)
        History command that can contain/execute multiple other commands
        c.beginUndoableChange = function(attrName,
        elems)
        This function tells the canvas to remember the old values of the attrName attribute for each element sent in.
        c.bind = function(event,
        f)
        Attaches a callback function to an event
        - - - -
        var ChangeElementCommand = this.undoCmd.changeElement = function(elem,
        attrs,
        text)
        History command to make a change to an element.
        var changeSelectedAttribute = this.changeSelectedAttribute = function(attr,
        val,
        elems)
        Change the given/selected element and add the original value to the history stack If you want to change all selectedElements, ignore the elems argument.
        var changeSelectedAttributeNoUndo = function(attr,
        newValue,
        elems)
        This function makes the changes to the elements.
        var cleanupElement = this.cleanupElement = function(element)
        Remove unneeded (default) attributes, makes resulting SVG smaller
        this.clear = function()
        Clears the current document.
        var clearSelection = this.clearSelection = function(noCall)
        Clears the selection.
        this.cloneSelectedElements = function()
        Create deep DOM copies (clones) of all selected elements and move them slightly from their originals
        convertToNum = function(attr,
        val)
        Converts given values to numbers.
        this.convertToPath = function(elem,
        getBBox)
        Convert selected element to a path, or get the BBox of an element-as-path
        Converts a string to use XML references
        var copyElem = function(el)
        Create a clone of an element, updating its ID and its children’s IDs when needed
        this.createLayer = function(name)
        Creates a new top-level layer in the drawing with the given name, sets the current layer to it, and then clears the selection This function then calls the ‘changed’ handler.
        this.cycleElement = function(next)
        Select the next/previous element within the current layer
        - - - -
        Converts a string from base64
        this.deleteCurrentLayer = function()
        Deletes the current layer from the drawing and then clears the selection.
        this.deleteSelectedElements = function()
        Removes all selected elements from the DOM and adds the change to the history stack
        - - - -
        Iterate through all our subcommands and returns all the elements we are changing
        Returns array with element associated with this command
        Returns array with element associated with this command
        Returns array with element associated with this command
        Returns array with element associated with this command
        this.embedImage = function(val,
        callback)
        Converts a given image file to a data URL when possible, then runs a given callback
        Converts a string to base64
        - - - -
        var ffClone = function(elem)
        Hack for Firefox bugs where text element features aren’t updated.
        var findDefs = function()
        Return the document’s defs element, create it first if necessary
        var findDuplicateGradient = function(grad)
        Check if exact gradient already exists
        c.finishUndoableChange = function()
        This function returns a BatchCommand object which summarizes the change since beginUndoableChange was called.
        Converts XML entities in a string to single characters.
        - -
        - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/javascript/main.js b/build/svg-edit-2.6-src/docs/javascript/main.js deleted file mode 100644 index efcdca9..0000000 --- a/build/svg-edit-2.6-src/docs/javascript/main.js +++ /dev/null @@ -1,836 +0,0 @@ -// This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure -// Natural Docs is licensed under the GPL - - -// -// Browser Styles -// ____________________________________________________________________________ - -var agt=navigator.userAgent.toLowerCase(); -var browserType; -var browserVer; - -if (agt.indexOf("opera") != -1) - { - browserType = "Opera"; - - if (agt.indexOf("opera 7") != -1 || agt.indexOf("opera/7") != -1) - { browserVer = "Opera7"; } - else if (agt.indexOf("opera 8") != -1 || agt.indexOf("opera/8") != -1) - { browserVer = "Opera8"; } - else if (agt.indexOf("opera 9") != -1 || agt.indexOf("opera/9") != -1) - { browserVer = "Opera9"; } - } - -else if (agt.indexOf("applewebkit") != -1) - { - browserType = "Safari"; - - if (agt.indexOf("version/3") != -1) - { browserVer = "Safari3"; } - else if (agt.indexOf("safari/4") != -1) - { browserVer = "Safari2"; } - } - -else if (agt.indexOf("khtml") != -1) - { - browserType = "Konqueror"; - } - -else if (agt.indexOf("msie") != -1) - { - browserType = "IE"; - - if (agt.indexOf("msie 6") != -1) - { browserVer = "IE6"; } - else if (agt.indexOf("msie 7") != -1) - { browserVer = "IE7"; } - } - -else if (agt.indexOf("gecko") != -1) - { - browserType = "Firefox"; - - if (agt.indexOf("rv:1.7") != -1) - { browserVer = "Firefox1"; } - else if (agt.indexOf("rv:1.8)") != -1 || agt.indexOf("rv:1.8.0") != -1) - { browserVer = "Firefox15"; } - else if (agt.indexOf("rv:1.8.1") != -1) - { browserVer = "Firefox2"; } - } - - -// -// Support Functions -// ____________________________________________________________________________ - - -function GetXPosition(item) - { - var position = 0; - - if (item.offsetWidth != null) - { - while (item != document.body && item != null) - { - position += item.offsetLeft; - item = item.offsetParent; - }; - }; - - return position; - }; - - -function GetYPosition(item) - { - var position = 0; - - if (item.offsetWidth != null) - { - while (item != document.body && item != null) - { - position += item.offsetTop; - item = item.offsetParent; - }; - }; - - return position; - }; - - -function MoveToPosition(item, x, y) - { - // Opera 5 chokes on the px extension, so it can use the Microsoft one instead. - - if (item.style.left != null) - { - item.style.left = x + "px"; - item.style.top = y + "px"; - } - else if (item.style.pixelLeft != null) - { - item.style.pixelLeft = x; - item.style.pixelTop = y; - }; - }; - - -// -// Menu -// ____________________________________________________________________________ - - -function ToggleMenu(id) - { - if (!window.document.getElementById) - { return; }; - - var display = window.document.getElementById(id).style.display; - - if (display == "none") - { display = "block"; } - else - { display = "none"; } - - window.document.getElementById(id).style.display = display; - } - -function HideAllBut(ids, max) - { - if (document.getElementById) - { - ids.sort( function(a,b) { return a - b; } ); - var number = 1; - - while (number < max) - { - if (ids.length > 0 && number == ids[0]) - { ids.shift(); } - else - { - document.getElementById("MGroupContent" + number).style.display = "none"; - }; - - number++; - }; - }; - } - - -// -// Tooltips -// ____________________________________________________________________________ - - -var tooltipTimer = 0; - -function ShowTip(event, tooltipID, linkID) - { - if (tooltipTimer) - { clearTimeout(tooltipTimer); }; - - var docX = event.clientX + window.pageXOffset; - var docY = event.clientY + window.pageYOffset; - - var showCommand = "ReallyShowTip('" + tooltipID + "', '" + linkID + "', " + docX + ", " + docY + ")"; - - tooltipTimer = setTimeout(showCommand, 1000); - } - -function ReallyShowTip(tooltipID, linkID, docX, docY) - { - tooltipTimer = 0; - - var tooltip; - var link; - - if (document.getElementById) - { - tooltip = document.getElementById(tooltipID); - link = document.getElementById(linkID); - } -/* else if (document.all) - { - tooltip = eval("document.all['" + tooltipID + "']"); - link = eval("document.all['" + linkID + "']"); - } -*/ - if (tooltip) - { - var left = GetXPosition(link); - var top = GetYPosition(link); - top += link.offsetHeight; - - - // The fallback method is to use the mouse X and Y relative to the document. We use a separate if and test if its a number - // in case some browser snuck through the above if statement but didn't support everything. - - if (!isFinite(top) || top == 0) - { - left = docX; - top = docY; - } - - // Some spacing to get it out from under the cursor. - - top += 10; - - // Make sure the tooltip doesnt get smushed by being too close to the edge, or in some browsers, go off the edge of the - // page. We do it here because Konqueror does get offsetWidth right even if it doesnt get the positioning right. - - if (tooltip.offsetWidth != null) - { - var width = tooltip.offsetWidth; - var docWidth = document.body.clientWidth; - - if (left + width > docWidth) - { left = docWidth - width - 1; } - - // If there's a horizontal scroll bar we could go past zero because it's using the page width, not the window width. - if (left < 0) - { left = 0; }; - } - - MoveToPosition(tooltip, left, top); - tooltip.style.visibility = "visible"; - } - } - -function HideTip(tooltipID) - { - if (tooltipTimer) - { - clearTimeout(tooltipTimer); - tooltipTimer = 0; - } - - var tooltip; - - if (document.getElementById) - { tooltip = document.getElementById(tooltipID); } - else if (document.all) - { tooltip = eval("document.all['" + tooltipID + "']"); } - - if (tooltip) - { tooltip.style.visibility = "hidden"; } - } - - -// -// Blockquote fix for IE -// ____________________________________________________________________________ - - -function NDOnLoad() - { - if (browserVer == "IE6") - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - if (scrollboxes.item(0)) - { - NDDoResize(); - window.onresize=NDOnResize; - }; - }; - }; - - -var resizeTimer = 0; - -function NDOnResize() - { - if (resizeTimer != 0) - { clearTimeout(resizeTimer); }; - - resizeTimer = setTimeout(NDDoResize, 250); - }; - - -function NDDoResize() - { - var scrollboxes = document.getElementsByTagName('blockquote'); - - var i; - var item; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = 100; - i++; - }; - - i = 0; - while (item = scrollboxes.item(i)) - { - item.style.width = item.parentNode.offsetWidth; - i++; - }; - - clearTimeout(resizeTimer); - resizeTimer = 0; - } - - - -/* ________________________________________________________________________________________________________ - - Class: SearchPanel - ________________________________________________________________________________________________________ - - A class handling everything associated with the search panel. - - Parameters: - - name - The name of the global variable that will be storing this instance. Is needed to be able to set timeouts. - mode - The mode the search is going to work in. Pass CommandLineOption()>, so the - value will be something like "HTML" or "FramedHTML". - - ________________________________________________________________________________________________________ -*/ - - -function SearchPanel(name, mode, resultsPath) - { - if (!name || !mode || !resultsPath) - { alert("Incorrect parameters to SearchPanel."); }; - - - // Group: Variables - // ________________________________________________________________________ - - /* - var: name - The name of the global variable that will be storing this instance of the class. - */ - this.name = name; - - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: resultsPath - The relative path from the current HTML page to the results page directory. - */ - this.resultsPath = resultsPath; - - /* - var: keyTimeout - The timeout used between a keystroke and when a search is performed. - */ - this.keyTimeout = 0; - - /* - var: keyTimeoutLength - The length of in thousandths of a second. - */ - this.keyTimeoutLength = 500; - - /* - var: lastSearchValue - The last search string executed, or an empty string if none. - */ - this.lastSearchValue = ""; - - /* - var: lastResultsPage - The last results page. The value is only relevant if is set. - */ - this.lastResultsPage = ""; - - /* - var: deactivateTimeout - - The timeout used between when a control is deactivated and when the entire panel is deactivated. Is necessary - because a control may be deactivated in favor of another control in the same panel, in which case it should stay - active. - */ - this.deactivateTimout = 0; - - /* - var: deactivateTimeoutLength - The length of in thousandths of a second. - */ - this.deactivateTimeoutLength = 200; - - - - - // Group: DOM Elements - // ________________________________________________________________________ - - - // Function: DOMSearchField - this.DOMSearchField = function() - { return document.getElementById("MSearchField"); }; - - // Function: DOMSearchType - this.DOMSearchType = function() - { return document.getElementById("MSearchType"); }; - - // Function: DOMPopupSearchResults - this.DOMPopupSearchResults = function() - { return document.getElementById("MSearchResults"); }; - - // Function: DOMPopupSearchResultsWindow - this.DOMPopupSearchResultsWindow = function() - { return document.getElementById("MSearchResultsWindow"); }; - - // Function: DOMSearchPanel - this.DOMSearchPanel = function() - { return document.getElementById("MSearchPanel"); }; - - - - - // Group: Event Handlers - // ________________________________________________________________________ - - - /* - Function: OnSearchFieldFocus - Called when focus is added or removed from the search field. - */ - this.OnSearchFieldFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchFieldChange - Called when the content of the search field is changed. - */ - this.OnSearchFieldChange = function() - { - if (this.keyTimeout) - { - clearTimeout(this.keyTimeout); - this.keyTimeout = 0; - }; - - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != this.lastSearchValue) - { - if (searchValue != "") - { - this.keyTimeout = setTimeout(this.name + ".Search()", this.keyTimeoutLength); - } - else - { - if (this.mode == "HTML") - { this.DOMPopupSearchResultsWindow().style.display = "none"; }; - this.lastSearchValue = ""; - }; - }; - }; - - - /* - Function: OnSearchTypeFocus - Called when focus is added or removed from the search type. - */ - this.OnSearchTypeFocus = function(isActive) - { - this.Activate(isActive); - }; - - - /* - Function: OnSearchTypeChange - Called when the search type is changed. - */ - this.OnSearchTypeChange = function() - { - var searchValue = this.DOMSearchField().value.replace(/ +/g, ""); - - if (searchValue != "") - { - this.Search(); - }; - }; - - - - // Group: Action Functions - // ________________________________________________________________________ - - - /* - Function: CloseResultsWindow - Closes the results window. - */ - this.CloseResultsWindow = function() - { - this.DOMPopupSearchResultsWindow().style.display = "none"; - this.Activate(false, true); - }; - - - /* - Function: Search - Performs a search. - */ - this.Search = function() - { - this.keyTimeout = 0; - - var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); - var searchTopic = this.DOMSearchType().value; - - var pageExtension = searchValue.substr(0,1); - - if (pageExtension.match(/^[a-z]/i)) - { pageExtension = pageExtension.toUpperCase(); } - else if (pageExtension.match(/^[0-9]/)) - { pageExtension = 'Numbers'; } - else - { pageExtension = "Symbols"; }; - - var resultsPage; - var resultsPageWithSearch; - var hasResultsPage; - - // indexSectionsWithContent is defined in searchdata.js - if (indexSectionsWithContent[searchTopic][pageExtension] == true) - { - resultsPage = this.resultsPath + '/' + searchTopic + pageExtension + '.html'; - resultsPageWithSearch = resultsPage+'?'+escape(searchValue); - hasResultsPage = true; - } - else - { - resultsPage = this.resultsPath + '/NoResults.html'; - resultsPageWithSearch = resultsPage; - hasResultsPage = false; - }; - - var resultsFrame; - if (this.mode == "HTML") - { resultsFrame = window.frames.MSearchResults; } - else if (this.mode == "FramedHTML") - { resultsFrame = window.top.frames['Content']; }; - - - if (resultsPage != this.lastResultsPage || - - // Bug in IE. If everything becomes hidden in a run, none of them will be able to be reshown in the next for some - // reason. It counts the right number of results, and you can even read the display as "block" after setting it, but it - // just doesn't work in IE 6 or IE 7. So if we're on the right page but the previous search had no results, reload the - // page anyway to get around the bug. - (browserType == "IE" && hasResultsPage && - (!resultsFrame.searchResults || resultsFrame.searchResults.lastMatchCount == 0)) ) - - { - resultsFrame.location.href = resultsPageWithSearch; - } - - // So if the results page is right and there's no IE bug, reperform the search on the existing page. We have to check if there - // are results because NoResults.html doesn't have any JavaScript, and it would be useless to do anything on that page even - // if it did. - else if (hasResultsPage) - { - // We need to check if this exists in case the frame is present but didn't finish loading. - if (resultsFrame.searchResults) - { resultsFrame.searchResults.Search(searchValue); } - - // Otherwise just reload instead of waiting. - else - { resultsFrame.location.href = resultsPageWithSearch; }; - }; - - - var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); - - if (this.mode == "HTML" && domPopupSearchResultsWindow.style.display != "block") - { - var domSearchType = this.DOMSearchType(); - - var left = GetXPosition(domSearchType); - var top = GetYPosition(domSearchType) + domSearchType.offsetHeight; - - MoveToPosition(domPopupSearchResultsWindow, left, top); - domPopupSearchResultsWindow.style.display = 'block'; - }; - - - this.lastSearchValue = searchValue; - this.lastResultsPage = resultsPage; - }; - - - - // Group: Activation Functions - // Functions that handle whether the entire panel is active or not. - // ________________________________________________________________________ - - - /* - Function: Activate - - Activates or deactivates the search panel, resetting things to their default values if necessary. You can call this on every - control's OnBlur() and it will handle not deactivating the entire panel when focus is just switching between them transparently. - - Parameters: - - isActive - Whether you're activating or deactivating the panel. - ignoreDeactivateDelay - Set if you're positive the action will deactivate the panel and thus want to skip the delay. - */ - this.Activate = function(isActive, ignoreDeactivateDelay) - { - // We want to ignore isActive being false while the results window is open. - if (isActive || (this.mode == "HTML" && this.DOMPopupSearchResultsWindow().style.display == "block")) - { - if (this.inactivateTimeout) - { - clearTimeout(this.inactivateTimeout); - this.inactivateTimeout = 0; - }; - - this.DOMSearchPanel().className = 'MSearchPanelActive'; - - var searchField = this.DOMSearchField(); - - if (searchField.value == 'Search') - { searchField.value = ""; } - } - else if (!ignoreDeactivateDelay) - { - this.inactivateTimeout = setTimeout(this.name + ".InactivateAfterTimeout()", this.inactivateTimeoutLength); - } - else - { - this.InactivateAfterTimeout(); - }; - }; - - - /* - Function: InactivateAfterTimeout - - Called by , which is set by . Inactivation occurs on a timeout because a control may - receive OnBlur() when focus is really transferring to another control in the search panel. In this case we don't want to - actually deactivate the panel because not only would that cause a visible flicker but it could also reset the search value. - So by doing it on a timeout instead, there's a short period where the second control's OnFocus() can cancel the deactivation. - */ - this.InactivateAfterTimeout = function() - { - this.inactivateTimeout = 0; - - this.DOMSearchPanel().className = 'MSearchPanelInactive'; - this.DOMSearchField().value = "Search"; - - this.lastSearchValue = ""; - this.lastResultsPage = ""; - }; - }; - - - - -/* ________________________________________________________________________________________________________ - - Class: SearchResults - _________________________________________________________________________________________________________ - - The class that handles everything on the search results page. - _________________________________________________________________________________________________________ -*/ - - -function SearchResults(name, mode) - { - /* - var: mode - The mode the search is going to work in, such as "HTML" or "FramedHTML". - */ - this.mode = mode; - - /* - var: lastMatchCount - The number of matches from the last run of . - */ - this.lastMatchCount = 0; - - - /* - Function: Toggle - Toggles the visibility of the passed element ID. - */ - this.Toggle = function(id) - { - if (this.mode == "FramedHTML") - { return; }; - - var parentElement = document.getElementById(id); - - var element = parentElement.firstChild; - - while (element && element != parentElement) - { - if (element.nodeName == 'DIV' && element.className == 'ISubIndex') - { - if (element.style.display == 'block') - { element.style.display = "none"; } - else - { element.style.display = 'block'; } - }; - - if (element.nodeName == 'DIV' && element.hasChildNodes()) - { element = element.firstChild; } - else if (element.nextSibling) - { element = element.nextSibling; } - else - { - do - { - element = element.parentNode; - } - while (element && element != parentElement && !element.nextSibling); - - if (element && element != parentElement) - { element = element.nextSibling; }; - }; - }; - }; - - - /* - Function: Search - - Searches for the passed string. If there is no parameter, it takes it from the URL query. - - Always returns true, since other documents may try to call it and that may or may not be possible. - */ - this.Search = function(search) - { - if (!search) - { - search = window.location.search; - search = search.substring(1); // Remove the leading ? - search = unescape(search); - }; - - search = search.replace(/^ +/, ""); - search = search.replace(/ +$/, ""); - search = search.toLowerCase(); - - if (search.match(/[^a-z0-9]/)) // Just a little speedup so it doesn't have to go through the below unnecessarily. - { - search = search.replace(/\_/g, "_und"); - search = search.replace(/\ +/gi, "_spc"); - search = search.replace(/\~/g, "_til"); - search = search.replace(/\!/g, "_exc"); - search = search.replace(/\@/g, "_att"); - search = search.replace(/\#/g, "_num"); - search = search.replace(/\$/g, "_dol"); - search = search.replace(/\%/g, "_pct"); - search = search.replace(/\^/g, "_car"); - search = search.replace(/\&/g, "_amp"); - search = search.replace(/\*/g, "_ast"); - search = search.replace(/\(/g, "_lpa"); - search = search.replace(/\)/g, "_rpa"); - search = search.replace(/\-/g, "_min"); - search = search.replace(/\+/g, "_plu"); - search = search.replace(/\=/g, "_equ"); - search = search.replace(/\{/g, "_lbc"); - search = search.replace(/\}/g, "_rbc"); - search = search.replace(/\[/g, "_lbk"); - search = search.replace(/\]/g, "_rbk"); - search = search.replace(/\:/g, "_col"); - search = search.replace(/\;/g, "_sco"); - search = search.replace(/\"/g, "_quo"); - search = search.replace(/\'/g, "_apo"); - search = search.replace(/\/g, "_ran"); - search = search.replace(/\,/g, "_com"); - search = search.replace(/\./g, "_per"); - search = search.replace(/\?/g, "_que"); - search = search.replace(/\//g, "_sla"); - search = search.replace(/[^a-z0-9\_]i/gi, "_zzz"); - }; - - var resultRows = document.getElementsByTagName("div"); - var matches = 0; - - var i = 0; - while (i < resultRows.length) - { - var row = resultRows.item(i); - - if (row.className == "SRResult") - { - var rowMatchName = row.id.toLowerCase(); - rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); - - if (search.length <= rowMatchName.length && rowMatchName.substr(0, search.length) == search) - { - row.style.display = "block"; - matches++; - } - else - { row.style.display = "none"; }; - }; - - i++; - }; - - document.getElementById("Searching").style.display="none"; - - if (matches == 0) - { document.getElementById("NoMatches").style.display="block"; } - else - { document.getElementById("NoMatches").style.display="none"; } - - this.lastMatchCount = matches; - - return true; - }; - }; - diff --git a/build/svg-edit-2.6-src/docs/javascript/searchdata.js b/build/svg-edit-2.6-src/docs/javascript/searchdata.js deleted file mode 100644 index eac176a..0000000 --- a/build/svg-edit-2.6-src/docs/javascript/searchdata.js +++ /dev/null @@ -1,122 +0,0 @@ -var indexSectionsWithContent = { - "General": { - "Symbols": false, - "Numbers": false, - "A": true, - "B": false, - "C": true, - "D": true, - "E": false, - "F": true, - "G": true, - "H": true, - "I": true, - "J": false, - "K": false, - "L": true, - "M": true, - "N": false, - "O": true, - "P": false, - "Q": false, - "R": true, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - }, - "Functions": { - "Symbols": false, - "Numbers": false, - "A": true, - "B": true, - "C": true, - "D": true, - "E": true, - "F": true, - "G": true, - "H": true, - "I": true, - "J": false, - "K": false, - "L": true, - "M": true, - "N": false, - "O": false, - "P": true, - "Q": false, - "R": true, - "S": true, - "T": true, - "U": true, - "V": false, - "W": true, - "X": false, - "Y": false, - "Z": false - }, - "Interfaces": { - "Symbols": false, - "Numbers": false, - "A": false, - "B": false, - "C": false, - "D": false, - "E": false, - "F": false, - "G": false, - "H": false, - "I": false, - "J": false, - "K": false, - "L": false, - "M": false, - "N": false, - "O": false, - "P": false, - "Q": false, - "R": false, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - }, - "Classes": { - "Symbols": false, - "Numbers": false, - "A": false, - "B": false, - "C": false, - "D": false, - "E": false, - "F": false, - "G": false, - "H": false, - "I": false, - "J": false, - "K": false, - "L": false, - "M": false, - "N": false, - "O": false, - "P": false, - "Q": false, - "R": false, - "S": true, - "T": false, - "U": false, - "V": false, - "W": false, - "X": false, - "Y": false, - "Z": false - } - } \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FilesS.html b/build/svg-edit-2.6-src/docs/search/FilesS.html deleted file mode 100644 index 690d961..0000000 --- a/build/svg-edit-2.6-src/docs/search/FilesS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsA.html b/build/svg-edit-2.6-src/docs/search/FunctionsA.html deleted file mode 100644 index de24e1f..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        addExtension, SelectorManager
        addSubCommand, SvgCanvas.BatchCommand
        addSvgElementFromJson, SelectorManager
        addToSelection, SelectorManager
        alignSelectedElements, SelectorManager
        assignAttributes, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsC.html b/build/svg-edit-2.6-src/docs/search/FunctionsC.html deleted file mode 100644 index eb4b747..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        changeSelectedAttribute, SelectorManager
        cleanupElement, SelectorManager
        clear, SelectorManager
        clearSelection, SelectorManager
        cloneSelectedElements, SelectorManager
        convertToNum, SvgCanvas
        convertToPath, SelectorManager
        convertToXMLReferences, SvgCanvas.Utils
        copyElem, SelectorManager
        createLayer, SelectorManager
        cycleElement, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsD.html b/build/svg-edit-2.6-src/docs/search/FunctionsD.html deleted file mode 100644 index 1c28ffc..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        decode64, SvgCanvas.Utils
        deleteCurrentLayer, SelectorManager
        deleteSelectedElements, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsG.html b/build/svg-edit-2.6-src/docs/search/FunctionsG.html deleted file mode 100644 index c7e504e..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsG.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        getBBox, SelectorManager
        getBlur, SelectorManager
        getBold, SelectorManager
        getColor, SelectorManager
        getContentElem, SelectorManager
        getCurrentLayer, SelectorManager
        getDocumentTitle, SelectorManager
        getEditorNS, SelectorManager
        getElem, SelectorManager
        getFontFamily, SelectorManager
        getFontSize, SelectorManager
        getId, SelectorManager
        getItalic, SelectorManager
        getLayer, SelectorManager
        getLayerOpacity, SelectorManager
        getLayerVisibility, SelectorManager
        getMatrix, SelectorManager
        getMode, SelectorManager
        getMouseTarget, SelectorManager
        getNextId, SelectorManager
        getNextRedoCommandText, SvgCanvas.undoMgr
        getNextUndoCommandText, SvgCanvas.undoMgr
        getNumLayers, SelectorManager
        getOffset, SelectorManager
        getOpacity, SelectorManager
        getPathBBox, SelectorManager
        getRedoStackSize, SvgCanvas.undoMgr
        getResolution, SelectorManager
        getRootElem, SelectorManager
        getRotationAngle, SelectorManager
        getRubberBandBox, SelectorManager.SelectorManager
        getSelectedElems, SelectorManager
        getStrokedBBox, SelectorManager
        getStrokeOpacity, SelectorManager
        getStrokeWidth, SelectorManager
        getSvgString, SelectorManager
        getText, SelectorManager
        getTransformList, SelectorManager
        getUndoStackSize, SvgCanvas.undoMgr
        getUrlFromAttr, SelectorManager
        getVersion, SelectorManager
        getVisibleElements, SelectorManager
        getZoom, SelectorManager
        groupSelectedElements, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsM.html b/build/svg-edit-2.6-src/docs/search/FunctionsM.html deleted file mode 100644 index fbb3112..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsM.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        matrixMultiply, SelectorManager
        moveSelectedElements, SelectorManager
        moveSelectedToLayer, SelectorManager
        moveToTopSelectedElement, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsO.html b/build/svg-edit-2.6-src/docs/search/FunctionsO.html deleted file mode 100644 index 76f92f6..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsO.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsR.html b/build/svg-edit-2.6-src/docs/search/FunctionsR.html deleted file mode 100644 index 3153d9d..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        rasterExport, SelectorManager
        recalculateDimensions, SelectorManager
        rectsIntersect, SvgCanvas
        redo, SvgCanvas.undoMgr
        releaseSelector, SelectorManager.SelectorManager
        remapElement, SelectorManager
        removeFromSelection, SelectorManager
        removeUnusedDefElems, SelectorManager
        renameCurrentLayer, SelectorManager
        requestSelector, SelectorManager.SelectorManager
        reset, Selector.Selector
        resetUndoStack, SvgCanvas
        resize, Selector.Selector
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/FunctionsS.html b/build/svg-edit-2.6-src/docs/search/FunctionsS.html deleted file mode 100644 index 13e3338..0000000 --- a/build/svg-edit-2.6-src/docs/search/FunctionsS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        sanitizeSvg, SelectorManager
        save, SelectorManager
        selectAllInCurrentLayer, SelectorManager
        setBackground, SelectorManager
        setBBoxZoom, SelectorManager
        setBlur, SelectorManager
        setBlurNoUndo, SelectorManager
        setBlurOffsets, SelectorManager
        setBold, SelectorManager
        setColor, SelectorManager
        setConfig, SelectorManager
        setCurrentLayer, SelectorManager
        setCurrentLayerPosition, SelectorManager
        setDocumentTitle, SelectorManager
        setFontFamily, SelectorManager
        setFontSize, SelectorManager
        setGradient, SelectorManager
        setIdPrefix, SelectorManager
        setImageURL, SelectorManager
        setItalic, SelectorManager
        setLayerOpacity, SelectorManager
        setLayerVisibility, SelectorManager
        setMode, SelectorManager
        setOpacity, SelectorManager
        setPaint, SelectorManager
        setPaintOpacity, SelectorManager
        setRectRadius, SelectorManager
        setResolution, SelectorManager
        setRotationAngle, SelectorManager
        setSegType, SelectorManager
        setStrokeAttr, SelectorManager
        setStrokeWidth, SelectorManager
        setSvgString, SelectorManager
        setTextContent, SelectorManager
        setUiStrings, SelectorManager
        setUnitAttr, SvgCanvas
        setZoom, SelectorManager
        shortFloat, SelectorManager
        showGrips, Selector.Selector
        smoothControlPoints, SelectorManager
        snapToAngle, SvgCanvas
        svgCanvasToString, SelectorManager
        svgToString, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralA.html b/build/svg-edit-2.6-src/docs/search/GeneralA.html deleted file mode 100644 index f3ee0f6..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralA.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        addExtension, SelectorManager
        Additional editor tools, SelectorManager
        addSubCommand, SvgCanvas.BatchCommand
        addSvgElementFromJson, SelectorManager
        addToSelection, SelectorManager
        alignSelectedElements, SelectorManager
        assignAttributes, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralC.html b/build/svg-edit-2.6-src/docs/search/GeneralC.html deleted file mode 100644 index eb4b747..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralC.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        changeSelectedAttribute, SelectorManager
        cleanupElement, SelectorManager
        clear, SelectorManager
        clearSelection, SelectorManager
        cloneSelectedElements, SelectorManager
        convertToNum, SvgCanvas
        convertToPath, SelectorManager
        convertToXMLReferences, SvgCanvas.Utils
        copyElem, SelectorManager
        createLayer, SelectorManager
        cycleElement, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralD.html b/build/svg-edit-2.6-src/docs/search/GeneralD.html deleted file mode 100644 index 6735300..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralD.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        decode64, SvgCanvas.Utils
        deleteCurrentLayer, SelectorManager
        deleteSelectedElements, SelectorManager
        Document functions, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralF.html b/build/svg-edit-2.6-src/docs/search/GeneralF.html deleted file mode 100644 index 55c21a8..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralF.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        ffClone, SelectorManager
        findDefs, SelectorManager
        findDuplicateGradient, SelectorManager
        fromXml, SvgCanvas.Utils
        Functions, Selector
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralG.html b/build/svg-edit-2.6-src/docs/search/GeneralG.html deleted file mode 100644 index c7e504e..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralG.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        getBBox, SelectorManager
        getBlur, SelectorManager
        getBold, SelectorManager
        getColor, SelectorManager
        getContentElem, SelectorManager
        getCurrentLayer, SelectorManager
        getDocumentTitle, SelectorManager
        getEditorNS, SelectorManager
        getElem, SelectorManager
        getFontFamily, SelectorManager
        getFontSize, SelectorManager
        getId, SelectorManager
        getItalic, SelectorManager
        getLayer, SelectorManager
        getLayerOpacity, SelectorManager
        getLayerVisibility, SelectorManager
        getMatrix, SelectorManager
        getMode, SelectorManager
        getMouseTarget, SelectorManager
        getNextId, SelectorManager
        getNextRedoCommandText, SvgCanvas.undoMgr
        getNextUndoCommandText, SvgCanvas.undoMgr
        getNumLayers, SelectorManager
        getOffset, SelectorManager
        getOpacity, SelectorManager
        getPathBBox, SelectorManager
        getRedoStackSize, SvgCanvas.undoMgr
        getResolution, SelectorManager
        getRootElem, SelectorManager
        getRotationAngle, SelectorManager
        getRubberBandBox, SelectorManager.SelectorManager
        getSelectedElems, SelectorManager
        getStrokedBBox, SelectorManager
        getStrokeOpacity, SelectorManager
        getStrokeWidth, SelectorManager
        getSvgString, SelectorManager
        getText, SelectorManager
        getTransformList, SelectorManager
        getUndoStackSize, SvgCanvas.undoMgr
        getUrlFromAttr, SelectorManager
        getVersion, SelectorManager
        getVisibleElements, SelectorManager
        getZoom, SelectorManager
        groupSelectedElements, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralL.html b/build/svg-edit-2.6-src/docs/search/GeneralL.html deleted file mode 100644 index 09038de..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralL.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        Layers, SelectorManager
        linkControlPoints, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralM.html b/build/svg-edit-2.6-src/docs/search/GeneralM.html deleted file mode 100644 index fbb3112..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralM.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        matrixMultiply, SelectorManager
        moveSelectedElements, SelectorManager
        moveSelectedToLayer, SelectorManager
        moveToTopSelectedElement, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralO.html b/build/svg-edit-2.6-src/docs/search/GeneralO.html deleted file mode 100644 index 76f92f6..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralO.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralR.html b/build/svg-edit-2.6-src/docs/search/GeneralR.html deleted file mode 100644 index 3153d9d..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralR.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        rasterExport, SelectorManager
        recalculateDimensions, SelectorManager
        rectsIntersect, SvgCanvas
        redo, SvgCanvas.undoMgr
        releaseSelector, SelectorManager.SelectorManager
        remapElement, SelectorManager
        removeFromSelection, SelectorManager
        removeUnusedDefElems, SelectorManager
        renameCurrentLayer, SelectorManager
        requestSelector, SelectorManager.SelectorManager
        reset, Selector.Selector
        resetUndoStack, SvgCanvas
        resize, Selector.Selector
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/GeneralS.html b/build/svg-edit-2.6-src/docs/search/GeneralS.html deleted file mode 100644 index 1176986..0000000 --- a/build/svg-edit-2.6-src/docs/search/GeneralS.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - -
        Loading...
        sanitizeSvg, SelectorManager
        save, SelectorManager
        selectAllInCurrentLayer, SelectorManager
        Selection, SelectorManager
        Serialization, SelectorManager
        setBackground, SelectorManager
        setBBoxZoom, SelectorManager
        setBlur, SelectorManager
        setBlurNoUndo, SelectorManager
        setBlurOffsets, SelectorManager
        setBold, SelectorManager
        setColor, SelectorManager
        setConfig, SelectorManager
        setCurrentLayer, SelectorManager
        setCurrentLayerPosition, SelectorManager
        setDocumentTitle, SelectorManager
        setFontFamily, SelectorManager
        setFontSize, SelectorManager
        setGradient, SelectorManager
        setIdPrefix, SelectorManager
        setImageURL, SelectorManager
        setItalic, SelectorManager
        setLayerOpacity, SelectorManager
        setLayerVisibility, SelectorManager
        setMode, SelectorManager
        setOpacity, SelectorManager
        setPaint, SelectorManager
        setPaintOpacity, SelectorManager
        setRectRadius, SelectorManager
        setResolution, SelectorManager
        setRotationAngle, SelectorManager
        setSegType, SelectorManager
        setStrokeAttr, SelectorManager
        setStrokeWidth, SelectorManager
        setSvgString, SelectorManager
        setTextContent, SelectorManager
        setUiStrings, SelectorManager
        setUnitAttr, SvgCanvas
        setZoom, SelectorManager
        shortFloat, SelectorManager
        showGrips, Selector.Selector
        smoothControlPoints, SelectorManager
        snapToAngle, SvgCanvas
        svgCanvasToString, SelectorManager
        svgToString, SelectorManager
        Searching...
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/search/NoResults.html b/build/svg-edit-2.6-src/docs/search/NoResults.html deleted file mode 100644 index 02ce888..0000000 --- a/build/svg-edit-2.6-src/docs/search/NoResults.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - -
        No Matches
        \ No newline at end of file diff --git a/build/svg-edit-2.6-src/docs/styles/main.css b/build/svg-edit-2.6-src/docs/styles/main.css deleted file mode 100644 index 17e9cbc..0000000 --- a/build/svg-edit-2.6-src/docs/styles/main.css +++ /dev/null @@ -1,767 +0,0 @@ -/* - IMPORTANT: If you're editing this file in the output directory of one of - your projects, your changes will be overwritten the next time you run - Natural Docs. Instead, copy this file to your project directory, make your - changes, and you can use it with -s. Even better would be to make a CSS - file in your project directory with only your changes, which you can then - use with -s [original style] [your changes]. - - On the other hand, if you're editing this file in the Natural Docs styles - directory, the changes will automatically be applied to all your projects - that use this style the next time Natural Docs is run on them. - - This file is part of Natural Docs, which is Copyright (C) 2003-2008 Greg Valure - Natural Docs is licensed under the GPL -*/ - -body { - font: 10pt Verdana, Arial, sans-serif; - color: #000000; - margin: 0; padding: 0; - } - -.ContentPage, -.IndexPage, -.FramedMenuPage { - background-color: #E8E8E8; - } -.FramedContentPage, -.FramedIndexPage, -.FramedSearchResultsPage, -.PopupSearchResultsPage { - background-color: #FFFFFF; - } - - -a:link, -a:visited { color: #900000; text-decoration: none } -a:hover { color: #900000; text-decoration: underline } -a:active { color: #FF0000; text-decoration: underline } - -td { - vertical-align: top } - -img { border: 0; } - - -/* - Comment out this line to use web-style paragraphs (blank line between - paragraphs, no indent) instead of print-style paragraphs (no blank line, - indented.) -*/ -p { - text-indent: 5ex; margin: 0 } - - -/* Opera doesn't break with just wbr, but will if you add this. */ -.Opera wbr:after { - content: "\00200B"; - } - - -/* Blockquotes are used as containers for things that may need to scroll. */ -blockquote { - padding: 0; - margin: 0; - overflow: auto; - } - - -.Firefox1 blockquote { - padding-bottom: .5em; - } - -/* Turn off scrolling when printing. */ -@media print { - blockquote { - overflow: visible; - } - .IE blockquote { - width: auto; - } - } - - - -#Menu { - font-size: 9pt; - padding: 10px 0 0 0; - } -.ContentPage #Menu, -.IndexPage #Menu { - position: absolute; - top: 0; - left: 0; - width: 31ex; - overflow: hidden; - } -.ContentPage .Firefox #Menu, -.IndexPage .Firefox #Menu { - width: 27ex; - } - - - .MTitle { - font-size: 16pt; font-weight: bold; font-variant: small-caps; - text-align: center; - padding: 5px 10px 15px 10px; - border-bottom: 1px dotted #000000; - margin-bottom: 15px } - - .MSubTitle { - font-size: 9pt; font-weight: normal; font-variant: normal; - margin-top: 1ex; margin-bottom: 5px } - - - .MEntry a:link, - .MEntry a:hover, - .MEntry a:visited { color: #606060; margin-right: 0 } - .MEntry a:active { color: #A00000; margin-right: 0 } - - - .MGroup { - font-variant: small-caps; font-weight: bold; - margin: 1em 0 1em 10px; - } - - .MGroupContent { - font-variant: normal; font-weight: normal } - - .MGroup a:link, - .MGroup a:hover, - .MGroup a:visited { color: #545454; margin-right: 10px } - .MGroup a:active { color: #A00000; margin-right: 10px } - - - .MFile, - .MText, - .MLink, - .MIndex { - padding: 1px 17px 2px 10px; - margin: .25em 0 .25em 0; - } - - .MText { - font-size: 8pt; font-style: italic } - - .MLink { - font-style: italic } - - #MSelected { - color: #000000; background-color: #FFFFFF; - /* Replace padding with border. */ - padding: 0 10px 0 10px; - border-width: 1px 2px 2px 0; border-style: solid; border-color: #000000; - margin-right: 5px; - } - - /* Close off the left side when its in a group. */ - .MGroup #MSelected { - padding-left: 9px; border-left-width: 1px } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Firefox #MSelected { - -moz-border-radius-topright: 10px; - -moz-border-radius-bottomright: 10px } - .Firefox .MGroup #MSelected { - -moz-border-radius-topleft: 10px; - -moz-border-radius-bottomleft: 10px } - - - #MSearchPanel { - padding: 0px 6px; - margin: .25em 0; - } - - - #MSearchField { - font: italic 9pt Verdana, sans-serif; - color: #606060; - background-color: #E8E8E8; - border: none; - padding: 2px 4px; - width: 100%; - } - /* Only Opera gets it right. */ - .Firefox #MSearchField, - .IE #MSearchField, - .Safari #MSearchField { - width: 94%; - } - .Opera9 #MSearchField, - .Konqueror #MSearchField { - width: 97%; - } - .FramedMenuPage .Firefox #MSearchField, - .FramedMenuPage .Safari #MSearchField, - .FramedMenuPage .Konqueror #MSearchField { - width: 98%; - } - - /* Firefox doesn't do this right in frames without #MSearchPanel added on. - It's presence doesn't hurt anything other browsers. */ - #MSearchPanel.MSearchPanelInactive:hover #MSearchField { - background-color: #FFFFFF; - border: 1px solid #C0C0C0; - padding: 1px 3px; - } - .MSearchPanelActive #MSearchField { - background-color: #FFFFFF; - border: 1px solid #C0C0C0; - font-style: normal; - padding: 1px 3px; - } - - #MSearchType { - visibility: hidden; - font: 8pt Verdana, sans-serif; - width: 98%; - padding: 0; - border: 1px solid #C0C0C0; - } - .MSearchPanelActive #MSearchType, - /* As mentioned above, Firefox doesn't do this right in frames without #MSearchPanel added on. */ - #MSearchPanel.MSearchPanelInactive:hover #MSearchType, - #MSearchType:focus { - visibility: visible; - color: #606060; - } - #MSearchType option#MSearchEverything { - font-weight: bold; - } - - .Opera8 .MSearchPanelInactive:hover, - .Opera8 .MSearchPanelActive { - margin-left: -1px; - } - - - iframe#MSearchResults { - width: 60ex; - height: 15em; - } - #MSearchResultsWindow { - display: none; - position: absolute; - left: 0; top: 0; - border: 1px solid #000000; - background-color: #E8E8E8; - } - #MSearchResultsWindowClose { - font-weight: bold; - font-size: 8pt; - display: block; - padding: 2px 5px; - } - #MSearchResultsWindowClose:link, - #MSearchResultsWindowClose:visited { - color: #000000; - text-decoration: none; - } - #MSearchResultsWindowClose:active, - #MSearchResultsWindowClose:hover { - color: #800000; - text-decoration: none; - background-color: #F4F4F4; - } - - - - -#Content { - padding-bottom: 15px; - } - -.ContentPage #Content { - border-width: 0 0 1px 1px; - border-style: solid; - border-color: #000000; - background-color: #FFFFFF; - font-size: 9pt; /* To make 31ex match the menu's 31ex. */ - margin-left: 31ex; - } -.ContentPage .Firefox #Content { - margin-left: 27ex; - } - - - - .CTopic { - font-size: 10pt; - margin-bottom: 3em; - } - - - .CTitle { - font-size: 12pt; font-weight: bold; - border-width: 0 0 1px 0; border-style: solid; border-color: #A0A0A0; - margin: 0 15px .5em 15px } - - .CGroup .CTitle { - font-size: 16pt; font-variant: small-caps; - padding-left: 15px; padding-right: 15px; - border-width: 0 0 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CClass .CTitle, - .CInterface .CTitle, - .CDatabase .CTitle, - .CDatabaseTable .CTitle, - .CSection .CTitle { - font-size: 18pt; - color: #FFFFFF; background-color: #A0A0A0; - padding: 10px 15px 10px 15px; - border-width: 2px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - #MainTopic .CTitle { - font-size: 20pt; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; - margin-left: 0; margin-right: 0 } - - .CBody { - margin-left: 15px; margin-right: 15px } - - - .CToolTip { - position: absolute; visibility: hidden; - left: 0; top: 0; - background-color: #FFFFE0; - padding: 5px; - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #000000; - font-size: 8pt; - } - - .Opera .CToolTip { - max-width: 98%; - } - - /* Scrollbars would be useless. */ - .CToolTip blockquote { - overflow: hidden; - } - .IE6 .CToolTip blockquote { - overflow: visible; - } - - .CHeading { - font-weight: bold; font-size: 10pt; - margin: 1.5em 0 .5em 0; - } - - .CBody pre { - font: 10pt "Courier New", Courier, monospace; - margin: 1em 0; - } - - .CBody ul { - /* I don't know why CBody's margin doesn't apply, but it's consistent across browsers so whatever. - Reapply it here as padding. */ - padding-left: 15px; padding-right: 15px; - margin: .5em 5ex .5em 5ex; - } - - .CDescriptionList { - margin: .5em 5ex 0 5ex } - - .CDLEntry { - font: 10pt "Courier New", Courier, monospace; color: #808080; - padding-bottom: .25em; - white-space: nowrap } - - .CDLDescription { - font-size: 10pt; /* For browsers that don't inherit correctly, like Opera 5. */ - padding-bottom: .5em; padding-left: 5ex } - - - .CTopic img { - text-align: center; - display: block; - margin: 1em auto; - } - .CImageCaption { - font-variant: small-caps; - font-size: 8pt; - color: #808080; - text-align: center; - position: relative; - top: 1em; - } - - .CImageLink { - color: #808080; - font-style: italic; - } - a.CImageLink:link, - a.CImageLink:visited, - a.CImageLink:hover { color: #808080 } - - - - - -.Prototype { - font: 10pt "Courier New", Courier, monospace; - padding: 5px 3ex; - border-width: 1px; border-style: solid; - margin: 0 5ex 1.5em 5ex; - } - - .Prototype td { - font-size: 10pt; - } - - .PDefaultValue, - .PDefaultValuePrefix, - .PTypePrefix { - color: #8F8F8F; - } - .PTypePrefix { - text-align: right; - } - .PAfterParameters { - vertical-align: bottom; - } - - .IE .Prototype table { - padding: 0; - } - - .CFunction .Prototype { - background-color: #F4F4F4; border-color: #D0D0D0 } - .CProperty .Prototype { - background-color: #F4F4FF; border-color: #C0C0E8 } - .CVariable .Prototype { - background-color: #FFFFF0; border-color: #E0E0A0 } - - .CClass .Prototype { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - background-color: #F4F4F4; - } - .CInterface .Prototype { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0D0; - background-color: #F4F4FF; - } - - .CDatabaseIndex .Prototype, - .CConstant .Prototype { - background-color: #D0D0D0; border-color: #000000 } - .CType .Prototype, - .CEnumeration .Prototype { - background-color: #FAF0F0; border-color: #E0B0B0; - } - .CDatabaseTrigger .Prototype, - .CEvent .Prototype, - .CDelegate .Prototype { - background-color: #F0FCF0; border-color: #B8E4B8 } - - .CToolTip .Prototype { - margin: 0 0 .5em 0; - white-space: nowrap; - } - - - - - -.Summary { - margin: 1.5em 5ex 0 5ex } - - .STitle { - font-size: 12pt; font-weight: bold; - margin-bottom: .5em } - - - .SBorder { - background-color: #FFFFF0; - padding: 15px; - border: 1px solid #C0C060 } - - /* In a frame IE 6 will make them too long unless you set the width to 100%. Without frames it will be correct without a width - or slightly too long (but not enough to scroll) with a width. This arbitrary weirdness simply astounds me. IE 7 has the same - problem with frames, haven't tested it without. */ - .FramedContentPage .IE .SBorder { - width: 100% } - - /* A treat for Mozilla users. Blatantly non-standard. Will be replaced with CSS 3 attributes when finalized/supported. */ - .Firefox .SBorder { - -moz-border-radius: 20px } - - - .STable { - font-size: 9pt; width: 100% } - - .SEntry { - width: 30% } - .SDescription { - width: 70% } - - - .SMarked { - background-color: #F8F8D8 } - - .SDescription { padding-left: 2ex } - .SIndent1 .SEntry { padding-left: 1.5ex } .SIndent1 .SDescription { padding-left: 3.5ex } - .SIndent2 .SEntry { padding-left: 3.0ex } .SIndent2 .SDescription { padding-left: 5.0ex } - .SIndent3 .SEntry { padding-left: 4.5ex } .SIndent3 .SDescription { padding-left: 6.5ex } - .SIndent4 .SEntry { padding-left: 6.0ex } .SIndent4 .SDescription { padding-left: 8.0ex } - .SIndent5 .SEntry { padding-left: 7.5ex } .SIndent5 .SDescription { padding-left: 9.5ex } - - .SDescription a { color: #800000} - .SDescription a:active { color: #A00000 } - - .SGroup td { - padding-top: .5em; padding-bottom: .25em } - - .SGroup .SEntry { - font-weight: bold; font-variant: small-caps } - - .SGroup .SEntry a { color: #800000 } - .SGroup .SEntry a:active { color: #F00000 } - - - .SMain td, - .SClass td, - .SDatabase td, - .SDatabaseTable td, - .SSection td { - font-size: 10pt; - padding-bottom: .25em } - - .SClass td, - .SDatabase td, - .SDatabaseTable td, - .SSection td { - padding-top: 1em } - - .SMain .SEntry, - .SClass .SEntry, - .SDatabase .SEntry, - .SDatabaseTable .SEntry, - .SSection .SEntry { - font-weight: bold; - } - - .SMain .SEntry a, - .SClass .SEntry a, - .SDatabase .SEntry a, - .SDatabaseTable .SEntry a, - .SSection .SEntry a { color: #000000 } - - .SMain .SEntry a:active, - .SClass .SEntry a:active, - .SDatabase .SEntry a:active, - .SDatabaseTable .SEntry a:active, - .SSection .SEntry a:active { color: #A00000 } - - - - - -.ClassHierarchy { - margin: 0 15px 1em 15px } - - .CHEntry { - border-width: 1px 2px 2px 1px; border-style: solid; border-color: #A0A0A0; - margin-bottom: 3px; - padding: 2px 2ex; - font-size: 10pt; - background-color: #F4F4F4; color: #606060; - } - - .Firefox .CHEntry { - -moz-border-radius: 4px; - } - - .CHCurrent .CHEntry { - font-weight: bold; - border-color: #000000; - color: #000000; - } - - .CHChildNote .CHEntry { - font-style: italic; - font-size: 8pt; - } - - .CHIndent { - margin-left: 3ex; - } - - .CHEntry a:link, - .CHEntry a:visited, - .CHEntry a:hover { - color: #606060; - } - .CHEntry a:active { - color: #800000; - } - - - - - -#Index { - background-color: #FFFFFF; - } - -/* As opposed to .PopupSearchResultsPage #Index */ -.IndexPage #Index, -.FramedIndexPage #Index, -.FramedSearchResultsPage #Index { - padding: 15px; - } - -.IndexPage #Index { - border-width: 0 0 1px 1px; - border-style: solid; - border-color: #000000; - font-size: 9pt; /* To make 27ex match the menu's 27ex. */ - margin-left: 27ex; - } - - - .IPageTitle { - font-size: 20pt; font-weight: bold; - color: #FFFFFF; background-color: #7070C0; - padding: 10px 15px 10px 15px; - border-width: 0 0 3px 0; border-color: #000000; border-style: solid; - margin: -15px -15px 0 -15px } - - .FramedSearchResultsPage .IPageTitle { - margin-bottom: 15px; - } - - .INavigationBar { - font-size: 10pt; - text-align: center; - background-color: #FFFFF0; - padding: 5px; - border-bottom: solid 1px black; - margin: 0 -15px 15px -15px; - } - - .INavigationBar a { - font-weight: bold } - - .IHeading { - font-size: 16pt; font-weight: bold; - padding: 2.5em 0 .5em 0; - text-align: center; - width: 3.5ex; - } - #IFirstHeading { - padding-top: 0; - } - - .IEntry { - font-size: 10pt; - padding-left: 1ex; - } - .PopupSearchResultsPage .IEntry { - font-size: 8pt; - padding: 1px 5px; - } - .PopupSearchResultsPage .Opera9 .IEntry, - .FramedSearchResultsPage .Opera9 .IEntry { - text-align: left; - } - .FramedSearchResultsPage .IEntry { - padding: 0; - } - - .ISubIndex { - padding-left: 3ex; padding-bottom: .5em } - .PopupSearchResultsPage .ISubIndex { - display: none; - } - - /* While it may cause some entries to look like links when they aren't, I found it's much easier to read the - index if everything's the same color. */ - .ISymbol { - font-weight: bold; color: #900000 } - - .IndexPage .ISymbolPrefix, - .FramedIndexPage .ISymbolPrefix { - font-size: 10pt; - text-align: right; - color: #C47C7C; - background-color: #F8F8F8; - border-right: 3px solid #E0E0E0; - border-left: 1px solid #E0E0E0; - padding: 0 1px 0 2px; - } - .PopupSearchResultsPage .ISymbolPrefix, - .FramedSearchResultsPage .ISymbolPrefix { - color: #900000; - } - .PopupSearchResultsPage .ISymbolPrefix { - font-size: 8pt; - } - - .IndexPage #IFirstSymbolPrefix, - .FramedIndexPage #IFirstSymbolPrefix { - border-top: 1px solid #E0E0E0; - } - .IndexPage #ILastSymbolPrefix, - .FramedIndexPage #ILastSymbolPrefix { - border-bottom: 1px solid #E0E0E0; - } - .IndexPage #IOnlySymbolPrefix, - .FramedIndexPage #IOnlySymbolPrefix { - border-top: 1px solid #E0E0E0; - border-bottom: 1px solid #E0E0E0; - } - - a.IParent, - a.IFile { - display: block; - } - - .PopupSearchResultsPage .SRStatus { - padding: 2px 5px; - font-size: 8pt; - font-style: italic; - } - .FramedSearchResultsPage .SRStatus { - font-size: 10pt; - font-style: italic; - } - - .SRResult { - display: none; - } - - - -#Footer { - font-size: 8pt; - color: #989898; - text-align: right; - } - -#Footer p { - text-indent: 0; - margin-bottom: .5em; - } - -.ContentPage #Footer, -.IndexPage #Footer { - text-align: right; - margin: 2px; - } - -.FramedMenuPage #Footer { - text-align: center; - margin: 5em 10px 10px 10px; - padding-top: 1em; - border-top: 1px solid #C8C8C8; - } - - #Footer a:link, - #Footer a:hover, - #Footer a:visited { color: #989898 } - #Footer a:active { color: #A00000 } - diff --git a/build/svg-edit-2.6-src/editor/.DS_Store b/build/svg-edit-2.6-src/editor/.DS_Store deleted file mode 100644 index daa51da..0000000 Binary files a/build/svg-edit-2.6-src/editor/.DS_Store and /dev/null differ diff --git a/build/svg-edit-2.6-src/editor/browser-not-supported.html b/build/svg-edit-2.6-src/editor/browser-not-supported.html deleted file mode 100644 index 3010fcf..0000000 --- a/build/svg-edit-2.6-src/editor/browser-not-supported.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - -Browser does not support SVG | SVG-edit - - - -
        -SVG-edit logo
        -

        Sorry, but your browser does not support SVG. Below is a list of alternate browsers and versions that support SVG and SVG-edit (from caniuse.com).

        -

        Try the latest version of Firefox, Google Chrome, Safari, Opera or Internet Explorer.

        -

        If you are unable to install one of these and must use an old version of Internet Explorer, you can install the Google Chrome Frame plugin.

        - - - -
        - - - diff --git a/build/svg-edit-2.6-src/editor/browser.js b/build/svg-edit-2.6-src/editor/browser.js deleted file mode 100644 index edfba7b..0000000 --- a/build/svg-edit-2.6-src/editor/browser.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Package: svgedit.browser - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Alexis Deveria - */ - -// Dependencies: -// 1) jQuery (for $.alert()) - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.browser) { - svgedit.browser = {}; -} -var supportsSvg_ = (function() { - return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect; -})(); -svgedit.browser.supportsSvg = function() { return supportsSvg_; } -if(!svgedit.browser.supportsSvg()) { - window.location = "browser-not-supported.html"; -} -else{ - -var svgns = 'http://www.w3.org/2000/svg'; -var userAgent = navigator.userAgent; -var svg = document.createElementNS(svgns, 'svg'); - -// Note: Browser sniffing should only be used if no other detection method is possible -var isOpera_ = !!window.opera; -var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0; -var isGecko_ = userAgent.indexOf('Gecko/') >= 0; -var isIE_ = userAgent.indexOf('MSIE') >= 0; -var isChrome_ = userAgent.indexOf('Chrome/') >= 0; -var isWindows_ = userAgent.indexOf('Windows') >= 0; -var isMac_ = userAgent.indexOf('Macintosh') >= 0; -var isTouch_ = 'ontouchstart' in window; - -var supportsSelectors_ = (function() { - return !!svg.querySelector; -})(); - -var supportsXpath_ = (function() { - return !!document.evaluate; -})(); - -// segList functions (for FF1.5 and 2.0) -var supportsPathReplaceItem_ = (function() { - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.replaceItem(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -var supportsPathInsertItemBefore_ = (function() { - var path = document.createElementNS(svgns,'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.insertItemBefore(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -// text character positioning (for IE9) -var supportsGoodTextCharPos_ = (function() { - var retValue = false; - var svgroot = document.createElementNS(svgns, 'svg'); - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgroot); - svgcontent.setAttribute('x', 5); - svgroot.appendChild(svgcontent); - var text = document.createElementNS(svgns,'text'); - text.textContent = 'a'; - svgcontent.appendChild(text); - var pos = text.getStartPositionOfChar(0).x; - document.documentElement.removeChild(svgroot); - return (pos === 0); -})(); - -var supportsPathBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 C0,0 10,10 10,0'); - svgcontent.appendChild(path); - var bbox = path.getBBox(); - document.documentElement.removeChild(svgcontent); - return (bbox.height > 4 && bbox.height < 5); -})(); - -// Support for correct bbox sizing on groups with horizontal/vertical lines -var supportsHVLineContainerBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,0'); - var path2 = document.createElementNS(svgns, 'path'); - path2.setAttribute('d','M5,0 15,0'); - var g = document.createElementNS(svgns, 'g'); - g.appendChild(path); - g.appendChild(path2); - svgcontent.appendChild(g); - var bbox = g.getBBox(); - document.documentElement.removeChild(svgcontent); - // Webkit gives 0, FF gives 10, Opera (correctly) gives 15 - return (bbox.width == 15); -})(); - -var supportsEditableText_ = (function() { - // TODO: Find better way to check support for this - return isOpera_; -})(); - -var supportsGoodDecimals_ = (function() { - // Correct decimals on clone attributes (Opera < 10.5/win/non-en) - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('x',.1); - var crect = rect.cloneNode(false); - var retValue = (crect.getAttribute('x').indexOf(',') == -1); - if(!retValue) { - $.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\ - Please upgrade to the latest version in which the problems have been fixed."); - } - return retValue; -})(); - -var supportsNonScalingStroke_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('style','vector-effect:non-scaling-stroke'); - return rect.style.vectorEffect === 'non-scaling-stroke'; -})(); - -var supportsNativeSVGTransformLists_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - var rxform = rect.transform.baseVal; - - var t1 = svg.createSVGTransform(); - rxform.appendItem(t1); - return rxform.getItem(0) == t1; -})(); - -// Public API - -svgedit.browser.isOpera = function() { return isOpera_; } -svgedit.browser.isWebkit = function() { return isWebkit_; } -svgedit.browser.isGecko = function() { return isGecko_; } -svgedit.browser.isIE = function() { return isIE_; } -svgedit.browser.isChrome = function() { return isChrome_; } -svgedit.browser.isWindows = function() { return isWindows_; } -svgedit.browser.isMac = function() { return isMac_; } -svgedit.browser.isTouch = function() { return isTouch_; } - -svgedit.browser.supportsSelectors = function() { return supportsSelectors_; } -svgedit.browser.supportsXpath = function() { return supportsXpath_; } - -svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; } -svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; } -svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; } -svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; } -svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; } -svgedit.browser.supportsEditableText = function() { return supportsEditableText_; } -svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; } -svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; } -svgedit.browser.supportsNativeTransformLists = function() { return supportsNativeSVGTransformLists_; } - -} - -})(); diff --git a/build/svg-edit-2.6-src/editor/canvg/canvg.js b/build/svg-edit-2.6-src/editor/canvg/canvg.js deleted file mode 100644 index 7b24a38..0000000 --- a/build/svg-edit-2.6-src/editor/canvg/canvg.js +++ /dev/null @@ -1,2620 +0,0 @@ -/* - * canvg.js - Javascript SVG parser and renderer on Canvas - * MIT Licensed - * Gabe Lerner (gabelerner@gmail.com) - * http://code.google.com/p/canvg/ - * - * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ - */ -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(!Array.prototype.indexOf){ - Array.prototype.indexOf = function(obj){ - for(var i=0; i ignore mouse events - // ignoreAnimation: true => ignore animations - // ignoreDimensions: true => does not try to resize canvas - // ignoreClear: true => does not clear canvas - // offsetX: int => draws at a x offset - // offsetY: int => draws at a y offset - // scaleWidth: int => scales horizontally to width - // scaleHeight: int => scales vertically to height - // renderCallback: function => will call the function after the first render is completed - // forceRedraw: function => will call the function on every frame, if it returns true, will redraw - this.canvg = function (target, s, opts) { - // no parameters - if (target == null && s == null && opts == null) { - var svgTags = document.getElementsByTagName('svg'); - for (var i=0; i]*>/, ''); - var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); - xmlDoc.async = 'false'; - xmlDoc.loadXML(xml); - return xmlDoc; - } - } - - svg.Property = function(name, value) { - this.name = name; - this.value = value; - - this.hasValue = function() { - return (this.value != null && this.value !== ''); - } - - // return the numerical value of the property - this.numValue = function() { - if (!this.hasValue()) return 0; - - var n = parseFloat(this.value); - if ((this.value + '').match(/%$/)) { - n = n / 100.0; - } - return n; - } - - this.valueOrDefault = function(def) { - if (this.hasValue()) return this.value; - return def; - } - - this.numValueOrDefault = function(def) { - if (this.hasValue()) return this.numValue(); - return def; - } - - /* EXTENSIONS */ - var that = this; - - // color extensions - this.Color = { - // augment the current color value with the opacity - addOpacity: function(opacity) { - var newValue = that.value; - if (opacity != null && opacity != '') { - var color = new RGBColor(that.value); - if (color.ok) { - newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')'; - } - } - return new svg.Property(that.name, newValue); - } - } - - // definition extensions - this.Definition = { - // get the definition from the definitions table - getDefinition: function() { - var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2'); - return svg.Definitions[name]; - }, - - isUrl: function() { - return that.value.indexOf('url(') == 0 - }, - - getFillStyle: function(e) { - var def = this.getDefinition(); - - // gradient - if (def != null && def.createGradient) { - return def.createGradient(svg.ctx, e); - } - - // pattern - if (def != null && def.createPattern) { - return def.createPattern(svg.ctx, e); - } - - return null; - } - } - - // length extensions - this.Length = { - DPI: function(viewPort) { - return 96.0; // TODO: compute? - }, - - EM: function(viewPort) { - var em = 12; - - var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); - if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort); - - return em; - }, - - // get the length as pixels - toPixels: function(viewPort) { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/em$/)) return that.numValue() * this.EM(viewPort); - if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0; - if (s.match(/px$/)) return that.numValue(); - if (s.match(/pt$/)) return that.numValue() * 1.25; - if (s.match(/pc$/)) return that.numValue() * 15; - if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54; - if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4; - if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort); - if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort); - return that.numValue(); - } - } - - // time extensions - this.Time = { - // get the time as milliseconds - toMilliseconds: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/s$/)) return that.numValue() * 1000; - if (s.match(/ms$/)) return that.numValue(); - return that.numValue(); - } - } - - // angle extensions - this.Angle = { - // get the angle as radians - toRadians: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0); - if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0); - if (s.match(/rad$/)) return that.numValue(); - return that.numValue() * (Math.PI / 180.0); - } - } - } - - // fonts - svg.Font = new (function() { - this.Styles = ['normal','italic','oblique','inherit']; - this.Variants = ['normal','small-caps','inherit']; - this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit']; - - this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { - var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); - return { - fontFamily: fontFamily || f.fontFamily, - fontSize: fontSize || f.fontSize, - fontStyle: fontStyle || f.fontStyle, - fontWeight: fontWeight || f.fontWeight, - fontVariant: fontVariant || f.fontVariant, - toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } - } - } - - var that = this; - this.Parse = function(s) { - var f = {}; - var d = svg.trim(svg.compressSpaces(s || '')).split(' '); - var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } - var ff = ''; - for (var i=0; i this.x2) this.x2 = x; - } - - if (y != null) { - if (isNaN(this.y1) || isNaN(this.y2)) { - this.y1 = y; - this.y2 = y; - } - if (y < this.y1) this.y1 = y; - if (y > this.y2) this.y2 = y; - } - } - this.addX = function(x) { this.addPoint(x, null); } - this.addY = function(y) { this.addPoint(null, y); } - - this.addBoundingBox = function(bb) { - this.addPoint(bb.x1, bb.y1); - this.addPoint(bb.x2, bb.y2); - } - - this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { - var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) - var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) - this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); - } - - this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { - // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; - this.addPoint(p0[0], p0[1]); - this.addPoint(p3[0], p3[1]); - - for (i=0; i<=1; i++) { - var f = function(t) { - return Math.pow(1-t, 3) * p0[i] - + 3 * Math.pow(1-t, 2) * t * p1[i] - + 3 * (1-t) * Math.pow(t, 2) * p2[i] - + Math.pow(t, 3) * p3[i]; - } - - var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; - var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; - var c = 3 * p1[i] - 3 * p0[i]; - - if (a == 0) { - if (b == 0) continue; - var t = -c / b; - if (0 < t && t < 1) { - if (i == 0) this.addX(f(t)); - if (i == 1) this.addY(f(t)); - } - continue; - } - - var b2ac = Math.pow(b, 2) - 4 * c * a; - if (b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); - if (0 < t1 && t1 < 1) { - if (i == 0) this.addX(f(t1)); - if (i == 1) this.addY(f(t1)); - } - var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); - if (0 < t2 && t2 < 1) { - if (i == 0) this.addX(f(t2)); - if (i == 1) this.addY(f(t2)); - } - } - } - - this.isPointInBox = function(x, y) { - return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); - } - - this.addPoint(x1, y1); - this.addPoint(x2, y2); - } - - // transforms - svg.Transform = function(v) { - var that = this; - this.Type = {} - - // translate - this.Type.translate = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.translate(this.p.x || 0.0, this.p.y || 0.0); - } - this.applyToPoint = function(p) { - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - } - } - - // rotate - this.Type.rotate = function(s) { - var a = svg.ToNumberArray(s); - this.angle = new svg.Property('angle', a[0]); - this.cx = a[1] || 0; - this.cy = a[2] || 0; - this.apply = function(ctx) { - ctx.translate(this.cx, this.cy); - ctx.rotate(this.angle.Angle.toRadians()); - ctx.translate(-this.cx, -this.cy); - } - this.applyToPoint = function(p) { - var a = this.angle.Angle.toRadians(); - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); - p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); - } - } - - this.Type.scale = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); - } - this.applyToPoint = function(p) { - p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); - } - } - - this.Type.matrix = function(s) { - this.m = svg.ToNumberArray(s); - this.apply = function(ctx) { - ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); - } - this.applyToPoint = function(p) { - p.applyTransform(this.m); - } - } - - this.Type.SkewBase = function(s) { - this.base = that.Type.matrix; - this.base(s); - this.angle = new svg.Property('angle', s); - } - this.Type.SkewBase.prototype = new this.Type.matrix; - - this.Type.skewX = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0]; - } - this.Type.skewX.prototype = new this.Type.SkewBase; - - this.Type.skewY = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0]; - } - this.Type.skewY.prototype = new this.Type.SkewBase; - - this.transforms = []; - - this.apply = function(ctx) { - for (var i=0; i= this.tokens.length - 1; - } - - this.isCommandOrEnd = function() { - if (this.isEnd()) return true; - return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; - } - - this.isRelativeCommand = function() { - return this.command == this.command.toLowerCase(); - } - - this.getToken = function() { - this.i = this.i + 1; - return this.tokens[this.i]; - } - - this.getScalar = function() { - return parseFloat(this.getToken()); - } - - this.nextCommand = function() { - this.previousCommand = this.command; - this.command = this.getToken(); - } - - this.getPoint = function() { - var p = new svg.Point(this.getScalar(), this.getScalar()); - return this.makeAbsolute(p); - } - - this.getAsControlPoint = function() { - var p = this.getPoint(); - this.control = p; - return p; - } - - this.getAsCurrentPoint = function() { - var p = this.getPoint(); - this.current = p; - return p; - } - - this.getReflectedControlPoint = function() { - if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') { - return this.current; - } - - // reflect point - var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); - return p; - } - - this.makeAbsolute = function(p) { - if (this.isRelativeCommand()) { - p.x = this.current.x + p.x; - p.y = this.current.y + p.y; - } - return p; - } - - this.addMarker = function(p, from, priorTo) { - // if the last angle isn't filled in because we didn't have this point yet ... - if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) { - this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo); - } - this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); - } - - this.addMarkerAngle = function(p, a) { - this.points.push(p); - this.angles.push(a); - } - - this.getMarkerPoints = function() { return this.points; } - this.getMarkerAngles = function() { - for (var i=0; i 1) { - rx *= Math.sqrt(l); - ry *= Math.sqrt(l); - } - // cx', cy' - var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( - ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / - (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) - ); - if (isNaN(s)) s = 0; - var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); - // cx, cy - var centp = new svg.Point( - (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, - (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y - ); - // vector magnitude - var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } - // ratio between two vectors - var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } - // angle between two vectors - var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } - // initial angle - var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); - // angle delta - var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; - var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; - var ad = a(u, v); - if (r(u,v) <= -1) ad = Math.PI; - if (r(u,v) >= 1) ad = 0; - - if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI; - if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI; - - // for markers - var halfWay = new svg.Point( - centp.x - rx * Math.cos((a1 + ad) / 2), - centp.y - ry * Math.sin((a1 + ad) / 2) - ); - pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - - bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better - if (ctx != null) { - var r = rx > ry ? rx : ry; - var sx = rx > ry ? 1 : rx / ry; - var sy = rx > ry ? ry / rx : 1; - - ctx.translate(centp.x, centp.y); - ctx.rotate(xAxisRotation); - ctx.scale(sx, sy); - ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); - ctx.scale(1/sx, 1/sy); - ctx.rotate(-xAxisRotation); - ctx.translate(-centp.x, -centp.y); - } - } - break; - case 'Z': - if (ctx != null) ctx.closePath(); - pp.current = pp.start; - } - } - - return bb; - } - - this.getMarkers = function() { - var points = this.PathParser.getMarkerPoints(); - var angles = this.PathParser.getMarkerAngles(); - - var markers = []; - for (var i=0; i this.maxDuration) { - // loop for indefinitely repeating animations - if (this.attribute('repeatCount').value == 'indefinite') { - this.duration = 0.0 - } - else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { - this.removed = true; - this.getProperty().value = this.initialValue; - return true; - } - else { - return false; // no updates made - } - } - this.duration = this.duration + delta; - - // if we're past the begin time - var updated = false; - if (this.begin < this.duration) { - var newValue = this.calcValue(); // tween - - if (this.attribute('type').hasValue()) { - // for transform, etc. - var type = this.attribute('type').value; - newValue = type + '(' + newValue + ')'; - } - - this.getProperty().value = newValue; - updated = true; - } - - return updated; - } - - // fraction of duration we've covered - this.progress = function() { - return ((this.duration - this.begin) / (this.maxDuration - this.begin)); - } - } - svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; - - // animate element - svg.Element.animate = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = this.attribute('from').numValue(); - var to = this.attribute('to').numValue(); - - // tween value linearly - return from + (to - from) * this.progress(); - }; - } - svg.Element.animate.prototype = new svg.Element.AnimateBase; - - // animate color element - svg.Element.animateColor = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = new RGBColor(this.attribute('from').value); - var to = new RGBColor(this.attribute('to').value); - - if (from.ok && to.ok) { - // tween color linearly - var r = from.r + (to.r - from.r) * this.progress(); - var g = from.g + (to.g - from.g) * this.progress(); - var b = from.b + (to.b - from.b) * this.progress(); - return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; - } - return this.attribute('from').value; - }; - } - svg.Element.animateColor.prototype = new svg.Element.AnimateBase; - - // animate transform element - svg.Element.animateTransform = function(node) { - this.base = svg.Element.animate; - this.base(node); - } - svg.Element.animateTransform.prototype = new svg.Element.animate; - - // font element - svg.Element.font = function(node) { - this.base = svg.Element.ElementBase; - this.base(node); - - this.horizAdvX = this.attribute('horiz-adv-x').numValue(); - - this.isRTL = false; - this.isArabic = false; - this.fontFace = null; - this.missingGlyph = null; - this.glyphs = []; - for (var i=0; i0 && text[i-1]!=' ' && i0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial'; - if (typeof(font.glyphs[c]) != 'undefined') { - glyph = font.glyphs[c][arabicForm]; - if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c]; - } - } - else { - glyph = font.glyphs[c]; - } - if (glyph == null) glyph = font.missingGlyph; - return glyph; - } - - this.renderChildren = function(ctx) { - var customFont = this.parent.style('font-family').Definition.getDefinition(); - if (customFont != null) { - var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); - var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle); - var text = this.getText(); - if (customFont.isRTL) text = text.split("").reverse().join(""); - - var dx = svg.ToNumberArray(this.parent.attribute('dx').value); - for (var i=0; i 0 ? node.childNodes[0].nodeValue : // element - node.text; - this.getText = function() { - return this.text; - } - } - svg.Element.tspan.prototype = new svg.Element.TextElementBase; - - // tref - svg.Element.tref = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.getText = function() { - var element = this.attribute('xlink:href').Definition.getDefinition(); - if (element != null) return element.children[0].getText(); - } - } - svg.Element.tref.prototype = new svg.Element.TextElementBase; - - // a element - svg.Element.a = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.hasText = true; - for (var i=0; i 1 ? node.childNodes[1].nodeValue : ''); - css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments - css = svg.compressSpaces(css); // replace whitespace - var cssDefs = css.split('}'); - for (var i=0; i 0) { - var urlStart = srcs[s].indexOf('url'); - var urlEnd = srcs[s].indexOf(')', urlStart); - var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6); - var doc = svg.parseXml(svg.ajax(url)); - var fonts = doc.getElementsByTagName('font'); - for (var f=0; f - * @link http://www.phpied.com/rgb-color-parser-in-javascript/ - * @license Use it if you like it - */ -function RGBColor(color_string) -{ - this.ok = false; - - // strip any leading # - if (color_string.charAt(0) == '#') { // remove # if any - color_string = color_string.substr(1,6); - } - - color_string = color_string.replace(/ /g,''); - color_string = color_string.toLowerCase(); - - // before getting into regexps, try simple matches - // and overwrite the input - var simple_colors = { - aliceblue: 'f0f8ff', - antiquewhite: 'faebd7', - aqua: '00ffff', - aquamarine: '7fffd4', - azure: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '000000', - blanchedalmond: 'ffebcd', - blue: '0000ff', - blueviolet: '8a2be2', - brown: 'a52a2a', - burlywood: 'deb887', - cadetblue: '5f9ea0', - chartreuse: '7fff00', - chocolate: 'd2691e', - coral: 'ff7f50', - cornflowerblue: '6495ed', - cornsilk: 'fff8dc', - crimson: 'dc143c', - cyan: '00ffff', - darkblue: '00008b', - darkcyan: '008b8b', - darkgoldenrod: 'b8860b', - darkgray: 'a9a9a9', - darkgreen: '006400', - darkkhaki: 'bdb76b', - darkmagenta: '8b008b', - darkolivegreen: '556b2f', - darkorange: 'ff8c00', - darkorchid: '9932cc', - darkred: '8b0000', - darksalmon: 'e9967a', - darkseagreen: '8fbc8f', - darkslateblue: '483d8b', - darkslategray: '2f4f4f', - darkturquoise: '00ced1', - darkviolet: '9400d3', - deeppink: 'ff1493', - deepskyblue: '00bfff', - dimgray: '696969', - dodgerblue: '1e90ff', - feldspar: 'd19275', - firebrick: 'b22222', - floralwhite: 'fffaf0', - forestgreen: '228b22', - fuchsia: 'ff00ff', - gainsboro: 'dcdcdc', - ghostwhite: 'f8f8ff', - gold: 'ffd700', - goldenrod: 'daa520', - gray: '808080', - green: '008000', - greenyellow: 'adff2f', - honeydew: 'f0fff0', - hotpink: 'ff69b4', - indianred : 'cd5c5c', - indigo : '4b0082', - ivory: 'fffff0', - khaki: 'f0e68c', - lavender: 'e6e6fa', - lavenderblush: 'fff0f5', - lawngreen: '7cfc00', - lemonchiffon: 'fffacd', - lightblue: 'add8e6', - lightcoral: 'f08080', - lightcyan: 'e0ffff', - lightgoldenrodyellow: 'fafad2', - lightgrey: 'd3d3d3', - lightgreen: '90ee90', - lightpink: 'ffb6c1', - lightsalmon: 'ffa07a', - lightseagreen: '20b2aa', - lightskyblue: '87cefa', - lightslateblue: '8470ff', - lightslategray: '778899', - lightsteelblue: 'b0c4de', - lightyellow: 'ffffe0', - lime: '00ff00', - limegreen: '32cd32', - linen: 'faf0e6', - magenta: 'ff00ff', - maroon: '800000', - mediumaquamarine: '66cdaa', - mediumblue: '0000cd', - mediumorchid: 'ba55d3', - mediumpurple: '9370d8', - mediumseagreen: '3cb371', - mediumslateblue: '7b68ee', - mediumspringgreen: '00fa9a', - mediumturquoise: '48d1cc', - mediumvioletred: 'c71585', - midnightblue: '191970', - mintcream: 'f5fffa', - mistyrose: 'ffe4e1', - moccasin: 'ffe4b5', - navajowhite: 'ffdead', - navy: '000080', - oldlace: 'fdf5e6', - olive: '808000', - olivedrab: '6b8e23', - orange: 'ffa500', - orangered: 'ff4500', - orchid: 'da70d6', - palegoldenrod: 'eee8aa', - palegreen: '98fb98', - paleturquoise: 'afeeee', - palevioletred: 'd87093', - papayawhip: 'ffefd5', - peachpuff: 'ffdab9', - peru: 'cd853f', - pink: 'ffc0cb', - plum: 'dda0dd', - powderblue: 'b0e0e6', - purple: '800080', - red: 'ff0000', - rosybrown: 'bc8f8f', - royalblue: '4169e1', - saddlebrown: '8b4513', - salmon: 'fa8072', - sandybrown: 'f4a460', - seagreen: '2e8b57', - seashell: 'fff5ee', - sienna: 'a0522d', - silver: 'c0c0c0', - skyblue: '87ceeb', - slateblue: '6a5acd', - slategray: '708090', - snow: 'fffafa', - springgreen: '00ff7f', - steelblue: '4682b4', - tan: 'd2b48c', - teal: '008080', - thistle: 'd8bfd8', - tomato: 'ff6347', - turquoise: '40e0d0', - violet: 'ee82ee', - violetred: 'd02090', - wheat: 'f5deb3', - white: 'ffffff', - whitesmoke: 'f5f5f5', - yellow: 'ffff00', - yellowgreen: '9acd32' - }; - for (var key in simple_colors) { - if (color_string == key) { - color_string = simple_colors[key]; - } - } - // emd of simple type-in colors - - // array of color definition objects - var color_defs = [ - { - re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, - example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], - process: function (bits){ - return [ - parseInt(bits[1]), - parseInt(bits[2]), - parseInt(bits[3]) - ]; - } - }, - { - re: /^(\w{2})(\w{2})(\w{2})$/, - example: ['#00ff00', '336699'], - process: function (bits){ - return [ - parseInt(bits[1], 16), - parseInt(bits[2], 16), - parseInt(bits[3], 16) - ]; - } - }, - { - re: /^(\w{1})(\w{1})(\w{1})$/, - example: ['#fb0', 'f0f'], - process: function (bits){ - return [ - parseInt(bits[1] + bits[1], 16), - parseInt(bits[2] + bits[2], 16), - parseInt(bits[3] + bits[3], 16) - ]; - } - } - ]; - - // search through the definitions to find a match - for (var i = 0; i < color_defs.length; i++) { - var re = color_defs[i].re; - var processor = color_defs[i].process; - var bits = re.exec(color_string); - if (bits) { - channels = processor(bits); - this.r = channels[0]; - this.g = channels[1]; - this.b = channels[2]; - this.ok = true; - } - - } - - // validate/cleanup values - this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); - this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); - this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); - - // some getters - this.toRGB = function () { - return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; - } - this.toHex = function () { - var r = this.r.toString(16); - var g = this.g.toString(16); - var b = this.b.toString(16); - if (r.length == 1) r = '0' + r; - if (g.length == 1) g = '0' + g; - if (b.length == 1) b = '0' + b; - return '#' + r + g + b; - } - - // help - this.getHelpXML = function () { - - var examples = new Array(); - // add regexps - for (var i = 0; i < color_defs.length; i++) { - var example = color_defs[i].example; - for (var j = 0; j < example.length; j++) { - examples[examples.length] = example[j]; - } - } - // add type-in colors - for (var sc in simple_colors) { - examples[examples.length] = sc; - } - - var xml = document.createElement('ul'); - xml.setAttribute('id', 'rgbcolor-examples'); - for (var i = 0; i < examples.length; i++) { - try { - var list_item = document.createElement('li'); - var list_color = new RGBColor(examples[i]); - var example_div = document.createElement('div'); - example_div.style.cssText = - 'margin: 3px; ' - + 'border: 1px solid black; ' - + 'background:' + list_color.toHex() + '; ' - + 'color:' + list_color.toHex() - ; - example_div.appendChild(document.createTextNode('test')); - var list_item_value = document.createTextNode( - ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() - ); - list_item.appendChild(example_div); - list_item.appendChild(list_item_value); - xml.appendChild(list_item); - - } catch(e){} - } - return xml; - - } - -} diff --git a/build/svg-edit-2.6-src/editor/contextmenu.js b/build/svg-edit-2.6-src/editor/contextmenu.js deleted file mode 100644 index afa4318..0000000 --- a/build/svg-edit-2.6-src/editor/contextmenu.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Package: svgedit.contextmenu - * - * Licensed under the Apache License, Version 2 - * - * Author: Adam Bender - */ -// Dependencies: -// 1) jQuery (for dom injection of context menus)\ - -var svgedit = svgedit || {}; -(function() { - var self = this; - if (!svgedit.contextmenu) { - svgedit.contextmenu = {}; - } - self.contextMenuExtensions = {} - var addContextMenuItem = function(menuItem) { - // menuItem: {id, label, shortcut, action} - if (!menuItemIsValid(menuItem)) { - console - .error("Menu items must be defined and have at least properties: id, label, action, where action must be a function"); - return; - } - if (menuItem.id in self.contextMenuExtensions) { - console.error('Cannot add extension "' + menuItem.id - + '", an extension by that name already exists"'); - return; - } - // Register menuItem action, see below for deferred menu dom injection - console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}"); - self.contextMenuExtensions[menuItem.id] = menuItem; - //TODO: Need to consider how to handle custom enable/disable behavior - } - var hasCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey] && true; - } - var getCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey].action; - } - var injectExtendedContextMenuItemIntoDom = function(menuItem) { - if (Object.keys(self.contextMenuExtensions).length == 0) { - // all menuItems appear at the bottom of the menu in their own container. - // if this is the first extension menu we need to add the separator. - $("#cmenu_canvas").append("
      • "); - } - var shortcut = menuItem.shortcut || ""; - $("#cmenu_canvas").append("
      • " - + menuItem.label + "" - + shortcut + "
      • "); - } - - var menuItemIsValid = function(menuItem) { - return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function'; - } - - // Defer injection to wait out initial menu processing. This probably goes away once all context - // menu behavior is brought here. - svgEditor.ready(function() { - for (menuItem in contextMenuExtensions) { - injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]); - } - }); - svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {}} - svgedit.contextmenu.add = addContextMenuItem; - svgedit.contextmenu.hasCustomHandler = hasCustomHandler; - svgedit.contextmenu.getCustomHandler = getCustomHandler; -})(); diff --git a/build/svg-edit-2.6-src/editor/contextmenu/jquery.contextMenu.js b/build/svg-edit-2.6-src/editor/contextmenu/jquery.contextMenu.js deleted file mode 100755 index 009d6cd..0000000 --- a/build/svg-edit-2.6-src/editor/contextmenu/jquery.contextMenu.js +++ /dev/null @@ -1,203 +0,0 @@ -// jQuery Context Menu Plugin -// -// Version 1.01 -// -// Cory S.N. LaViska -// A Beautiful Site (http://abeautifulsite.net/) -// Modified by Alexis Deveria -// -// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/ -// -// Terms of Use -// -// This plugin is dual-licensed under the GNU General Public License -// and the MIT License and is copyright A Beautiful Site, LLC. -// -if(jQuery)( function() { - var win = $(window); - var doc = $(document); - - $.extend($.fn, { - - contextMenu: function(o, callback) { - // Defaults - if( o.menu == undefined ) return false; - if( o.inSpeed == undefined ) o.inSpeed = 150; - if( o.outSpeed == undefined ) o.outSpeed = 75; - // 0 needs to be -1 for expected results (no fade) - if( o.inSpeed == 0 ) o.inSpeed = -1; - if( o.outSpeed == 0 ) o.outSpeed = -1; - // Loop each context menu - $(this).each( function() { - var el = $(this); - var offset = $(el).offset(); - - var menu = $('#' + o.menu); - - // Add contextMenu class - menu.addClass('contextMenu'); - // Simulate a true right click - $(this).bind( "mousedown", function(e) { - var evt = e; - $(this).mouseup( function(e) { - var srcElement = $(this); - srcElement.unbind('mouseup'); - $(".contextMenu").hide(); - if( evt.button === 2 || o.allowLeft || (evt.ctrlKey && svgedit.browser.isMac()) ) { - e.stopPropagation(); - - // Get this context menu - - if( el.hasClass('disabled') ) return false; - - // Detect mouse position - var d = {}, x = e.pageX, y = e.pageY; - - var x_off = win.width() - menu.width(), - y_off = win.height() - menu.height(); - - if(x > x_off - 15) x = x_off-15; - if(y > y_off - 30) y = y_off-30; // 30 is needed to prevent scrollbars in FF - - // Show the menu - doc.unbind('click'); - menu.css({ top: y, left: x }).fadeIn(o.inSpeed); - // Hover events - menu.find('A').mouseover( function() { - menu.find('LI.hover').removeClass('hover'); - $(this).parent().addClass('hover'); - }).mouseout( function() { - menu.find('LI.hover').removeClass('hover'); - }); - - // Keyboard - doc.keypress( function(e) { - switch( e.keyCode ) { - case 38: // up - if( !menu.find('LI.hover').length ) { - menu.find('LI:last').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:last').addClass('hover'); - } - break; - case 40: // down - if( menu.find('LI.hover').length == 0 ) { - menu.find('LI:first').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:first').addClass('hover'); - } - break; - case 13: // enter - menu.find('LI.hover A').trigger('click'); - break; - case 27: // esc - doc.trigger('click'); - break - } - }); - - // When items are selected - menu.find('A').unbind('mouseup'); - menu.find('LI:not(.disabled) A').mouseup( function() { - doc.unbind('click').unbind('keypress'); - $(".contextMenu").hide(); - // Callback - if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); - return false; - }); - - // Hide bindings - setTimeout( function() { // Delay for Mozilla - doc.click( function() { - doc.unbind('click').unbind('keypress'); - menu.fadeOut(o.outSpeed); - return false; - }); - }, 0); - } - }); - }); - - // Disable text selection - if( $.browser.mozilla ) { - $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); - } else if( $.browser.msie ) { - $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); - } else { - $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); - } - // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) - $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); - - }); - return $(this); - }, - - // Disable context menu items on the fly - disableContextMenuItems: function(o) { - if( o == undefined ) { - // Disable all - $(this).find('LI').addClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Enable context menu items on the fly - enableContextMenuItems: function(o) { - if( o == undefined ) { - // Enable all - $(this).find('LI.disabled').removeClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Disable context menu(s) - disableContextMenu: function() { - $(this).each( function() { - $(this).addClass('disabled'); - }); - return( $(this) ); - }, - - // Enable context menu(s) - enableContextMenu: function() { - $(this).each( function() { - $(this).removeClass('disabled'); - }); - return( $(this) ); - }, - - // Destroy context menu(s) - destroyContextMenu: function() { - // Destroy specified context menus - $(this).each( function() { - // Disable action - $(this).unbind('mousedown').unbind('mouseup'); - }); - return( $(this) ); - } - - }); -})(jQuery); \ No newline at end of file diff --git a/build/svg-edit-2.6-src/editor/draginput.js b/build/svg-edit-2.6-src/editor/draginput.js deleted file mode 100644 index 0c172b1..0000000 --- a/build/svg-edit-2.6-src/editor/draginput.js +++ /dev/null @@ -1,47 +0,0 @@ -;(function($) { - - var methods = { - - init : function(options) { - - return this.each(function() { - - var settings = { - }; - - if(options) { - $.extend(settings, options); - } - - var plugin = this; - var $plugin = $(this); - - $plugin.settings = settings; - - this.privateMethod = function() { - } - - $plugin.data("example", {}); - - // Plug-in code here... - }); - - }, - - publicFunction : function() { - } - }; - - $.fn.example = function(method) { - if(methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } - else if(typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } - else { - $.error("Method " + method + " does not exist on jQuery.example"); - } - }; - -})(jQuery); \ No newline at end of file diff --git a/build/svg-edit-2.6-src/editor/draw.js b/build/svg-edit-2.6-src/editor/draw.js deleted file mode 100644 index 8db3138..0000000 --- a/build/svg-edit-2.6-src/editor/draw.js +++ /dev/null @@ -1,528 +0,0 @@ -/** - * Package: svgedit.draw - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2011 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgutils.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.draw) { - svgedit.draw = {}; -} - -var svg_ns = "http://www.w3.org/2000/svg"; -var se_ns = "http://svg-edit.googlecode.com"; -var xmlns_ns = "http://www.w3.org/2000/xmlns/"; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); - -var RandomizeModes = { - LET_DOCUMENT_DECIDE: 0, - ALWAYS_RANDOMIZE: 1, - NEVER_RANDOMIZE: 2 -}; -var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE; - -/** - * This class encapsulates the concept of a layer in the drawing - * @param name {String} Layer name - * @param child {SVGGElement} Layer SVG group. - */ -svgedit.draw.Layer = function(name, group) { - this.name_ = name; - this.group_ = group; -}; - -svgedit.draw.Layer.prototype.getName = function() { - return this.name_; -}; - -svgedit.draw.Layer.prototype.getGroup = function() { - return this.group_; -}; - - -// Called to ensure that drawings will or will not have randomized ids. -// The current_drawing will have its nonce set if it doesn't already. -// -// Params: -// enableRandomization - flag indicating if documents should have randomized ids -svgedit.draw.randomizeIds = function(enableRandomization, current_drawing) { - randomize_ids = enableRandomization == false ? - RandomizeModes.NEVER_RANDOMIZE : - RandomizeModes.ALWAYS_RANDOMIZE; - - if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !current_drawing.getNonce()) { - current_drawing.setNonce(Math.floor(Math.random() * 100001)); - } else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && current_drawing.getNonce()) { - current_drawing.clearNonce(); - } -}; - -/** - * This class encapsulates the concept of a SVG-edit drawing - * - * @param svgElem {SVGSVGElement} The SVG DOM Element that this JS object - * encapsulates. If the svgElem has a se:nonce attribute on it, then - * IDs will use the nonce as they are generated. - * @param opt_idPrefix {String} The ID prefix to use. Defaults to "svg_" - * if not specified. - */ -svgedit.draw.Drawing = function(svgElem, opt_idPrefix) { - if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI || - svgElem.tagName != 'svg' || svgElem.namespaceURI != svg_ns) { - throw "Error: svgedit.draw.Drawing instance initialized without a element"; - } - - /** - * The SVG DOM Element that represents this drawing. - * @type {SVGSVGElement} - */ - this.svgElem_ = svgElem; - - /** - * The latest object number used in this drawing. - * @type {number} - */ - this.obj_num = 0; - - /** - * The prefix to prepend to each element id in the drawing. - * @type {String} - */ - this.idPrefix = opt_idPrefix || "svg_"; - - /** - * An array of released element ids to immediately reuse. - * @type {Array.} - */ - this.releasedNums = []; - - /** - * The z-ordered array of tuples containing layer names and elements. - * The first layer is the one at the bottom of the rendering. - * TODO: Turn this into an Array. - * @type {Array.>} - */ - this.all_layers = []; - - /** - * The current layer being used. - * TODO: Make this a {Layer}. - * @type {SVGGElement} - */ - this.current_layer = null; - - /** - * The nonce to use to uniquely identify elements across drawings. - * @type {!String} - */ - this.nonce_ = ""; - var n = this.svgElem_.getAttributeNS(se_ns, 'nonce'); - // If already set in the DOM, use the nonce throughout the document - // else, if randomizeIds(true) has been called, create and set the nonce. - if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) { - this.nonce_ = n; - } else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) { - this.setNonce(Math.floor(Math.random() * 100001)); - } -}; - -svgedit.draw.Drawing.prototype.getElem_ = function(id) { - if(this.svgElem_.querySelector) { - // querySelector lookup - return this.svgElem_.querySelector('#'+id); - } else { - // jQuery lookup: twice as slow as xpath in FF - return $(this.svgElem_).find('[id=' + id + ']')[0]; - } -}; - -svgedit.draw.Drawing.prototype.getSvgElem = function() { - return this.svgElem_; -}; - -svgedit.draw.Drawing.prototype.getNonce = function() { - return this.nonce_; -}; - -svgedit.draw.Drawing.prototype.setNonce = function(n) { - this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns); - this.svgElem_.setAttributeNS(se_ns, 'se:nonce', n); - this.nonce_ = n; -}; - -svgedit.draw.Drawing.prototype.clearNonce = function() { - // We deliberately leave any se:nonce attributes alone, - // we just don't use it to randomize ids. - this.nonce_ = ""; -}; - -/** - * Returns the latest object id as a string. - * @return {String} The latest object Id. - */ -svgedit.draw.Drawing.prototype.getId = function() { - return this.nonce_ ? - this.idPrefix + this.nonce_ +'_' + this.obj_num : - this.idPrefix + this.obj_num; -}; - -/** - * Returns the next object Id as a string. - * @return {String} The next object Id to use. - */ -svgedit.draw.Drawing.prototype.getNextId = function() { - var oldObjNum = this.obj_num; - var restoreOldObjNum = false; - - // If there are any released numbers in the release stack, - // use the last one instead of the next obj_num. - // We need to temporarily use obj_num as that is what getId() depends on. - if (this.releasedNums.length > 0) { - this.obj_num = this.releasedNums.pop(); - restoreOldObjNum = true; - } else { - // If we are not using a released id, then increment the obj_num. - this.obj_num++; - } - - // Ensure the ID does not exist. - var id = this.getId(); - while (this.getElem_(id)) { - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - restoreOldObjNum = false; - } - this.obj_num++; - id = this.getId(); - } - // Restore the old object number if required. - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - } - return id; -}; - -// Function: svgedit.draw.Drawing.releaseId -// Releases the object Id, letting it be used as the next id in getNextId(). -// This method DOES NOT remove any elements from the DOM, it is expected -// that client code will do this. -// -// Parameters: -// id - The id to release. -// -// Returns: -// True if the id was valid to be released, false otherwise. -svgedit.draw.Drawing.prototype.releaseId = function(id) { - // confirm if this is a valid id for this Document, else return false - var front = this.idPrefix + (this.nonce_ ? this.nonce_ +'_' : ''); - if (typeof id != typeof '' || id.indexOf(front) != 0) { - return false; - } - // extract the obj_num of this id - var num = parseInt(id.substr(front.length)); - - // if we didn't get a positive number or we already released this number - // then return false. - if (typeof num != typeof 1 || num <= 0 || this.releasedNums.indexOf(num) != -1) { - return false; - } - - // push the released number into the released queue - this.releasedNums.push(num); - - return true; -}; - -// Function: svgedit.draw.Drawing.getNumLayers -// Returns the number of layers in the current drawing. -// -// Returns: -// The number of layers in the current drawing. -svgedit.draw.Drawing.prototype.getNumLayers = function() { - return this.all_layers.length; -}; - -// Function: svgedit.draw.Drawing.hasLayer -// Check if layer with given name already exists -svgedit.draw.Drawing.prototype.hasLayer = function(name) { - for(var i = 0; i < this.getNumLayers(); i++) { - if(this.all_layers[i][0] == name) return true; - } - return false; -}; - - -// Function: svgedit.draw.Drawing.getLayerName -// Returns the name of the ith layer. If the index is out of range, an empty string is returned. -// -// Parameters: -// i - the zero-based index of the layer you are querying. -// -// Returns: -// The name of the ith layer -svgedit.draw.Drawing.prototype.getLayerName = function(i) { - if (i >= 0 && i < this.getNumLayers()) { - return this.all_layers[i][0]; - } - return ""; -}; - -// Function: svgedit.draw.Drawing.getCurrentLayer -// Returns: -// The SVGGElement representing the current layer. -svgedit.draw.Drawing.prototype.getCurrentLayer = function() { - return this.current_layer; -}; - -// Function: getCurrentLayerName -// Returns the name of the currently selected layer. If an error occurs, an empty string -// is returned. -// -// Returns: -// The name of the currently active layer. -svgedit.draw.Drawing.prototype.getCurrentLayerName = function() { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.all_layers[i][1] == this.current_layer) { - return this.getLayerName(i); - } - } - return ""; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (name == this.getLayerName(i)) { - if (this.current_layer != this.all_layers[i][1]) { - this.current_layer.setAttribute("style", "pointer-events:none"); - this.current_layer = this.all_layers[i][1]; - this.current_layer.setAttribute("style", "pointer-events:all"); - } - return true; - } - } - return false; -}; - - -// Function: svgedit.draw.Drawing.deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -// Returns: -// The SVGGElement of the layer removed or null. -svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() { - if (this.current_layer && this.getNumLayers() > 1) { - // actually delete from the DOM and return it - var parent = this.current_layer.parentNode; - var nextSibling = this.current_layer.nextSibling; - var oldLayerGroup = parent.removeChild(this.current_layer); - this.identifyLayers(); - return oldLayerGroup; - } - return null; -}; - -// Function: svgedit.draw.Drawing.identifyLayers -// Updates layer system and sets the current layer to the -// top-most layer (last child of this drawing). -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 a_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] ); - a_layer = child; - svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); - a_layer.setAttribute("style", "pointer-events:none"); - } - // if group did not have a name, it is an orphan - else { - orphans.push(child); - } - } - // if child has is "visible" (i.e. not a or element), then it is an orphan - else if(~visElems_arr.indexOf(child.nodeName)) { - 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; - a_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = newname; - a_layer.appendChild(layer_title); - for (var j = 0; j < orphans.length; ++j) { - a_layer.appendChild(orphans[j]); - } - this.svgElem_.appendChild(a_layer); - this.all_layers.push( [newname, a_layer] ); - } - svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style","pointer-events:inherit");}); - this.current_layer = a_layer; - this.current_layer.setAttribute("style","pointer-events:all"); -}; - -// Function: svgedit.draw.Drawing.createLayer -// Creates a new top-level layer in the drawing with the given name and -// sets the current layer to it. -// -// Parameters: -// name - The given name -// -// Returns: -// The SVGGElement of the new layer, which is also the current layer -// of this drawing. -svgedit.draw.Drawing.prototype.createLayer = function(name) { - var svgdoc = this.svgElem_.ownerDocument; - var new_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - this.svgElem_.appendChild(new_layer); - this.identifyLayers(); - return new_layer; -}; - -// Function: svgedit.draw.Drawing.getLayerVisibility -// Returns whether the layer is visible. If the layer name is not valid, then this function -// returns false. -// -// Parameters: -// layername - the name of the layer which you want to query. -// -// Returns: -// The visibility state of the layer, or false if the layer name was invalid. -svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) { - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return false; - return (layer.getAttribute('display') != 'none'); -}; - -// Function: svgedit.draw.Drawing.setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// The SVGGElement representing the layer if the layername was valid, otherwise null. -svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) { - if (typeof bVisible != typeof true) { - return null; - } - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return null; - - var oldDisplay = layer.getAttribute("display"); - if (!oldDisplay) oldDisplay = "inline"; - layer.setAttribute("display", bVisible ? "inline" : "none"); - return layer; -}; - - -// Function: svgedit.draw.Drawing.getLayerOpacity -// Returns the opacity of the given layer. If the input name is not a layer, null is returned. -// -// Parameters: -// layername - name of the layer on which to get the opacity -// -// Returns: -// The opacity value of the given layer. This will be a value between 0.0 and 1.0, or null -// if layername is not a valid layer -svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - var opacity = g.getAttribute('opacity'); - if (!opacity) { - opacity = '1.0'; - } - return parseFloat(opacity); - } - } - return null; -}; - -// Function: svgedit.draw.Drawing.setLayerOpacity -// Sets the opacity of the given layer. If the input name is not a layer, nothing happens. -// If opacity is not a value between 0.0 and 1.0, then nothing happens. -// -// Parameters: -// layername - name of the layer on which to set the opacity -// opacity - a float value in the range 0.0-1.0 -svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) { - if (typeof opacity != typeof 1.0 || opacity < 0.0 || opacity > 1.0) { - return; - } - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - g.setAttribute("opacity", opacity); - break; - } - } -}; - -})(); diff --git a/build/svg-edit-2.6-src/editor/embedapi.html b/build/svg-edit-2.6-src/editor/embedapi.html deleted file mode 100644 index 3db0364..0000000 --- a/build/svg-edit-2.6-src/editor/embedapi.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - -
        - - - - diff --git a/build/svg-edit-2.6-src/editor/embedapi.js b/build/svg-edit-2.6-src/editor/embedapi.js deleted file mode 100644 index 8debfd6..0000000 --- a/build/svg-edit-2.6-src/editor/embedapi.js +++ /dev/null @@ -1,173 +0,0 @@ -/* -function embedded_svg_edit(frame){ - //initialize communication - this.frame = frame; - this.stack = []; //callback stack - - var editapi = this; - - window.addEventListener("message", function(e){ - if(e.data.substr(0,5) == "ERROR"){ - editapi.stack.splice(0,1)[0](e.data,"error") - }else{ - editapi.stack.splice(0,1)[0](e.data) - } - }, false) -} - -embedded_svg_edit.prototype.call = function(code, callback){ - this.stack.push(callback); - this.frame.contentWindow.postMessage(code,"*"); -} - -embedded_svg_edit.prototype.getSvgString = function(callback){ - this.call("svgCanvas.getSvgString()",callback) -} - -embedded_svg_edit.prototype.setSvgString = function(svg){ - this.call("svgCanvas.setSvgString('"+svg.replace(/'/g, "\\'")+"')"); -} -*/ - - -/* -Embedded SVG-edit API - -General usage: -- Have an iframe somewhere pointing to a version of svg-edit > r1000 -- Initialize the magic with: -var svgCanvas = new embedded_svg_edit(window.frames['svgedit']); -- Pass functions in this format: -svgCanvas.setSvgString("string") -- Or if a callback is needed: -svgCanvas.setSvgString("string")(function(data, error){ - if(error){ - //there was an error - }else{ - //handle data - } -}) - -Everything is done with the same API as the real svg-edit, -and all documentation is unchanged. The only difference is -when handling returns, the callback notation is used instead. - -var blah = new embedded_svg_edit(window.frames['svgedit']); -blah.clearSelection("woot","blah",1337,[1,2,3,4,5,"moo"],-42,{a: "tree",b:6, c: 9})(function(){console.log("GET DATA",arguments)}) -*/ - -function embedded_svg_edit(frame){ - //initialize communication - this.frame = frame; - //this.stack = [] //callback stack - this.callbacks = {}; //successor to stack - this.encode = embedded_svg_edit.encode; - //List of functions extracted with this: - //Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html - - //for(var i=0,q=[],f = document.querySelectorAll("div.CFunction h3.CTitle a");i - - - - Layer 1 - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/editor/extensions/ext-arrows.js b/build/svg-edit-2.6-src/editor/extensions/ext-arrows.js deleted file mode 100644 index 4bb5cd2..0000000 --- a/build/svg-edit-2.6-src/editor/extensions/ext-arrows.js +++ /dev/null @@ -1,298 +0,0 @@ -/* - * ext-arrows.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - - -svgEditor.addExtension("Arrows", function(S) { - var svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomize_ids = S.randomize_ids, - selElems; - - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); - - var lang_list = { - "en":[ - {"id": "arrow_none", "textContent": "No arrow" } - ], - "fr":[ - {"id": "arrow_none", "textContent": "Sans flèche" } - ] - }; - - var prefix = 'se_arrow_'; - if (randomize_ids) { - var arrowprefix = prefix + nonce + '_'; - } else { - var arrowprefix = prefix; - } - - var pathdata = { - fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, - bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} - } - - function setArrowNonce(window, n) { - randomize_ids = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function unsetArrowNonce(window) { - randomize_ids = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if(!str) return null; - var m = str.match(/\(\#(.*)\)/); - if(!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } - - function showPanel(on) { - $('#arrow_panel').toggle(on); - - if(on) { - var el = selElems[0]; - var end = el.getAttribute("marker-end"); - var start = el.getAttribute("marker-start"); - var mid = el.getAttribute("marker-mid"); - var val; - - if(end && start) { - val = "both"; - } else if(end) { - val = "end"; - } else if(start) { - val = "start"; - } else if(mid) { - val = "mid"; - if(mid.indexOf("bk") != -1) { - val = "mid_bk"; - } - } - - if(!start && !mid && !end) { - val = "none"; - } - - $("#arrow_list").val(val); - } - } - - function resetMarker() { - var el = selElems[0]; - el.removeAttribute("marker-start"); - el.removeAttribute("marker-mid"); - el.removeAttribute("marker-end"); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var marker = S.getElem(id); - - var data = pathdata[dir]; - - if(type == "mid") { - data.refx = 5; - } - - if(!marker) { - marker = addElem({ - "element": "marker", - "attr": { - "viewBox": "0 0 10 10", - "id": id, - "refY": 5, - "markerUnits": "strokeWidth", - "markerWidth": 5, - "markerHeight": 5, - "orient": "auto", - "style": "pointer-events:none" // Currently needed for Opera - } - }); - var arrow = addElem({ - "element": "path", - "attr": { - "d": data.d, - "fill": "#000000" - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - var type = this.value; - resetMarker(); - - if(type == "none") { - return; - } - - // Set marker on element - var dir = "fw"; - if(type == "mid_bk") { - type = "mid"; - dir = "bk"; - } else if(type == "both") { - addMarker("bk", type); - svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); - type = "end"; - dir = "fw"; - } else if (type == "start") { - dir = "bk"; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); - S.call("changed", selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - - var mtypes = ['start','mid','end']; - var defs = S.findDefs(); - - $.each(mtypes, function(i, type) { - var marker = getLinked(elem, 'marker-'+type); - if(!marker) return; - - var cur_color = $(marker).children().attr('fill'); - var cur_d = $(marker).children().attr('d'); - var new_marker = null; - if(cur_color === color) return; - - var all_markers = $(defs).find('marker'); - // Different color, check if already made - all_markers.each(function() { - var attrs = $(this).children().attr(['fill', 'd']); - if(attrs.fill === color && attrs.d === cur_d) { - // Found another marker with this color and this path - new_marker = this; - } - }); - - if(!new_marker) { - // Create a new marker with this color - var last_id = marker.id; - var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; - - new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); - - $(new_marker).children().attr('fill', color); - } - - $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function() { - var elem = this; - $.each(mtypes, function(j, mtype) { - if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { - return remove = false; - } - }); - if(!remove) return false; - }); - - // Not found, so can safely remove - if(remove) { - $(marker).remove(); - } - - }); - - } - - return { - name: "Arrows", - context_tools: [{ - type: "select", - panel: "arrow_panel", - title: "Select arrow type", - id: "arrow_list", - options: { - none: "No arrow", - end: "---->", - start: "<----", - both: "<--->", - mid: "-->--", - mid_bk: "--<--" - }, - defval: "none", - events: { - change: setArrow - } - }], - callback: function() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function(lang) { - return { - data: lang_list[lang] - }; - }, - selectedChanged: function(opts) { - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - var marker_elems = ['line','path','polyline','polygon']; - - while(i--) { - var elem = selElems[i]; - if(elem && $.inArray(elem.tagName, marker_elems) != -1) { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function(opts) { - var elem = opts.elems[0]; - if(elem && ( - elem.getAttribute("marker-start") || - elem.getAttribute("marker-mid") || - elem.getAttribute("marker-end") - )) { - // var start = elem.getAttribute("marker-start"); - // var mid = elem.getAttribute("marker-mid"); - // var end = elem.getAttribute("marker-end"); - // Has marker, so see if it should match color - colorChanged(elem); - } - - } - }; -}); diff --git a/build/svg-edit-2.6-src/editor/extensions/ext-closepath.js b/build/svg-edit-2.6-src/editor/extensions/ext-closepath.js deleted file mode 100644 index bf8e72c..0000000 --- a/build/svg-edit-2.6-src/editor/extensions/ext-closepath.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ext-closepath.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * - */ - -// This extension adds a simple button to the contextual panel for paths -// The button toggles whether the path is open or closed -svgEditor.addExtension("ClosePath", function(S) { - var selElems, - updateButton = function(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) updateButton(path); - } - }, - - toggleClosed = function() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if(seglist.getItem(last).pathSegType == 1) { - seglist.removeItem(last); - } - else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; - - return { - name: "ClosePath", - svgicons: "extensions/closepath_icons.svg", - buttons: [{ - id: "tool_openpath", - type: "context", - panel: "closepath_panel", - title: "Open path", - events: { - 'click': function() { - toggleClosed(); - } - } - }, - { - id: "tool_closepath", - type: "context", - panel: "closepath_panel", - title: "Close path", - events: { - 'click': function() { - toggleClosed(); - } - } - }], - callback: function() { - $('#closepath_panel').hide(); - }, - selectedChanged: function(opts) { - selElems = opts.elems; - var i = selElems.length; - - while(i--) { - var elem = selElems[i]; - if(elem && elem.tagName == 'path') { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; -}); diff --git a/build/svg-edit-2.6-src/editor/extensions/ext-connector.js b/build/svg-edit-2.6-src/editor/extensions/ext-connector.js deleted file mode 100644 index 3498c7f..0000000 --- a/build/svg-edit-2.6-src/editor/extensions/ext-connector.js +++ /dev/null @@ -1,587 +0,0 @@ -/* - * ext-connector.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - -svgEditor.addExtension("Connector", function(S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = svgEditor.curConfig, - started = false, - start_x, - start_y, - cur_line, - start_elem, - end_elem, - connections = [], - conn_sel = ".se_connector", - se_ns, -// connect_str = "-SE_CONNECT-", - selElems = []; - - elData = $.data; - - var lang_list = { - "en":[ - {"id": "mode_connect", "title": "Connect two objects" } - ], - "fr":[ - {"id": "mode_connect", "title": "Connecter deux objets"} - ] - }; - - function getOffset(side, line) { - var give_offset = !!line.getAttribute('marker-' + side); -// var give_offset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return give_offset ? size : 0; - } - - function showPanel(on) { - var conn_rules = $('#connector_rules'); - if(!conn_rules.length) { - conn_rules = $(' -
        - -
        - - -
        -
        -

        Layers

        -
        -
        -
        -
        -
        -
        -
        -
        - - - - - - -
        Layer 1
        - Move elements to: - -
        -
        L a y e r s
        -
        - - - - - -
        - -
        - -
        -

        Canvas

        - - -
        - -
        - -
        -

        Rectangle

        -
        - - -
        - -
        - -
        -

        Path

        -
        - -
        -

        Image

        -
        - - -
        -
        - - -
        -
        - -
        -
        - - -
        -
        - -
        -
        - -
        -

        Ellipse

        -
        - - -
        -
        - - -
        -
        - -
        -

        Line

        -
        - - -
        -
        - - -
        -
        - -
        -

        Text

        - -
        - - - - -
        - -
        -
        B
        -
        i
        -
        - - - - - -
        - - -
        - - - - -
        - -
        - -
        - -
        -

        Group

        -
        - - -
        - -
        - -
        -

        Path

        -
        - -
        - - - - -
        -
        -
        -
        -
        - - -
        - - - - - - - - -

        Stroke

        -
        - -
        - - - - - - -

        Align

        -
        - -
        -
        -

        Position

        - - -
        -
        - - -
        -

        Multiple Elements

        - - - - - - -
        -

        Align

        - -
        - -
        - -
        - -
        -
        - -
        - - -
        -
        -
        -
        -
        -
        -
        -
        -
        -
        - -
        -
        -
        - -
        -
        -
        -
        -
        - -
        - -
        -
        -
        -
        -
        - -
        -
        -
        -
        -
        -
        -
        -
        -
        -
        - -
        - - -
        - -
        - -
        - -
        - -
        -
        -
        -
        - - - - - -
        - - - -
        -
        -
        -
        -

        Copy the contents of this box into a text editor, then save the file with a .svg extension.

        - -
        -
        - -
        -
        - - -
        -
        -
        - - -
        -
        -
        - -
        - Canvas Dimensions - - - - - - -
        -
        - - -
        -
        -
        - -
        -
        -
        - -
        - Editor Preferences - - - - - - - - - - - - - - - - - -
        -
        - - -
        -
        -
        - -
        -
        -
        -
        -
        -
        -
        - - - - - - - - diff --git a/build/svg-edit-2.6-src/editor/svg-editor.js b/build/svg-edit-2.6-src/editor/svg-editor.js deleted file mode 100644 index 861b40a..0000000 --- a/build/svg-edit-2.6-src/editor/svg-editor.js +++ /dev/null @@ -1,4892 +0,0 @@ -/* - * svg-editor.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Narendra Sisodiya - * - */ - -// Dependencies: -// 1) units.js -// 2) browser.js -// 3) svgcanvas.js - -(function() { - - document.addEventListener("touchstart", touchHandler, true); - document.addEventListener("touchmove", touchHandler, true); - document.addEventListener("touchend", touchHandler, true); - document.addEventListener("touchcancel", touchHandler, true); - if(!window.svgEditor) window.svgEditor = function($) { - var svgCanvas; - var Editor = {}; - var is_ready = false; - - var defaultPrefs = { - lang:'en', - iconsize:'m', - bkgd_color:'FFF', - bkgd_url:'', - img_save:'embed' - }, - curPrefs = {}, - - // Note: Difference between Prefs and Config is that Prefs can be - // changed in the UI and are stored in the browser, config can not - - curConfig = { - canvas_expansion: 1.2, - dimensions: [640,480], - initFill: { - color: 'fff', // solid red - opacity: 1 - }, - initStroke: { - width: 1.5, - color: '000', // solid black - opacity: 1 - }, - initOpacity: 1, - imgPath: 'images/', - langPath: 'locale/', - extPath: 'extensions/', - jGraduatePath: 'jgraduate/images/', - extensions: ['ext-markers.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-grid.js'], - initTool: 'select', - wireframe: false, - colorPickerCSS: false, - gridSnapping: false, - gridColor: "#000", - baseUnit: 'px', - snappingStep: 10, - showRulers: true, - show_outside_canvas: false - }, - uiStrings = Editor.uiStrings = { - common: { - "ok":"OK", - "cancel":"Cancel", - "key_up":"Up", - "key_down":"Down", - "key_backspace":"Backspace", - "key_del":"Del" - - }, - // This is needed if the locale is English, since the locale strings are not read in that instance. - layers: { - "layer":"Layer" - }, - notification: { - "invalidAttrValGiven":"Invalid value given", - "noContentToFitTo":"No content to fit to", - "dupeLayerName":"There is already a layer named that!", - "enterUniqueLayerName":"Please enter a unique layer name", - "enterNewLayerName":"Please enter the new layer name", - "layerHasThatName":"Layer already has that name", - "QmoveElemsToLayer":"Move selected elements to layer \"%s\"?", - "QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!", - "QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!", - "QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?", - "QignoreSourceChanges":"Ignore changes made to SVG source?", - "featNotSupported":"Feature not supported", - "enterNewImgURL":"Enter the new image URL", - "defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.", - "loadingImage":"Loading image, please wait...", - "saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.", - "noteTheseIssues": "Also note the following issues: ", - "unsavedChanges": "There are unsaved changes.", - "enterNewLinkURL": "Enter the new hyperlink URL", - "errorLoadingSVG": "Error: Unable to load SVG data", - "URLloadFail": "Unable to load from URL", - "retrieving": 'Retrieving "%s" ...' - } - }; - - var curPrefs = {}; //$.extend({}, defaultPrefs); - - var customHandlers = {}; - - Editor.curConfig = curConfig; - - Editor.tool_scale = 1; - -// window.ontouchmove = function(e) { -// e.stopPropagation(); -// }; -// -// $(document).bind("touchmove", function(evt) { -// if (evt.target.tagName.toLowerCase() !== "path" && evt.target.tagName.toLowerCase() !== "a") { -// return evt.preventDefault(); -// } -// }); - - // Store and retrieve preferences - $.pref = function(key, val) { - if(val) curPrefs[key] = val; - key = 'svg-edit-'+key; - var host = location.hostname, - onweb = host && host.indexOf('.') >= 0, - store = (val != undefined), - storage = false; - // Some FF versions throw security errors here - try { - if(window.localStorage) { // && onweb removed so Webkit works locally - storage = localStorage; - } - } catch(e) {} - try { - if(window.globalStorage && onweb) { - storage = globalStorage[host]; - } - } catch(e) {} - - if(storage) { - if(store) storage.setItem(key, val); - else if (storage.getItem(key)) return storage.getItem(key) + ''; // Convert to string for FF (.value fails in Webkit) - } else if(window.widget) { - if(store) widget.setPreferenceForKey(val, key); - else return widget.preferenceForKey(key); - } else { - if(store) { - var d = new Date(); - d.setTime(d.getTime() + 31536000000); - val = encodeURIComponent(val); - document.cookie = key+'='+val+'; expires='+d.toUTCString(); - } else { - var result = document.cookie.match(new RegExp(key + "=([^;]+)")); - return result?decodeURIComponent(result[1]):''; - } - } - } - - Editor.setConfig = function(opts) { - $.each(opts, function(key, val) { - // Only allow prefs defined in defaultPrefs - if(key in defaultPrefs) { - $.pref(key, val); - } - }); - $.extend(true, curConfig, opts); - if(opts.extensions) { - curConfig.extensions = opts.extensions; - } - - } - - // Extension mechanisms must call setCustomHandlers with two functions: opts.open and opts.save - // opts.open's responsibilities are: - // - invoke a file chooser dialog in 'open' mode - // - let user pick a SVG file - // - calls setCanvas.setSvgString() with the string contents of that file - // opts.save's responsibilities are: - // - accept the string contents of the current document - // - invoke a file chooser dialog in 'save' mode - // - save the file to location chosen by the user - Editor.setCustomHandlers = function(opts) { - Editor.ready(function() { - if(opts.open) { - $('#tool_open > input[type="file"]').remove(); - $('#tool_open').show(); - svgCanvas.open = opts.open; - } - if(opts.save) { - Editor.show_save_warning = false; - svgCanvas.bind("saved", opts.save); - } - if(opts.pngsave) { - svgCanvas.bind("exported", opts.pngsave); - } - customHandlers = opts; - }); - } - - Editor.randomizeIds = function() { - svgCanvas.randomizeIds(arguments) - } - - Editor.init = function() { - // For external openers - (function() { - // let the opener know SVG Edit is ready - var w = window.opener; - if (w) { - try { - var svgEditorReadyEvent = w.document.createEvent("Event"); - svgEditorReadyEvent.initEvent("svgEditorReady", true, true); - w.document.documentElement.dispatchEvent(svgEditorReadyEvent); - } - catch(e) {} - } - })(); - - (function() { - // Load config/data from URL if given - var urldata = $.deparam.querystring(true); - if(!$.isEmptyObject(urldata)) { - if(urldata.dimensions) { - urldata.dimensions = urldata.dimensions.split(','); - } - - if(urldata.extensions) { - urldata.extensions = urldata.extensions.split(','); - } - - if(urldata.bkgd_color) { - urldata.bkgd_color = '#' + urldata.bkgd_color; - } - - svgEditor.setConfig(urldata); - - var src = urldata.source; - var qstr = $.param.querystring(); - - if(!src) { // urldata.source may have been null if it ended with '=' - if(qstr.indexOf('source=data:') >= 0) { - src = qstr.match(/source=(data:[^&]*)/)[1]; - } - } - - if(src) { - if(src.indexOf("data:") === 0) { - // plusses get replaced by spaces, so re-insert - src = src.replace(/ /g, "+"); - Editor.loadFromDataURI(src); - } else { - Editor.loadFromString(src); - } - } else if(qstr.indexOf('paramurl=') !== -1) { - // Get paramater URL (use full length of remaining location.href) - svgEditor.loadFromURL(qstr.substr(9)); - } else if(urldata.url) { - svgEditor.loadFromURL(urldata.url); - } - } - })(); - - var extFunc = function() { - $.each(curConfig.extensions, function() { - 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); - } - }); - }); - - var good_langs = []; - - $('#lang_select option').each(function() { - good_langs.push(this.value); - }); - - // var lang = ('lang' in curPrefs) ? curPrefs.lang : null; - Editor.putLocale(null, good_langs); - } - - // Load extensions - // Bit of a hack to run extensions in local Opera/IE9 - if(document.location.protocol === 'file:') { - setTimeout(extFunc, 100); - } else { - extFunc(); - } - $.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { - w:24, h:24, - id_match: false, - no_img: !svgedit.browser.isWebkit(), // Opera & Firefox 4 gives odd behavior w/images - fallback_path: curConfig.imgPath, - fallback:{ - 'new_image':'clear.png', - 'save':'save.png', - 'open':'open.png', - 'source':'source.png', - 'docprops':'document-properties.png', - 'wireframe':'wireframe.png', - - 'undo':'undo.png', - 'redo':'redo.png', - - 'select':'select.png', - 'select_node':'select_node.png', - 'pencil':'fhpath.png', - 'pen':'line.png', - 'square':'square.png', - 'rect':'rect.png', - 'fh_rect':'freehand-square.png', - 'circle':'circle.png', - 'ellipse':'ellipse.png', - 'fh_ellipse':'freehand-circle.png', - 'path':'path.png', - 'text':'text.png', - 'image':'image.png', - 'zoom':'zoom.png', - - 'clone':'clone.png', - 'node_clone':'node_clone.png', - 'delete':'delete.png', - 'node_delete':'node_delete.png', - //'group':'shape_group.png', - //'ungroup':'shape_ungroup.png', - 'move_top':'move_top.png', - 'move_bottom':'move_bottom.png', - 'to_path':'to_path.png', - 'link_controls':'link_controls.png', - 'reorient':'reorient.png', - - 'align_left':'align-left.png', - 'align_center':'align-center', - 'align_right':'align-right', - 'align_top':'align-top', - 'align_middle':'align-middle', - 'align_bottom':'align-bottom', - - 'go_up':'go-up.png', - 'go_down':'go-down.png', - - 'ok':'save.png', - 'cancel':'cancel.png', - - 'arrow_right':'flyouth.png', - 'arrow_down':'dropdown.gif' - }, - placement: { - '#tool_docprops > div':'docprops', - - '#tool_select':'select', - '#tool_fhpath':'pencil', - '#tool_line':'pen', - '#tool_rect,#tools_rect_show':'rect', - '#tool_square':'square', - '#tool_fhrect':'fh_rect', - '#tool_ellipse,#tools_ellipse_show':'ellipse', - '#tool_circle':'circle', - '#tool_fhellipse':'fh_ellipse', - '#tool_path':'path', - '#tool_text,#layer_rename':'text', - '#tool_image':'image', - '#tool_zoom':'zoom', - - '#tool_node_clone':'node_clone', - '#tool_node_delete':'node_delete', - '#tool_add_subpath':'add_subpath', - '#tool_openclose_path':'open_path', - '#tool_node_link':'link_controls', - //'#tool_group':'group', - //'#tool_ungroup':'ungroup', - //'#tool_unlink_use':'unlink_use', - - '#tool_alignleft, #tool_posleft':'align_left', - '#tool_aligncenter, #tool_poscenter':'align_center', - '#tool_alignright, #tool_posright':'align_right', - '#tool_aligntop, #tool_postop':'align_top', - '#tool_alignmiddle, #tool_posmiddle':'align_middle', - '#tool_alignbottom, #tool_posbottom':'align_bottom', - '#cur_position':'align', - - '#linecap_butt,#cur_linecap':'linecap_butt', - '#linecap_round':'linecap_round', - '#linecap_square':'linecap_square', - - '#linejoin_miter,#cur_linejoin':'linejoin_miter', - '#linejoin_round':'linejoin_round', - '#linejoin_bevel':'linejoin_bevel', - - '#url_notice':'warning', - - '#layer_up':'go_up', - '#layer_down':'go_down', - '#layer_moreopts':'context_menu', - '#layerlist td.layervis':'eye', - - '#tool_source_save,#tool_docprops_save,#tool_prefs_save':'ok', - '#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel':'cancel', - - '#rwidthLabel, #iwidthLabel':'width', - '#rheightLabel, #iheightLabel':'height', - //'#cornerRadiusLabel span':'c_radius', - '#angleLabel':'angle', - '#linkLabel,#tool_make_link,#tool_make_link_multi':'globe_link', - '#zoomLabel':'zoom', - //'#tool_fill label': 'fill', - //'#tool_stroke .icon_label': 'stroke', - //'#group_opacityLabel': 'opacity', - '#blurLabel': 'blur', - //'#font_sizeLabel': 'fontsize', - - '.flyout_arrow_horiz':'arrow_right', - //'.dropdown button, #main_button .dropdown':'arrow_down', - '#palette .palette_item:first, #fill_bg, #stroke_bg':'no_color' - }, - resize: { - '#logo .svg_icon': 32, - '.flyout_arrow_horiz .svg_icon': 5, - '.layer_button .svg_icon, #layerlist td.layervis .svg_icon': 14, - //'.dropdown button .svg_icon': 7, - '#main_button .dropdown .svg_icon': 9, - '#fill_bg .svg_icon, #stroke_bg .svg_icon': 24, - '.palette_item:first .svg_icon': 16, - '.toolbar_button button .svg_icon':16, - '.stroke_tool div div .svg_icon': 20, - '#tools_bottom label .svg_icon': 18, - '#zoom_dropdown .svg_icon': 7 - }, - callback: function(icons) { - $('.toolbar_button button > svg, .toolbar_button button > img').each(function() { - $(this).parent().prepend(this); - }); - - var tleft = $('#tools_left'); - if (tleft.length != 0) { - var min_height = tleft.offset().top + tleft.outerHeight(); - } - - // Look for any missing flyout icons from plugins - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var sel = shower.attr('data-curopt'); - // Check if there's an icon here - if(!shower.children('svg, img').length) { - var clone = $(sel).children().clone(); - if(clone.length) { - clone[0].removeAttribute('style'); //Needed for Opera - shower.append(clone); - } - } - }); - - svgEditor.runCallbacks(); - - setTimeout(function() { - $('.flyout_arrow_horiz:empty').each(function() { - $(this).append($.getSvgIcon('arrow_right').width(5).height(5)); - }); - }, 1); - } - }); - - Editor.canvas = svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), curConfig); - Editor.show_save_warning = false; - var palette = ["#000000", "#3f3f3f", "#7f7f7f", "#bfbfbf", "#ffffff", - "#ff0000", "#ff7f00", "#ffff00", "#7fff00", - "#00ff00", "#00ff7f", "#00ffff", "#007fff", - "#0000ff", "#7f00ff", "#ff00ff", "#ff007f", - "#7f0000", "#7f3f00", "#7f7f00", "#3f7f00", - "#007f00", "#007f3f", "#007f7f", "#003f7f", - "#00007f", "#3f007f", "#7f007f", "#7f003f", - "#ffaaaa", "#ffd4aa", "#ffffaa", "#d4ffaa", - "#aaffaa", "#aaffd4", "#aaffff", "#aad4ff", - "#aaaaff", "#d4aaff", "#ffaaff", "#ffaad4" - ], - isMac = (navigator.platform.indexOf("Mac") >= 0), - isWebkit = (navigator.userAgent.indexOf("AppleWebKit") >= 0), - modKey = (isMac ? "meta+" : "ctrl+"), // ⌘ - path = svgCanvas.pathActions, - undoMgr = svgCanvas.undoMgr, - Utils = svgedit.utilities, - default_img_url = curConfig.imgPath + "placeholder.svg", - workarea = $("#workarea"), - canv_menu = $("#cmenu_canvas"), - layer_menu = $("#cmenu_layers"), - exportWindow = null, - tool_scale = 1, - zoomInIcon = 'crosshair', - zoomOutIcon = 'crosshair', - ui_context = 'toolbars', - orig_source = '', - paintBox = {fill: null, stroke:null}; - - // This sets up alternative dialog boxes. They mostly work the same way as - // their UI counterparts, expect instead of returning the result, a callback - // needs to be included that returns the result as its first parameter. - // In the future we may want to add additional types of dialog boxes, since - // they should be easy to handle this way. - (function() { - $('#dialog_container').draggable({cancel:'#dialog_content, #dialog_buttons *', containment: 'window'}); - var box = $('#dialog_box'), btn_holder = $('#dialog_buttons'); - - var dbox = function(type, msg, callback, defText) { - $('#dialog_content').html('

        '+msg.replace(/\n/g,'

        ')+'

        ') - .toggleClass('prompt',(type=='prompt')); - btn_holder.empty(); - - var ok = $('').appendTo(btn_holder); - - if(type != 'alert') { - $('') - .appendTo(btn_holder) - .click(function() { box.hide();callback(false)}); - } - - if(type == 'prompt') { - var input = $('').prependTo(btn_holder); - input.val(defText || ''); - input.bind('keydown', 'return', function() {ok.click();}); - } - - if(type == 'process') { - ok.hide(); - } - - box.show(); - - ok.click(function() { - box.hide(); - var resp = (type == 'prompt')?input.val():true; - if(callback) callback(resp); - }).focus(); - - if(type == 'prompt') input.focus(); - } - - $.alert = function(msg, cb) { dbox('alert', msg, cb);}; - $.confirm = function(msg, cb) { dbox('confirm', msg, cb);}; - $.process_cancel = function(msg, cb) { dbox('process', msg, cb);}; - $.prompt = function(msg, txt, cb) { dbox('prompt', msg, cb, txt);}; - }()); - - var setSelectMode = function() { - var curr = $('.tool_button_current'); - if(curr.length && curr[0].id !== 'tool_select') { - curr.removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}'); - } - svgCanvas.setMode('select'); - }; - - var togglePathEditMode = function(editmode, elems) { - $('#path_node_panel').toggle(editmode); - $('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); - if(editmode) { - // Change select icon - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - setIcon('#tool_select', 'select_node'); - multiselected = false; - if(elems.length) { - selectedElement = elems[0]; - } - } else { - setIcon('#tool_select', 'select'); - } - } - - // used to make the flyouts stay on the screen longer the very first time - var flyoutspeed = 1250; - var textBeingEntered = false; - var selectedElement = null; - var multiselected = false; - var editingsource = false; - var docprops = false; - var preferences = false; - var cur_context = ''; - var orig_title = $('title:first').text(); - - var saveHandler = function(window,svg) { - Editor.show_save_warning = false; - - // 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; - - // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable - - var ua = navigator.userAgent; - - // Chrome 5 (and 6?) don't allow saving, show source instead ( http://code.google.com/p/chromium/issues/detail?id=46735 ) - // IE9 doesn't allow standalone Data URLs ( https://connect.microsoft.com/IE/feedback/details/542600/data-uri-images-fail-when-loaded-by-themselves ) - if((~ua.indexOf('Chrome') && $.browser.version >= 533) || ~ua.indexOf('MSIE')) { - showSourceEditor(0,true); - return; - } - var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg)); - - // Alert will only appear the first time saved OR the first time the bug is encountered - var done = $.pref('save_notice_done'); - if(done !== "all") { - - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'SVG'); - - // Check if FF and has - if(ua.indexOf('Gecko/') !== -1) { - if(svg.indexOf('', {id: 'export_canvas'}).hide().appendTo('body'); - } - var c = $('#export_canvas')[0]; - - c.width = svgCanvas.contentW; - c.height = svgCanvas.contentH; - canvg(c, data.svg, {renderCallback: function() { - var datauri = c.toDataURL('image/png'); - exportWindow.location.href = datauri; - var done = $.pref('export_notice_done'); - if(done !== "all") { - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'PNG'); - - // Check if there's issues - if(issues.length) { - var pre = "\n \u2022 "; - note += ("\n\n" + uiStrings.notification.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 - var selectedChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") setSelectMode(); - var is_node = (mode == "pathedit"); - // if elems[1] is present, then we have more than one element - selectedElement = (elems.length == 1 || elems[1] == null ? elems[0] : null); - multiselected = (elems.length >= 2 && elems[1] != null); - if (selectedElement != null) { - // unless we're already in always set the mode of the editor to select because - // upon creation of a text element the editor is switched into - // select mode and this event fires - we need our UI to be in sync - - if (!is_node) { - updateToolbar(); - } - - } // if (elem != null) - // Deal with pathedit mode - togglePathEditMode(is_node, elems); - updateContextPanel(); - svgCanvas.runExtensions("selectedChanged", { - elems: elems, - selectedElement: selectedElement, - multiselected: multiselected - }); - }; - - // Call when part of element is in process of changing, generally - // on mousemove actions like rotate, move, etc. - var elementTransition = function(window,elems) { - var mode = svgCanvas.getMode(); - var elem = elems[0]; - - if(!elem) return; - - multiselected = (elems.length >= 2 && elems[1] != null); - // Only updating fields for single elements for now - if(!multiselected) { - switch ( mode ) { - case "rotate": - var ang = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(ang)); - $('#tool_reorient').toggleClass('disabled', ang == 0); - break; - - // TODO: Update values that change on move/resize, etc -// case "select": -// case "resize": -// break; - } - } - svgCanvas.runExtensions("elementTransition", { - elems: elems - }); - }; - - // called when any element has changed - var elementChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") { - setSelectMode(); - } - - for (var i = 0; i < elems.length; ++i) { - var elem = elems[i]; - - // if the element changed was the svg, then it could be a resolution change - if (elem && elem.tagName === "svg") { - populateLayers(); - updateCanvas(); - } - // 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) { // This was added in r1430, but not sure why - selectedElement = elem; - } - } - - Editor.show_save_warning = true; - - // we update the contextual panel with potentially new - // positional/sizing information (we DON'T want to update the - // toolbar here as that creates an infinite loop) - // also this updates the history buttons - - // we tell it to skip focusing the text control if the - // text element was previously in focus - updateContextPanel(); - - // In the event a gradient was flipped: - if(selectedElement && mode === "select") { - paintBox.fill.update(); - paintBox.stroke.update(); - } - - svgCanvas.runExtensions("elementChanged", { - elems: elems - }); - }; - - var zoomChanged = function(window, bbox, autoCenter) { - var scrbar = 15, - res = svgCanvas.getResolution(), - w_area = workarea, - canvas_pos = $('#svgcanvas').position(); - var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); - if(!z_info) return; - var zoomlevel = z_info.zoom, - bb = z_info.bbox; - - if(zoomlevel < .001) { - changeZoom({value: .1}); - return; - } - -// $('#zoom').val(Math.round(zoomlevel*100)); - $('#zoom').val(zoomlevel*100); - - if(autoCenter) { - updateCanvas(); - } else { - updateCanvas(false, {x: bb.x * zoomlevel + (bb.width * zoomlevel)/2, y: bb.y * zoomlevel + (bb.height * zoomlevel)/2}); - } - - if(svgCanvas.getMode() == 'zoom' && bb.width) { - // Go to select if a zoom box was drawn - setSelectMode(); - } - - zoomDone(); - } - - $('#cur_context_panel').delegate('a', 'click', function() { - var link = $(this); - if(link.attr('data-root')) { - svgCanvas.leaveContext(); - } else { - svgCanvas.setContext(link.text()); - } - return false; - }); - - var contextChanged = function(win, context) { - - var link_str = ''; - if(context) { - var str = ''; - link_str = '' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + ''; - - $(context).parentsUntil('#svgcontent > g').andSelf().each(function() { - if(this.id) { - str += ' > ' + this.id; - if(this !== context) { - link_str += ' > ' + this.id + ''; - } else { - link_str += ' > ' + this.id; - } - } - }); - - cur_context = str; - } else { - cur_context = null; - } - $('#cur_context_panel').toggle(!!context).html(link_str); - - - updateTitle(); - } - - // Makes sure the current selected paint is available to work with - var prepPaints = function() { - paintBox.fill.prep(); - paintBox.stroke.prep(); - } - - var flyout_funcs = {}; - - var setupFlyouts = function(holders) { - $.each(holders, function(hold_sel, btn_opts) { - var buttons = $(hold_sel).children(); - var show_sel = hold_sel + '_show'; - var shower = $(show_sel); - var def = false; - buttons.addClass('tool_button') - .unbind('click mousedown mouseup') // may not be necessary - .each(function(i) { - // Get this buttons options - var opts = btn_opts[i]; - - // Remember the function that goes with this ID - flyout_funcs[opts.sel] = opts.fn; - - if(opts.isDefault) def = i; - - // Clicking the icon in flyout should set this set's icon - var func = function(event) { - var options = opts; - //find the currently selected tool if comes from keystroke - if (event.type === "keydown") { - var flyoutIsSelected = $(options.parent + "_show").hasClass('tool_button_current'); - var currentOperation = $(options.parent + "_show").attr("data-curopt"); - $.each(holders[opts.parent], function(i, tool){ - if (tool.sel == currentOperation) { - if(!event.shiftKey || !flyoutIsSelected) { - options = tool; - } - else { - options = holders[opts.parent][i+1] || holders[opts.parent][0]; - } - } - }); - } - if($(this).hasClass('disabled')) return false; - if (toolButtonClick(show_sel)) { - options.fn(); - } - if(options.icon) { - var icon = $.getSvgIcon(options.icon, true); - } else { - var icon = $(options.sel).children().eq(0).clone(); - } - - icon[0].setAttribute('width',shower.width()); - icon[0].setAttribute('height',shower.height()); - shower.children(':not(.flyout_arrow_horiz)').remove(); - shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode - } - - $(this).mouseup(func); - - if(opts.key) { - $(document).bind('keydown', opts.key[0] + " shift+" + opts.key[0], func); - } - }); - - if(def) { - shower.attr('data-curopt', btn_opts[def].sel); - } else if(!shower.attr('data-curopt')) { - // Set first as default - shower.attr('data-curopt', btn_opts[0].sel); - } - - var timer; - - var pos = $(show_sel).position(); - $(hold_sel).css({'left': pos.left+34, 'top': pos.top+77}); - - // Clicking the "show" icon should set the current mode - shower.mousedown(function(evt) { - if ($('#tools_shapelib').is(":visible")) toolButtonClick(show_sel, false); - if(shower.hasClass('disabled')) return false; - var holder = $(hold_sel); - var l = pos.left+34; - var w = holder.width()*-1; - var time = holder.data('shown_popop')?200:0; - timer = setTimeout(function() { - // Show corresponding menu - if(!shower.data('isLibrary')) { - holder.css('left', w).show().animate({ - left: l - },150); - } else { - holder.css('left', l).show(); - } - holder.data('shown_popop',true); - },time); - evt.preventDefault(); - }).mouseup(function(evt) { - clearTimeout(timer); - var opt = $(this).attr('data-curopt'); - // Is library and popped up, so do nothing - if(shower.data('isLibrary') && $(show_sel.replace('_show','')).is(':visible')) { - toolButtonClick(show_sel, true); - return; - } - if (toolButtonClick(show_sel) && (opt in flyout_funcs)) { - flyout_funcs[opt](); - } - }); - - // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();}); - }); - - setFlyoutTitles(); - } - - var makeFlyoutHolder = function(id, child) { - var div = $('
        ',{ - 'class': 'tools_flyout', - id: id - }).appendTo('#svg_editor').append(child); - - return div; - } - - var setFlyoutPositions = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var pos = shower.offset(); - var w = shower.outerWidth(); - $(this).css({left: (pos.left + w)*tool_scale, top: pos.top}); - }); - } - - var setFlyoutTitles = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - if(shower.data('isLibrary')) return; - - var tooltips = []; - $(this).children().each(function() { - tooltips.push(this.title); - }); - 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 && cb_ready) { - cb_called = true; - ext.callback(); - } - } - - var btn_selects = []; - - if(ext.context_tools) { - $.each(ext.context_tools, function(i, tool) { - // Add select tool - var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):""; - - var panel = $('#' + tool.panel); - - // create the panel if it doesn't exist - if(!panel.length) - panel = $('
        ', {id: tool.panel}).appendTo("#tools_top"); - - // TODO: Allow support for other types, or adding to existing tool - switch (tool.type) { - case 'tool_button': - var html = '
        ' + tool.id + '
        '; - var div = $(html).appendTo(panel); - if (tool.events) { - $.each(tool.events, function(evt, func) { - $(div).bind(evt, func); - }); - } - break; - case 'select': - var html = '' - + '"; - // Creates the tool, hides & adds it, returns the select element - var sel = $(html).appendTo(panel).find('select'); - - $.each(tool.events, function(evt, func) { - $(sel).bind(evt, func); - }); - break; - case 'button-select': - var html = ''; - - var list = $('
          ').appendTo('#option_lists'); - - if(tool.colnum) { - list.addClass('optcols' + tool.colnum); - } - - // Creates the tool, hides & adds it, returns the select element - var dropdown = $(html).appendTo(panel).children(); - - btn_selects.push({ - elem: ('#' + tool.id), - list: ('#' + tool.id + '_opts'), - title: tool.title, - callback: tool.events.change, - cur: ('#cur_' + tool.id) - }); - - break; - case 'input': - var html = '' - + '' - + tool.label + ':' - + '' - - // Creates the tool, hides & adds it, returns the select element - - // Add to given tool.panel - var inp = $(html).appendTo(panel).find('input'); - - if(tool.spindata) { - inp.SpinButton(tool.spindata); - } - - if(tool.events) { - $.each(tool.events, function(evt, func) { - inp.bind(evt, func); - }); - } - break; - - default: - break; - } - }); - } - - if(ext.buttons) { - var fallback_obj = {}, - placement_obj = {}, - svgicons = ext.svgicons; - var holders = {}; - - - // Add buttons given by extension - $.each(ext.buttons, function(i, btn) { - var icon; - var id = btn.id; - var num = i; - - // Give button a unique ID - while($('#'+id).length) { - id = btn.id + '_' + (++num); - } - - if(!svgicons) { - icon = (btn.type == "menu") ? "" : $(''); - } else { - fallback_obj[id] = btn.icon; - var svgicon = btn.svgicon?btn.svgicon:btn.id; - if(btn.type == 'app_menu') { - placement_obj['#' + id + ' > div'] = svgicon; - } else { - placement_obj['#' + id] = svgicon; - } - } - - var cls, parent; - - - - // Set button up according to its type - switch ( btn.type ) { - case 'mode_flyout': - case 'mode': - cls = 'tool_button'; - if(btn.cls) { - cls += " " + btn.cls; - } - parent = "#tools_left"; - break; - case 'context': - cls = 'tool_button'; - parent = "#" + btn.panel; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
          ', {id: btn.panel}).appendTo("#tools_top"); - break; - case 'menu': - cls = 'menu_item tool_button'; - parent = "#" + (btn.after || btn.panel); - break; - case 'app_menu': - cls = ''; - parent = btn.parent || '#main_menu ul'; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
          ', {id: btn.panel}).appendTo("#tools_top"); - break; - } - - var button = $((btn.list || btn.type == 'app_menu')?'
        • ':'
          ') - .attr("id", id) - .attr("title", btn.title) - .addClass(cls); - if(!btn.includeWith && !btn.list) { - if("position" in btn) { - $(parent).children().eq(btn.position).before(button); - } else { - if (btn.type != "menu" || !btn.after) button.appendTo(parent); - else $(parent).after(button); - } - - if(btn.type =='mode_flyout') { - // Add to flyout menu / make flyout menu - // var opts = btn.includeWith; - // // opts.button, default, position - var ref_btn = $(button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
          ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - flyout_holder.data('isLibrary', true); - show_btn.data('isLibrary', true); - } - - - - // var ref_data = Actions.getButtonData(opts.button); - - placement_obj['#' + tls_id + '_show'] = btn.id; - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, -// key: btn.key, - isDefault: true - }, ref_data]; - - } else if(btn.type == 'app_menu' || btn.type == 'menu') { - button.append(btn.title); - } - - } else if(btn.list) { - // Add button to list - button.addClass('push_button'); - $('#' + btn.list + '_opts').append(button); - if(btn.isDefault) { - $('#cur_' + btn.list).append(button.children().clone()); - var svgicon = btn.svgicon?btn.svgicon:btn.id; - placement_obj['#cur_' + btn.list] = svgicon; - } - } else if(btn.includeWith) { - // Add to flyout menu / make flyout menu - var opts = btn.includeWith; - // opts.button, default, position - var ref_btn = $(opts.button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
          ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - } - - var ref_data = Actions.getButtonData(opts.button); - - if(opts.isDefault) { - placement_obj['#' + tls_id + '_show'] = btn.id; - } - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, - key: btn.key, - isDefault: btn.includeWith?btn.includeWith.isDefault:0 - }, ref_data]; - - // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} - - var pos = ("position" in opts)?opts.position:'last'; - var len = flyout_holder.children().length; - - // Add at given position or end - if(!isNaN(pos) && pos >= 0 && pos < len) { - flyout_holder.children().eq(pos).before(button); - } else { - flyout_holder.append(button); - cur_h.reverse(); - } - } - - if(!svgicons) { - button.append(icon); - } - - if(!btn.list) { - // Add given events to button - $.each(btn.events, function(name, func) { - if(name == "click") { - if(btn.type == 'mode') { - if(btn.includeWith) { - button.bind(name, func); - } else { - button.bind(name, function() { - if(toolButtonClick(button)) { - func(); - } - }); - } - if(btn.key) { - $(document).bind('keydown', btn.key, func); - if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']'); - } - } else { - button.bind(name, func); - } - } else { - button.bind(name, func); - } - }); - } - setupFlyouts(holders); - }); - - $.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, - id_match: false, - no_img: (!isWebkit), - fallback: fallback_obj, - placement: placement_obj, - callback: function(icons) { - // Non-ideal hack to make the icon match the current size - if(curPrefs.iconsize && curPrefs.iconsize != 'm') { - prepResize(); - } - cb_ready = true; // Ready for callback - runCallback(); - } - - }); - } - - runCallback(); - }; - - var getPaint = function(color, opac, type) { - // update the editor's fill paint - var opts = null; - if (color.indexOf("url(#") === 0) { - var refElem = svgCanvas.getRefElem(color); - if(refElem) { - refElem = refElem.cloneNode(true); - } else { - refElem = $("#" + type + "_color defs *")[0]; - } - - opts = { alpha: opac }; - opts[refElem.tagName] = refElem; - } - else if (color.indexOf("#") === 0) { - opts = { - alpha: opac, - solidColor: color.substr(1) - }; - } - else { - opts = { - alpha: opac, - solidColor: 'none' - }; - } - return new $.jGraduate.Paint(opts); - }; - - // set the canvas properties at init - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#docprops_button').on("click", function(){showDocProperties()}); - - // 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) { - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - break; - case 'g': - case 'a': - // Look for common styles - - var gWidth = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var swidth = childs[i].getAttribute("stroke-width"); - - if(i === 0) { - gWidth = swidth; - } else if(gWidth !== swidth) { - gWidth = null; - } - } - - $('#stroke_width').val(gWidth === null ? "" : gWidth); - - paintBox.fill.update(true); - paintBox.stroke.update(true); - - - break; - default: - paintBox.fill.update(true); - paintBox.stroke.update(true); - - $('#stroke_width').val(selectedElement.getAttribute("stroke-width") || 1); - $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none"); - - var attr = selectedElement.getAttribute("stroke-linejoin") || 'miter'; - - if ($('#linejoin_' + attr).length != 0) - setStrokeOpt($('#linejoin_' + attr)[0]); - - attr = selectedElement.getAttribute("stroke-linecap") || 'butt'; - - if ($('#linecap_' + attr).length != 0) - setStrokeOpt($('#linecap_' + attr)[0]); - } - - } - - // All elements including image and group have opacity - if(selectedElement != null) { - var opac_perc = ((selectedElement.getAttribute("opacity")||1.0)*100); - $('#group_opacity').val(opac_perc); - $('#opac_slider').slider('option', 'value', opac_perc); - $('#elem_id').val(selectedElement.id); - } - - updateToolButtonState(); - }; - - var setImageURL = Editor.setImageURL = function(url) { - if(!url) url = default_img_url; - - svgCanvas.setImageURL(url); - $('#image_url').val(url); - - if(url.indexOf('data:') === 0) { - // data URI found - $('#image_url').hide(); - $('#change_image_url').show(); - } else { - // regular URL - - svgCanvas.embedImage(url, function(datauri) { - if(!datauri) { - // Couldn't embed, so show warning - $('#url_notice').show(); - } else { - $('#url_notice').hide(); - } - default_img_url = url; - }); - $('#image_url').show(); - $('#change_image_url').hide(); - } - } - - 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; - // If element has just been deleted, consider it null - if(elem != null && !elem.parentNode) elem = null; - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var currentMode = svgCanvas.getMode(); - var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; - - var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false; - var menu_items = $('#cmenu_canvas li'); - $('#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\ - #ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel').hide(); - $('.menu_item', '#edit_menu').addClass('disabled'); - $('.menu_item', '#object_menu').addClass('disabled'); - if (!elem && !multiselected) $("#canvas_panel").show(); - if (elem != null) { - var elname = elem.nodeName; - var angle = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(angle)); - - var blurval = svgCanvas.getBlur(elem); - $('#blur').val(blurval); - $('#blur_slider').slider('option', 'value', blurval); - - if(svgCanvas.addedNew) { - if(elname === 'image') { - // Prompt for URL if not a data URL - if(svgCanvas.getHref(elem).indexOf('data:') !== 0) { - promptImgURL(); - } - } /*else if(elname == 'text') { - // TODO: Do something here for new text - }*/ - } - - if(!is_node && currentMode != 'pathedit') { - $('#selected_panel').show(); - $('.action_selected').removeClass('disabled'); - // Elements in this array already have coord fields - if(['line', 'circle', 'ellipse'].indexOf(elname) >= 0) { - $('#xy_panel').hide(); - } else { - var x,y; - - // Get BBox vals for g, polyline and path - if(['g', 'polyline', 'path'].indexOf(elname) >= 0) { - var bb = svgCanvas.getStrokedBBox([elem]); - if(bb) { - x = bb.x; - y = bb.y; - } - } else { - x = elem.getAttribute('x'); - y = elem.getAttribute('y'); - } - - if(unit) { - x = svgedit.units.convertUnit(x); - y = svgedit.units.convertUnit(y); - } - - $('#selected_x').val(x || 0); - $('#selected_y').val(y || 0); - $('#xy_panel').show(); - } - - // Elements in this array cannot be converted to a path - var no_path = ['image', 'text', 'path', 'g', 'use'].indexOf(elname) == -1; - if (no_path) $('.action_path_convert_selected').removeClass('disabled'); - if (elname === "path") $('.action_path_selected').removeClass('disabled'); - } else { - var point = path.getNodePoint(); - $('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); - $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); - - // Show open/close button based on selected point - setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); - - if(point) { - var seg_type = $('#seg_type'); - if(unit) { - point.x = svgedit.units.convertUnit(point.x); - point.y = svgedit.units.convertUnit(point.y); - } - $('#path_node_x').val(point.x); - $('#path_node_y').val(point.y); - if(point.type) { - seg_type.val(point.type).removeAttr('disabled'); - } else { - seg_type.val(4).attr('disabled','disabled'); - } - } - return; - } - - // update contextual tools here - var panels = { - g: [], - a: [], - rect: ['rx','width','height'], - image: ['width','height'], - circle: ['cx','cy','r'], - ellipse: ['cx','cy','rx','ry'], - line: ['x1','y1','x2','y2'], - text: [], - 'use': [] - }; - - var el_name = elem.tagName; - - if($(elem).data('gsvg')) { - $('#g_panel').show(); - } - - if (el_name == "path") { - $('#path_panel').show(); - } - -// var link_href = null; -// if (el_name === 'a') { -// link_href = svgCanvas.getHref(elem); -// $('#g_panel').show(); -// } -// -// if(elem.parentNode.tagName === 'a') { -// if(!$(elem).siblings().length) { -// $('#a_panel').show(); -// link_href = svgCanvas.getHref(elem.parentNode); -// } -// } -// -// // Hide/show the make_link buttons -// $('#tool_make_link, #tool_make_link').toggle(!link_href); -// -// if(link_href) { -// $('#link_url').val(link_href); -// } - - if(panels[el_name]) { - var cur_panel = panels[el_name]; - $('#' + el_name + '_panel').show(); - - $.each(cur_panel, function(i, item) { - var attrVal = elem.getAttribute(item); - if(curConfig.baseUnit !== 'px' && elem[item]) { - var bv = elem[item].baseVal.value; - attrVal = svgedit.units.convertUnit(bv); - } - - $('#' + el_name + '_' + item).val(attrVal || 0); - }); - if(el_name == 'text') { - $('#text_panel').css("display", "inline"); - if (svgCanvas.getItalic()) { - $('#tool_italic').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_italic').removeClass('push_button_pressed').addClass('tool_button'); - } - if (svgCanvas.getBold()) { - $('#tool_bold').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_bold').removeClass('push_button_pressed').addClass('tool_button'); - } - $('#font_family').val(elem.getAttribute("font-family")); - $('#font_size').val(elem.getAttribute("font-size")); - $('#text').val(elem.textContent); - if (svgCanvas.addedNew) { - // Timeout needed for IE9 - setTimeout(function() { - $('#text').focus().select(); - },100); - } - } // text - else if(el_name == 'image') { - setImageURL(svgCanvas.getHref(elem)); - } // image - else if(el_name === 'g' || el_name === 'use') { - $('#container_panel').show(); - $('.action_group_selected').removeClass('disabled'); - 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); - } - } - } - menu_items[(el_name === 'g' ? 'en':'dis') + 'ableContextMenuItems']('#ungroup'); - menu_items[((el_name === 'g' || !multiselected) ? 'dis':'en') + 'ableContextMenuItems']('#group'); - } // if (elem != null) - else if (multiselected) { - $('#multiselected_panel').show(); - $('.action_multi_selected').removeClass('disabled'); - menu_items - .enableContextMenuItems('#group') - .disableContextMenuItems('#ungroup'); - } else { - menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); - } - - // update history buttons - if (undoMgr.getUndoStackSize() > 0) { - $('#tool_undo').removeClass( 'disabled'); - } - else { - $('#tool_undo').addClass( 'disabled'); - } - if (undoMgr.getRedoStackSize() > 0) { - $('#tool_redo').removeClass( 'disabled'); - } - else { - $('#tool_redo').addClass( 'disabled'); - } - - svgCanvas.addedNew = false; - - if ( (elem && !is_node) || multiselected) { - // update the selected elements' layer - $('#selLayerNames').removeAttr('disabled').val(currentLayerName); - - // Enable regular menu options - canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); - } - else { - $('#selLayerNames').attr('disabled', 'disabled'); - } - }; - - $('#text').focus( function(){ textBeingEntered = true; } ); - $('#text').blur( function(){ textBeingEntered = false; } ); - - // bind the selected event to our function that handles updates to the UI - svgCanvas.bind("selected", selectedChanged); - svgCanvas.bind("transition", elementTransition); - svgCanvas.bind("changed", elementChanged); - svgCanvas.bind("saved", saveHandler); - svgCanvas.bind("exported", exportHandler); - svgCanvas.bind("zoomed", zoomChanged); - svgCanvas.bind("contextset", contextChanged); - svgCanvas.bind("extension_added", extAdded); - svgCanvas.textActions.setInputElem($("#text")[0]); - - var str = '
          ' - $.each(palette, function(i,item){ - str += '
          '; - }); - $('#palette').append(str); - - // Set up editor background functionality - // TODO add checkerboard as "pattern" - var color_blocks = ['#FFF','#888','#000']; // ,'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP%2F%2F%2F9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG%2Bgq4jM3IFLJgpswNly%2FXkcBpIiVaInlLJr9FZWAQA7)']; - var str = ''; - $.each(color_blocks, function() { - str += '
          '; - }); - $('#bg_blocks').append(str); - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - blocks.each(function() { - var blk = $(this); - blk.click(function() { - blocks.removeClass(cur_bg); - $(this).addClass(cur_bg); - }); - }); - - if($.pref('bkgd_color')) { - setBackground($.pref('bkgd_color'), $.pref('bkgd_url')); - } else if($.pref('bkgd_url')) { - // No color set, only URL - setBackground(defaultPrefs.bkgd_color, $.pref('bkgd_url')); - } - - if($.pref('img_save')) { - curPrefs.img_save = $.pref('img_save'); - $('#image_save_opts input').val([curPrefs.img_save]); - } - - var changeRectRadius = function(ctl) { - svgCanvas.setRectRadius(ctl.value); - } - - var changeFontSize = function(ctl) { - svgCanvas.setFontSize(ctl.value); - } - - var changeStrokeWidth = function(ctl) { - var val = ctl.value; - if(val == 0 && selectedElement && ['line', 'polyline'].indexOf(selectedElement.nodeName) >= 0) { - val = ctl.value = 1; - } - svgCanvas.setStrokeWidth(val); - } - - var changeRotationAngle = function(ctl) { - svgCanvas.setRotationAngle(ctl.value); - $('#tool_reorient').toggleClass('disabled', ctl.value == 0); - } - var changeZoom = function(ctl) { - var zoomlevel = ctl.value / 100; - if(zoomlevel < .001) { - ctl.value = .1; - return; - } - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - - zoomChanged(window, { - width: 0, - height: 0, - // center pt of scroll position - x: (w_area[0].scrollLeft + w_area.width()/2)/zoom, - y: (w_area[0].scrollTop + w_area.height()/2)/zoom, - zoom: zoomlevel - }, true); - } - - var changeOpacity = function(ctl, val) { - if(val == null) val = ctl.value; - $('#group_opacity').val(val); - if(!ctl || !ctl.handle) { - $('#opac_slider').slider('option', 'value', val); - } - svgCanvas.setOpacity(val/100); - } - - var changeBlur = function(ctl, val, noUndo) { - if(val == null) val = ctl.value; - $('#blur').val(val); - var complete = false; - if(!ctl || !ctl.handle) { - $('#blur_slider').slider('option', 'value', val); - complete = true; - } - if(noUndo) { - svgCanvas.setBlurNoUndo(val); - } else { - svgCanvas.setBlur(val, complete); - } - } - - var operaRepaint = function() { - // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change - if(!window.opera) return; - $('

          ').hide().appendTo('body').remove(); - } - - $('#stroke_style').change(function(){ - svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val()); - operaRepaint(); - }); - - $('#stroke_linejoin').change(function(){ - svgCanvas.setStrokeAttr('stroke-linejoin', $(this).val()); - operaRepaint(); - }); - - - // Lose focus for select elements when changed (Allows keyboard shortcuts to work better) - $('select').change(function(){$(this).blur();}); - - // fired when user wants to move elements to another layer - var promptMoveLayerOnce = false; - $('#selLayerNames').change(function(){ - var destLayer = this.options[this.selectedIndex].value; - var confirm_str = uiStrings.notification.QmoveElemsToLayer.replace('%s',destLayer); - var moveToLayer = function(ok) { - if(!ok) return; - promptMoveLayerOnce = true; - svgCanvas.moveSelectedToLayer(destLayer); - svgCanvas.clearSelection(); - populateLayers(); - } - if (destLayer) { - if(promptMoveLayerOnce) { - moveToLayer(true); - } else { - $.confirm(confirm_str, moveToLayer); - } - } - }); - - $('#font_family').change(function() { - svgCanvas.setFontFamily(this.value); - }); - - $('#seg_type').change(function() { - svgCanvas.setSegType($(this).val()); - }); - - $('#text').keyup(function(){ - svgCanvas.setTextContent(this.value); - }); - - $('#image_url').change(function(){ - setImageURL(this.value); - }); - - $('#link_url').change(function() { - if(this.value.length) { - svgCanvas.setLinkURL(this.value); - } else { - svgCanvas.removeHyperlink(); - } - }); - - $('#g_title').change(function() { - svgCanvas.setGroupTitle(this.value); - }); - - $('.attr_changer').change(function() { - var attr = this.getAttribute("data-attr"); - var val = this.value; - var valid = svgedit.units.isValidUnit(attr, val, selectedElement); - if(!valid) { - $.alert(uiStrings.notification.invalidAttrValGiven); - this.value = selectedElement.getAttribute(attr); - return false; - } - else{ - this.blur() - } - - if (attr !== "id") { - if (isNaN(val)) { - val = svgCanvas.convertToNum(attr, val); - } else if(curConfig.baseUnit !== 'px') { - // Convert unitless value to one with given unit - - var unitData = svgedit.units.getTypeMap(); - - if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") { - val *= unitData[curConfig.baseUnit]; - } - } - } - - // if the user is changing the id, then de-select the element first - // change the ID, then re-select it with the new ID - if (attr === "id") { - var elem = selectedElement; - svgCanvas.clearSelection(); - elem.id = val; - svgCanvas.addToSelection([elem],true); - } - else { - svgCanvas.changeSelectedAttribute(attr, val); - } - this.blur(); - }); - - // Prevent selection of elements when shift-clicking - $('#palette').mouseover(function() { - var inp = $(''); - $(this).append(inp); - inp.focus().remove(); - }); - - $('.palette_item').mousedown(function(evt){ - var isStroke = $('#tool_stroke').hasClass('active'); - var picker = isStroke ? "stroke" : "fill"; - var color = $(this).attr('data-rgb'); - var paint = null; - - // Webkit-based browsers returned 'initial' here for no stroke - console.log(color); - if (color === 'transparent' || color === 'initial' || color === '#none') { - color = 'none'; - paint = new $.jGraduate.Paint(); - } - else { - paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)}); - } - - paintBox[picker].setPaint(paint); - - if (isStroke) { - svgCanvas.setColor('stroke', color); - if (color != 'none' && svgCanvas.getStrokeOpacity() != 1) { - svgCanvas.setPaintOpacity('stroke', 1.0); - } - } else { - svgCanvas.setColor('fill', color); - if (color != 'none' && svgCanvas.getFillOpacity() != 1) { - svgCanvas.setPaintOpacity('fill', 1.0); - } - } - updateToolButtonState(); - }).bind('contextmenu', function(e) {e.preventDefault()}); - - $("#toggle_stroke_tools").toggle(function() { - $(".stroke_tool").css('display','table-cell'); - $(this).addClass('expanded'); - resetScrollPos(); - }, function() { - $(".stroke_tool").css('display','none'); - $(this).removeClass('expanded'); - resetScrollPos(); - }); - - // This is a common function used when a tool has been clicked (chosen) - // It does several common things: - // - removes the tool_button_current class from whatever tool currently has it - // - hides any flyouts - // - adds the tool_button_current class to the button passed in - var toolButtonClick = function(button, noHiding) { - if ($(button).hasClass('disabled')) return false; - if($(button).parent().hasClass('tools_flyout')) return true; - var fadeFlyouts = fadeFlyouts || 'normal'; - if(!noHiding) { - $('.tools_flyout').fadeOut(fadeFlyouts); - } - $('#styleoverrides').text(''); - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $(button).addClass('tool_button_current').removeClass('tool_button'); - return true; - }; - - (function() { - var last_x = null, last_y = null, w_area = workarea[0], - panning = false, keypan = false; - - $('#svgcanvas').bind('mousemove mouseup', function(evt) { - if(panning === false) return; - - w_area.scrollLeft -= (evt.clientX - last_x); - w_area.scrollTop -= (evt.clientY - last_y); - - last_x = evt.clientX; - last_y = evt.clientY; - - if(evt.type === 'mouseup') panning = false; - return false; - }).mousedown(function(evt) { - if(evt.button === 1 || keypan === true) { - panning = true; - last_x = evt.clientX; - last_y = evt.clientY; - return false; - } - }); - - $(window).mouseup(function() { - panning = false; - }); - - $(document).bind('keydown', 'space', function(evt) { - svgCanvas.spaceKey = keypan = true; - evt.preventDefault(); - }).bind('keyup', 'space', function(evt) { - evt.preventDefault(); - svgCanvas.spaceKey = keypan = false; - }).bind('keydown', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.addClass('out'); - } - }).bind('keyup', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.removeClass('out'); - } - }) - }()); - - - function setStrokeOpt(opt, changeElem) { - var id = opt.id; - var bits = id.split('_'); - var pre = bits[0]; - var val = bits[1]; - - if(changeElem) { - svgCanvas.setStrokeAttr('stroke-' + pre, val); - } - operaRepaint(); - setIcon('#cur_' + pre , id, 20); - $(opt).addClass('current').siblings().removeClass('current'); - } - - //menu handling - var menus = $('.menu'); - var blinker = function(e) { - e.target.style.background = "#fff"; - setTimeout(function(){e.target.style.background = "#ddd";}, 50); - setTimeout(function(){e.target.style.background = "#fff";}, 150); - setTimeout(function(){e.target.style.background = "#ddd";}, 200); - setTimeout(function(){e.target.style.background = "";}, 200); - setTimeout(function(){$('#menu_bar').removeClass('active')}, 220); - return false; - } - var closer = function(e){ - if (!$(e.target).hasClass("menu_title") && $('#menu_bar').hasClass("active")) { - if(!$(e.target).hasClass("disabled") && $(e.target).hasClass("menu_item")) { - blinker(e); - return; - } - $('#menu_bar').removeClass('active') - $('.tools_flyout').hide(); - $('input').blur(); - } - } - $('.menu_item').live('click', function(e){blinker(e)}); - $("svg, body").on('click', function(e){closer(e)}); - $('.menu_title').on('click', function() {$("#menu_bar").toggleClass('active');}); - $('.menu_title').on('mouseover', function() { - menus.removeClass('open'); - $(this).parent().addClass('open'); - }); - - // Made public for UI customization. - // TODO: Group UI functions into a public svgEditor.ui interface. - Editor.addDropDown = function(elem, callback, dropUp) { - if ($(elem).length == 0) return; // Quit if called on non-existant element - var button = $(elem).find('button'); - - var list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list'); - - if(!dropUp) { - // Move list to place where it can overflow container - $('#option_lists').append(list); - } - - var on_button = false; - if(dropUp) { - $(elem).addClass('dropup'); - } - - list.find('li').bind('mouseup', callback); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - } - on_button = false; - }); - - button.bind('mousedown',function() { - if (!button.hasClass('down')) { - button.addClass('down'); - - if(!dropUp) { - var pos = $(elem).offset(); - // position slider - list.css({ - top: pos.top, - left: pos.left - 110 - }); - } - list.show(); - - on_button = true; - } else { - button.removeClass('down'); - list.hide(); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - } - - // TODO: Combine this with addDropDown or find other way to optimize - var addAltDropDown = function(elem, list, callback, opts) { - var button = $(elem); - var list = $(list); - var on_button = false; - var dropUp = opts.dropUp; - if(dropUp) { - $(elem).addClass('dropup'); - } - list.find('li').bind('mouseup', function() { - if(opts.seticon) { - setIcon('#cur_' + button[0].id , $(this).children()); - $(this).addClass('current').siblings().removeClass('current'); - } - callback.apply(this, arguments); - - }); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - list.css({top:0, left:0}); - } - on_button = false; - }); - - var height = list.height(); - $(elem).bind('mousedown',function() { - var off = $(elem).offset(); - if(dropUp) { - off.top -= list.height(); - off.left += 8; - } else { - off.top += $(elem).height(); - } - $(list).offset(off); - - if (!button.hasClass('down')) { - button.addClass('down'); - list.show(); - on_button = true; - return false; - } else { - button.removeClass('down'); - // CSS position must be reset for Webkit - list.hide(); - list.css({top:0, left:0}); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - - if(opts.multiclick) { - list.mousedown(function() { - on_button = true; - }); - } - } - - Editor.addDropDown('#font_family_dropdown', function() { - var fam = $(this).text(); - $('#font_family').val($(this).text()).change(); - }); - - Editor.addDropDown('#opacity_dropdown', function() { - if($(this).find('div').length) return; - var perc = parseInt($(this).text().split('%')[0]); - changeOpacity(false, perc); - }, false); - - // For slider usage, see: http://jqueryui.com/demos/slider/ - $("#opac_slider").slider({ - start: function() { - $('#opacity_dropdown li:not(.special)').hide(); - }, - stop: function() { - $('#opacity_dropdown li').show(); - $(window).mouseup(); - }, - slide: function(evt, ui){ - changeOpacity(ui); - } - }); - - Editor.addDropDown('#blur_dropdown', $.noop); - - var slideStart = false; - - $("#blur_slider").slider({ - max: 10, - step: .1, - stop: function(evt, ui) { - slideStart = false; - changeBlur(ui); - $('#blur_dropdown li').show(); - $(window).mouseup(); - }, - start: function() { - slideStart = true; - }, - slide: function(evt, ui){ - changeBlur(ui, null, slideStart); - } - }); - - - Editor.addDropDown('#zoom_dropdown', function() { - var item = $(this); - var val = item.attr('data-val'); - if(val) { - zoomChanged(window, val); - } else { - changeZoom({value:parseInt(item.text())}); - } - }, true); - - addAltDropDown('#stroke_linecap', '#linecap_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - addAltDropDown('#stroke_linejoin', '#linejoin_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - $('div', '#position_opts').each(function(){ - this.addEventListener("mouseup", function(){ - var letter = this.id.replace('tool_pos','').charAt(0); - svgCanvas.alignSelectedElements(letter, 'page'); - }) - }); - - /* - - When a flyout icon is selected - (if flyout) { - - Change the icon - - Make pressing the button run its stuff - } - - Run its stuff - - When its shortcut key is pressed - - If not current in list, do as above - , else: - - Just run its stuff - - */ - - // Unfocus text input when workarea is mousedowned. - (function() { - var inp; - var unfocus = function() { - $(inp).blur(); - } - - $('#svg_editor').find('button, select, input:not(#text)').focus(function() { - inp = this; - ui_context = 'toolbars'; - workarea.mousedown(unfocus); - }).blur(function() { - ui_context = 'canvas'; - workarea.unbind('mousedown', unfocus); - // Go back to selecting text if in textedit mode - if(svgCanvas.getMode() == 'textedit') { - $('#text').focus(); - } - }); - - }()); - - var clickSelect = function() { - if (toolButtonClick('#tool_select')) { - svgCanvas.setMode('select'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}'); - } - }; - - var clickFHPath = function() { - if (toolButtonClick('#tool_fhpath')) { - svgCanvas.setMode('fhpath'); - } - }; - - var clickLine = function() { - if (toolButtonClick('#tool_line')) { - svgCanvas.setMode('line'); - } - }; - - var clickSquare = function(){ - if (toolButtonClick('#tool_square')) { - svgCanvas.setMode('square'); - } - }; - - var clickRect = function(){ - if (toolButtonClick('#tool_rect')) { - svgCanvas.setMode('rect'); - } - }; - - var clickFHRect = function(){ - if (toolButtonClick('#tool_fhrect')) { - svgCanvas.setMode('fhrect'); - } - }; - - var clickCircle = function(){ - if (toolButtonClick('#tool_circle')) { - svgCanvas.setMode('circle'); - } - }; - - var clickEllipse = function(){ - if (toolButtonClick('#tool_ellipse')) { - svgCanvas.setMode('ellipse'); - } - }; - - var clickFHEllipse = function(){ - if (toolButtonClick('#tool_fhellipse')) { - svgCanvas.setMode('fhellipse'); - } - }; - - var clickImage = function(){ - if (toolButtonClick('#tool_image')) { - svgCanvas.setMode('image'); - } - }; - - var clickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - svgCanvas.setMode('zoom'); - } - }; - - var dblclickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - zoomImage(); - setSelectMode(); - } - }; - - var clickText = function(){ - if (toolButtonClick('#tool_text')) { - svgCanvas.setMode('text'); - } - }; - - var clickPath = function(){ - if (toolButtonClick('#tool_path')) { - svgCanvas.setMode('path'); - } - }; - - // Delete is a contextual tool that only appears in the ribbon if - // an element has been selected - var deleteSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.deleteSelectedElements(); - } - }; - - var cutSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.cutSelectedElements(); - } - }; - - var copySelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.copySelectedElements(); - } - }; - - var pasteInCenter = function() { - var zoom = svgCanvas.getZoom(); - - var x = (workarea[0].scrollLeft + workarea.width()/2)/zoom - svgCanvas.contentW; - var y = (workarea[0].scrollTop + workarea.height()/2)/zoom - svgCanvas.contentH; - svgCanvas.pasteElements('point', x, y); - } - - var moveToTopSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToTopSelectedElement(); - } - }; - - var moveToBottomSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToBottomSelectedElement(); - } - }; - - var moveUpSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Up"); - } - }; - - var moveDownSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Down"); - } - }; - - var moveUpDownSelected = function(dir) { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected(dir); - } - }; - - var convertToPath = function() { - if (selectedElement != null) { - svgCanvas.convertToPath(); - } - } - - var reorientPath = function() { - if (selectedElement != null) { - path.reorient(); - } - } - - var makeHyperlink = function() { - if (selectedElement != null || multiselected) { - $.prompt(uiStrings.notification.enterNewLinkURL, "http://", function(url) { - if(url) svgCanvas.makeHyperlink(url); - }); - } - } - - var moveSelected = function(dx,dy) { - if (selectedElement != null || multiselected) { - if(curConfig.gridSnapping) { - // Use grid snap value regardless of zoom level - var multi = svgCanvas.getZoom() * curConfig.snappingStep; - dx *= multi; - dy *= multi; - } - svgCanvas.moveSelectedElements(dx,dy); - } - }; - - var linkControlPoints = function() { - var linked = !$('#tool_node_link').hasClass('push_button_pressed'); - if (linked) - $('#tool_node_link').addClass('push_button_pressed').removeClass('tool_button'); - else - $('#tool_node_link').removeClass('push_button_pressed').addClass('tool_button'); - - path.linkControlPoints(linked); - } - - var clonePathNode = function() { - if (path.getNodePoint()) { - path.clonePathNode(); - } - }; - - var deletePathNode = function() { - if (path.getNodePoint()) { - path.deletePathNode(); - } - }; - - var addSubPath = function() { - var button = $('#tool_add_subpath'); - var sp = !button.hasClass('push_button_pressed'); - if (sp) { - button.addClass('push_button_pressed').removeClass('tool_button'); - } else { - button.removeClass('push_button_pressed').addClass('tool_button'); - } - - path.addSubPath(sp); - - }; - - var opencloseSubPath = function() { - path.opencloseSubPath(); - } - - var selectNext = function() { - svgCanvas.cycleElement(1); - }; - - var selectPrev = function() { - svgCanvas.cycleElement(0); - }; - - var rotateSelected = function(cw,step) { - if (selectedElement == null || multiselected) return; - if(!cw) step *= -1; - var new_angle = $('#angle').val()*1 + step; - svgCanvas.setRotationAngle(new_angle); - updateContextPanel(); - }; - - var clickClear = function(){ - var dims = curConfig.dimensions; - $.confirm(uiStrings.notification.QwantToClear, function(ok) { - if(!ok) return; - setSelectMode(); - svgCanvas.clear(); - svgCanvas.setResolution(dims[0], dims[1]); - updateCanvas(true); - zoomImage(); - populateLayers(); - updateContextPanel(); - prepPaints(); - svgCanvas.runExtensions('onNewDocument'); - }); - }; - - var clickBold = function(){ - svgCanvas.setBold( !svgCanvas.getBold() ); - updateContextPanel(); - return false; - }; - - var clickItalic = function(){ - svgCanvas.setItalic( !svgCanvas.getItalic() ); - updateContextPanel(); - return false; - }; - - var clickSave = function(){ - // In the future, more options can be provided here - var saveOpts = { - 'images': curPrefs.img_save, - 'round_digits': 6 - } - svgCanvas.save(saveOpts); - }; - - var clickExport = function() { - // Open placeholder window (prevents popup) - if(!customHandlers.pngsave) { - var str = uiStrings.notification.loadingImage; - exportWindow = window.open("data:text/html;charset=utf-8," + str + "<\/title><h1>" + str + "<\/h1>"); - } - - if(window.canvg) { - svgCanvas.rasterExport(); - } else { - $.getScript('canvg/rgbcolor.js', function() { - $.getScript('canvg/canvg.js', function() { - svgCanvas.rasterExport(); - }); - }); - } - } - - // by default, svgCanvas.open() is a no-op. - // it is up to an extension mechanism (opera widget, etc) - // to call setCustomHandlers() which will make it do something - var clickOpen = function(){ - svgCanvas.open(); - }; - var clickImport = function(){ - }; - - var flash = function($menu){ - var menu_title = $menu.prev(); - menu_title.css("background", "#09f"); - setTimeout(function(){menu_title.css("background", "")}, 200); - } - - var clickUndo = function(){ - if (undoMgr.getUndoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.undo(); - populateLayers(); - } - }; - - var clickRedo = function(){ - if (undoMgr.getRedoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.redo(); - populateLayers(); - } - }; - - var clickGroup = function(){ - // group - if (multiselected) { - svgCanvas.groupSelectedElements(); - } - // ungroup - else if(selectedElement){ - svgCanvas.ungroupSelectedElement(); - } - }; - - var clickClone = function(){ - if (window.event.type === "keydown") flash($('#edit_menu')); - svgCanvas.cloneSelectedElements(20,20); - }; - - var clickAlign = function() { - var letter = this.id.replace('tool_align','').charAt(0); - svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val()); - }; - - var clickSwitch = function() { - var stroke_rect = document.querySelector('#tool_stroke rect'); - var fill_rect = document.querySelector('#tool_fill rect'); - var fill_color = fill_rect.getAttribute("fill"); - var stroke_color = stroke_rect.getAttribute("fill"); - var stroke_opacity = parseFloat(stroke_rect.getAttribute("stroke-opacity")); - if (isNaN(stroke_opacity)) {stroke_opacity = 100;} - var fill_opacity = parseFloat(fill_rect.getAttribute("fill-opacity")); - if (isNaN(fill_opacity)) {fill_opacity = 100;} - var stroke = getPaint(stroke_color, stroke_opacity, "stroke"); - var fill = getPaint(fill_color, fill_opacity, "fill"); - paintBox.fill.setPaint(stroke, true); - paintBox.stroke.setPaint(fill, true); - - }; - - var zoomImage = function(multiplier) { - var res = svgCanvas.getResolution(); - multiplier = multiplier?res.zoom * multiplier:1; - // setResolution(res.w * multiplier, res.h * multiplier, true); - $('#zoom').val(multiplier * 100); - svgCanvas.setZoom(multiplier); - zoomDone(); - updateCanvas(true); - }; - - var zoomDone = function() { - // updateBgImage(); - updateWireFrame(); - //updateCanvas(); // necessary? - } - - var clickWireframe = function() { - var wf = !$('#tool_wireframe').hasClass('push_button_pressed'); - if (wf) - $('#tool_wireframe').addClass('push_button_pressed'); - else - $('#tool_wireframe').removeClass('push_button_pressed'); - workarea.toggleClass('wireframe'); - - if(supportsNonSS) return; - var wf_rules = $('#wireframe_rules'); - if(!wf_rules.length) { - wf_rules = $('<style id="wireframe_rules"><\/style>').appendTo('head'); - } else { - wf_rules.empty(); - } - - updateWireFrame(); - } - - var clickRulers = function() { - var rulers = !$('#tool_rulers').hasClass('push_button_pressed'); - if (rulers) { - $('#tool_rulers').addClass('push_button_pressed'); - $('#show_rulers').attr("checked", true); - curConfig.showRulers = true; - } - else { - $('#tool_rulers').removeClass('push_button_pressed'); - $('#show_rulers').attr("checked", false); - curConfig.showRulers = false; - } - $('#rulers').toggle(!!curConfig.showRulers) - } - - var updateWireFrame = function() { - // Test support - if(supportsNonSS) return; - - var rule = "#workarea.wireframe #svgcontent * { stroke-width: " + 1/svgCanvas.getZoom() + "px; }"; - $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ""); - } - - var showSourceEditor = function(e, forSaving){ - if (editingsource) return; - editingsource = true; - - $('#save_output_btns').toggle(!!forSaving); - $('#tool_source_back').toggle(!forSaving); - - var str = orig_source = svgCanvas.getSvgString(); - $('#svg_source_textarea').val(str); - $('#svg_source_editor').fadeIn(); - properlySourceSizeTextArea(); - $('#svg_source_textarea').focus(); - }; - - var showDocProperties = function(){ - if (docprops) return; - docprops = true; - - // This selects the correct radio button by using the array notation - $('#image_save_opts input').val([curPrefs.img_save]); - - // update resolution option with actual resolution - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#canvas_title').val(svgCanvas.getDocumentTitle()); - - $('#svg_docprops').show(); - }; - - var showPreferences = function(){ - if (preferences) return; - preferences = true; - - // Update background color with current one - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - var canvas_bg = $.pref('bkgd_color'); - var url = $.pref('bkgd_url'); - // if(url) url = url[1]; - blocks.each(function() { - var blk = $(this); - var is_bg = blk.css('background-color') == canvas_bg; - blk.toggleClass(cur_bg, is_bg); - if(is_bg) $('#canvas_bg_url').removeClass(cur_bg); - }); - if(!canvas_bg) blocks.eq(0).addClass(cur_bg); - if(url) { - $('#canvas_bg_url').val(url); - } - $('grid_snapping_step').attr('value', curConfig.snappingStep); - if (curConfig.gridSnapping == true) { - $('#grid_snapping_on').attr('checked', 'checked'); - } else { - $('#grid_snapping_on').removeAttr('checked'); - } - - $('#svg_prefs').show(); - }; - - var properlySourceSizeTextArea = function(){ - // TODO: remove magic numbers here and get values from CSS - var height = $('#svg_source_container').height() - 50; - $('#svg_source_textarea').css('height', height); - }; - - var saveSourceEditor = function(){ - if (!editingsource) return; - - var saveChanges = function() { - svgCanvas.clearSelection(); - hideSourceEditor(); - zoomImage(); - populateLayers(); - updateTitle(); - prepPaints(); - } - - if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { - $.confirm(uiStrings.notification.QerrorsRevertToSource, function(ok) { - if(!ok) return false; - saveChanges(); - }); - } else { - saveChanges(); - } - setSelectMode(); - }; - - var updateTitle = function(title) { - title = title || svgCanvas.getDocumentTitle(); - var new_title = orig_title + (title?': ' + title:''); - - // Remove title update with current context info, isn't really necessary -// if(cur_context) { -// new_title = new_title + cur_context; -// } - $('title:first').text(new_title); - } - - var saveDocProperties = function(){ - - // update resolution - var width = $('#canvas_width'), w = width.val(); - var height = $('#canvas_height'), h = height.val(); - - if(w != "fit" && !svgedit.units.isValidUnit('width', w)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - width.parent().addClass('error'); - return false; - } - - width.parent().removeClass('error'); - - if(h != "fit" && !svgedit.units.isValidUnit('height', h)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - height.parent().addClass('error'); - return false; - } - - height.parent().removeClass('error'); - - if(!svgCanvas.setResolution(w, h)) { - $.alert(uiStrings.notification.noContentToFitTo); - return false; - } - - // set image save option - curPrefs.img_save = $('#image_save_opts :checked').val(); - $.pref('img_save',curPrefs.img_save); - updateCanvas(); - hideDocProperties(); - }; - - var savePreferences = function() { - // set background - var color = $('#bg_blocks div.cur_background').css('background-color') || '#FFF'; - setBackground(color, $('#canvas_bg_url').val()); - - // set language - var lang = $('#lang_select').val(); - if(lang != curPrefs.lang) { - Editor.putLocale(lang); - } - - // set icon size - setIconSize($('#iconsize').val()); - - // set grid setting - curConfig.gridSnapping = $('#grid_snapping_on')[0].checked; - curConfig.snappingStep = $('#grid_snapping_step').val(); - curConfig.showRulers = $('#show_rulers')[0].checked; - - $('#rulers').toggle(curConfig.showRulers); - if(curConfig.showRulers) updateRulers(); - curConfig.baseUnit = $('#base_unit').val(); - - svgCanvas.setConfig(curConfig); - - updateCanvas(); - hidePreferences(); - } - - function setBackground(color, url) { -// if(color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return; - $.pref('bkgd_color', color); - $.pref('bkgd_url', url); - - // This should be done in svgcanvas.js for the borderRect fill - svgCanvas.setBackground(color, url); - } - - var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { - var icon = (typeof icon_id === 'string') ? $.getSvgIcon(icon_id, true) : icon_id.clone(); - if(!icon) { - console.log('NOTE: Icon image missing: ' + icon_id); - return; - } - - $(elem).empty().append(icon); - } - - 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); - - - // 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}); -// } - - // 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'} -// }, - "#tools_top": { - 'left': 50, - 'height': 72 - }, - "#tools_left": { - 'width': 31, - 'top': 74 - }, - "div#workarea": { - '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'} -// } - }; - - var rule_elem = $('#tool_size_rules'); - if(!rule_elem.length) { - rule_elem = $('<style id="tool_size_rules"><\/style>').appendTo('head'); - } else { - rule_elem.empty(); - } - - if(size != 'm') { - var style_str = ''; - $.each(cssResizeRules, function(selector, rules) { - selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor'); - style_str += selector + '{'; - $.each(rules, function(prop, values) { - 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); - } - - setFlyoutPositions(); - } - - var cancelOverlays = function() { - $('#dialog_box').hide(); - if (!editingsource && !docprops && !preferences) { - if(cur_context) { - svgCanvas.leaveContext(); - } - return; - }; - - if (editingsource) { - if (orig_source !== $('#svg_source_textarea').val()) { - $.confirm(uiStrings.notification.QignoreSourceChanges, function(ok) { - if(ok) hideSourceEditor(); - }); - } else { - hideSourceEditor(); - } - } - else if (docprops) { - hideDocProperties(); - } else if (preferences) { - hidePreferences(); - } - resetScrollPos(); - }; - - var hideSourceEditor = function(){ - $('#svg_source_editor').hide(); - editingsource = false; - $('#svg_source_textarea').blur(); - }; - - var hideDocProperties = function(){ - $('#svg_docprops').hide(); - $('#canvas_width,#canvas_height').removeAttr('disabled'); - $('#resolution')[0].selectedIndex = 0; - $('#image_save_opts input').val([curPrefs.img_save]); - docprops = false; - }; - - var hidePreferences = function(){ - $('#svg_prefs').hide(); - preferences = false; - }; - - var win_wh = {width:$(window).width(), height:$(window).height()}; - - var resetScrollPos = $.noop, curScrollPos; - - // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9) - if(svgedit.browser.isIE()) { - (function() { - resetScrollPos = function() { - if(workarea[0].scrollLeft === 0 - && workarea[0].scrollTop === 0) { - workarea[0].scrollLeft = curScrollPos.left; - workarea[0].scrollTop = curScrollPos.top; - } - } - - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - - $(window).resize(resetScrollPos); - svgEditor.ready(function() { - // TODO: Find better way to detect when to do this to minimize - // flickering effect - setTimeout(function() { - resetScrollPos(); - }, 500); - }); - - workarea.scroll(function() { - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - }); - }()); - } - - $(window).resize(function(evt) { - if (editingsource) { - properlySourceSizeTextArea(); - } - - $.each(win_wh, function(type, val) { - var curval = $(window)[type](); - workarea[0]['scroll' + (type==='width'?'Left':'Top')] -= (curval - val)/2; - win_wh[type] = curval; - }); - }); - - (function() { - workarea.scroll(function() { - // TODO: jQuery's scrollLeft/Top() wouldn't require a null check - if ($('#ruler_x').length != 0) { - $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; - } - if ($('#ruler_y').length != 0) { - $('#ruler_y')[0].scrollTop = workarea[0].scrollTop; - } - }); - - }()); - - $('#url_notice').click(function() { - $.alert(this.title); - }); - - $('#change_image_url').click(promptImgURL); - - function promptImgURL() { - var curhref = svgCanvas.getHref(selectedElement); - curhref = curhref.indexOf("data:") === 0?"":curhref; - $.prompt(uiStrings.notification.enterNewImgURL, curhref, function(url) { - if(url) setImageURL(url); - }); - } - - // added these event handlers for all the push buttons so they - // behave more like buttons being pressed-in and not images - (function() { - var toolnames = ['clear','open','save','source','delete','delete_multi','paste','clone','clone_multi','move_top','move_bottom']; - var all_tools = ''; - var cur_class = 'tool_button_current'; - - $.each(toolnames, function(i,item) { - all_tools += '#tool_' + item + (i==toolnames.length-1?',':''); - }); - - $(all_tools).mousedown(function() { - $(this).addClass(cur_class); - }).bind('mousedown mouseout', function() { - $(this).removeClass(cur_class); - }); - - $('#tool_undo, #tool_redo').mousedown(function(){ - if (!$(this).hasClass('disabled')) $(this).addClass(cur_class); - }).bind('mousedown mouseout',function(){ - $(this).removeClass(cur_class);} - ); - }()); - - // switch modifier key in tooltips if mac - // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta - // in Opera and Chrome - if (isMac && !window.opera) { - var shortcutButtons = ["tool_clear", "tool_save", "tool_source", "tool_undo", "tool_redo", "tool_clone"]; - var i = shortcutButtons.length; - while (i--) { - var button = document.getElementById(shortcutButtons[i]); - if (button != null) { - var title = button.title; - var index = title.indexOf("Ctrl+"); - button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join(''); - } - } - } - - // TODO: go back to the color boxes having white background-color and then setting - // background-image to none.png (otherwise partially transparent gradients look weird) - var colorPicker = function(elem) { - var picker = elem.attr('id') == 'stroke_color' ? 'stroke' : 'fill'; -// var opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); - var paint = paintBox[picker].paint; - var title = (picker == 'stroke' ? 'Pick a Stroke Paint and Opacity' : 'Pick a Fill Paint and Opacity'); - var was_none = false; - var pos = elem.position(); - $("#color_picker") - .draggable({cancel:'.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window'}) - .css(curConfig.colorPickerCSS || {'left': pos.left, 'bottom': 50 - pos.top}) - .jGraduate( - { - paint: paint, - window: { pickerTitle: title }, - images: { clientPath: curConfig.jGraduatePath }, - newstop: 'inverse' - }, - function(p) { - paint = new $.jGraduate.Paint(p); - - paintBox[picker].setPaint(paint); - svgCanvas.setPaint(picker, paint); - - $('#color_picker').hide(); - }, - function(p) { - $('#color_picker').hide(); - }); - }; - - var updateToolButtonState = function() { - var bNoFill = (svgCanvas.getColor('fill') == 'none'); - var bNoStroke = (svgCanvas.getColor('stroke') == 'none'); - var buttonsNeedingStroke = [ '#tool_fhpath', '#tool_line' ]; - var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; - if (bNoStroke) { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - $(button).removeClass('disabled'); - } - } - - if (bNoStroke && bNoFill) { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - $(button).removeClass('disabled'); - } - } - - svgCanvas.runExtensions("toolButtonStateUpdate", { - nofill: bNoFill, - nostroke: bNoStroke - }); - - // Disable flyouts if all inside are disabled - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var has_enabled = false; - $(this).children().each(function() { - if(!$(this).hasClass('disabled')) { - has_enabled = true; - } - }); - shower.toggleClass('disabled', !has_enabled); - }); - - operaRepaint(); - }; - - - - var PaintBox = function(container, type) { - var cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke']; - - // set up gradients to be used for the buttons - var svgdocbox = new DOMParser().parseFromString( - '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\ - fill="#' + cur.color + '" opacity="' + cur.opacity + '"/>\ - <defs><linearGradient id="gradbox_"/></defs></svg>', 'text/xml'); - var docElem = svgdocbox.documentElement; - - docElem = $(container)[0].appendChild(document.importNode(docElem, true)); - - docElem.setAttribute('width',24.5); - - this.rect = docElem.firstChild; - this.defs = docElem.getElementsByTagName('defs')[0]; - this.grad = this.defs.firstChild; - this.paint = new $.jGraduate.Paint({solidColor: cur.color}); - this.type = type; - - this.setPaint = function(paint, apply) { - this.paint = paint; - - var fillAttr = "none"; - var ptype = paint.type; - var opac = paint.alpha / 100; - - switch ( ptype ) { - case 'solidColor': - fillAttr = "#" + paint[ptype]; - break; - case 'linearGradient': - case 'radialGradient': - this.defs.removeChild(this.grad); - this.grad = this.defs.appendChild(paint[ptype]); - var id = this.grad.id = 'gradbox_' + this.type; - fillAttr = "url(#" + id + ')'; - } - - this.rect.setAttribute('fill', fillAttr); - this.rect.setAttribute('opacity', opac); - - if(apply) { - svgCanvas.setColor(this.type, fillAttr, true); - svgCanvas.setPaintOpacity(this.type, opac, true); - } - } - - this.update = function(apply) { - if(!selectedElement) return; - var type = this.type; - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - // These elements don't have fill or stroke, so don't change - // the current value - return; - case 'g': - case 'a': - var gPaint = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var elem = childs[i]; - var p = elem.getAttribute(type); - if(i === 0) { - gPaint = p; - } else if(gPaint !== p) { - gPaint = null; - break; - } - } - if(gPaint === null) { - // No common color, don't update anything - var paintColor = null; - return; - } - var paintColor = gPaint; - - var paintOpacity = 1; - break; - default: - var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity")); - if (isNaN(paintOpacity)) { - paintOpacity = 1.0; - } - - var defColor = type === "fill" ? "black" : "none"; - var paintColor = selectedElement.getAttribute(type) || defColor; - } - - if(apply) { - svgCanvas.setColor(type, paintColor, true); - svgCanvas.setPaintOpacity(type, paintOpacity, true); - } - - paintOpacity *= 100; - - var paint = getPaint(paintColor, paintOpacity, type); - // update the rect inside #fill_color/#stroke_color - this.setPaint(paint); - } - - this.prep = function() { - var ptype = this.paint.type; - - switch ( ptype ) { - case 'linearGradient': - case 'radialGradient': - var paint = new $.jGraduate.Paint({copy: this.paint}); - svgCanvas.setPaint(type, paint); - } - } - }; - - paintBox.fill = new PaintBox('#fill_color', 'fill'); - paintBox.stroke = new PaintBox('#stroke_color', 'stroke'); - - $('#stroke_width').val(curConfig.initStroke.width); - $('#group_opacity').val(curConfig.initOpacity * 100); - - // Use this SVG elem to test vectorEffect support - var test_el = paintBox.fill.rect.cloneNode(false); - test_el.setAttribute('style','vector-effect:non-scaling-stroke'); - var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke'); - test_el.removeAttribute('style'); - var svgdocbox = paintBox.fill.rect.ownerDocument; - // Use this to test support for blur element. Seems to work to test support in Webkit - var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur'); - if(typeof blur_test.stdDeviationX === "undefined") { - $('#tool_blur').hide(); - } - $(blur_test).remove(); - - - - // Test for embedImage support (use timeout to not interfere with page load) - setTimeout(function() { - svgCanvas.embedImage('images/placeholder.svg', function(datauri) { - if(!datauri) { - // Disable option - $('#image_save_opts [value=embed]').attr('disabled','disabled'); - $('#image_save_opts input').val(['ref']); - curPrefs.img_save = 'ref'; - $('#image_opt_embed').css('color','#666').attr('title',uiStrings.notification.featNotSupported); - } - }); - },1000); - - $('#tool_fill').click(function(){ - if ($('#tool_fill').hasClass('active')) { - colorPicker($('#fill_color')); - updateToolButtonState(); - } - else { - $('#tool_fill').addClass('active'); - $("#tool_stroke").removeClass('active'); - } - }); - - $('#tool_stroke').click(function(){ - - if ($('#tool_stroke').hasClass('active')) { - colorPicker($('#stroke_color')); - updateToolButtonState(); - } - else { - $('#tool_stroke').addClass('active'); - console.log($('#tool_stroke')); - $("#tool_fill").removeClass('active'); - } - }); - - $('#group_opacityLabel').click(function() { - $('#opacity_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#zoomLabel').click(function() { - $('#zoom_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#tool_move_top').mousedown(function(evt){ - $('#tools_stacking').show(); - evt.preventDefault(); - }); - - $('.layer_button').mousedown(function() { - $(this).addClass('layer_buttonpressed'); - }).mouseout(function() { - $(this).removeClass('layer_buttonpressed'); - }).mouseup(function() { - $(this).removeClass('layer_buttonpressed'); - }); - - $('.push_button').mousedown(function() { - if (!$(this).hasClass('disabled')) { - $(this).addClass('push_button_pressed').removeClass('push_button'); - } - }).mouseout(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }).mouseup(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }); - - $('#layer_new').click(function() { - var i = svgCanvas.getCurrentDrawing().getNumLayers(); - do { - var uniqName = uiStrings.layers.layer + " " + ++i; - } while(svgCanvas.getCurrentDrawing().hasLayer(uniqName)); - - $.prompt(uiStrings.notification.enterUniqueLayerName,uniqName, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.createLayer(newName); - updateContextPanel(); - populateLayers(); - }); - }); - - function deleteLayer() { - if (svgCanvas.deleteCurrentLayer()) { - updateContextPanel(); - populateLayers(); - // This matches what SvgCanvas does - // TODO: make this behavior less brittle (svg-editor should get which - // layer is selected from the canvas and then select that one in the UI) - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:first').addClass("layersel"); - } - } - - function cloneLayer() { - var name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy'; - - $.prompt(uiStrings.notification.enterUniqueLayerName, name, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.cloneLayer(newName); - updateContextPanel(); - populateLayers(); - }); - } - - function mergeLayer() { - if($('#layerlist tr.layersel').index() == svgCanvas.getCurrentDrawing().getNumLayers()-1) return; - svgCanvas.mergeLayer(); - updateContextPanel(); - populateLayers(); - } - - function moveLayer(pos) { - var curIndex = $('#layerlist tr.layersel').index(); - var total = svgCanvas.getCurrentDrawing().getNumLayers(); - if(curIndex > 0 || curIndex < total-1) { - curIndex += pos; - svgCanvas.setCurrentLayerPosition(total-curIndex-1); - populateLayers(); - } - } - - $('#layer_delete').click(deleteLayer); - - $('#layer_up').click(function() { - moveLayer(-1); - }); - - $('#layer_down').click(function() { - moveLayer(1); - }); - - $('#layer_rename').click(function() { - var curIndex = $('#layerlist tr.layersel').prevAll().length; - var oldName = $('#layerlist tr.layersel td.layername').text(); - $.prompt(uiStrings.notification.enterNewLayerName,"", function(newName) { - if (!newName) return; - if (oldName == newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.layerHasThatName); - return; - } - - svgCanvas.renameCurrentLayer(newName); - populateLayers(); - }); - }); - - var SIDEPANEL_MAXWIDTH = 300; - var SIDEPANEL_OPENWIDTH = 150; - var sidedrag = -1, sidedragging = false, allowmove = false; - - var resizePanel = function(evt) { - if (!allowmove) return; - if (sidedrag == -1) return; - sidedragging = true; - var deltax = sidedrag - evt.pageX; - - var sidepanels = $('#sidepanels'); - var sidewidth = parseInt(sidepanels.css('width')); - if (sidewidth+deltax > SIDEPANEL_MAXWIDTH) { - deltax = SIDEPANEL_MAXWIDTH - sidewidth; - sidewidth = SIDEPANEL_MAXWIDTH; - } - else if (sidewidth+deltax < 2) { - deltax = 2 - sidewidth; - sidewidth = 2; - } - - if (deltax == 0) return; - sidedrag -= deltax; - - var layerpanel = $('#layerpanel'); - workarea.css('right', parseInt(workarea.css('right'))+deltax); - sidepanels.css('width', parseInt(sidepanels.css('width'))+deltax); - layerpanel.css('width', parseInt(layerpanel.css('width'))+deltax); - var ruler_x = $('#ruler_x'); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - } - - $('#sidepanel_handle') - .mousedown(function(evt) { - sidedrag = evt.pageX; - $(window).mousemove(resizePanel); - allowmove = false; - // Silly hack for Chrome, which always runs mousemove right after mousedown - setTimeout(function() { - allowmove = true; - }, 20); - }) - .mouseup(function(evt) { - if (!sidedragging) toggleSidePanel(); - sidedrag = -1; - sidedragging = false; - }); - - $(window).mouseup(function() { - sidedrag = -1; - sidedragging = false; - $('#svg_editor').unbind('mousemove', resizePanel); - }); - - // if width is non-zero, then fully close it, otherwise fully open it - // the optional close argument forces the side panel closed - var toggleSidePanel = function(close){ - var w = parseInt($('#sidepanels').css('width')); - var deltax = (w > 2 || close ? 2 : SIDEPANEL_OPENWIDTH) - w; - var sidepanels = $('#sidepanels'); - var layerpanel = $('#layerpanel'); - var ruler_x = $('#ruler_x'); - workarea.css('right', parseInt(workarea.css('right')) + deltax); - sidepanels.css('width', parseInt(sidepanels.css('width')) + deltax); - layerpanel.css('width', parseInt(layerpanel.css('width')) + deltax); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - }; - - // this function highlights the layer passed in (by fading out the other layers) - // if no layer is passed in, this function restores the other layers - var toggleHighlightLayer = function(layerNameToHighlight) { - var curNames = new Array(svgCanvas.getCurrentDrawing().getNumLayers()); - for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getCurrentDrawing().getLayerName(i); } - - if (layerNameToHighlight) { - for (var i = 0; i < curNames.length; ++i) { - if (curNames[i] != layerNameToHighlight) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 0.5); - } - } - } - else { - for (var i = 0; i < curNames.length; ++i) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 1.0); - } - } - }; - - var populateLayers = function(){ - var layerlist = $('#layerlist tbody'); - var selLayerNames = $('#selLayerNames'); - layerlist.empty(); - selLayerNames.empty(); - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var layer = svgCanvas.getCurrentDrawing().getNumLayers(); - var icon = $.getSvgIcon('eye'); - // we get the layers in the reverse z-order (the layer rendered on top is listed first) - while (layer--) { - var name = svgCanvas.getCurrentDrawing().getLayerName(layer); - // contenteditable=\"true\" - var appendstr = "<tr class=\"layer"; - if (name == currentLayerName) { - appendstr += " layersel" - } - appendstr += "\">"; - - if (svgCanvas.getCurrentDrawing().getLayerVisibility(name)) { - appendstr += "<td class=\"layervis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - else { - appendstr += "<td class=\"layervis layerinvis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - layerlist.append(appendstr); - selLayerNames.append("<option value=\"" + name + "\">" + name + "</option>"); - } - if(icon !== undefined) { - var copy = icon.clone(); - $('td.layervis',layerlist).append(icon.clone()); - $.resizeSvgIcons({'td.layervis .svg_icon':14}); - } - // handle selection of layer - $('#layerlist td.layername') - .mouseup(function(evt){ - $('#layerlist tr.layer').removeClass("layersel"); - var row = $(this.parentNode); - row.addClass("layersel"); - svgCanvas.setCurrentLayer(this.textContent); - evt.preventDefault(); - }) - .mouseover(function(evt){ - $(this).css({"font-style": "italic", "color":"blue"}); - toggleHighlightLayer(this.textContent); - }) - .mouseout(function(evt){ - $(this).css({"font-style": "normal", "color":"black"}); - toggleHighlightLayer(); - }); - $('#layerlist td.layervis').click(function(evt){ - var row = $(this.parentNode).prevAll().length; - var name = $('#layerlist tr.layer:eq(' + row + ') td.layername').text(); - var vis = $(this).hasClass('layerinvis'); - svgCanvas.setLayerVisibility(name, vis); - if (vis) { - $(this).removeClass('layerinvis'); - } - else { - $(this).addClass('layerinvis'); - } - }); - - // if there were too few rows, let's add a few to make it not so lonely - var num = 5 - $('#layerlist tr.layer').size(); - while (num-- > 0) { - // FIXME: there must a better way to do this - layerlist.append("<tr><td style=\"color:white\">_</td><td/></tr>"); - } - }; - populateLayers(); - - // function changeResolution(x,y) { - // var zoom = svgCanvas.getResolution().zoom; - // setResolution(x * zoom, y * zoom); - // } - - var centerCanvas = function() { - // this centers the canvas vertically in the workarea (horizontal handled in CSS) - workarea.css('line-height', workarea.height() + 'px'); - }; - - $(window).bind('load resize', centerCanvas); - - function stepFontSize(elem, step) { - var orig_val = elem.value-0; - var sug_val = orig_val + step; - var increasing = sug_val >= orig_val; - if(step === 0) return orig_val; - - if(orig_val >= 24) { - if(increasing) { - return Math.round(orig_val * 1.1); - } else { - return Math.round(orig_val / 1.1); - } - } else if(orig_val <= 1) { - if(increasing) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } else { - return sug_val; - } - } - - function stepZoom(elem, step) { - var orig_val = elem.value-0; - if(orig_val === 0) return 100; - var sug_val = orig_val + step; - if(step === 0) return orig_val; - - if(orig_val >= 100) { - return sug_val; - } else { - if(sug_val >= orig_val) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } - } - - // function setResolution(w, h, center) { - // updateCanvas(); - // // w-=0; h-=0; - // // $('#svgcanvas').css( { 'width': w, 'height': h } ); - // // $('#canvas_width').val(w); - // // $('#canvas_height').val(h); - // // - // // if(center) { - // // var w_area = workarea; - // // var scroll_y = h/2 - w_area.height()/2; - // // var scroll_x = w/2 - w_area.width()/2; - // // w_area[0].scrollTop = scroll_y; - // // w_area[0].scrollLeft = scroll_x; - // // } - // } - - $('#resolution').change(function(){ - var wh = $('#canvas_width,#canvas_height'); - if(!this.selectedIndex) { - if($('#canvas_width').val() == 'fit') { - wh.removeAttr("disabled").val(100); - } - } else if(this.value == 'content') { - wh.val('fit').attr("disabled","disabled"); - } else { - var dims = this.value.split('x'); - $('#canvas_width').val(dims[0]); - $('#canvas_height').val(dims[1]); - wh.removeAttr("disabled"); - } - }); - - //Prevent browser from erroneously repopulating fields - $('input,select').attr("autocomplete","off"); - - // Associate all button actions as well as non-button keyboard shortcuts - var Actions = function() { - // sel:'selector', fn:function, evt:'event', key:[key, preventDefault, NoDisableInInput] - var tool_buttons = [ - {sel:'#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]}, - {sel:'#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]}, - {sel:'#tool_line', fn: clickLine, evt: 'click', key: ['L', true]}, - {sel:'#tool_rect', fn: clickRect, evt: 'click', key: ['R', true], icon: 'rect'}, - {sel:'#tool_ellipse', fn: clickEllipse, evt: 'mouseup', key: ['C', true], icon: 'ellipse'}, - //{sel:'#tool_circle', fn: clickCircle, evt: 'mouseup', icon: 'circle'}, - //{sel:'#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup', parent: '#tools_ellipse', icon: 'fh_ellipse'}, - {sel:'#tool_path', fn: clickPath, evt: 'click', key: ['P', true]}, - {sel:'#tool_text', fn: clickText, evt: 'click', key: ['T', true]}, - {sel:'#tool_image', fn: clickImage, evt: 'mouseup'}, - {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]}, - {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey + 'N', true]}, - {sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey + 'S', true]}, - {sel:'#tool_export', fn: clickExport, evt: 'mouseup'}, - {sel:'#tool_open', fn: clickOpen, evt: 'mouseup'}, - {sel:'#tool_import', fn: clickImport, evt: 'mouseup'}, - {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: [modKey + 'U', true]}, - {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click'}, - {sel:'#tool_rulers', fn: clickRulers, evt: 'click'}, - {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, - {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'}, - {sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'}, - {sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup'}, - {sel:'#tool_prefs_save', fn: savePreferences, evt: 'click'}, - {sel:'#tool_prefs_option', fn: function() {showPreferences();return false}, evt: 'mouseup'}, - {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]}, - {sel:'#tool_reorient', fn: reorientPath, evt: 'click'}, - {sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'}, - {sel:'#tool_node_clone', fn: clonePathNode, evt: 'click'}, - {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'}, - {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'}, - {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'}, - {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: modKey + 'shift+up'}, - {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: modKey + 'shift+down'}, - {sel:'#tool_move_up', fn: moveUpSelected, evt:'click', key: [modKey+'up', true]}, - {sel:'#tool_move_down', fn: moveDownSelected, evt:'click', key: [modKey+'down', true]}, - {sel:'#tool_topath', fn: convertToPath, evt: 'click'}, - {sel:'#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'}, - {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: [modKey + 'Z', true]}, - {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]}, - {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey + 'D', true]}, - {sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey + 'G', true]}, - {sel:'#tool_ungroup', fn: clickGroup, evt: 'click', key: modKey + 'shift+G'}, - {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, - {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, - {sel:'#tool_switch', fn: clickSwitch, evt: 'click', key: ['X', true]}, - // these two lines are required to make Opera work properly with the flyout mechanism - // {sel:'#tools_rect_show', fn: clickRect, evt: 'click'}, - // {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'}, - {sel:'#tool_bold', fn: clickBold, evt: 'mousedown', key: [modKey + 'B', true]}, - {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown', key: [modKey + 'I', true]}, - //{sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']}, - {sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'}, - - // Shortcuts not associated with buttons - - {key: 'ctrl+left', fn: function(){rotateSelected(0,1)}}, - {key: 'ctrl+right', fn: function(){rotateSelected(1,1)}}, - {key: 'ctrl+shift+left', fn: function(){rotateSelected(0,5)}}, - {key: 'ctrl+shift+right', fn: function(){rotateSelected(1,5)}}, - {key: 'shift+O', fn: selectPrev}, - {key: 'shift+P', fn: selectNext}, - {key: [modKey+'+', true], fn: function(){zoomImage(2);}}, - {key: [modKey+'-', true], fn: function(){zoomImage(.5);}}, - {key: ['up', true], fn: function(){moveSelected(0,-1);}}, - {key: ['down', true], fn: function(){moveSelected(0,1);}}, - {key: ['left', true], fn: function(){moveSelected(-1,0);}}, - {key: ['right', true], fn: function(){moveSelected(1,0);}}, - {key: 'shift+up', fn: function(){moveSelected(0,-10)}}, - {key: 'shift+down', fn: function(){moveSelected(0,10)}}, - {key: 'shift+left', fn: function(){moveSelected(-10,0)}}, - {key: 'shift+right', fn: function(){moveSelected(10,0)}}, - {key: ['alt+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-1)}}, - {key: ['alt+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,1)}}, - {key: ['alt+left', true], fn: function(){svgCanvas.cloneSelectedElements(-1,0)}}, - {key: ['alt+right', true], fn: function(){svgCanvas.cloneSelectedElements(1,0)}}, - {key: ['alt+shift+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-10)}}, - {key: ['alt+shift+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,10)}}, - {key: ['alt+shift+left', true], fn: function(){svgCanvas.cloneSelectedElements(-10,0)}}, - {key: ['alt+shift+right', true], fn: function(){svgCanvas.cloneSelectedElements(10,0)}}, - {key: modKey + 'A', fn: function(){svgCanvas.selectAllInCurrentLayer();}}, - - // Standard shortcuts - {key: modKey + 'z', fn: clickUndo}, - {key: modKey + 'shift+z', fn: clickRedo}, - {key: modKey + 'y', fn: clickRedo}, - - {key: modKey+'x', fn: cutSelected}, - {key: modKey+'c', fn: copySelected}, - {key: modKey+'v', fn: pasteInCenter} - - - ]; - - // Tooltips not directly associated with a single function - var key_assocs = { - '4/Shift+4': '#tools_rect_show', - '5/Shift+5': '#tools_ellipse_show' - }; - - return { - setAll: function() { - var flyouts = {}; - - $.each(tool_buttons, function(i, opts) { - // Bind function to button - if(opts.sel) { - var btn = $(opts.sel); - if (btn.length == 0) return true; // Skip if markup does not exist - if(opts.evt) { - if (svgedit.browser.isTouch() && opts.evt === "click") opts.evt = "mousedown" - btn[opts.evt](opts.fn); - } - - // Add to parent flyout menu, if able to be displayed - if(opts.parent && $(opts.parent + '_show').length != 0) { - var f_h = $(opts.parent); - if(!f_h.length) { - f_h = makeFlyoutHolder(opts.parent.substr(1)); - } - - f_h.append(btn); - - if(!$.isArray(flyouts[opts.parent])) { - flyouts[opts.parent] = []; - } - flyouts[opts.parent].push(opts); - } - } - - - // Bind function to shortcut key - if(opts.key) { - // Set shortcut based on options - var keyval, shortcut = '', disInInp = true, fn = opts.fn, pd = false; - if($.isArray(opts.key)) { - keyval = opts.key[0]; - if(opts.key.length > 1) pd = opts.key[1]; - if(opts.key.length > 2) disInInp = opts.key[2]; - } else { - keyval = opts.key; - } - keyval += ''; - if (svgedit.browser.isMac && keyval.indexOf("+") != -1) { - var modifier_key = keyval.split("+")[0]; - if (modifier_key == "ctrl") keyval.replace("ctrl", "cmd") - } - - $.each(keyval.split('/'), function(i, key) { - $(document).bind('keydown', key, function(e) { - fn(); - if(pd) { - e.preventDefault(); - } - // Prevent default on ALL keys? - return false; - }); - }); - - // Put shortcut in title - if(opts.sel && !opts.hidekey && btn.attr('title')) { - var new_title = btn.attr('title').split('[')[0] + ' (' + keyval + ')'; - key_assocs[keyval] = opts.sel; - // Disregard for menu items - if(!btn.parents('#main_menu').length) { - btn.attr('title', new_title); - } - } - } - }); - - // Setup flyouts - setupFlyouts(flyouts); - - - // Misc additional actions - - // Make "return" keypress trigger the change event - $('.attr_changer, #image_url').bind('keydown', 'return', - function(evt) {$(this).change();evt.preventDefault();} - ); - - $(window).bind('keydown', 'tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectNext(); - } - }).bind('keydown', 'shift+tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectPrev(); - } - }); - - $('#tool_zoom').dblclick(dblclickZoom); - }, - setTitles: function() { - $.each(key_assocs, function(keyval, sel) { - var menu = ($(sel).parents('#main_menu').length); - - $(sel).each(function() { - if(menu) { - var t = $(this).text().split(' [')[0]; - } else { - var t = this.title.split(' [')[0]; - } - var key_str = ''; - // Shift+Up - $.each(keyval.split('/'), function(i, key) { - var mod_bits = key.split('+'), mod = ''; - if(mod_bits.length > 1) { - mod = mod_bits[0] + '+'; - key = mod_bits[1]; - } - key_str += (i?'/':'') + mod + (uiStrings['key_'+key] || key); - }); - if(menu) { - this.lastChild.textContent = t +' ['+key_str+']'; - } else { - this.title = t +' ['+key_str+']'; - } - }); - }); - }, - getButtonData: function(sel) { - var b; - $.each(tool_buttons, function(i, btn) { - if(btn.sel === sel) b = btn; - }); - return b; - } - }; - }(); - - Actions.setAll(); - - // Select given tool - Editor.ready(function() { - var tool, - itool = curConfig.initTool, - container = $("#tools_left, #svg_editor .tools_flyout"), - pre_tool = container.find("#tool_" + itool), - reg_tool = container.find("#" + itool); - if(pre_tool.length) { - tool = pre_tool; - } else if(reg_tool.length){ - tool = reg_tool; - } else { - tool = $("#tool_select"); - } - tool.click().mouseup(); - - if(curConfig.wireframe) { - $('#tool_wireframe').click(); - } - - if(curConfig.showlayers) { - toggleSidePanel(); - } - - $('#rulers').toggle(!!curConfig.showRulers); - - if (curConfig.showRulers) { - $('#show_rulers')[0].checked = true; - } - - if(curConfig.gridSnapping) { - $('#grid_snapping_on')[0].checked = true; - } - - if(curConfig.baseUnit) { - $('#base_unit').val(curConfig.baseUnit); - } - - if(curConfig.snappingStep) { - $('#grid_snapping_step').val(curConfig.snappingStep); - } - }); - - $('#rect_rx').SpinButton({ min: 0, max: 1000, step: 1, callback: changeRectRadius }); - $('#stroke_width').SpinButton({ min: 0, max: 99, step: 1, smallStep: 0.1, callback: changeStrokeWidth }); - $('#angle').SpinButton({ min: -180, max: 180, step: 5, callback: changeRotationAngle }); - $('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize }); - $('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity }); - $('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur }); - $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom }) - // Set default zoom - .val(svgCanvas.getZoom() * 100); - - $("#workarea").contextMenu({ - menu: 'cmenu_canvas', - inSpeed: 0 - }, - function(action, el, pos) { - switch ( action ) { - case 'delete': - deleteSelected(); - break; - case 'cut': - cutSelected(); - break; - case 'copy': - copySelected(); - break; - case 'paste': - svgCanvas.pasteElements(); - break; - case 'paste_in_place': - svgCanvas.pasteElements('in_place'); - break; - case 'group': - svgCanvas.groupSelectedElements(); - break; - case 'ungroup': - svgCanvas.ungroupSelectedElement(); - break; - case 'move_front': - moveToTopSelected(); - break; - case 'move_up': - moveUpDownSelected('Up'); - break; - case 'move_down': - moveUpDownSelected('Down'); - break; - case 'move_back': - moveToBottomSelected(); - break; - default: - if(svgedit.contextmenu && svgedit.contextmenu.hasCustomHandler(action)){ - svgedit.contextmenu.getCustomHandler(action).call(); - } - break; - } - - if(svgCanvas.clipBoard.length) { - canv_menu.enableContextMenuItems('#paste,#paste_in_place'); - } - }); - - var lmenu_func = function(action, el, pos) { - switch ( action ) { - case 'dupe': - cloneLayer(); - break; - case 'delete': - deleteLayer(); - break; - case 'merge_down': - mergeLayer(); - break; - case 'merge_all': - svgCanvas.mergeAllLayers(); - updateContextPanel(); - populateLayers(); - break; - } - } - - $("#layerlist").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0 - }, - lmenu_func - ); - - $("#layer_moreopts").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0, - allowLeft: true - }, - lmenu_func - ); - - $('.contextMenu li').mousedown(function(ev) { - ev.preventDefault(); - }) - - $('#cmenu_canvas li').disableContextMenu(); - canv_menu.enableContextMenuItems('#delete,#cut,#copy'); - - window.onbeforeunload = function() { - // Suppress warning if page is empty - if(undoMgr.getUndoStackSize() === 0) { - Editor.show_save_warning = false; - } - - // show_save_warning is set to "false" when the page is saved. - if(!curConfig.no_save_warning && Editor.show_save_warning) { - // Browser already asks question about closing the page - return uiStrings.notification.unsavedChanges; - } - }; - - Editor.openPrep = function(func) { - $('#main_menu').hide(); - if(undoMgr.getUndoStackSize() === 0) { - func(true); - } else { - $.confirm(uiStrings.notification.QwantToOpen, func); - } - } - - // use HTML5 File API: http://www.w3.org/TR/FileAPI/ - // if browser has HTML5 File API support, then we will show the open menu item - // and provide a file input to click. When that change event fires, it will - // get the text contents of the file and send it to the canvas - if (window.FileReader) { - var inp = $('<input type="file">').change(function() { - var f = this; - Editor.openPrep(function(ok) { - if(!ok) return; - svgCanvas.clear(); - if(f.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - loadSvgString(e.target.result); - updateCanvas(); - }; - reader.readAsText(f.files[0]); - } - }); - }); - $("#tool_open").show().prepend(inp); - var inp2 = $('<input type="file">').change(function() { - $('#main_menu').hide(); - if(this.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - svgCanvas.importSvgString(e.target.result, true); - updateCanvas(); - }; - reader.readAsText(this.files[0]); - } - }); - $("#tool_import").show().prepend(inp2); - } - - var updateCanvas = Editor.updateCanvas = function(center, new_ctr) { - - var w = workarea.width(), h = workarea.height(); - var w_orig = w, h_orig = h; - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - var cnvs = $("#svgcanvas"); - - var old_ctr = { - x: w_area[0].scrollLeft + w_orig/2, - y: w_area[0].scrollTop + h_orig/2 - }; - - var multi = curConfig.canvas_expansion; - w = Math.max(w_orig, svgCanvas.contentW * zoom * multi); - h = Math.max(h_orig, svgCanvas.contentH * zoom * multi); - - if(w == w_orig && h == h_orig) { - workarea.css('overflow','hidden'); - } else { - workarea.css('overflow','scroll'); - } - - var old_can_y = cnvs.height()/2; - var old_can_x = cnvs.width()/2; - cnvs.width(w).height(h); - var new_can_y = h/2; - var new_can_x = w/2; - var offset = svgCanvas.updateCanvas(w, h); - - var ratio = new_can_x / old_can_x; - - var scroll_x = w/2 - w_orig/2; - var scroll_y = h/2 - h_orig/2; - - if(!new_ctr) { - - var old_dist_x = old_ctr.x - old_can_x; - var new_x = new_can_x + old_dist_x * ratio; - - var old_dist_y = old_ctr.y - old_can_y; - var new_y = new_can_y + old_dist_y * ratio; - - new_ctr = { - x: new_x, - y: new_y - }; - - } else { - new_ctr.x += offset.x, - new_ctr.y += offset.y; - } - - if(center) { - // Go to top-left for larger documents - if(svgCanvas.contentW > w_area.width()) { - // Top-left - workarea[0].scrollLeft = offset.x - 10; - workarea[0].scrollTop = offset.y - 10; - } else { - // Center - w_area[0].scrollLeft = scroll_x; - w_area[0].scrollTop = scroll_y; - } - } else { - w_area[0].scrollLeft = new_ctr.x - w_orig/2; - w_area[0].scrollTop = new_ctr.y - h_orig/2; - } - if(curConfig.showRulers) { - updateRulers(cnvs, zoom); - workarea.scroll(); - } - } - - // Make [1,2,5] array - var r_intervals = []; - for(var i = .1; i < 1E5; i *= 10) { - r_intervals.push(1 * i); - r_intervals.push(2 * i); - r_intervals.push(5 * i); - } - - function updateRulers(scanvas, zoom) { - var ruler_x_cursor = document.getElementById("ruler_x_cursor"); - var ruler_y_cursor = document.getElementById("ruler_y_cursor"); - var workarea = document.getElementById("workarea"); - var title_show = document.getElementById("title_show"); - var offset_x = 66; - var offset_y = 48; - $("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers", function(e){ - e.stopPropagation(); - ruler_x_cursor.style.left = (e.pageX-offset_x+workarea.scrollLeft) + "px"; - ruler_y_cursor.style.top = (e.pageY-offset_y+workarea.scrollTop) + "px"; - var title = e.target.getAttribute("title"); - if (typeof title != 'undefined' && title) title_show.innerHTML(title); - }) - if(!zoom) zoom = svgCanvas.getZoom(); - if(!scanvas) scanvas = $("#svgcanvas"); - - var limit = 30000; - - var c_elem = svgCanvas.getContentElem(); - - var units = svgedit.units.getTypeMap(); - var unit = units[curConfig.baseUnit]; // 1 = 1px - - for(var d = 0; d < 2; d++) { - var is_x = (d === 0); - var dim = is_x ? 'x' : 'y'; - var lentype = is_x?'width':'height'; - var content_d = c_elem.getAttribute(dim)-0; - - var $hcanv_orig = $('#ruler_' + dim + ' canvas:first'); - - // Bit of a hack to fully clear the canvas in Safari & IE9 - $hcanv = $hcanv_orig.clone(); - $hcanv_orig.replaceWith($hcanv); - - var hcanv = $hcanv[0]; - - // Set the canvas size to the width of the container - var ruler_len = scanvas[lentype]()*2; - var total_len = ruler_len; - hcanv.parentNode.style[lentype] = total_len + 'px'; - - var canv_count = 1; - var ctx_num = 0; - var ctx_arr; - var ctx = hcanv.getContext("2d"); - - ctx.fillStyle = "rgb(200,0,0)"; - ctx.fillRect(0,0,hcanv.width,hcanv.height); - - // Remove any existing canvasses - $hcanv.siblings().remove(); - - // Create multiple canvases when necessary (due to browser limits) - if(ruler_len >= limit) { - var num = parseInt(ruler_len / limit) + 1; - ctx_arr = Array(num); - ctx_arr[0] = ctx; - for(var i = 1; i < num; i++) { - hcanv[lentype] = limit; - var copy = hcanv.cloneNode(true); - hcanv.parentNode.appendChild(copy); - ctx_arr[i] = copy.getContext('2d'); - } - - copy[lentype] = ruler_len % limit; - - // set copy width to last - ruler_len = limit; - } - - hcanv[lentype] = ruler_len; - - var u_multi = unit * zoom; - - // Calculate the main number interval - var raw_m = 50 / u_multi; - var multi = 1; - for(var i = 0; i < r_intervals.length; i++) { - var num = r_intervals[i]; - multi = num; - if(raw_m <= num) { - break; - } - } - - var big_int = multi * u_multi; - ctx.font = "normal 9px 'Lucida Grande', sans-serif"; - ctx.fillStyle = "#777"; - - var ruler_d = ((content_d / u_multi) % multi) * u_multi; - var label_pos = ruler_d - big_int; - for (; ruler_d < total_len; ruler_d += big_int) { - label_pos += big_int; - var real_d = ruler_d - content_d; - - var cur_d = Math.round(ruler_d) + .5; - if(is_x) { - ctx.moveTo(cur_d, 15); - ctx.lineTo(cur_d, 0); - } else { - ctx.moveTo(15, cur_d); - ctx.lineTo(0, cur_d); - } - - var num = (label_pos - content_d) / u_multi; - var label; - if(multi >= 1) { - label = Math.round(num); - } else { - var decs = (multi+'').split('.')[1].length; - label = num.toFixed(decs)-0; - } - - // Do anything special for negative numbers? -// var is_neg = label < 0; -// real_d2 = Math.abs(real_d2); - - // Change 1000s to Ks - if(label !== 0 && label !== 1000 && label % 1000 === 0) { - label = (label / 1000) + 'K'; - } - - if(is_x) { - ctx.fillText(label, ruler_d+2, 8); - ctx.fillStyle = "#777"; - } else { - var str = (label+'').split(''); - for(var i = 0; i < str.length; i++) { - ctx.fillText(str[i], 1, (ruler_d+9) + i*9); - ctx.fillStyle = "#777"; - } - } - - var part = big_int / 10; - for(var i = 1; i < 10; i++) { - var sub_d = Math.round(ruler_d + part * i) + .5; - if(ctx_arr && sub_d > ruler_len) { - ctx_num++; - ctx.stroke(); - if(ctx_num >= ctx_arr.length) { - i = 10; - ruler_d = total_len; - continue; - } - ctx = ctx_arr[ctx_num]; - ruler_d -= limit; - sub_d = Math.round(ruler_d + part * i) + .5; - } - - var line_num = (i % 2)?12:10; - if(is_x) { - ctx.moveTo(sub_d, 15); - ctx.lineTo(sub_d, line_num); - } else { - ctx.moveTo(15, sub_d); - ctx.lineTo(line_num ,sub_d); - } - } - } - - // console.log('ctx', ctx); - ctx.strokeStyle = "#666"; - ctx.stroke(); - } - } - -// $(function() { - updateCanvas(true); -// }); - - // var revnums = "svg-editor.js ($Rev: 2083 $) "; - // revnums += svgCanvas.getVersion(); - // $('#copyright')[0].setAttribute("title", revnums); - - // Callback handler for embedapi.js - try{ - var json_encode = function(obj){ - //simple partial JSON encoder implementation - if(window.JSON && JSON.stringify) return JSON.stringify(obj); - var enc = arguments.callee; //for purposes of recursion - if(typeof obj == "boolean" || typeof obj == "number"){ - return obj+'' //should work... - }else if(typeof obj == "string"){ - //a large portion of this is stolen from Douglas Crockford's json2.js - return '"'+ - obj.replace( - /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g - , function (a) { - return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) - +'"'; //note that this isn't quite as purtyful as the usualness - }else if(obj.length){ //simple hackish test for arrayish-ness - for(var i = 0; i < obj.length; i++){ - obj[i] = enc(obj[i]); //encode every sub-thingy on top - } - return "["+obj.join(",")+"]"; - }else{ - var pairs = []; //pairs will be stored here - for(var k in obj){ //loop through thingys - pairs.push(enc(k)+":"+enc(obj[k])); //key: value - } - return "{"+pairs.join(",")+"}" //wrap in the braces - } - } - window.addEventListener("message", function(e){ - var cbid = parseInt(e.data.substr(0, e.data.indexOf(";"))); - try{ - e.source.postMessage("SVGe"+cbid+";"+json_encode(eval(e.data)), "*"); - }catch(err){ - e.source.postMessage("SVGe"+cbid+";error:"+err.message, "*"); - } - }, false) - }catch(err){ - window.embed_error = err; - } - - - - // For Compatibility with older extensions - $(function() { - window.svgCanvas = svgCanvas; - svgCanvas.ready = svgEditor.ready; - }); - - - Editor.setLang = function(lang, allStrings) { - $.pref('lang', lang); - $('#lang_select').val(lang); - if(allStrings) { - - var notif = allStrings.notification; - - - - // $.extend will only replace the given strings - var oldLayerName = $('#layerlist tr.layersel td.layername').text(); - var rename_layer = (oldLayerName == uiStrings.common.layer + ' 1'); - - $.extend(uiStrings, allStrings); - svgCanvas.setUiStrings(allStrings); - Actions.setTitles(); - - if(rename_layer) { - svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1'); - populateLayers(); - } - - svgCanvas.runExtensions("langChanged", lang); - - // Update flyout tooltips - setFlyoutTitles(); - - // Copy title for certain tool elements - var elems = { - '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', - '#fill_color': '#tool_fill label, #tool_fill .color_block', - '#linejoin_miter': '#cur_linejoin', - '#linecap_butt': '#cur_linecap' - } - - $.each(elems, function(source, dest) { - $(dest).attr('title', $(source)[0].title); - }); - - // Copy alignment titles - $('#multiselected_panel div[id^=tool_align]').each(function() { - $('#tool_pos' + this.id.substr(10))[0].title = this.title; - }); - - } - }; - }; - - var callbacks = []; - - function loadSvgString(str, callback) { - var success = svgCanvas.setSvgString(str) !== false; - callback = callback || $.noop; - if(success) { - callback(true); - } else { - $.alert(uiStrings.notification.errorLoadingSVG, function() { - callback(false); - }); - } - } - - Editor.ready = function(cb) { - if(!is_ready) { - callbacks.push(cb); - } else { - cb(); - } - }; - - Editor.runCallbacks = function() { - $.each(callbacks, function() { - this(); - }); - is_ready = true; - }; - - Editor.loadFromString = function(str) { - Editor.ready(function() { - loadSvgString(str); - }); - }; - - Editor.disableUI = function(featList) { -// $(function() { -// $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove(); -// $('#tools_top').css('left', 5); -// }); - }; - - Editor.loadFromURL = function(url, opts) { - if(!opts) opts = {}; - - var cache = opts.cache; - var cb = opts.callback; - - Editor.ready(function() { - $.ajax({ - 'url': url, - 'dataType': 'text', - cache: !!cache, - success: function(str) { - loadSvgString(str, cb); - }, - error: function(xhr, stat, err) { - if(xhr.status != 404 && xhr.responseText) { - loadSvgString(xhr.responseText, cb); - } else { - $.alert(uiStrings.notification.URLloadFail + ": \n"+err+'', cb); - } - } - }); - }); - }; - - Editor.loadFromDataURI = function(str) { - Editor.ready(function() { - var pre = 'data:image/svg+xml;base64,'; - var src = str.substring(pre.length); - loadSvgString(svgedit.utilities.decode64(src)); - }); - }; - - Editor.addExtension = function() { - var args = arguments; - - // Note that we don't want this on Editor.ready since some extensions - // may want to run before then (like server_opensave). - $(function() { - if(svgCanvas) svgCanvas.addExtension.apply(this, args); - }); - }; - - return Editor; - }(jQuery); - - // Run init once DOM is loaded - $(svgEditor.init); - -})(); - -// ?iconsize=s&bkgd_color=555 - -// svgEditor.setConfig({ -// // imgPath: 'foo', -// dimensions: [800, 600], -// canvas_expansion: 5, -// initStroke: { -// color: '0000FF', -// width: 3.5, -// opacity: .5 -// }, -// initFill: { -// color: '550000', -// opacity: .75 -// }, -// extensions: ['ext-helloworld.js'] -// }) diff --git a/build/svg-edit-2.6-src/editor/svg-editor.manifest b/build/svg-edit-2.6-src/editor/svg-editor.manifest deleted file mode 100644 index b156374..0000000 --- a/build/svg-edit-2.6-src/editor/svg-editor.manifest +++ /dev/null @@ -1,121 +0,0 @@ -CACHE MANIFEST -svg-editor.html -images/logo.png -jgraduate/css/jPicker-1.0.9.css -jgraduate/css/jGraduate-0.2.0.css -svg-editor.css -spinbtn/JQuerySpinBtn.css -jquery.js -js-hotkeys/jquery.hotkeys.min.js -jquery-ui/jquery-ui-1.7.2.custom.min.js -jgraduate/jpicker-1.0.9.min.js -jgraduate/jquery.jgraduate.js -spinbtn/JQuerySpinBtn.js -svgcanvas.js -svg-editor.js -images/align-bottom.png -images/align-center.png -images/align-left.png -images/align-middle.png -images/align-right.png -images/align-top.png -images/bold.png -images/cancel.png -images/circle.png -images/clear.png -images/clone.png -images/copy.png -images/cut.png -images/delete.png -images/document-properties.png -images/dropdown.gif -images/ellipse.png -images/eye.png -images/flyouth.png -images/flyup.gif -images/freehand-circle.png -images/freehand-square.png -images/go-down.png -images/go-up.png -images/image.png -images/italic.png -images/line.png -images/logo.png -images/logo.svg -images/move_bottom.png -images/move_top.png -images/none.png -images/open.png -images/paste.png -images/path.png -images/polygon.png -images/rect.png -images/redo.png -images/save.png -images/select.png -images/sep.png -images/shape_group.png -images/shape_ungroup.png -images/source.png -images/square.png -images/text.png -images/undo.png -images/view-refresh.png -images/wave.png -images/zoom.png -locale/locale.js -locale/lang.af.js -locale/lang.ar.js -locale/lang.az.js -locale/lang.be.js -locale/lang.bg.js -locale/lang.ca.js -locale/lang.cs.js -locale/lang.cy.js -locale/lang.da.js -locale/lang.de.js -locale/lang.el.js -locale/lang.en.js -locale/lang.es.js -locale/lang.et.js -locale/lang.fa.js -locale/lang.fi.js -locale/lang.fr.js -locale/lang.ga.js -locale/lang.gl.js -locale/lang.hi.js -locale/lang.hr.js -locale/lang.hu.js -locale/lang.hy.js -locale/lang.id.js -locale/lang.is.js -locale/lang.it.js -locale/lang.iw.js -locale/lang.ja.js -locale/lang.ko.js -locale/lang.lt.js -locale/lang.lv.js -locale/lang.mk.js -locale/lang.ms.js -locale/lang.mt.js -locale/lang.nl.js -locale/lang.no.js -locale/lang.pl.js -locale/lang.pt-PT.js -locale/lang.ro.js -locale/lang.ru.js -locale/lang.sk.js -locale/lang.sl.js -locale/lang.sq.js -locale/lang.sr.js -locale/lang.sv.js -locale/lang.sw.js -locale/lang.th.js -locale/lang.tl.js -locale/lang.tr.js -locale/lang.uk.js -locale/lang.vi.js -locale/lang.yi.js -locale/lang.zh-CN.js -locale/lang.zh-TW.js -locale/lang.zh.js diff --git a/build/svg-edit-2.6-src/editor/svgcanvas.js b/build/svg-edit-2.6-src/editor/svgcanvas.js deleted file mode 100644 index faafdae..0000000 --- a/build/svg-edit-2.6-src/editor/svgcanvas.js +++ /dev/null @@ -1,8818 +0,0 @@ -/* - * svgcanvas.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js -// 4) math.js -// 5) units.js -// 6) svgutils.js -// 7) sanitize.js -// 8) history.js -// 9) select.js -// 10) draw.js -// 11) path.js - -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(window.opera) { - window.console.log = function(str) { opera.postError(str); }; - window.console.dir = function(str) {}; -} - -(function() { - - // This fixes $(...).attr() to work as expected with SVG elements. - // Does not currently use *AttributeNS() since we rarely need that. - - // See http://api.jquery.com/attr/ for basic documentation of .attr() - - // Additional functionality: - // - When getting attributes, a string that's a number is return as type number. - // - If an array is supplied as first parameter, multiple values are returned - // as an object with values for each given attributes - - var proxied = jQuery.fn.attr, svgns = "http://www.w3.org/2000/svg"; - jQuery.fn.attr = function(key, value) { - var len = this.length; - if(!len) return proxied.apply(this, arguments); - for(var i=0; i<len; i++) { - var elem = this[i]; - // set/get SVG attribute - if(elem.namespaceURI === svgns) { - // Setting attribute - if(value !== undefined) { - elem.setAttribute(key, value); - } else if($.isArray(key)) { - // Getting attributes from array - var j = key.length, obj = {}; - - while(j--) { - var aname = key[j]; - var attr = elem.getAttribute(aname); - // This returns a number when appropriate - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - obj[aname] = attr; - } - return obj; - - } else if(typeof key === "object") { - // Setting attributes form object - for(var v in key) { - elem.setAttribute(v, key[v]); - } - // Getting attribute - } else { - var attr = elem.getAttribute(key); - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - - return attr; - } - } else { - return proxied.apply(this, arguments); - } - } - return this; - }; - -}()); - -// Class: SvgCanvas -// The main SvgCanvas class that manages all SVG-related functions -// -// Parameters: -// container - The container HTML element that should hold the SVG root element -// config - An object that contains configuration data -$.SvgCanvas = function(container, config) -{ -// Namespace constants -var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - xmlns = "http://www.w3.org/XML/1998/namespace", - xmlnsns = "http://www.w3.org/2000/xmlns/", // see http://www.w3.org/TR/REC-xml-names/#xmlReserved - se_ns = "http://svg-edit.googlecode.com", - htmlns = "http://www.w3.org/1999/xhtml", - mathns = "http://www.w3.org/1998/Math/MathML"; - -// Default configuration options -var curConfig = { - show_outside_canvas: true, - selectNew: true, - dimensions: [640, 480] -}; - -// Update config with new one if given -if(config) { - $.extend(curConfig, config); -} - -// Array with width/height of canvas -var dimensions = curConfig.dimensions; - -var canvas = this; - -// "document" element associated with the container (same as window.document using default svg-editor.js) -// NOTE: This is not actually a SVG document, but a HTML document. -var svgdoc = container.ownerDocument; - -// This is a container for the document being edited, not the document itself. -var svgroot = svgdoc.importNode(svgedit.utilities.text2xml( - '<svg id="svgroot" xmlns="' + svgns + '" xlinkns="' + xlinkns + '" ' + - 'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' + - '<defs>' + - '<filter id="canvashadow" filterUnits="objectBoundingBox">' + - '<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>'+ - '<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>'+ - '<feMerge>'+ - '<feMergeNode in="offsetBlur"/>'+ - '<feMergeNode in="SourceGraphic"/>'+ - '</feMerge>'+ - '</filter>'+ - '</defs>'+ - '</svg>').documentElement, true); -container.appendChild(svgroot); - -// The actual element that represents the final output SVG element -var svgcontent = svgdoc.createElementNS(svgns, "svg"); - -// This function resets the svgcontent element while keeping it in the DOM. -var clearSvgContentElement = canvas.clearSvgContentElement = function() { - while (svgcontent.firstChild) { svgcontent.removeChild(svgcontent.firstChild); } - - // TODO: Clear out all other attributes first? - $(svgcontent).attr({ - id: 'svgcontent', - width: dimensions[0], - height: dimensions[1], - x: dimensions[0], - y: dimensions[1], - overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden', - xmlns: svgns, - "xmlns:se": se_ns, - "xmlns:xlink": xlinkns - }).appendTo(svgroot); - - // TODO: make this string optional and set by the client - var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ "); - svgcontent.appendChild(comment); -}; -clearSvgContentElement(); - -// Prefix string for element IDs -var idprefix = "svg_"; - -// Function: setIdPrefix -// Changes the ID prefix to the given value -// -// Parameters: -// p - String with the new prefix -canvas.setIdPrefix = function(p) { - idprefix = p; -}; - -// Current svgedit.draw.Drawing object -// @type {svgedit.draw.Drawing} -canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - -// Function: getCurrentDrawing -// Returns the current Drawing. -// @return {svgedit.draw.Drawing} -var getCurrentDrawing = canvas.getCurrentDrawing = function() { - return canvas.current_drawing_; -}; - -// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc) -var current_zoom = 1; - -// pointer to current group (for in-group editing) -var current_group = null; - -// Object containing data for the currently selected styles -var all_properties = { - shape: { - fill: (curConfig.initFill.color == 'none' ? '' : '#') + curConfig.initFill.color, - fill_paint: null, - fill_opacity: curConfig.initFill.opacity, - stroke: "#" + curConfig.initStroke.color, - stroke_paint: null, - stroke_opacity: curConfig.initStroke.opacity, - stroke_width: curConfig.initStroke.width, - stroke_dasharray: 'none', - stroke_linejoin: 'miter', - stroke_linecap: 'butt', - opacity: curConfig.initOpacity - } -}; - -all_properties.text = $.extend(true, {}, all_properties.shape); -$.extend(all_properties.text, { - fill: "#000000", - stroke_width: 0, - font_size: 24, - font_family: 'Junction' -}); - -// Current shape style properties -var cur_shape = all_properties.shape; - -// Array with all the currently selected elements -// default size of 1 until it needs to grow bigger -var selectedElements = new Array(1); - -// Function: addSvgElementFromJson -// Create a new SVG element based on the given object keys/values and add it to the current layer -// The element will be ran through cleanupElement before being returned -// -// Parameters: -// data - Object with the following keys/values: -// * element - tag name of the SVG element to create -// * attr - Object with attributes key-values to assign to the new element -// * curStyles - Boolean indicating that current style attributes should be applied first -// -// Returns: The new element -var addSvgElementFromJson = this.addSvgElementFromJson = function(data) { - var shape = svgedit.utilities.getElem(data.attr.id); - // if shape is a path but we need to create a rect/ellipse, then remove the path - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (shape && data.element != shape.tagName) { - current_layer.removeChild(shape); - shape = null; - } - if (!shape) { - shape = svgdoc.createElementNS(svgns, data.element); - if (current_layer) { - (current_group || current_layer).appendChild(shape); - } - } - if(data.curStyles) { - svgedit.utilities.assignAttributes(shape, { - "fill": cur_shape.fill, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - }, 100); - } - svgedit.utilities.assignAttributes(shape, data.attr, 100); - svgedit.utilities.cleanupElement(shape); - return shape; -}; - - -// import svgtransformlist.js -var getTransformList = canvas.getTransformList = svgedit.transformlist.getTransformList; - -// import from math.js. -var transformPoint = svgedit.math.transformPoint; -var matrixMultiply = canvas.matrixMultiply = svgedit.math.matrixMultiply; -var hasMatrixTransform = canvas.hasMatrixTransform = svgedit.math.hasMatrixTransform; -var transformListToTransform = canvas.transformListToTransform = svgedit.math.transformListToTransform; -var snapToAngle = svgedit.math.snapToAngle; -var getMatrix = svgedit.math.getMatrix; - -// initialize from units.js -// send in an object implementing the ElementContainer interface (see units.js) -svgedit.units.init({ - getBaseUnit: function() { return curConfig.baseUnit; }, - getElement: svgedit.utilities.getElem, - getHeight: function() { return svgcontent.getAttribute("height")/current_zoom; }, - getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; }, - getRoundDigits: function() { return save_options.round_digits; } -}); -// import from units.js -var convertToNum = canvas.convertToNum = svgedit.units.convertToNum; - -// import from svgutils.js -svgedit.utilities.init({ - getDOMDocument: function() { return svgdoc; }, - getDOMContainer: function() { return container; }, - getSVGRoot: function() { return svgroot; }, - // TODO: replace this mostly with a way to get the current drawing. - getSelectedElements: function() { return selectedElements; }, - getSVGContent: function() { return svgcontent; } -}); -var getUrlFromAttr = canvas.getUrlFromAttr = svgedit.utilities.getUrlFromAttr; -var getHref = canvas.getHref = svgedit.utilities.getHref; -var setHref = canvas.setHref = svgedit.utilities.setHref; -var getPathBBox = svgedit.utilities.getPathBBox; -var getBBox = canvas.getBBox = svgedit.utilities.getBBox; -var getRotationAngle = canvas.getRotationAngle = svgedit.utilities.getRotationAngle; -var getElem = canvas.getElem = svgedit.utilities.getElem; -var assignAttributes = canvas.assignAttributes = svgedit.utilities.assignAttributes; -var cleanupElement = this.cleanupElement = svgedit.utilities.cleanupElement; - -// import from sanitize.js -var nsMap = svgedit.sanitize.getNSMap(); -var sanitizeSvg = canvas.sanitizeSvg = svgedit.sanitize.sanitizeSvg; - -// import from history.js -var MoveElementCommand = svgedit.history.MoveElementCommand; -var InsertElementCommand = svgedit.history.InsertElementCommand; -var RemoveElementCommand = svgedit.history.RemoveElementCommand; -var ChangeElementCommand = svgedit.history.ChangeElementCommand; -var BatchCommand = svgedit.history.BatchCommand; -// Implement the svgedit.history.HistoryEventHandler interface. -canvas.undoMgr = new svgedit.history.UndoManager({ - handleHistoryEvent: function(eventType, cmd) { - var EventTypes = svgedit.history.HistoryEventTypes; - // TODO: handle setBlurOffsets. - if (eventType == EventTypes.BEFORE_UNAPPLY || eventType == EventTypes.BEFORE_APPLY) { - canvas.clearSelection(); - } else if (eventType == EventTypes.AFTER_APPLY || eventType == EventTypes.AFTER_UNAPPLY) { - var elems = cmd.elements(); - canvas.pathActions.clear(); - call("changed", elems); - - var cmdType = cmd.type(); - var isApply = (eventType == EventTypes.AFTER_APPLY); - if (cmdType == MoveElementCommand.type()) { - var parent = isApply ? cmd.newParent : cmd.oldParent; - if (parent == svgcontent) { - canvas.identifyLayers(); - } - } else if (cmdType == InsertElementCommand.type() || - cmdType == RemoveElementCommand.type()) { - if (cmd.parent == svgcontent) { - canvas.identifyLayers(); - } - if (cmdType == InsertElementCommand.type()) { - if (isApply) restoreRefElems(cmd.elem); - } else { - if (!isApply) restoreRefElems(cmd.elem); - } - - if(cmd.elem.tagName === 'use') { - setUseData(cmd.elem); - } - } else if (cmdType == ChangeElementCommand.type()) { - // if we are changing layer names, re-identify all layers - if (cmd.elem.tagName == "title" && cmd.elem.parentNode.parentNode == svgcontent) { - canvas.identifyLayers(); - } - var values = isApply ? cmd.newValues : cmd.oldValues; - // If stdDeviation was changed, update the blur. - if (values["stdDeviation"]) { - canvas.setBlurOffsets(cmd.elem.parentNode, values["stdDeviation"]); - } - - // Remove & Re-add hack for Webkit (issue 775) - if(cmd.elem.tagName === 'use' && svgedit.browser.isWebkit()) { - var elem = cmd.elem; - if(!elem.getAttribute('x') && !elem.getAttribute('y')) { - var parent = elem.parentNode; - var sib = elem.nextSibling; - parent.removeChild(elem); - parent.insertBefore(elem, sib); - } - } - } - } - } -}); -var addCommandToHistory = function(cmd) { - canvas.undoMgr.addCommandToHistory(cmd); -}; - -// import from select.js -svgedit.select.init(curConfig, { - createSVGElement: function(jsonMap) { return canvas.addSvgElementFromJson(jsonMap); }, - svgRoot: function() { return svgroot; }, - svgContent: function() { return svgcontent; }, - currentZoom: function() { return current_zoom; }, - // TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js. - getStrokedBBox: function(elems) { return canvas.getStrokedBBox([elems]); } -}); -// this object manages selectors for us -var selectorManager = this.selectorManager = svgedit.select.getSelectorManager(); - -// Import from path.js -svgedit.path.init({ - getCurrentZoom: function() { return current_zoom; }, - getSVGRoot: function() { return svgroot; } -}); - -// Function: snapToGrid -// round value to for snapping -// NOTE: This function did not move to svgutils.js since it depends on curConfig. -svgedit.utilities.snapToGrid = function(value){ - var stepSize = curConfig.snappingStep; - var unit = curConfig.baseUnit; - if(unit !== "px") { - stepSize *= svgedit.units.getTypeMap()[unit]; - } - value = Math.round(value/stepSize)*stepSize; - return value; -}; -var snapToGrid = svgedit.utilities.snapToGrid; - -// Interface strings, usually for title elements -var uiStrings = { - "exportNoBlur": "Blurred elements will appear as un-blurred", - "exportNoforeignObject": "foreignObject elements will not appear", - "exportNoDashArray": "Strokes will appear filled", - "exportNoText": "Text may not appear as expected" -}; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var ref_attrs = ["clip-path", "fill", "filter", "marker-end", "marker-mid", "marker-start", "mask", "stroke"]; - -var elData = $.data; - -// Animation element to change the opacity of any newly created element -var opac_ani = false; //document.createElementNS(svgns, 'animate'); -//$(opac_ani).attr({ -// attributeName: 'opacity', -// begin: 'indefinite', -// dur: 0, -// fill: 'freeze' -//}).appendTo(svgroot); - -var restoreRefElems = function(elem) { - // Look for missing reference elements, restore any found - var attrs = $(elem).attr(ref_attrs); - for(var o in attrs) { - var val = attrs[o]; - if (val && val.indexOf('url(') === 0) { - var id = getUrlFromAttr(val).substr(1); - var ref = getElem(id); - if(!ref) { - findDefs().appendChild(removedElements[id]); - delete removedElements[id]; - } - } - } - - var childs = elem.getElementsByTagName('*'); - - if(childs.length) { - for(var i = 0, l = childs.length; i < l; i++) { - restoreRefElems(childs[i]); - } - } -}; - -(function() { - // TODO For Issue 208: this is a start on a thumbnail - // var svgthumb = svgdoc.createElementNS(svgns, "use"); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // svgedit.utilities.setHref(svgthumb, '#svgcontent'); - // svgroot.appendChild(svgthumb); - -})(); - -// Object to contain image data for raster images that were found encodable -var encodableImages = {}, - - // String with image URL of last loadable image - last_good_img_url = curConfig.imgPath + 'logo.png', - - // Array with current disabled elements (for in-group editing) - disabled_elems = [], - - // Object with save options - save_options = {round_digits: 5}, - - // Boolean indicating whether or not a draw action has been started - started = false, - - // String with an element's initial transform attribute value - start_transform = null, - - // String indicating the current editor mode - current_mode = "select", - - // String with the current direction in which an element is being resized - current_resize_mode = "none", - - // Object with IDs for imported files, to see if one was already added - import_ids = {}; - -// Current text style properties -var cur_text = all_properties.text, - - // Current general properties - cur_properties = cur_shape, - - // Array with selected elements' Bounding box object -// selectedBBoxes = new Array(1), - - // The DOM element that was just selected - justSelected = null, - - // DOM element for selection rectangle drawn by the user - rubberBox = null, - - // Array of current BBoxes (still needed?) - curBBoxes = [], - - // Object to contain all included extensions - extensions = {}, - - // Canvas point for the most recent right click - lastClickPoint = null, - - // Map of deleted reference elements - removedElements = {} - -// Clipboard for cut, copy&pasted elements -canvas.clipBoard = []; - -// Should this return an array by default, so extension results aren't overwritten? -var runExtensions = this.runExtensions = function(action, vars, returnArray) { - var result = false; - if(returnArray) result = []; - $.each(extensions, function(name, opts) { - if(action in opts) { - if(returnArray) { - result.push(opts[action](vars)) - } else { - result = opts[action](vars); - } - } - }); - return result; -} - -// Function: addExtension -// Add an extension to the editor -// -// Parameters: -// name - String with the ID of the extension -// ext_func - Function supplied by the extension with its data -this.addExtension = function(name, ext_func) { - if(!(name in extensions)) { - // Provide private vars/funcs here. Is there a better way to do this? - - if($.isFunction(ext_func)) { - var ext = ext_func($.extend(canvas.getPrivateMethods(), { - svgroot: svgroot, - svgcontent: svgcontent, - nonce: getCurrentDrawing().getNonce(), - selectorManager: selectorManager - })); - } else { - var ext = ext_func; - } - extensions[name] = ext; - call("extension_added", ext); - } else { - console.log('Cannot add extension "' + name + '", an extension by that name already exists"'); - } -}; - -// This method rounds the incoming value to the nearest value based on the current_zoom -var round = this.round = function(val) { - return parseInt(val*current_zoom)/current_zoom; -}; - -// This method sends back an array or a NodeList full of elements that -// intersect the multi-select rubber-band-box on the current_layer only. -// -// Since the only browser that supports the SVG DOM getIntersectionList is Opera, -// we need to provide an implementation here. We brute-force it for now. -// -// Reference: -// Firefox does not implement getIntersectionList(), see https://bugzilla.mozilla.org/show_bug.cgi?id=501421 -// Webkit does not implement getIntersectionList(), see https://bugs.webkit.org/show_bug.cgi?id=11274 -var getIntersectionList = this.getIntersectionList = function(rect) { - if (rubberBox == null) { return null; } - - var parent = current_group || getCurrentDrawing().getCurrentLayer(); - - if(!curBBoxes.length) { - // Cache all bboxes - curBBoxes = getVisibleElementsAndBBoxes(parent); - } - - var resultList = null; - try { - resultList = parent.getIntersectionList(rect, null); - } catch(e) { } - - if (resultList == null || typeof(resultList.item) != "function") { - resultList = []; - - if(!rect) { - var rubberBBox = rubberBox.getBBox(); - var bb = {}; - - for(var o in rubberBBox) { - bb[o] = rubberBBox[o] / current_zoom; - } - rubberBBox = bb; - - } else { - var rubberBBox = rect; - } - var i = curBBoxes.length; - while (i--) { - if(!rubberBBox.width || !rubberBBox.width) continue; - if (svgedit.math.rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); - } - } - } - // addToSelection expects an array, but it's ok to pass a NodeList - // because using square-bracket notation is allowed: - // http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html - return resultList; -}; - -// TODO(codedread): Migrate this into svgutils.js -// Function: getStrokedBBox -// Get the bounding box for one or more stroked and/or transformed elements -// -// Parameters: -// elems - Array with DOM elements to check -// -// Returns: -// A single bounding box object -getStrokedBBox = this.getStrokedBBox = function(elems) { - if(!elems) elems = getVisibleElements(); - if(!elems.length) return false; - // Make sure the expected BBox is returned if the element is a group - 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 - // in Issue 339 comment #2). - - var bb = svgedit.utilities.getBBox(elem); - - var angle = svgedit.utilities.getRotationAngle(elem); - if ((angle && angle % 90) || - svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(elem))) { - // Accurate way to get BBox of rotated element in Firefox: - // Put element in group and get its BBox - - var good_bb = false; - - // Get the BBox from the raw path for these elements - var elemNames = ['ellipse','path','line','polyline','polygon']; - if(elemNames.indexOf(elem.tagName) >= 0) { - bb = good_bb = canvas.convertToPath(elem, true); - } else if(elem.tagName == 'rect') { - // Look for radius - var rx = elem.getAttribute('rx'); - var ry = elem.getAttribute('ry'); - if(rx || ry) { - bb = good_bb = canvas.convertToPath(elem, true); - } - } - - if(!good_bb) { - // Must use clone else FF freaks out - var clone = elem.cloneNode(true); - var g = document.createElementNS(svgns, "g"); - var parent = elem.parentNode; - parent.appendChild(g); - g.appendChild(clone); - bb = svgedit.utilities.bboxToObj(g.getBBox()); - parent.removeChild(g); - } - - - // Old method: Works by giving the rotated BBox, - // this is (unfortunately) what Opera and Safari do - // natively when getting the BBox of the parent group -// var angle = angle * Math.PI / 180.0; -// var rminx = Number.MAX_VALUE, rminy = Number.MAX_VALUE, -// rmaxx = Number.MIN_VALUE, rmaxy = Number.MIN_VALUE; -// var cx = round(bb.x + bb.width/2), -// cy = round(bb.y + bb.height/2); -// var pts = [ [bb.x - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y + bb.height - cy], -// [bb.x - cx, bb.y + bb.height - cy] ]; -// var j = 4; -// while (j--) { -// var x = pts[j][0], -// y = pts[j][1], -// r = Math.sqrt( x*x + y*y ); -// var theta = Math.atan2(y,x) + angle; -// x = round(r * Math.cos(theta) + cx); -// y = round(r * Math.sin(theta) + cy); -// -// // now set the bbox for the shape after it's been rotated -// if (x < rminx) rminx = x; -// if (y < rminy) rminy = y; -// if (x > rmaxx) rmaxx = x; -// if (y > rmaxy) rmaxy = y; -// } -// -// bb.x = rminx; -// bb.y = rminy; -// bb.width = rmaxx - rminx; -// bb.height = rmaxy - rminy; - } - return bb; - } catch(e) { - console.log(elem, e); - return null; - } - }; - - var full_bb; - $.each(elems, function() { - if(full_bb) return; - if(!this.parentNode) return; - full_bb = getCheckedBBox(this); - }); - - // This shouldn't ever happen... - if(full_bb == null) return null; - - // full_bb doesn't include the stoke, so this does no good! -// if(elems.length == 1) return full_bb; - - var max_x = full_bb.x + full_bb.width; - var max_y = full_bb.y + full_bb.height; - var min_x = full_bb.x; - var min_y = full_bb.y; - - // FIXME: same re-creation problem with this function as getCheckedBBox() above - var getOffset = function(elem) { - var sw = elem.getAttribute("stroke-width"); - var offset = 0; - if (elem.getAttribute("stroke") != "none" && !isNaN(sw)) { - offset += sw/2; - } - return offset; - } - var bboxes = []; - $.each(elems, function(i, elem) { - var cur_bb = getCheckedBBox(elem); - if(cur_bb) { - var offset = getOffset(elem); - min_x = Math.min(min_x, cur_bb.x - offset); - min_y = Math.min(min_y, cur_bb.y - offset); - bboxes.push(cur_bb); - } - }); - - full_bb.x = min_x; - full_bb.y = min_y; - - $.each(elems, function(i, elem) { - var cur_bb = bboxes[i]; - // ensure that elem is really an element node - if (cur_bb && elem.nodeType == 1) { - var offset = getOffset(elem); - max_x = Math.max(max_x, cur_bb.x + cur_bb.width + offset); - max_y = Math.max(max_y, cur_bb.y + cur_bb.height + offset); - } - }); - - full_bb.width = max_x - min_x; - full_bb.height = max_y - min_y; - return full_bb; -} - -// Function: getVisibleElements -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with all "visible" elements. -var getVisibleElements = this.getVisibleElements = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push(elem); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: getVisibleElementsAndBBoxes -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with objects that include: -// * elem - The element -// * bbox - The element's BBox as retrieved from getStrokedBBox -var getVisibleElementsAndBBoxes = this.getVisibleElementsAndBBoxes = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push({'elem':elem, 'bbox':getStrokedBBox([elem])}); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: groupSvgElem -// Wrap an SVG element into a group element, mark the group as 'gsvg' -// -// Parameters: -// elem - SVG element to wrap -var groupSvgElem = this.groupSvgElem = function(elem) { - var g = document.createElementNS(svgns, "g"); - elem.parentNode.replaceChild(g, elem); - $(g).append(elem).data('gsvg', elem)[0].id = getNextId(); -} - -// Function: copyElem -// Create a clone of an element, updating its ID and its children's IDs when needed -// -// Parameters: -// el - DOM element to clone -// -// Returns: The cloned element -var copyElem = function(el) { - var new_el = document.createElementNS(el.namespaceURI, el.nodeName); - // set the copied element's new id - new_el.removeAttribute("id"); - // manually create a copy of the element - $.each(el.attributes, function(i, attr) { - if (attr.localName != '-moz-math-font-style') { - new_el.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.nodeValue); - } - }); - - // Opera's "d" value needs to be reset for Opera/Win/non-EN - // Also needed for webkit (else does not keep curved segments on clone) - if(svgedit.browser.isWebkit() && el.nodeName == 'path') { - var fixed_d = pathActions.convertPath(el); - new_el.setAttribute('d', fixed_d); - } - - // now create copies of all children - $.each(el.childNodes, function(i, child) { - switch(child.nodeType) { - case 1: // element node - new_el.appendChild(copyElem(child)); - break; - case 3: // text node - new_el.textContent = child.nodeValue; - break; - default: - break; - } - }); - - if($(el).data('gsvg')) { - $(new_el).data('gsvg', new_el.firstChild); - } 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); - } - new_el.id = getNextId(); - console.log(new_el); - return new_el; -}; - -// Set scope for these functions -var getId, getNextId, call; - -(function(c) { - - // Object to contain editor event names and callback functions - var events = {}; - - getId = c.getId = function() { return getCurrentDrawing().getId(); }; - getNextId = c.getNextId = function() { return getCurrentDrawing().getNextId(); }; - - // Function: call - // Run the callback function associated with the given event - // - // Parameters: - // event - String with the event name - // arg - Argument to pass through to the callback function - call = c.call = function(event, arg) { - if (events[event]) { - return events[event](this, arg); - } - }; - - // Function: bind - // Attaches a callback function to an event - // - // Parameters: - // event - String indicating the name of the event - // f - The callback function to bind to the event - // - // Return: - // The previous event - c.bind = function(event, f) { - var old = events[event]; - events[event] = f; - return old; - }; - -}(canvas)); - -// Function: canvas.prepareSvg -// Runs the SVG Document through the sanitizer and then updates its paths. -// -// Parameters: -// newDoc - The SVG DOM document -this.prepareSvg = function(newDoc) { - this.sanitizeSvg(newDoc.documentElement); - - // convert paths into absolute commands - var paths = newDoc.getElementsByTagNameNS(svgns, "path"); - for (var i = 0, len = paths.length; i < len; ++i) { - var path = paths[i]; - path.setAttribute('d', pathActions.convertPath(path)); - pathActions.fixEnd(path); - } -}; - -// Function getRefElem -// Get the reference element associated with the given attribute value -// -// Parameters: -// attrVal - The attribute value as a string -var getRefElem = this.getRefElem = function(attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); -} - -// Function: ffClone -// Hack for Firefox bugs where text element features aren't updated or get -// messed up. See issue 136 and issue 137. -// This function clones the element and re-selects it -// TODO: Test for this bug on load and add it to "support" object instead of -// browser sniffing -// -// Parameters: -// elem - The (text) DOM element to clone -var ffClone = function(elem) { - if(!svgedit.browser.isGecko()) return elem; - var clone = elem.cloneNode(true) - elem.parentNode.insertBefore(clone, elem); - elem.parentNode.removeChild(elem); - selectorManager.releaseSelector(elem); - selectedElements[0] = clone; - selectorManager.requestSelector(clone).showGrips(true); - return clone; -} - - -// this.each is deprecated, if any extension used this it can be recreated by doing this: -// $(canvas.getRootElem()).children().each(...) - -// this.each = function(cb) { -// $(svgroot).children().each(cb); -// }; - - -// Function: setRotationAngle -// Removes any old rotations if present, prepends a new rotation at the -// transformed center -// -// Parameters: -// val - The new rotation angle in degrees -// preventUndo - Boolean indicating whether the action should be undoable or not -this.setRotationAngle = function(val, preventUndo) { - // ensure val is the proper type - val = parseFloat(val); - var elem = selectedElements[0]; - var oldTransform = elem.getAttribute("transform"); - var bbox = svgedit.utilities.getBBox(elem); - var cx = bbox.x+bbox.width/2, cy = bbox.y+bbox.height/2; - var tlist = getTransformList(elem); - - // only remove the real rotational transform if present (i.e. at index=0) - if (tlist.numberOfItems > 0) { - var xform = tlist.getItem(0); - if (xform.type == 4) { - tlist.removeItem(0); - } - } - // find R_nc and insert it - if (val != 0) { - var center = transformPoint(cx,cy,transformListToTransform(tlist).matrix); - var R_nc = svgroot.createSVGTransform(); - R_nc.setRotate(val, center.x, center.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(R_nc, 0); - } else { - tlist.appendItem(R_nc); - } - } - else if (tlist.numberOfItems == 0) { - elem.removeAttribute("transform"); - } - - if (!preventUndo) { - // we need to undo it, then redo it so it can be undo-able! :) - // TODO: figure out how to make changes to transform list undo-able cross-browser? - var newTransform = elem.getAttribute("transform"); - elem.setAttribute("transform", oldTransform); - changeSelectedAttribute("transform",newTransform,selectedElements); - call("changed", selectedElements); - } - var pointGripContainer = getElem("pathpointgrip_container"); -// if(elem.nodeName == "path" && pointGripContainer) { -// pathActions.setPointContainerTransform(elem.getAttribute("transform")); -// } - var selector = selectorManager.requestSelector(selectedElements[0]); - selector.resize(); - selector.updateGripCursors(val); -}; - -// Function: recalculateAllSelectedDimensions -// Runs recalculateDimensions on the selected elements, -// adding the changes to a single batch command -var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function() { - var text = (current_resize_mode == "none" ? "position" : "size"); - var batchCmd = new BatchCommand(text); - - var i = selectedElements.length; - while(i--) { - var elem = selectedElements[i]; -// if(getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) continue; - var cmd = recalculateDimensions(elem); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - } - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - call("changed", selectedElements); - } -}; - -// this is how we map paths to our preferred relative segment types -var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', - 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; - -// Debug tool to easily see the current matrix in the browser's console -var logMatrix = function(m) { - console.log([m.a,m.b,m.c,m.d,m.e,m.f]); -}; - -// Function: remapElement -// Applies coordinate changes to an element based on the given matrix -// -// Parameters: -// selected - DOM element to be changed -// changes - Object with changes to be remapped -// m - Matrix object to use for remapping coordinates -var remapElement = this.remapElement = function(selected,changes,m) { - - var remap = function(x,y) { return transformPoint(x,y,m); }, - scalew = function(w) { return m.a*w; }, - scaleh = function(h) { return m.d*h; }, - doSnapping = curConfig.gridSnapping && selected.parentNode.parentNode.localName === "svg", - finishUp = function() { - if(doSnapping) for(var o in changes) changes[o] = snapToGrid(changes[o]); - assignAttributes(selected, changes, 1000, true); - } - box = svgedit.utilities.getBBox(selected); - - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = selected.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - if(m.a < 0 || m.d < 0) { - var grad = getRefElem(attrVal); - var newgrad = grad.cloneNode(true); - - if(m.a < 0) { - //flip x - var x1 = newgrad.getAttribute('x1'); - var x2 = newgrad.getAttribute('x2'); - newgrad.setAttribute('x1', -(x1 - 1)); - newgrad.setAttribute('x2', -(x2 - 1)); - } - - if(m.d < 0) { - //flip y - var y1 = newgrad.getAttribute('y1'); - var y2 = newgrad.getAttribute('y2'); - newgrad.setAttribute('y1', -(y1 - 1)); - newgrad.setAttribute('y2', -(y2 - 1)); - } - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - selected.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - - // Not really working :( -// if(selected.tagName === 'path') { -// reorientGrads(selected, m); -// } - } - } - - - var elName = selected.tagName; - if(elName === "g" || elName === "text" || elName === "use") { - // if it was a translate, then just update x,y - if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && - (m.e != 0 || m.f != 0) ) - { - // [T][M] = [M][T'] - // therefore [T'] = [M_inv][T][M] - var existing = transformListToTransform(selected).matrix, - t_new = matrixMultiply(existing.inverse(), m, existing); - changes.x = parseFloat(changes.x) + t_new.e; - changes.y = parseFloat(changes.y) + t_new.f; - } - else { - // we just absorb all matrices into the element and don't do any remapping - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } - } - - // now we have a set of changes and an applied reduced transform list - // we apply the changes directly to the DOM - switch (elName) - { - case "foreignObject": - case "rect": - case "image": - - // Allow images to be inverted (give them matrix when flipped) - if(elName === 'image' && (m.a < 0 || m.d < 0)) { - // Convert to matrix - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } else { - var pt1 = remap(changes.x,changes.y); - - changes.width = scalew(changes.width); - changes.height = scaleh(changes.height); - - changes.x = pt1.x + Math.min(0,changes.width); - changes.y = pt1.y + Math.min(0,changes.height); - changes.width = Math.abs(changes.width); - changes.height = Math.abs(changes.height); - } - finishUp(); - break; - case "ellipse": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - changes.rx = scalew(changes.rx); - changes.ry = scaleh(changes.ry); - - changes.rx = Math.abs(changes.rx); - changes.ry = Math.abs(changes.ry); - finishUp(); - break; - case "circle": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - // take the minimum of the new selected box's dimensions for the new circle radius - var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m); - var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y; - changes.r = Math.min(w/2, h/2); - - if(changes.r) changes.r = Math.abs(changes.r); - finishUp(); - break; - case "line": - var pt1 = remap(changes.x1,changes.y1), - pt2 = remap(changes.x2,changes.y2); - changes.x1 = pt1.x; - changes.y1 = pt1.y; - changes.x2 = pt2.x; - changes.y2 = pt2.y; - - case "text": - var tspan = selected.querySelectorAll('tspan'); - var i = tspan.length - while(i--) { - var selX = convertToNum("x", selected.getAttribute('x')); - var tx = convertToNum("x", tspan[i].getAttribute('x')); - var selY = convertToNum("y", selected.getAttribute('y')); - var ty = convertToNum("y", tspan[i].getAttribute('y')); - var offset = new Object(); - if (!isNaN(selX) && !isNaN(tx) && selX!=0 && tx!=0 && changes.x) - offset.x = changes.x - (selX - tx); - if (!isNaN(selY) && !isNaN(ty) && selY!=0 && ty!=0 && changes.y) - offset.y = changes.y - (selY - ty); - if (offset.x || offset.y) - assignAttributes(tspan[i], offset, 1000, true); - } - finishUp(); - break; - case "use": - finishUp(); - break; - case "g": - var gsvg = $(selected).data('gsvg'); - if(gsvg) { - assignAttributes(gsvg, changes, 1000, true); - } - break; - case "polyline": - case "polygon": - var len = changes.points.length; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pt = remap(pt.x,pt.y); - changes.points[i].x = pt.x; - changes.points[i].y = pt.y; - } - - var len = changes.points.length; - var pstr = ""; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pstr += pt.x + "," + pt.y + " "; - } - selected.setAttribute("points", pstr); - break; - case "path": - - var segList = selected.pathSegList; - var len = segList.numberOfItems; - changes.d = new Array(len); - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - changes.d[i] = { - type: seg.pathSegType, - x: seg.x, - y: seg.y, - x1: seg.x1, - y1: seg.y1, - x2: seg.x2, - y2: seg.y2, - r1: seg.r1, - r2: seg.r2, - angle: seg.angle, - largeArcFlag: seg.largeArcFlag, - sweepFlag: seg.sweepFlag - }; - } - - var len = changes.d.length, - firstseg = changes.d[0], - currentpt = remap(firstseg.x,firstseg.y); - changes.d[0].x = currentpt.x; - changes.d[0].y = currentpt.y; - for (var i = 1; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 - // if relative, we want to scalew, scaleh - if (type % 2 == 0) { // absolute - var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands - thisy = (seg.y != undefined) ? seg.y : currentpt.y, // for H commands - pt = remap(thisx,thisy), - pt1 = remap(seg.x1,seg.y1), - pt2 = remap(seg.x2,seg.y2); - seg.x = pt.x; - seg.y = pt.y; - seg.x1 = pt1.x; - seg.y1 = pt1.y; - seg.x2 = pt2.x; - seg.y2 = pt2.y; - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - else { // relative - seg.x = scalew(seg.x); - seg.y = scaleh(seg.y); - seg.x1 = scalew(seg.x1); - seg.y1 = scaleh(seg.y1); - seg.x2 = scalew(seg.x2); - seg.y2 = scaleh(seg.y2); - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - } // for each segment - - var dstr = ""; - var len = changes.d.length; - for (var i = 0; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - dstr += pathMap[type]; - switch(type) { - case 13: // relative horizontal line (h) - case 12: // absolute horizontal line (H) - dstr += seg.x + " "; - break; - case 15: // relative vertical line (v) - case 14: // absolute vertical line (V) - dstr += seg.y + " "; - break; - case 3: // relative move (m) - case 5: // relative line (l) - case 19: // relative smooth quad (t) - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - dstr += seg.x + "," + seg.y + " "; - break; - case 7: // relative cubic (c) - case 6: // absolute cubic (C) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x2 + "," + seg.y2 + " " + - seg.x + "," + seg.y + " "; - break; - case 9: // relative quad (q) - case 8: // absolute quad (Q) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x + "," + seg.y + " "; - break; - case 11: // relative elliptical arc (a) - case 10: // absolute elliptical arc (A) - dstr += seg.r1 + "," + seg.r2 + " " + seg.angle + " " + (+seg.largeArcFlag) + - " " + (+seg.sweepFlag) + " " + seg.x + "," + seg.y + " "; - break; - case 17: // relative smooth cubic (s) - case 16: // absolute smooth cubic (S) - dstr += seg.x2 + "," + seg.y2 + " " + seg.x + "," + seg.y + " "; - break; - } - } - - selected.setAttribute("d", dstr); - break; - } -}; - -// Function: updateClipPath -// Updates a <clipPath>s values based on the given translation of an element -// -// Parameters: -// attr - The clip-path attribute value with the clipPath's ID -// tx - The translation's x value -// ty - The translation's y value -var updateClipPath = function(attr, tx, ty) { - var path = getRefElem(attr).firstChild; - - var cp_xform = getTransformList(path); - - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx, ty); - - cp_xform.appendItem(newxlate); - - // Update clipPath's dimensions - recalculateDimensions(path); -} - -// Function: recalculateDimensions -// Decides the course of action based on the element's transform list -// -// Parameters: -// selected - The DOM element to recalculate -// -// Returns: -// Undo command object with the resulting change -var recalculateDimensions = this.recalculateDimensions = function(selected) { - if (selected == null) return null; - - var tlist = getTransformList(selected); - - // remove any unnecessary transforms - if (tlist && tlist.numberOfItems > 0) { - var k = tlist.numberOfItems; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 0) { - tlist.removeItem(k); - } - // remove identity matrices - else if (xform.type === 1) { - if (svgedit.math.isIdentity(xform.matrix)) { - tlist.removeItem(k); - } - } - // remove zero-degree rotations - else if (xform.type === 4) { - if (xform.angle === 0) { - tlist.removeItem(k); - } - } - } - // End here if all it has is a rotation - if(tlist.numberOfItems === 1 && getRotationAngle(selected)) return null; - } - - // if this element had no transforms, we are done - if (!tlist || tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - return null; - } - - // TODO: Make this work for more than 2 - if (tlist) { - var k = tlist.numberOfItems; - var mxs = []; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 1) { - mxs.push([xform.matrix, k]); - } else if(mxs.length) { - mxs = []; - } - } - if(mxs.length === 2) { - var m_new = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])); - tlist.removeItem(mxs[0][1]); - tlist.removeItem(mxs[1][1]); - tlist.insertItemBefore(m_new, mxs[1][1]); - } - - // combine matrix + translate - k = tlist.numberOfItems; - if(k >= 2 && tlist.getItem(k-2).type === 1 && tlist.getItem(k-1).type === 2) { - var mt = svgroot.createSVGTransform(); - - var m = matrixMultiply( - tlist.getItem(k-2).matrix, - tlist.getItem(k-1).matrix - ); - mt.setMatrix(m); - tlist.removeItem(k-2); - tlist.removeItem(k-2); - tlist.appendItem(mt); - } - } - - // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). - switch ( selected.tagName ) { - // Ignore these elements, as they can absorb the [M] - case 'line': - case 'polyline': - case 'polygon': - case 'path': - break; - default: - if( - (tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) - || (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4) - ) { - return null; - } - } - - // Grouped SVG element - var gsvg = $(selected).data('gsvg'); - - // we know we have some transforms, so set up return variable - var batchCmd = new BatchCommand("Transform"); - - // store initial values that will be affected by reducing the transform list - var changes = {}, initial = null, attrs = []; - switch (selected.tagName) - { - case "line": - attrs = ["x1", "y1", "x2", "y2"]; - break; - case "circle": - attrs = ["cx", "cy", "r"]; - break; - case "ellipse": - attrs = ["cx", "cy", "rx", "ry"]; - break; - case "foreignObject": - case "rect": - case "image": - attrs = ["width", "height", "x", "y"]; - break; - case "use": - case "text": - case "tspan": - attrs = ["x", "y"]; - break; - case "polygon": - case "polyline": - initial = {}; - initial["points"] = selected.getAttribute("points"); - var list = selected.points; - var len = list.numberOfItems; - changes["points"] = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes["points"][i] = {x:pt.x,y:pt.y}; - } - break; - case "path": - initial = {}; - initial["d"] = selected.getAttribute("d"); - changes["d"] = selected.getAttribute("d"); - break; - } // switch on element type to get initial values - - if(attrs.length) { - changes = $(selected).attr(attrs); - $.each(changes, function(attr, val) { - changes[attr] = convertToNum(attr, val); - }); - } else if(gsvg) { - // GSVG exception - changes = { - x: $(gsvg).attr('x') || 0, - y: $(gsvg).attr('y') || 0 - }; - } - - // if we haven't created an initial array in polygon/polyline/path, then - // make a copy of initial values and include the transform - if (initial == null) { - initial = $.extend(true, {}, changes); - $.each(initial, function(attr, val) { - initial[attr] = convertToNum(attr, val); - }); - } - // save the start transform value too - initial["transform"] = start_transform ? start_transform : ""; - - // if it's a regular group, we have special processing to flatten transforms - if ((selected.tagName == "g" && !gsvg) || selected.tagName == "a") { - var box = svgedit.utilities.getBBox(selected), - oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix), - m = svgroot.createSVGMatrix(); - - - // temporarily strip off the rotate and save the old center - var gangle = getRotationAngle(selected); - if (gangle) { - var a = gangle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - var tx = 0, ty = 0, - operation = 0, - N = tlist.numberOfItems; - - if(N) { - var first_m = tlist.getItem(0).matrix; - } - - // first, if it was a scale then the second-last transform will be it - if (N >= 3 && tlist.getItem(N-2).type == 3 && - tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2) - { - operation = 3; // scale - - // if the children are unrotated, pass the scale down directly - // otherwise pass the equivalent matrix() down directly - var tm = tlist.getItem(N-3).matrix, - sm = tlist.getItem(N-2).matrix, - tmn = tlist.getItem(N-1).matrix; - - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - tx = 0; - ty = 0; - if (child.nodeType == 1) { - var childTlist = getTransformList(child); - - // some children might not have a transform (<metadata>, <defs>, etc) - 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; - var childxforms = []; - start_transform = child.getAttribute("transform"); - if(angle || hasMatrixTransform(childTlist)) { - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(matrixMultiply(tm, sm, tmn, m)); - childTlist.clear(); - childTlist.appendItem(e2t); - childxforms.push(e2t); - } - // if not rotated or skewed, push the [T][S][-T] down to the child - else { - // update the transform list with translate,scale,translate - - // slide the [T][S][-T] from the front to the back - // [T][S][-T][M] = [M][T2][S2][-T2] - - // (only bringing [-T] to the right of [M]) - // [T][S][-T][M] = [T][S][M][-T2] - // [-T2] = [M_inv][-T][M] - var t2n = matrixMultiply(m.inverse(), tmn, m); - // [T2] is always negative translation of [-T2] - var t2 = svgroot.createSVGMatrix(); - t2.e = -t2n.e; - t2.f = -t2n.f; - - // [T][S][-T][M] = [M][T2][S2][-T2] - // [S2] = [T2_inv][M_inv][T][S][-T][M][-T2_inv] - var s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()); - - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - translateOrigin.setTranslate(t2n.e, t2n.f); - scale.setScale(s2.a, s2.d); - translateBack.setTranslate(t2.e, t2.f); - childTlist.appendItem(translateBack); - childTlist.appendItem(scale); - childTlist.appendItem(translateOrigin); - childxforms.push(translateBack); - childxforms.push(scale); - childxforms.push(translateOrigin); -// logMatrix(translateBack.matrix); -// logMatrix(scale.matrix); - } // not rotated - batchCmd.addSubCommand( recalculateDimensions(child) ); - // TODO: If any <use> have this group as a parent and are - // referencing this child, then we need to impose a reverse - // scale on it so that when it won't get double-translated -// var uses = selected.getElementsByTagNameNS(svgns, "use"); -// var href = "#"+child.id; -// var u = uses.length; -// while (u--) { -// var useElem = uses.item(u); -// if(href == getHref(useElem)) { -// var usexlate = svgroot.createSVGTransform(); -// usexlate.setTranslate(-tx,-ty); -// getTransformList(useElem).insertItemBefore(usexlate,0); -// batchCmd.addSubCommand( recalculateDimensions(useElem) ); -// } -// } - start_transform = old_start_transform; - } // element - } // for each child - // Remove these transforms from group - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } - else if (N >= 3 && tlist.getItem(N-1).type == 1) - { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - } - // next, check if the first transform was a translate - // if we had [ T1 ] [ M ] we want to transform this into [ M ] [ T2 ] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var T_M = transformListToTransform(tlist).matrix; - tlist.removeItem(0); - var M_inv = transformListToTransform(tlist).matrix.inverse(); - var M2 = matrixMultiply( M_inv, T_M ); - - tx = M2.e; - ty = M2.f; - - if (tx != 0 || ty != 0) { - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - - var clipPaths_done = []; - - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - - // Check if child has clip-path - if(child.getAttribute('clip-path')) { - // tx, ty - var attr = child.getAttribute('clip-path'); - if(clipPaths_done.indexOf(attr) === -1) { - updateClipPath(attr, tx, ty); - clipPaths_done.push(attr); - } - } - - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - - var childTlist = getTransformList(child); - // some children might not have a transform (<metadata>, <defs>, etc) - if (childTlist) { - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - batchCmd.addSubCommand( recalculateDimensions(child) ); - // If any <use> have this group as a parent and are - // referencing this child, then impose a reverse translate on it - // so that when it won't get double-translated - var uses = selected.getElementsByTagNameNS(svgns, "use"); - var href = "#"+child.id; - var u = uses.length; - while (u--) { - var useElem = uses.item(u); - if(href == getHref(useElem)) { - var usexlate = svgroot.createSVGTransform(); - usexlate.setTranslate(-tx,-ty); - getTransformList(useElem).insertItemBefore(usexlate,0); - batchCmd.addSubCommand( recalculateDimensions(useElem) ); - } - } - start_transform = old_start_transform; - } - } - } - - clipPaths_done = []; - - start_transform = old_start_transform; - } - } - // else, a matrix imposition from a parent group - // keep pushing it down to the children - else if (N == 1 && tlist.getItem(0).type == 1 && !gangle) { - operation = 1; - var m = tlist.getItem(0).matrix, - children = selected.childNodes, - c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - 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); - childTlist.clear(); - childTlist.appendItem(e2m,0); - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - - // Convert stroke - // TODO: Find out if this should actually happen somewhere else - var sw = child.getAttribute("stroke-width"); - if (child.getAttribute("stroke") !== "none" && !isNaN(sw)) { - var avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; - child.setAttribute('stroke-width', sw * avg); - } - - } - } - tlist.clear(); - } - // else it was just a rotate - else { - if (gangle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (gangle) { - newcenter = { - x: oldcenter.x + first_m.e, - y: oldcenter.y + first_m.f - }; - - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // if it was a resize - else if (operation == 3) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(gangle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(gangle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(), - m_inv = m.inverse(), - extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - tx = extrat.e; - ty = extrat.f; - - if (tx != 0 || ty != 0) { - // now push this transform down to the children - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - var childTlist = getTransformList(child); - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - } - } - } - - if (gangle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } - // else, it's a non-group - else { - - // FIXME: box might be null for some elements (<metadata> etc), need to handle this - var box = svgedit.utilities.getBBox(selected); - - // Paths (and possbly other shapes) will have no BBox while still in <defs>, - // but we still may need to recalculate them (see issue 595). - // TODO: Figure out how to get BBox from these elements in case they - // have a rotation transform - - if(!box && selected.tagName != 'path') return null; - - - var m = svgroot.createSVGMatrix(), - // temporarily strip off the rotate and save the old center - angle = getRotationAngle(selected); - if (angle) { - var oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix); - - var a = angle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - - // 2 = translate, 3 = scale, 4 = rotate, 1 = matrix imposition - var operation = 0; - var N = tlist.numberOfItems; - - // Check if it has a gradient with userSpaceOnUse, in which case - // adjust it by recalculating the matrix transform. - // TODO: Make this work in Webkit using svgedit.transformlist.SVGTransformList - if(!svgedit.browser.isWebkit()) { - var fill = selected.getAttribute('fill'); - if(fill && fill.indexOf('url(') === 0) { - var paint = getRefElem(fill); - var type = 'pattern'; - if(paint.tagName !== type) type = 'gradient'; - var attrVal = paint.getAttribute(type + 'Units'); - if(attrVal === 'userSpaceOnUse') { - //Update the userSpaceOnUse element - m = transformListToTransform(tlist).matrix; - var gtlist = getTransformList(paint); - var gmatrix = transformListToTransform(gtlist).matrix; - m = matrixMultiply(m, gmatrix); - var m_str = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - paint.setAttribute(type + 'Transform', m_str); - } - } - } - - // first, if it was a scale of a non-skewed element, then the second-last - // transform will be the [S] - // 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) - - // Removed this so a <use> 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; - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } // if we had [T][S][-T][M], then this was a skewed element being resized - // Thus, we simply combine it all into one matrix - else if(N == 4 && tlist.getItem(N-1).type == 1) { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - // reset the matrix so that the element is not re-mapped - m = svgroot.createSVGMatrix(); - } // if we had [R][T][S][-T][M], then this was a rotated matrix-element - // if we had [T1][M] we want to transform this into [M][T2] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] and we can push [T2] - // down to the element - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var oldxlate = tlist.getItem(0).matrix, - meq = transformListToTransform(tlist,1).matrix, - meq_inv = meq.inverse(); - m = matrixMultiply( meq_inv, oldxlate, meq ); - tlist.removeItem(0); - } - // else if this child now has a matrix imposition (from a parent group) - // we might be able to simplify - else if (N == 1 && tlist.getItem(0).type == 1 && !angle) { - // Remap all point-based elements - m = transformListToTransform(tlist).matrix; - switch (selected.tagName) { - case 'line': - changes = $(selected).attr(["x1","y1","x2","y2"]); - case 'polyline': - case 'polygon': - changes.points = selected.getAttribute("points"); - if(changes.points) { - var list = selected.points; - var len = list.numberOfItems; - changes.points = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes.points[i] = {x:pt.x,y:pt.y}; - } - } - case 'path': - changes.d = selected.getAttribute("d"); - operation = 1; - tlist.clear(); - break; - default: - break; - } - } - // if it was a rotation, put the rotate back and return without a command - // (this function has zero work to do for a rotate()) - else { - operation = 4; // rotation - if (angle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle,newcenter.x,newcenter.y); - - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate or resize, we need to remap the element and absorb the xform - if (operation == 1 || operation == 2 || operation == 3) { - remapElement(selected,changes,m); - } // if we are remapping - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (angle) { - if(!hasMatrixTransform(tlist)) { - newcenter = { - x: oldcenter.x + m.e, - y: oldcenter.y + m.f - }; - } - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle, newcenter.x, newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // [Rold][M][T][S][-T] became [Rold][M] - // we want it to be [Rnew][M][Tr] where Tr is the - // translation required to re-center it - // Therefore, [Tr] = [M_inv][Rnew_inv][Rold][M] - else if (operation == 3 && angle) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(angle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(angle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(); - var m_inv = m.inverse(); - var extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - remapElement(selected,changes,extrat); - if (angle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } // a non-group - - // if the transform list has been emptied, remove it - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - - batchCmd.addSubCommand(new ChangeElementCommand(selected, initial)); - - return batchCmd; -}; - -// Root Current Transformation Matrix in user units -var root_sctm = null; - -// Group: Selection - -// Function: clearSelection -// Clears the selection. The 'selected' handler is then called. -// Parameters: -// noCall - Optional boolean that when true does not call the "selected" handler -var clearSelection = this.clearSelection = function(noCall) { - if (selectedElements[0] != null) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - selectorManager.releaseSelector(elem); - selectedElements[i] = null; - } -// selectedBBoxes[0] = null; - } - if(!noCall) call("selected", selectedElements); -}; - -// TODO: do we need to worry about selectedBBoxes here? - - -// Function: addToSelection -// Adds a list of elements to the selection. The 'selected' handler is then called. -// -// Parameters: -// elemsToAdd - an array of DOM elements to add to the selection -// showGrips - a boolean flag indicating whether the resize grips should be shown -var addToSelection = this.addToSelection = function(elemsToAdd, showGrips) { - if (elemsToAdd.length == 0) { return; } - // find the first null in our selectedElements array - var j = 0; - - while (j < selectedElements.length) { - if (selectedElements[j] == null) { - break; - } - ++j; - } - - // now add each element consecutively - var i = elemsToAdd.length; - while (i--) { - var elem = elemsToAdd[i]; - if (!elem || !svgedit.utilities.getBBox(elem)) continue; - - if(elem.tagName === 'a' && elem.childNodes.length === 1) { - // Make "a" element's child be the selected element - elem = elem.firstChild; - } - - // if it's not already there, add it - if (selectedElements.indexOf(elem) == -1) { - - selectedElements[j] = elem; - - // only the first selectedBBoxes element is ever used in the codebase these days -// if (j == 0) selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - j++; - var sel = selectorManager.requestSelector(elem); - - if (selectedElements.length > 1) { - sel.showGrips(false); - } - } - } - call("selected", selectedElements); - - if (showGrips || selectedElements.length == 1) { - selectorManager.requestSelector(selectedElements[0]).showGrips(true); - } - else { - selectorManager.requestSelector(selectedElements[0]).showGrips(false); - } - - // make sure the elements are in the correct order - // See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - - selectedElements.sort(function(a,b) { - if(a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); - } else if(a == null) { - return 1; - } - }); - - // Make sure first elements are not null - while(selectedElements[0] == null) selectedElements.shift(0); -}; - -// Function: selectOnly() -// Selects only the given elements, shortcut for clearSelection(); addToSelection() -// -// Parameters: -// elems - an array of DOM elements to be selected -var selectOnly = this.selectOnly = function(elems, showGrips) { - clearSelection(true); - addToSelection(elems, showGrips); -} - -// TODO: could use slice here to make this faster? -// TODO: should the 'selected' handler - -// Function: removeFromSelection -// Removes elements from the selection. -// -// Parameters: -// elemsToRemove - an array of elements to remove from selection -var removeFromSelection = this.removeFromSelection = function(elemsToRemove) { - if (selectedElements[0] == null) { return; } - if (elemsToRemove.length == 0) { return; } - - // find every element and remove it from our array copy - var newSelectedItems = new Array(selectedElements.length); - j = 0, - len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem) { - // keep the item - if (elemsToRemove.indexOf(elem) == -1) { - newSelectedItems[j] = elem; - j++; - } - else { // remove the item and its selector - selectorManager.releaseSelector(elem); - } - } - } - // the copy becomes the master now - selectedElements = newSelectedItems; -}; - -// Function: selectAllInCurrentLayer -// Clears the selection, then adds all elements in the current layer to the selection. -this.selectAllInCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (current_layer) { - current_mode = "select"; - selectOnly($(current_group || current_layer).children()); - } -}; - -// Function: getMouseTarget -// Gets the desired element from a mouse event -// -// Parameters: -// evt - Event object from the mouse event -// -// Returns: -// DOM element we want -var getMouseTarget = this.getMouseTarget = function(evt) { - if (evt == null) { - return null; - } - var mouse_target = evt.target; - - // if it was a <use>, Opera and WebKit return the SVGElementInstance - if (mouse_target.correspondingUseElement) mouse_target = mouse_target.correspondingUseElement; - - // for foreign content, go up until we find the foreignObject - // WebKit browsers set the mouse target to the svgcanvas div - if ([mathns, htmlns].indexOf(mouse_target.namespaceURI) >= 0 && - mouse_target.id != "svgcanvas") - { - while (mouse_target.nodeName != "foreignObject") { - mouse_target = mouse_target.parentNode; - if(!mouse_target) return svgroot; - } - } - - // Get the desired mouse_target with jQuery selector-fu - // If it's root-like, select the root - var current_layer = getCurrentDrawing().getCurrentLayer(); - if([svgroot, container, svgcontent, current_layer].indexOf(mouse_target) >= 0) { - return svgroot; - } - - var $target = $(mouse_target); - - // If it's a selection grip, return the grip parent - if($target.closest('#selectorParentGroup').length) { - // While we could instead have just returned mouse_target, - // this makes it easier to indentify as being a selector grip - return selectorManager.selectorParentGroup; - } - - while (mouse_target.parentNode !== (current_group || current_layer)) { - mouse_target = mouse_target.parentNode; - } - -// -// // go up until we hit a child of a layer -// while (mouse_target.parentNode.parentNode.tagName == 'g') { -// mouse_target = mouse_target.parentNode; -// } - // Webkit bubbles the mouse event all the way up to the div, so we - // set the mouse_target to the svgroot like the other browsers -// if (mouse_target.nodeName.toLowerCase() == "div") { -// mouse_target = svgroot; -// } - - return mouse_target; -}; - -// Mouse events -(function() { - var d_attr = null, - start_x = null, - start_y = null, - r_start_x = null, - r_start_y = null, - init_bbox = {}, - freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - - // - when we are in a create mode, the element is added to the canvas - // but the action is not recorded until mousing up - // - when we are in select mode, select the element, remember the position - // and do nothing else - var mouseDown = function(evt) - { - if(canvas.spaceKey || evt.button === 1) return; - - var right_click = evt.button === 2; - - if(evt.altKey) { // duplicate when dragging - svgCanvas.cloneSelectedElements(0,0); - } - - root_sctm = svgcontent.getScreenCTM().inverse(); - - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom; - - evt.preventDefault(); - - if(right_click) { - current_mode = "select"; - lastClickPoint = pt; - } - - // This would seem to be unnecessary... -// if(['select', 'resize'].indexOf(current_mode) == -1) { -// setGradient(); -// } - - var x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - mouse_target = getMouseTarget(evt); - - if(mouse_target.tagName === 'a' && mouse_target.childNodes.length === 1) { - mouse_target = mouse_target.firstChild; - } - - // real_x/y ignores grid-snap value - var real_x = r_start_x = start_x = x; - var real_y = r_start_y = start_y = y; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - - // if it is a selector grip, then it must be a single element selected, - // set the mouse_target to that and update the mode to rotate/resize - - if (mouse_target == selectorManager.selectorParentGroup && selectedElements[0] != null) { - var grip = evt.target; - var griptype = elData(grip, "type"); - // rotating - if (griptype == "rotate") { - current_mode = "rotate"; - current_rotate_mode = elData(grip, "dir"); - } - // resizing - else if(griptype == "resize") { - current_mode = "resize"; - current_resize_mode = elData(grip, "dir"); - } - mouse_target = selectedElements[0]; - } - - start_transform = mouse_target.getAttribute("transform"); - var tlist = getTransformList(mouse_target); - switch (current_mode) { - case "select": - started = true; - current_resize_mode = "none"; - if(right_click) started = false; - - if (mouse_target != svgroot) { - // if this element is not yet selected, clear selection and select it - if (selectedElements.indexOf(mouse_target) == -1) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) - if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection - clearSelection(true); - } - addToSelection([mouse_target]); - justSelected = mouse_target; - pathActions.clear(); - } - // else if it's a path, go into pathedit mode in mouseup - - if(!right_click) { - // insert a dummy transform so if the element(s) are moved it will have - // a transform to use for its translate - for (var i = 0; i < selectedElements.length; ++i) { - if(selectedElements[i] == null) continue; - var slist = getTransformList(selectedElements[i]); - if(slist.numberOfItems) { - slist.insertItemBefore(svgroot.createSVGTransform(), 0); - } else { - slist.appendItem(svgroot.createSVGTransform()); - } - } - } - } - else if(!right_click){ - clearSelection(); - current_mode = "multiselect"; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - r_start_x *= current_zoom; - r_start_y *= current_zoom; -// console.log('p',[evt.pageX, evt.pageY]); -// console.log('c',[evt.clientX, evt.clientY]); -// console.log('o',[evt.offsetX, evt.offsetY]); -// console.log('s',[start_x, start_y]); - - assignAttributes(rubberBox, { - 'x': r_start_x, - 'y': r_start_y, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - break; - case "zoom": - started = true; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': real_x * current_zoom, - 'y': real_x * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - break; - case "resize": - started = true; - start_x = x; - start_y = y; - - // Getting the BBox from the selection box, since we know we - // want to orient around it - init_bbox = svgedit.utilities.getBBox($('#selectedBox0')[0]); - var bb = {}; - $.each(init_bbox, function(key, val) { - bb[key] = val/current_zoom; - }); - init_bbox = bb; - // append three dummy transforms to the tlist so that - // we can translate,scale,translate in mousemove - var pos = getRotationAngle(mouse_target)?1:0; - - if(hasMatrixTransform(tlist)) { - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - } else { - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - - if(svgedit.browser.supportsNonScalingStroke()) { - //Handle crash for newer Chrome: https://code.google.com/p/svg-edit/issues/detail?id=904 - //Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 - // TODO: Remove this workaround (all isChrome blocks) once vendor fixes the issue - var isChrome = svgedit.browser.isChrome(); - if(isChrome) { - var delayedStroke = function(ele) { - var _stroke = ele.getAttributeNS(null, 'stroke'); - ele.removeAttributeNS(null, 'stroke'); - //Re-apply stroke after delay. Anything higher than 1 seems to cause flicker - setTimeout(function() { ele.setAttributeNS(null, 'stroke', _stroke) }, 1); - } - } - mouse_target.style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(mouse_target); - - var all = mouse_target.getElementsByTagName('*'), - len = all.length; - for(var i = 0; i < len; i++) { - all[i].style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(all[i]); - } - } - } - break; - case "fhellipse": - case "fhrect": - case "fhpath": - started = true; - d_attr = real_x + "," + real_y + " "; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "polyline", - "curStyles": true, - "attr": { - "points": d_attr, - "id": getNextId(), - "fill": "none", - "opacity": cur_shape.opacity / 2, - "stroke-linecap": "round", - "style": "pointer-events:none" - } - }); - freehand.minx = real_x; - freehand.maxx = real_x; - freehand.miny = real_y; - freehand.maxy = real_y; - break; - case "image": - started = true; - var newImage = addSvgElementFromJson({ - "element": "image", - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - } - }); - setHref(newImage, last_good_img_url); - preventClickDefault(newImage); - break; - case "square": - // FIXME: once we create the rect, we lose information that this was a square - // (for resizing purposes this could be important) - case "rect": - started = true; - start_x = x; - start_y = y; - addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "line": - started = true; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "line", - "curStyles": true, - "attr": { - "x1": x, - "y1": y, - "x2": x, - "y2": y, - "id": getNextId(), - "stroke": cur_shape.stroke, - "stroke-width": stroke_w, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill": "none", - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:none" - } - }); - break; - case "circle": - started = true; - addSvgElementFromJson({ - "element": "circle", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "r": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "ellipse": - started = true; - addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "rx": 0, - "ry": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "text": - started = true; - var newText = addSvgElementFromJson({ - "element": "text", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "id": getNextId(), - "fill": cur_text.fill, - "stroke-width": cur_text.stroke_width, - "font-size": cur_text.font_size, - "font-family": cur_text.font_family, - "text-anchor": "middle", - "xml:space": "preserve", - "opacity": cur_shape.opacity - } - }); -// newText.textContent = "text"; - break; - case "path": - // Fall through - case "pathedit": - start_x *= current_zoom; - start_y *= current_zoom; - pathActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "textedit": - start_x *= current_zoom; - start_y *= current_zoom; - textActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "rotate": - started = true; - // we are starting an undoable change (a drag-rotation) - canvas.undoMgr.beginUndoableChange("transform", selectedElements); - document.getElementById("workarea").className = "rotate"; - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseDown", { - event: evt, - start_x: start_x, - start_y: start_y, - selectedElements: selectedElements - }, true); - - $.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 - // any elements that are still being created, moved or resized on the canvas) - var mouseMove = function(evt) - { - if (!started) return; - if(evt.button === 1 || canvas.spaceKey) return; - - var selected = selectedElements[0], - pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - shape = getElem(getId()); - - var real_x = x = mouse_x / current_zoom; - var real_y = y = mouse_y / current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - evt.preventDefault(); - - switch (current_mode) - { - case "select": - // we temporarily use a translate on the element(s) being dragged - // this transform is removed upon mousing up and the element is - // relocated to the new location - if (selectedElements[0] !== null) { - var dx = x - start_x; - var dy = y - start_y; - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - } - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x,y); x=xya.x; y=xya.y; } - - if (dx != 0 || dy != 0) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; -// if (i==0) { -// var box = svgedit.utilities.getBBox(selected); -// selectedBBoxes[i].x = box.x + dx; -// selectedBBoxes[i].y = box.y + dy; -// } - - // update the dummy transform in our transform list - // 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); - } else { - tlist.appendItem(xform); - } - - // update our internal bbox that we're tracking while dragging - selectorManager.requestSelector(selected).resize(); - } - - call("transition", selectedElements); - } - } - break; - case "multiselect": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y) - },100); - - // for each selected: - // - if newList contains selected, do nothing - // - if newList doesn't contain selected, remove it from selected - // - for any newList that was not in selectedElements, add it to selected - var elemsToRemove = [], elemsToAdd = [], - newList = getIntersectionList(), - len = selectedElements.length; - - for (var i = 0; i < len; ++i) { - var ind = newList.indexOf(selectedElements[i]); - if (ind == -1) { - elemsToRemove.push(selectedElements[i]); - } - else { - newList[ind] = null; - } - } - - len = newList.length; - for (i = 0; i < len; ++i) { if (newList[i]) elemsToAdd.push(newList[i]); } - - if (elemsToRemove.length > 0) - canvas.removeFromSelection(elemsToRemove); - - if (elemsToAdd.length > 0) - addToSelection(elemsToAdd); - - break; - case "resize": - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates - var tlist = getTransformList(selected), - hasMatrix = hasMatrixTransform(tlist), - box = hasMatrix ? init_bbox : svgedit.utilities.getBBox(selected), - left=box.x, top=box.y, width=box.width, - height=box.height, dx=(x-start_x), dy=(y-start_y); - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - height = snapToGrid(height); - width = snapToGrid(width); - } - - // if rotated, adjust the dx,dy values - var angle = getRotationAngle(selected); - if (angle) { - var r = Math.sqrt( dx*dx + dy*dy ), - theta = Math.atan2(dy,dx) - angle * Math.PI / 180.0; - dx = r * Math.cos(theta); - dy = r * Math.sin(theta); - } - - // if not stretching in y direction, set dy to 0 - // if not stretching in x direction, set dx to 0 - if(current_resize_mode.indexOf("n")==-1 && current_resize_mode.indexOf("s")==-1) { - dy = 0; - } - if(current_resize_mode.indexOf("e")==-1 && current_resize_mode.indexOf("w")==-1) { - dx = 0; - } - - var ts = null, - tx = 0, ty = 0, - sy = height ? (height+dy)/height : 1, - sx = width ? (width+dx)/width : 1; - // if we are dragging on the north side, then adjust the scale factor and ty - if(current_resize_mode.indexOf("n") >= 0) { - sy = height ? (height-dy)/height : 1; - ty = height; - } - - // if we dragging on the east side, then adjust the scale factor and tx - if(current_resize_mode.indexOf("w") >= 0) { - sx = width ? (width-dx)/width : 1; - tx = width; - } - - // update the transform list with translate,scale,translate - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - - if(curConfig.gridSnapping){ - left = snapToGrid(left); - tx = snapToGrid(tx); - top = snapToGrid(top); - ty = snapToGrid(ty); - } - - translateOrigin.setTranslate(-(left+tx),-(top+ty)); - if(evt.shiftKey) { - if(sx == 1) sx = sy - else sy = sx; - } - scale.setScale(sx,sy); - - translateBack.setTranslate(left+tx,top+ty); - if(hasMatrix) { - var diff = angle?1:0; - tlist.replaceItem(translateOrigin, 2+diff); - tlist.replaceItem(scale, 1+diff); - tlist.replaceItem(translateBack, 0+diff); - } else { - var N = tlist.numberOfItems; - tlist.replaceItem(translateBack, N-3); - tlist.replaceItem(scale, N-2); - tlist.replaceItem(translateOrigin, N-1); - } - - selectorManager.requestSelector(selected).resize(); - - call("transition", selectedElements); - - break; - case "zoom": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - break; - case "text": - assignAttributes(shape,{ - 'x': x, - 'y': y - },1000); - break; - case "line": - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - var x2 = x; - var y2 = y; - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x2,y2); x2=xya.x; y2=xya.y; } - - shape.setAttributeNS(null, "x2", x2); - shape.setAttributeNS(null, "y2", y2); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "foreignObject": - // fall through - case "square": - // fall through - case "rect": - // fall through - case "image": - var square = (current_mode == 'square') || evt.shiftKey, - w = Math.abs(x - start_x), - h = Math.abs(y - start_y), - new_x, new_y; - if(square) { - w = h = Math.max(w, h); - new_x = start_x < x ? start_x : start_x - w; - new_y = start_y < y ? start_y : start_y - h; - } else { - new_x = Math.min(start_x,x); - new_y = Math.min(start_y,y); - } - - if(curConfig.gridSnapping){ - w = snapToGrid(w); - h = snapToGrid(h); - new_x = snapToGrid(new_x); - new_y = snapToGrid(new_y); - } - - assignAttributes(shape,{ - 'width': w, - 'height': h, - 'x': new_x, - 'y': new_y - },1000); - - break; - case "circle": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy, - rad = Math.sqrt( (x-cx)*(x-cx) + (y-cy)*(y-cy) ); - if(curConfig.gridSnapping){ - rad = snapToGrid(rad); - } - shape.setAttributeNS(null, "r", rad); - break; - case "ellipse": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy; - // Opera has a problem with suspendRedraw() apparently - handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - if(curConfig.gridSnapping){ - x = snapToGrid(x); - cx = snapToGrid(cx); - y = snapToGrid(y); - cy = snapToGrid(cy); - } - shape.setAttributeNS(null, "rx", Math.abs(x - cx) ); - var ry = Math.abs(evt.shiftKey?(x - cx):(y - cy)); - shape.setAttributeNS(null, "ry", ry ); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "fhellipse": - case "fhrect": - freehand.minx = Math.min(real_x, freehand.minx); - freehand.maxx = Math.max(real_x, freehand.maxx); - freehand.miny = Math.min(real_y, freehand.miny); - freehand.maxy = Math.max(real_y, freehand.maxy); - // break; missing on purpose - case "fhpath": - d_attr += + real_x + "," + real_y + " "; - shape.setAttributeNS(null, "points", d_attr); - break; - // update path stretch line coordinates - case "path": - // fall through - case "pathedit": - x *= current_zoom; - y *= current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - if(evt.shiftKey) { - var path = svgedit.path.path; - if(path) { - var x1 = path.dragging?path.dragging[0]:start_x; - var y1 = path.dragging?path.dragging[1]:start_y; - } else { - var x1 = start_x; - var y1 = start_y; - } - var xya = snapToAngle(x1,y1,x,y); - x=xya.x; y=xya.y; - } - - if(rubberBox && rubberBox.getAttribute('display') !== 'none') { - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - } - pathActions.mouseMove(evt, x, y); - - break; - case "textedit": - x *= current_zoom; - y *= current_zoom; -// if(rubberBox && rubberBox.getAttribute('display') != 'none') { -// assignAttributes(rubberBox, { -// 'x': Math.min(start_x,x), -// 'y': Math.min(start_y,y), -// 'width': Math.abs(x-start_x), -// 'height': Math.abs(y-start_y) -// },100); -// } - - textActions.mouseMove(mouse_x, mouse_y); - - break; - case "rotate": - var box = svgedit.utilities.getBBox(selected), - cx = box.x + box.width/2, - cy = box.y + box.height/2, - m = getMatrix(selected), - center = transformPoint(cx,cy,m); - cx = center.x; - cy = center.y; - var ccx = box.x // ne - var ccy = box.y // ne - if (current_rotate_mode == "nw") ccx = box.x + box.width; - if (current_rotate_mode == "se") ccy = box.y + box.height; - if (current_rotate_mode == "sw"){ ccx = box.x + box.width; ccy = box.y + box.height; } - compensation_angle = ((Math.atan2(cy-ccy,cx-ccx) * (180/Math.PI))-90) % 360; - var angle = ((Math.atan2(cy-y,cx-x) * (180/Math.PI))-90) % 360; - angle += compensation_angle; - if(curConfig.gridSnapping){ - angle = snapToGrid(angle); - } - if(evt.shiftKey) { // restrict rotations to nice angles (WRS) - var snap = 45; - angle= Math.round(angle/snap)*snap; - } - - canvas.setRotationAngle(angle<-180?(360+angle):angle, true); - call("transition", selectedElements); - break; - default: - break; - } - - runExtensions("mouseMove", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y, - selected: selected - }); - - }; // mouseMove() - - // - in create mode, the element's opacity is set properly, we create an InsertElementCommand - // and store it on the Undo stack - // - in move/resize mode, the element's attributes which were affected by the move/resize are - // identified, a ChangeElementCommand is created and stored on the stack for those attrs - // this is done in when we recalculate the selected dimensions() - var mouseUp = function(evt) - { - if(evt.button === 2) return; - var tempJustSelected = justSelected; - justSelected = null; - if (!started) return; - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - element = getElem(getId()), - keep = false; - - var real_x = x; - var real_y = y; - - // TODO: Make true when in multi-unit mode - var useUnit = false; // (curConfig.baseUnit !== 'px'); - started = false; - switch (current_mode) - { - // intentionally fall-through to select here - case "resize": - case "multiselect": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - curBBoxes = []; - } - current_mode = "select"; - case "select": - if (selectedElements[0] != null) { - // if we only have one selected element - if (selectedElements[1] == null) { - // set our current stroke/fill properties to the element's - var selected = selectedElements[0]; - switch ( selected.tagName ) { - case "g": - case "use": - case "image": - case "foreignObject": - break; - default: - cur_properties.fill = selected.getAttribute("fill"); - cur_properties.fill_opacity = selected.getAttribute("fill-opacity"); - cur_properties.stroke = selected.getAttribute("stroke"); - cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity"); - cur_properties.stroke_width = selected.getAttribute("stroke-width"); - cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray"); - cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin"); - cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap"); - } - - if (selected.tagName == "text") { - cur_text.font_size = selected.getAttribute("font-size"); - cur_text.font_family = selected.getAttribute("font-family"); - } - selectorManager.requestSelector(selected).showGrips(true); - - // This shouldn't be necessary as it was done on mouseDown... -// call("selected", [selected]); - } - // always recalculate dimensions to strip off stray identity transforms - recalculateAllSelectedDimensions(); - // if it was being dragged/resized - if (real_x != r_start_x || real_y != r_start_y) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - if(!selectedElements[i].firstChild) { - // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - selectorManager.requestSelector(selectedElements[i]).resize(); - } - } - } - // no change in position/size, so maybe we should move to pathedit - else { - var t = evt.target; - if (selectedElements[0].nodeName === "path" && selectedElements[1] == null) { - pathActions.select(selectedElements[0]); - } // if it was a path - // else, if it was selected and this is a shift-click, remove it from selection - else if (evt.shiftKey) { - if(tempJustSelected != t) { - canvas.removeFromSelection([t]); - } - } - } // no change in mouse position - - // Remove non-scaling stroke - if(svgedit.browser.supportsNonScalingStroke()) { - var elem = selectedElements[0]; - if (elem) { - elem.removeAttribute('style'); - svgedit.utilities.walkTree(elem, function(elem) { - elem.removeAttribute('style'); - }); - } - } - - } - return; - break; - case "zoom": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - } - var factor = evt.altKey?.5:2; - call("zoomed", { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y), - 'factor': factor - }); - return; - case "fhpath": - // Check that the path contains at least 2 points; a degenerate one-point path - // causes problems. - // Webkit ignores how we set the points attribute with commas and uses space - // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 - var coords = element.getAttribute('points'); - var commaIndex = coords.indexOf(','); - if (commaIndex >= 0) { - keep = coords.indexOf(',', commaIndex+1) >= 0; - } else { - keep = coords.indexOf(' ', coords.indexOf(' ')+1) >= 0; - } - if (keep) { - element = pathActions.smoothPolylineIntoPath(element); - } - break; - case "line": - var attrs = $(element).attr(["x1", "x2", "y1", "y2"]); - keep = (attrs.x1 != attrs.x2 || attrs.y1 != attrs.y2); - break; - case "foreignObject": - case "square": - case "rect": - case "image": - var attrs = $(element).attr(["width", "height"]); - // Image should be kept regardless of size (use inherit dimensions later) - keep = (attrs.width != 0 || attrs.height != 0) || current_mode === "image"; - break; - case "circle": - keep = (element.getAttribute('r') != 0); - break; - case "ellipse": - var attrs = $(element).attr(["rx", "ry"]); - keep = (attrs.rx != null || attrs.ry != null); - break; - case "fhellipse": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": (freehand.minx + freehand.maxx) / 2, - "cy": (freehand.miny + freehand.maxy) / 2, - "rx": (freehand.maxx - freehand.minx) / 2, - "ry": (freehand.maxy - freehand.miny) / 2, - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "fhrect": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": freehand.minx, - "y": freehand.miny, - "width": (freehand.maxx - freehand.minx), - "height": (freehand.maxy - freehand.miny), - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "text": - keep = true; - selectOnly([element]); - textActions.start(element); - break; - case "path": - // set element to null here so that it is not removed nor finalized - element = null; - // continue to be set to true so that mouseMove happens - started = true; - - var res = pathActions.mouseUp(evt, element, mouse_x, mouse_y); - element = res.element - keep = res.keep; - break; - case "pathedit": - keep = true; - element = null; - pathActions.mouseUp(evt); - break; - case "textedit": - keep = false; - element = null; - textActions.mouseUp(evt, mouse_x, mouse_y); - break; - case "rotate": - keep = true; - element = null; - current_mode = "select"; - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } - // perform recalculation to weed out any stray identity transforms that might get stuck - recalculateAllSelectedDimensions(); - call("changed", selectedElements); - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseUp", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y - }, true); - - $.each(ext_result, function(i, r) { - if(r) { - keep = r.keep || keep; - element = r.element; - started = r.started || started; - } - }); - - if (!keep && element != null) { - getCurrentDrawing().releaseId(getId()); - element.parentNode.removeChild(element); - element = null; - - var t = evt.target; - - // if this element is in a group, go up until we reach the top-level group - // just below the layer groups - // TODO: once we implement links, we also would have to check for <a> elements - while (t.parentNode.parentNode.tagName == "g") { - t = t.parentNode; - } - // if we are not in the middle of creating a path, and we've clicked on some shape, - // then go to Select mode. - // WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> - if ( (current_mode != "path" || !drawn_path) && - t.parentNode.id != "selectorParentGroup" && - t.id != "svgcanvas" && t.id != "svgroot") - { - // switch into "select" mode if we've clicked on an element - canvas.setMode("select"); - selectOnly([t], true); - } - - } else if (element != null) { - canvas.addedNew = true; - - if(useUnit) svgedit.units.convertAttrs(element); - - var ani_dur = .2, c_ani; - if(opac_ani.beginElement && element.getAttribute('opacity') != cur_shape.opacity) { - c_ani = $(opac_ani).clone().attr({ - to: cur_shape.opacity, - dur: ani_dur - }).appendTo(element); - try { - // Fails in FF4 on foreignObject - c_ani[0].beginElement(); - } catch(e){} - } else { - ani_dur = 0; - } - - // Ideally this would be done on the endEvent of the animation, - // but that doesn't seem to be supported in Webkit - setTimeout(function() { - if(c_ani) c_ani.remove(); - element.setAttribute("opacity", cur_shape.opacity); - element.setAttribute("style", "pointer-events:inherit"); - cleanupElement(element); - if(current_mode === "path") { - pathActions.toEditMode(element); - } else { - if(curConfig.selectNew) { - selectOnly([element], true); - } - } - // we create the insert command that is stored on the stack - // undo means to call cmd.unapply(), redo means to call cmd.apply() - addCommandToHistory(new InsertElementCommand(element)); - - call("changed",[element]); - }, ani_dur * 1000); - } - - start_transform = null; - }; - - var dblClick = function(evt) { - var evt_target = evt.target; - var parent = evt_target.parentNode; - - // Do nothing if already in current group - if(parent === current_group) return; - - var mouse_target = getMouseTarget(evt); - var tagName = mouse_target.tagName; - - if(tagName === 'text' && current_mode !== 'textedit') { - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ); - textActions.select(mouse_target, pt.x, pt.y); - } - - if((tagName === "g" || tagName === "a") && getRotationAngle(mouse_target)) { - // TODO: Allow method of in-group editing without having to do - // this (similar to editing rotated paths) - - // Ungroup and regroup - pushGroupProperties(mouse_target); - mouse_target = selectedElements[0]; - clearSelection(true); - } - // Reset context - if(current_group) { - leaveContext(); - } - - if((parent.tagName !== 'g' && parent.tagName !== 'a') || - parent === getCurrentDrawing().getCurrentLayer() || - mouse_target === selectorManager.selectorParentGroup) - { - // Escape from in-group edit - return; - } - setContext(mouse_target); - } - - // prevent links from being followed in the canvas - var handleLinkInCanvas = function(e) { - e.preventDefault(); - return false; - }; - - // Added mouseup to the container here. - // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. - $(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp); -// $(window).mouseup(mouseUp); - - $(container).bind("mousewheel DOMMouseScroll", function(e){ - if(!e.shiftKey) return; - e.preventDefault(); - - root_sctm = svgcontent.getScreenCTM().inverse(); - var pt = transformPoint( e.pageX, e.pageY, root_sctm ); - var bbox = { - 'x': pt.x, - 'y': pt.y, - 'width': 0, - 'height': 0 - }; - - // Respond to mouse wheel in IE/Webkit/Opera. - // (It returns up/dn motion in multiples of 120) - if(e.wheelDelta) { - if (e.wheelDelta >= 120) { - bbox.factor = 2; - } else if (e.wheelDelta <= -120) { - bbox.factor = .5; - } - } else if(e.detail) { - if (e.detail > 0) { - bbox.factor = .5; - } else if (e.detail < 0) { - bbox.factor = 2; - } - } - - if(!bbox.factor) return; - call("zoomed", bbox); - }); - -}()); - -// Function: preventClickDefault -// Prevents default browser click behaviour on the given element -// -// Parameters: -// img - The DOM element to prevent the cilck on -var preventClickDefault = function(img) { - $(img).click(function(e){e.preventDefault()}); -} - -// Group: Text edit functions -// Functions relating to editing text elements -var textActions = canvas.textActions = function() { - var curtext; - var textinput; - var cursor; - var selblock; - var blinker; - var chardata = []; - var textbb, transbb; - var matrix; - var last_x, last_y; - var allow_dbl; - - function setCursor(index) { - var empty = (textinput.value === ""); - $(textinput).focus(); - - if(!arguments.length) { - if(empty) { - index = 0; - } else { - if(textinput.selectionEnd !== textinput.selectionStart) return; - index = textinput.selectionEnd; - } - } - - var charbb; - charbb = chardata[index]; - if(!empty) { - textinput.setSelectionRange(index, index); - } - cursor = getElem("text_cursor"); - if (!cursor) { - cursor = document.createElementNS(svgns, "line"); - assignAttributes(cursor, { - 'id': "text_cursor", - 'stroke': "#333", - 'stroke-width': 1 - }); - cursor = getElem("selectorParentGroup").appendChild(cursor); - } - - if(!blinker) { - blinker = setInterval(function() { - var show = (cursor.getAttribute('display') === 'none'); - cursor.setAttribute('display', show?'inline':'none'); - }, 600); - - } - - - var start_pt = ptToScreen(charbb.x, textbb.y); - var end_pt = ptToScreen(charbb.x, (textbb.y + textbb.height)); - - assignAttributes(cursor, { - x1: start_pt.x, - y1: start_pt.y, - x2: end_pt.x, - y2: end_pt.y, - visibility: 'visible', - display: 'inline' - }); - - if(selblock) selblock.setAttribute('d', ''); - } - - function setSelection(start, end, skipInput) { - if(start === end) { - setCursor(end); - return; - } - - if(!skipInput) { - textinput.setSelectionRange(start, end); - } - - selblock = getElem("text_selectblock"); - if (!selblock) { - - selblock = document.createElementNS(svgns, "path"); - assignAttributes(selblock, { - 'id': "text_selectblock", - 'fill': "green", - 'opacity': .5, - 'style': "pointer-events:none" - }); - getElem("selectorParentGroup").appendChild(selblock); - } - - - var startbb = chardata[start]; - - var endbb = chardata[end]; - - cursor.setAttribute('visibility', 'hidden'); - - var tl = ptToScreen(startbb.x, textbb.y), - tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y), - bl = ptToScreen(startbb.x, textbb.y + textbb.height), - br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); - - - var dstr = "M" + tl.x + "," + tl.y - + " L" + tr.x + "," + tr.y - + " " + br.x + "," + br.y - + " " + bl.x + "," + bl.y + "z"; - - assignAttributes(selblock, { - d: dstr, - 'display': 'inline' - }); - } - - function getIndexFromPoint(mouse_x, mouse_y) { - // Position cursor here - var pt = svgroot.createSVGPoint(); - pt.x = mouse_x; - pt.y = mouse_y; - - // No content, so return 0 - if(chardata.length == 1) return 0; - // Determine if cursor should be on left or right of character - var charpos = curtext.getCharNumAtPosition(pt); - if(charpos < 0) { - // Out of text range, look at mouse coords - charpos = chardata.length - 2; - if(mouse_x <= chardata[0].x) { - charpos = 0; - } - } else if(charpos >= chardata.length - 2) { - charpos = chardata.length - 2; - } - var charbb = chardata[charpos]; - var mid = charbb.x + (charbb.width/2); - if(mouse_x > mid) { - charpos++; - } - return charpos; - } - - function setCursorFromPoint(mouse_x, mouse_y) { - setCursor(getIndexFromPoint(mouse_x, mouse_y)); - } - - function setEndSelectionFromPoint(x, y, apply) { - var i1 = textinput.selectionStart; - var i2 = getIndexFromPoint(x, y); - - var start = Math.min(i1, i2); - var end = Math.max(i1, i2); - setSelection(start, end, !apply); - } - - function screenToPt(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - out.x /= current_zoom; - out.y /= current_zoom; - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix.inverse()); - out.x = pt.x; - out.y = pt.y; - } - - return out; - } - - function ptToScreen(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix); - out.x = pt.x; - out.y = pt.y; - } - - out.x *= current_zoom; - out.y *= current_zoom; - - return out; - } - - function hideCursor() { - if(cursor) { - cursor.setAttribute('visibility', 'hidden'); - } - } - - function selectAll(evt) { - setSelection(0, curtext.textContent.length); - $(this).unbind(evt); - } - - function selectWord(evt) { - if(!allow_dbl || !curtext) return; - - var ept = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = ept.x * current_zoom, - mouse_y = ept.y * current_zoom; - var pt = screenToPt(mouse_x, mouse_y); - - var index = getIndexFromPoint(pt.x, pt.y); - var str = curtext.textContent; - var first = str.substr(0, index).replace(/[a-z0-9]+$/i, '').length; - var m = str.substr(index).match(/^[a-z0-9]+/i); - var last = (m?m[0].length:0) + index; - setSelection(first, last); - - // Set tripleclick - $(evt.target).click(selectAll); - setTimeout(function() { - $(evt.target).unbind('click', selectAll); - }, 300); - - } - - return { - select: function(target, x, y) { - curtext = target; - textActions.toEditMode(x, y); - }, - start: function(elem) { - curtext = elem; - textActions.toEditMode(); - }, - mouseDown: function(evt, mouse_target, start_x, start_y) { - var pt = screenToPt(start_x, start_y); - - textinput.focus(); - setCursorFromPoint(pt.x, pt.y); - last_x = start_x; - last_y = start_y; - - // TODO: Find way to block native selection - }, - mouseMove: function(mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - setEndSelectionFromPoint(pt.x, pt.y); - }, - mouseUp: function(evt, mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - - setEndSelectionFromPoint(pt.x, pt.y, true); - - // TODO: Find a way to make this work: Use transformed BBox instead of evt.target -// if(last_x === mouse_x && last_y === mouse_y -// && !svgedit.math.rectsIntersect(transbb, {x: pt.x, y: pt.y, width:0, height:0})) { -// textActions.toSelectMode(true); -// } - - if( - evt.target !== curtext - && mouse_x < last_x + 2 - && mouse_x > last_x - 2 - && mouse_y < last_y + 2 - && mouse_y > last_y - 2) { - - textActions.toSelectMode(true); - } - - }, - setCursor: setCursor, - toEditMode: function(x, y) { - 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'); - -// if(svgedit.browser.supportsEditableText()) { -// curtext.setAttribute('editable', 'simple'); -// return; -// } - - if(!arguments.length) { - setCursor(); - } else { - var pt = screenToPt(x, y); - setCursorFromPoint(pt.x, pt.y); - } - - setTimeout(function() { - allow_dbl = true; - }, 300); - }, - toSelectMode: function(selectElem) { - current_mode = "select"; - clearInterval(blinker); - blinker = null; - if(selblock) $(selblock).attr('display','none'); - if(cursor) $(cursor).attr('visibility','hidden'); - $(curtext).css('cursor', 'move'); - - if(selectElem) { - clearSelection(); - $(curtext).css('cursor', 'move'); - - call("selected", [curtext]); - addToSelection([curtext], true); - } - if(curtext && !curtext.textContent.length) { - // No content, so delete - canvas.deleteSelectedElements(); - } - - $(textinput).blur(); - - curtext = false; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.removeAttribute('editable'); -// } - }, - setInputElem: function(elem) { - textinput = elem; -// $(textinput).blur(hideCursor); - }, - clear: function() { - if(current_mode == "textedit") { - textActions.toSelectMode(); - } - }, - init: function(inputElem) { - if(!curtext) return; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.select(); -// return; -// } - - if(!curtext.parentNode) { - // Result of the ffClone, need to get correct element - curtext = selectedElements[0]; - selectorManager.requestSelector(curtext).showGrips(false); - } - - var str = curtext.textContent; - var len = str.length; - - var xform = curtext.getAttribute('transform'); - - textbb = svgedit.utilities.getBBox(curtext); - - matrix = xform?getMatrix(curtext):null; - - chardata = Array(len); - textinput.focus(); - - $(curtext).unbind('dblclick', selectWord).dblclick(selectWord); - - if(!len) { - var end = {x: textbb.x + (textbb.width/2), width: 0}; - } - - for(var i=0; i<len; i++) { - var start = curtext.getStartPositionOfChar(i); - var end = curtext.getEndPositionOfChar(i); - - if(!svgedit.browser.supportsGoodTextCharPos()) { - var offset = canvas.contentW * current_zoom; - start.x -= offset; - end.x -= offset; - - start.x /= current_zoom; - end.x /= current_zoom; - } - - // Get a "bbox" equivalent for each character. Uses the - // bbox data of the actual text for y, height purposes - - // TODO: Decide if y, width and height are actually necessary - chardata[i] = { - x: start.x, - y: textbb.y, // start.y? - width: end.x - start.x, - height: textbb.height - }; - } - - // Add a last bbox for cursor at end of text - chardata.push({ - x: end.x, - width: 0 - }); - setSelection(textinput.selectionStart, textinput.selectionEnd, true); - } - } -}(); - -// TODO: Migrate all of this code into path.js -// Group: Path edit functions -// Functions relating to editing path elements -var pathActions = canvas.pathActions = function() { - - var subpath = false; - var current_path; - var newPoint, firstCtrl; - - function resetD(p) { - p.setAttribute("d", pathActions.convertPath(p)); - } - - // TODO: Move into path.js - svgedit.path.Path.prototype.endChanges = function(text) { - if(svgedit.browser.isWebkit()) resetD(this.elem); - var cmd = new ChangeElementCommand(this.elem, {d: this.last_d}, text); - addCommandToHistory(cmd); - call("changed", [this.elem]); - } - - svgedit.path.Path.prototype.addPtsToSelection = function(indexes) { - if(!$.isArray(indexes)) indexes = [indexes]; - for(var i=0; i< indexes.length; i++) { - var index = indexes[i]; - var seg = this.segs[index]; - if(seg.ptgrip) { - if(this.selected_pts.indexOf(index) == -1 && index >= 0) { - this.selected_pts.push(index); - } - } - }; - this.selected_pts.sort(); - var i = this.selected_pts.length, - grips = new Array(i); - // Loop through points to be selected and highlight each - while(i--) { - var pt = this.selected_pts[i]; - var seg = this.segs[pt]; - seg.select(true); - grips[i] = seg.ptgrip; - } - // TODO: Correct this: - pathActions.canDeleteNodes = true; - - pathActions.closed_subpath = this.subpathIsClosed(this.selected_pts[0]); - - call("selected", grips); - } - - var current_path = null, - drawn_path = null, - hasMoved = false; - - // This function converts a polyline (created by the fh_path tool) into - // a path element and coverts every three line segments into a single bezier - // curve in an attempt to smooth out the free-hand - var smoothPolylineIntoPath = function(element) { - var points = element.points; - var N = points.numberOfItems; - if (N >= 4) { - // loop through every 3 points and convert to a cubic bezier curve segment - // - // NOTE: this is cheating, it means that every 3 points has the potential to - // be a corner instead of treating each point in an equal manner. In general, - // this technique does not look that good. - // - // I am open to better ideas! - // - // Reading: - // - http://www.efg2.com/Lab/Graphics/Jean-YvesQueinecBezierCurves.htm - // - http://www.codeproject.com/KB/graphics/BezierSpline.aspx?msg=2956963 - // - http://www.ian-ko.com/ET_GeoWizards/UserGuide/smooth.htm - // - http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html - var curpos = points.getItem(0), prevCtlPt = null; - var d = []; - d.push(["M",curpos.x,",",curpos.y," C"].join("")); - for (var i = 1; i <= (N-4); i += 3) { - var ct1 = points.getItem(i); - var ct2 = points.getItem(i+1); - var end = points.getItem(i+2); - - // if the previous segment had a control point, we want to smooth out - // the control points on both sides - if (prevCtlPt) { - var newpts = svgedit.path.smoothControlPoints( prevCtlPt, ct1, curpos ); - if (newpts && newpts.length == 2) { - var prevArr = d[d.length-1].split(','); - prevArr[2] = newpts[0].x; - prevArr[3] = newpts[0].y; - d[d.length-1] = prevArr.join(','); - ct1 = newpts[1]; - } - } - - d.push([ct1.x,ct1.y,ct2.x,ct2.y,end.x,end.y].join(',')); - - curpos = end; - prevCtlPt = ct2; - } - // handle remaining line segments - d.push("L"); - for(;i < N;++i) { - var pt = points.getItem(i); - d.push([pt.x,pt.y].join(",")); - } - d = d.join(" "); - - // create new path element - element = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "id": getId(), - "d": d, - "fill": "none" - } - }); - // No need to call "changed", as this is already done under mouseUp - } - return element; - }; - - return { - mouseDown: function(evt, mouse_target, start_x, start_y) { - if(current_mode === "path") { - mouse_x = start_x; - mouse_y = start_y; - - var x = mouse_x/current_zoom, - y = mouse_y/current_zoom, - stretchy = getElem("path_stretch_line"); - newPoint = [x, y]; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - mouse_x = snapToGrid(mouse_x); - mouse_y = snapToGrid(mouse_y); - } - - if (!stretchy) { - stretchy = document.createElementNS(svgns, "path"); - assignAttributes(stretchy, { - 'id': "path_stretch_line", - 'stroke': "#22C", - 'stroke-width': "0.5", - 'fill': 'none' - }); - stretchy = getElem("selectorParentGroup").appendChild(stretchy); - } - stretchy.setAttribute("display", "inline"); - - var keep = null; - - // if pts array is empty, create path element with M at current point - if (!drawn_path) { - d_attr = "M" + x + "," + y + " "; - drawn_path = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "d": d_attr, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - // set stretchy line to first point - stretchy.setAttribute('d', ['M', mouse_x, mouse_y, mouse_x, mouse_y].join(' ')); - var index = subpath ? svgedit.path.path.segs.length : 0; - svgedit.path.addPointGrip(index, mouse_x, mouse_y); - } - else { - // determine if we clicked on an existing point - var seglist = drawn_path.pathSegList; - var i = seglist.numberOfItems; - var FUZZ = 6/current_zoom; - var clickOnPoint = false; - while(i) { - i --; - var item = seglist.getItem(i); - var px = item.x, py = item.y; - // found a matching point - if ( x >= (px-FUZZ) && x <= (px+FUZZ) && y >= (py-FUZZ) && y <= (py+FUZZ) ) { - clickOnPoint = true; - break; - } - } - - // get path element that we are in the process of creating - var id = getId(); - - // Remove previous path object if previously created - svgedit.path.removePath_(id); - - var newpath = getElem(id); - - var len = seglist.numberOfItems; - // if we clicked on an existing point, then we are done this path, commit it - // (i,i+1) are the x,y that were clicked on - if (clickOnPoint) { - // if clicked on any other point but the first OR - // the first point was clicked on and there are less than 3 points - // then leave the path open - // otherwise, close the path - if (i <= 1 && len >= 2) { - // Create end segment - var abs_x = seglist.getItem(0).x; - var abs_y = seglist.getItem(0).y; - - - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(abs_x, abs_y); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - abs_x, - abs_y, - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - abs_x, - abs_y - ); - } - - var endseg = drawn_path.createSVGPathSegClosePath(); - seglist.appendItem(newseg); - seglist.appendItem(endseg); - } else if(len < 3) { - keep = false; - return keep; - } - $(stretchy).remove(); - - // this will signal to commit the path - element = newpath; - drawn_path = null; - started = false; - - if(subpath) { - if(svgedit.path.path.matrix) { - remapElement(newpath, {}, svgedit.path.path.matrix.inverse()); - } - - var new_d = newpath.getAttribute("d"); - var orig_d = $(svgedit.path.path.elem).attr("d"); - $(svgedit.path.path.elem).attr("d", orig_d + new_d); - $(newpath).remove(); - if(svgedit.path.path.matrix) { - svgedit.path.recalcRotatedPath(); - } - svgedit.path.path.init(); - pathActions.toEditMode(svgedit.path.path.elem); - svgedit.path.path.selectPt(); - return false; - } - } - // else, create a new point, update path element - else { - // Checks if current target or parents are #svgcontent - if(!$.contains(container, getMouseTarget(evt))) { - // Clicked outside canvas, so don't make point - console.log("Clicked outside canvas"); - return false; - } - - var num = drawn_path.pathSegList.numberOfItems; - var last = drawn_path.pathSegList.getItem(num -1); - var lastx = last.x, lasty = last.y; - - if(evt.shiftKey) { var xya = snapToAngle(lastx,lasty,x,y); x=xya.x; y=xya.y; } - - // Use the segment defined by stretchy - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(round(x), round(y)); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - round(x), - round(y), - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - s_seg.x2 / current_zoom, - s_seg.y2 / current_zoom - ); - } - - drawn_path.pathSegList.appendItem(newseg); - - x *= current_zoom; - y *= current_zoom; - - // set stretchy line to latest point - stretchy.setAttribute('d', ['M', x, y, x, y].join(' ')); - var index = num; - if(subpath) index += svgedit.path.path.segs.length; - svgedit.path.addPointGrip(index, x, y); - } -// keep = true; - } - - return; - } - - // TODO: Make sure current_path isn't null at this point - if(!svgedit.path.path) return; - - svgedit.path.path.storeD(); - - var id = evt.target.id; - if (id.substr(0,14) == "pathpointgrip_") { - // Select this point - var cur_pt = svgedit.path.path.cur_pt = parseInt(id.substr(14)); - svgedit.path.path.dragging = [start_x, start_y]; - var seg = svgedit.path.path.segs[cur_pt]; - - // only clear selection if shift is not pressed (otherwise, add - // node to selection) - if (!evt.shiftKey) { - if(svgedit.path.path.selected_pts.length <= 1 || !seg.selected) { - svgedit.path.path.clearSelection(); - } - svgedit.path.path.addPtsToSelection(cur_pt); - } else if(seg.selected) { - svgedit.path.path.removePtFromSelection(cur_pt); - } else { - svgedit.path.path.addPtsToSelection(cur_pt); - } - } else if(id.indexOf("ctrlpointgrip_") == 0) { - svgedit.path.path.dragging = [start_x, start_y]; - - var parts = id.split('_')[1].split('c'); - var cur_pt = parts[0]-0; - var ctrl_num = parts[1]-0; - svgedit.path.path.selectPt(cur_pt, ctrl_num); - } - - // Start selection box - if(!svgedit.path.path.dragging) { - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': start_x * current_zoom, - 'y': start_y * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - }, - mouseMove: function(evt, mouse_x, mouse_y) { - hasMoved = true; - if(current_mode === "path") { - if(!drawn_path) return; - var seglist = drawn_path.pathSegList; - var index = seglist.numberOfItems - 1; - - if(newPoint) { - // First point -// if(!index) return; - - // Set control points - var pointGrip1 = svgedit.path.addCtrlGrip('1c1'); - var pointGrip2 = svgedit.path.addCtrlGrip('0c2'); - - // dragging pointGrip1 - pointGrip1.setAttribute('cx', mouse_x); - pointGrip1.setAttribute('cy', mouse_y); - pointGrip1.setAttribute('display', 'inline'); - - var pt_x = newPoint[0]; - var pt_y = newPoint[1]; - - // set curve - var seg = seglist.getItem(index); - var cur_x = mouse_x / current_zoom; - var cur_y = mouse_y / current_zoom; - var alt_x = (pt_x + (pt_x - cur_x)); - var alt_y = (pt_y + (pt_y - cur_y)); - - if (!evt.altKey) { - pointGrip2.setAttribute('cx', alt_x * current_zoom); - pointGrip2.setAttribute('cy', alt_y * current_zoom); - pointGrip2.setAttribute('display', 'inline'); - } - - var ctrlLine = svgedit.path.getCtrlLine(1); - var ctrlLine2 = svgedit.path.getCtrlLine(2); - assignAttributes(ctrlLine, { - x1: mouse_x, - y1: mouse_y, - x2: pt_x, - y2: pt_y, - display: 'inline' - }); - - if (!evt.altKey) { - assignAttributes(ctrlLine2, { - x1: alt_x * current_zoom, - y1: alt_y * current_zoom, - x2: pt_x, - y2: pt_y, - display: 'inline' - }); - } - - if(index === 0) { - firstCtrl = [mouse_x, mouse_y]; - } else { - var last_x, last_y; - - var last = seglist.getItem(index - 1); - var last_x = last.x; - var last_y = last.y - - if(last.pathSegType === 6) { - last_x += (last_x - last.x2); - last_y += (last_y - last.y2); - } else if(firstCtrl) { - last_x = firstCtrl[0]/current_zoom; - last_y = firstCtrl[1]/current_zoom; - } - svgedit.path.replacePathSeg(6, index, [pt_x, pt_y, last_x, last_y, alt_x, alt_y], drawn_path); - } - } else { - var stretchy = getElem("path_stretch_line"); - if (stretchy) { - var prev = seglist.getItem(index); - if(prev.pathSegType === 6) { - var prev_x = prev.x + (prev.x - prev.x2); - var prev_y = prev.y + (prev.y - prev.y2); - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, prev_x * current_zoom, prev_y * current_zoom, mouse_x, mouse_y], stretchy); - } else if(firstCtrl) { - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, firstCtrl[0], firstCtrl[1], mouse_x, mouse_y], stretchy); - } else { - svgedit.path.replacePathSeg(4, 1, [mouse_x, mouse_y], stretchy); - } - } - } - return; - } - // if we are dragging a point, let's move it - if (svgedit.path.path.dragging) { - var pt = svgedit.path.getPointFromGrip({ - x: svgedit.path.path.dragging[0], - y: svgedit.path.path.dragging[1] - }, svgedit.path.path); - var mpt = svgedit.path.getPointFromGrip({ - x: mouse_x, - y: mouse_y - }, svgedit.path.path); - var diff_x = mpt.x - pt.x; - var diff_y = mpt.y - pt.y; - svgedit.path.path.dragging = [mouse_x, mouse_y]; - - if(svgedit.path.path.dragctrl) { - svgedit.path.path.moveCtrl(diff_x, diff_y); - } else { - svgedit.path.path.movePts(diff_x, diff_y); - } - } else { - svgedit.path.path.selected_pts = []; - svgedit.path.path.eachSeg(function(i) { - var seg = this; - if(!seg.next && !seg.prev) return; - - var item = seg.item; - var rbb = rubberBox.getBBox(); - - var pt = svgedit.path.getGripPt(seg); - var pt_bb = { - x: pt.x, - y: pt.y, - width: 0, - height: 0 - }; - - var sel = svgedit.math.rectsIntersect(rbb, pt_bb); - - this.select(sel); - //Note that addPtsToSelection is not being run - if(sel) svgedit.path.path.selected_pts.push(seg.index); - }); - - } - }, - mouseUp: function(evt, element, mouse_x, mouse_y) { - - // Create mode - if(current_mode === "path") { - newPoint = null; - if(!drawn_path) { - element = getElem(getId()); - started = false; - firstCtrl = null; - } - - return { - keep: true, - element: element - } - } - - // Edit mode - - if (svgedit.path.path.dragging) { - var last_pt = svgedit.path.path.cur_pt; - - svgedit.path.path.dragging = false; - svgedit.path.path.dragctrl = false; - svgedit.path.path.update(); - - - if(hasMoved) { - svgedit.path.path.endChanges("Move path point(s)"); - } - - if(!evt.shiftKey && !hasMoved) { - svgedit.path.path.selectPt(last_pt); - } - } - else if(rubberBox && rubberBox.getAttribute('display') != 'none') { - // Done with multi-node-select - rubberBox.setAttribute("display", "none"); - - if(rubberBox.getAttribute('width') <= 2 && rubberBox.getAttribute('height') <= 2) { - pathActions.toSelectMode(evt.target); - } - - // else, move back to select mode - } else { - pathActions.toSelectMode(evt.target); - } - hasMoved = false; - }, - toEditMode: function(element) { - svgedit.path.path = svgedit.path.getPath_(element); - current_mode = "pathedit"; - clearSelection(); - svgedit.path.path.show(true).update(); - svgedit.path.path.oldbbox = svgedit.utilities.getBBox(svgedit.path.path.elem); - subpath = false; - }, - toSelectMode: function(elem) { - var selPath = (elem == svgedit.path.path.elem); - current_mode = "select"; - svgedit.path.path.show(false); - current_path = false; - clearSelection(); - - if(svgedit.path.path.matrix) { - // Rotated, so may need to re-calculate the center - svgedit.path.recalcRotatedPath(); - } - - if(selPath) { - call("selected", [elem]); - addToSelection([elem], true); - } - }, - addSubPath: function(on) { - if(on) { - // Internally we go into "path" mode, but in the UI it will - // still appear as if in "pathedit" mode. - current_mode = "path"; - subpath = true; - } else { - pathActions.clear(true); - pathActions.toEditMode(svgedit.path.path.elem); - } - }, - select: function(target) { - if (current_path === target) { - pathActions.toEditMode(target); - current_mode = "pathedit"; - } // going into pathedit mode - else { - current_path = target; - } - }, - reorient: function() { - var elem = selectedElements[0]; - if(!elem) return; - var angle = getRotationAngle(elem); - if(angle == 0) return; - - var batchCmd = new BatchCommand("Reorient path"); - var changes = { - d: elem.getAttribute('d'), - transform: elem.getAttribute('transform') - }; - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - clearSelection(); - this.resetOrientation(elem); - - addCommandToHistory(batchCmd); - - // Set matrix to null - svgedit.path.getPath_(elem).show(false).matrix = null; - - this.clear(); - - addToSelection([elem], true); - call("changed", selectedElements); - }, - - clear: function(remove) { - current_path = null; - if (drawn_path) { - var elem = getElem(getId()); - $(getElem("path_stretch_line")).remove(); - $(elem).remove(); - $(getElem("pathpointgrip_container")).find('*').attr('display', 'none'); - drawn_path = firstCtrl = null; - started = false; - } else if (current_mode == "pathedit") { - this.toSelectMode(); - } - if(svgedit.path.path) svgedit.path.path.init().show(false); - }, - resetOrientation: function(path) { - if(path == null || path.nodeName != 'path') return false; - var tlist = getTransformList(path); - var m = transformListToTransform(tlist).matrix; - tlist.clear(); - path.removeAttribute("transform"); - var segList = path.pathSegList; - - // Opera/win/non-EN throws an error here. - // TODO: Find out why! - // Presumed fixed in Opera 10.5, so commented out for now - -// try { - var len = segList.numberOfItems; -// } catch(err) { -// var fixed_d = pathActions.convertPath(path); -// path.setAttribute('d', fixed_d); -// segList = path.pathSegList; -// var len = segList.numberOfItems; -// } - var last_x, last_y; - - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - var type = seg.pathSegType; - if(type == 1) continue; - var pts = []; - $.each(['',1,2], function(j, n) { - var x = seg['x'+n], y = seg['y'+n]; - if(x !== undefined && y !== undefined) { - var pt = transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); - } - }); - svgedit.path.replacePathSeg(type, i, pts, path); - } - - reorientGrads(path, m); - - - }, - zoomChange: function() { - if(current_mode == "pathedit") { - svgedit.path.path.update(); - } - }, - getNodePoint: function() { - var sel_pt = svgedit.path.path.selected_pts.length ? svgedit.path.path.selected_pts[0] : 1; - - var seg = svgedit.path.path.segs[sel_pt]; - return { - x: seg.item.x, - y: seg.item.y, - type: seg.type - }; - }, - linkControlPoints: function(linkPoints) { - svgedit.path.setLinkControlPoints(linkPoints); - }, - clonePathNode: function() { - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var segs = svgedit.path.path.segs; - - var i = sel_pts.length; - var nums = []; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.addSeg(pt); - - nums.push(pt + i); - nums.push(pt + i + 1); - } - svgedit.path.path.init().addPtsToSelection(nums); - - svgedit.path.path.endChanges("Clone path node(s)"); - }, - opencloseSubPath: function() { - var sel_pts = svgedit.path.path.selected_pts; - // Only allow one selected node for now - if(sel_pts.length !== 1) return; - - var elem = svgedit.path.path.elem; - var list = elem.pathSegList; - - var len = list.numberOfItems; - - var index = sel_pts[0]; - - var open_pt = null; - var start_item = null; - - // Check if subpath is already open - svgedit.path.path.eachSeg(function(i) { - if(this.type === 2 && i <= index) { - start_item = this.item; - } - if(i <= index) return true; - if(this.type === 2) { - // Found M first, so open - open_pt = i; - return false; - } else if(this.type === 1) { - // Found Z first, so closed - open_pt = false; - return false; - } - }); - - if(open_pt == null) { - // Single path, so close last seg - open_pt = svgedit.path.path.segs.length - 1; - } - - if(open_pt !== false) { - // Close this path - - // Create a line going to the previous "M" - var newseg = elem.createSVGPathSegLinetoAbs(start_item.x, start_item.y); - - var closer = elem.createSVGPathSegClosePath(); - if(open_pt == svgedit.path.path.segs.length - 1) { - list.appendItem(newseg); - list.appendItem(closer); - } else { - svgedit.path.insertItemBefore(elem, closer, open_pt); - svgedit.path.insertItemBefore(elem, newseg, open_pt); - } - - svgedit.path.path.init().selectPt(open_pt+1); - return; - } - - - - // M 1,1 L 2,2 L 3,3 L 1,1 z // open at 2,2 - // M 2,2 L 3,3 L 1,1 - - // M 1,1 L 2,2 L 1,1 z M 4,4 L 5,5 L6,6 L 5,5 z - // M 1,1 L 2,2 L 1,1 z [M 4,4] L 5,5 L(M)6,6 L 5,5 z - - var seg = svgedit.path.path.segs[index]; - - if(seg.mate) { - list.removeItem(index); // Removes last "L" - list.removeItem(index); // Removes the "Z" - svgedit.path.path.init().selectPt(index - 1); - return; - } - - var last_m, z_seg; - - // Find this sub-path's closing point and remove - for(var i=0; i<list.numberOfItems; i++) { - var item = list.getItem(i); - - if(item.pathSegType === 2) { - // Find the preceding M - last_m = i; - } else if(i === index) { - // Remove it - list.removeItem(last_m); -// index--; - } else if(item.pathSegType === 1 && index < i) { - // Remove the closing seg of this subpath - z_seg = i-1; - list.removeItem(i); - break; - } - } - - var num = (index - last_m) - 1; - - while(num--) { - svgedit.path.insertItemBefore(elem, list.getItem(last_m), z_seg); - } - - var pt = list.getItem(last_m); - - // Make this point the new "M" - svgedit.path.replacePathSeg(2, last_m, [pt.x, pt.y]); - - var i = index - - svgedit.path.path.init().selectPt(0); - }, - deletePathNode: function() { - if(!pathActions.canDeleteNodes) return; - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var i = sel_pts.length; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.deleteSeg(pt); - } - - // Cleanup - var cleanup = function() { - var segList = svgedit.path.path.elem.pathSegList; - var len = segList.numberOfItems; - - var remItems = function(pos, count) { - while(count--) { - segList.removeItem(pos); - } - } - - if(len <= 1) return true; - - while(len--) { - var item = segList.getItem(len); - if(item.pathSegType === 1) { - var prev = segList.getItem(len-1); - var nprev = segList.getItem(len-2); - if(prev.pathSegType === 2) { - remItems(len-1, 2); - cleanup(); - break; - } else if(nprev.pathSegType === 2) { - remItems(len-2, 3); - cleanup(); - break; - } - - } else if(item.pathSegType === 2) { - if(len > 0) { - var prev_type = segList.getItem(len-1).pathSegType; - // Path has M M - if(prev_type === 2) { - remItems(len-1, 1); - cleanup(); - break; - // Entire path ends with Z M - } else if(prev_type === 1 && segList.numberOfItems-1 === len) { - remItems(len, 1); - cleanup(); - break; - } - } - } - } - return false; - } - - cleanup(); - - // Completely delete a path with 1 or 0 segments - if(svgedit.path.path.elem.pathSegList.numberOfItems <= 1) { - pathActions.toSelectMode(svgedit.path.path.elem); - canvas.deleteSelectedElements(); - return; - } - - svgedit.path.path.init(); - - svgedit.path.path.clearSelection(); - - // TODO: Find right way to select point now - // path.selectPt(sel_pt); - if(window.opera) { // Opera repaints incorrectly - var cp = $(svgedit.path.path.elem); cp.attr('d',cp.attr('d')); - } - svgedit.path.path.endChanges("Delete path node(s)"); - }, - smoothPolylineIntoPath: smoothPolylineIntoPath, - setSegType: function(v) { - svgedit.path.path.setSegType(v); - }, - moveNode: function(attr, newValue) { - var sel_pts = svgedit.path.path.selected_pts; - if(!sel_pts.length) return; - - svgedit.path.path.storeD(); - - // Get first selected point - var seg = svgedit.path.path.segs[sel_pts[0]]; - var diff = {x:0, y:0}; - diff[attr] = newValue - seg.item[attr]; - - seg.move(diff.x, diff.y); - svgedit.path.path.endChanges("Move path point"); - }, - fixEnd: function(elem) { - // Adds an extra segment if the last seg before a Z doesn't end - // at its M point - // M0,0 L0,100 L100,100 z - var segList = elem.pathSegList; - var len = segList.numberOfItems; - var last_m; - for (var i = 0; i < len; ++i) { - var item = segList.getItem(i); - if(item.pathSegType === 2) { - last_m = item; - } - - if(item.pathSegType === 1) { - var prev = segList.getItem(i-1); - if(prev.x != last_m.x || prev.y != last_m.y) { - // Add an L segment here - var newseg = elem.createSVGPathSegLinetoAbs(last_m.x, last_m.y); - svgedit.path.insertItemBefore(elem, newseg, i); - // Can this be done better? - pathActions.fixEnd(elem); - break; - } - - } - } - if(svgedit.browser.isWebkit()) resetD(elem); - }, - // Convert a path to one with only absolute or relative values - convertPath: function(path, toRel) { - var segList = path.pathSegList; - var len = segList.numberOfItems; - var curx = 0, cury = 0; - var d = ""; - var last_m = null; - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - // if these properties are not in the segment, set them to zero - var x = seg.x || 0, - y = seg.y || 0, - x1 = seg.x1 || 0, - y1 = seg.y1 || 0, - x2 = seg.x2 || 0, - y2 = seg.y2 || 0; - - var type = seg.pathSegType; - var letter = pathMap[type]['to'+(toRel?'Lower':'Upper')+'Case'](); - - var addToD = function(pnts, more, last) { - var str = ''; - var more = more?' '+more.join(' '):''; - var last = last?' '+svgedit.units.shortFloat(last):''; - $.each(pnts, function(i, pnt) { - pnts[i] = svgedit.units.shortFloat(pnt); - }); - d += letter + pnts.join(' ') + more + last; - } - - switch (type) { - case 1: // z,Z closepath (Z/z) - d += "z"; - break; - case 12: // absolute horizontal line (H) - x -= curx; - case 13: // relative horizontal line (h) - if(toRel) { - curx += x; - letter = 'l'; - } else { - x += curx; - curx = x; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[x, cury]]); - break; - case 14: // absolute vertical line (V) - y -= cury; - case 15: // relative vertical line (v) - if(toRel) { - cury += y; - letter = 'l'; - } else { - y += cury; - cury = y; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[curx, y]]); - break; - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - x -= curx; - y -= cury; - case 5: // relative line (l) - case 3: // relative move (m) - // If the last segment was a "z", this must be relative to - if(last_m && segList.getItem(i-1).pathSegType === 1 && !toRel) { - curx = last_m[0]; - cury = last_m[1]; - } - - case 19: // relative smooth quad (t) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - if(type === 3) last_m = [curx, cury]; - - addToD([[x,y]]); - break; - case 6: // absolute cubic (C) - x -= curx; x1 -= curx; x2 -= curx; - y -= cury; y1 -= cury; y2 -= cury; - case 7: // relative cubic (c) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; x2 += curx; - y += cury; y1 += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x2,y2],[x,y]]); - break; - case 8: // absolute quad (Q) - x -= curx; x1 -= curx; - y -= cury; y1 -= cury; - case 9: // relative quad (q) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; - y += cury; y1 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x,y]]); - break; - case 10: // absolute elliptical arc (A) - x -= curx; - y -= cury; - case 11: // relative elliptical arc (a) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - addToD([[seg.r1,seg.r2]], [ - seg.angle, - (seg.largeArcFlag ? 1 : 0), - (seg.sweepFlag ? 1 : 0) - ],[x,y] - ); - break; - case 16: // absolute smooth cubic (S) - x -= curx; x2 -= curx; - y -= cury; y2 -= cury; - case 17: // relative smooth cubic (s) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x2 += curx; - y += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x2,y2],[x,y]]); - break; - } // switch on path segment type - } // for each segment - return d; - } - } -}(); -// end pathActions - -// Group: Serialization - -// Function: removeUnusedDefElems -// Looks at DOM elements inside the <defs> to see if they are referred to, -// removes them from the DOM if they are not. -// -// Returns: -// The amount of elements that were removed -var removeUnusedDefElems = this.removeUnusedDefElems = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if(!defs || !defs.length) return 0; - -// if(!defs.firstChild) return; - - var defelem_uses = [], - numRemoved = 0; - var attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']; - var alen = attrs.length; - - var all_els = svgcontent.getElementsByTagNameNS(svgns, '*'); - var all_len = all_els.length; - - for(var i=0; i<all_len; i++) { - var el = all_els[i]; - for(var j = 0; j < alen; j++) { - var ref = getUrlFromAttr(el.getAttribute(attrs[j])); - if(ref) { - defelem_uses.push(ref.substr(1)); - } - } - - // gradients can refer to other gradients - var href = getHref(el); - if (href && href.indexOf('#') === 0) { - defelem_uses.push(href.substr(1)); - } - }; - - var defelems = $(defs).find("linearGradient, radialGradient, filter, marker, svg, symbol"); - defelem_ids = [], - i = defelems.length; - while (i--) { - var defelem = defelems[i]; - var id = defelem.id; - if(defelem_uses.indexOf(id) < 0) { - // Not found, so remove (but remember) - removedElements[id] = defelem; - defelem.parentNode.removeChild(defelem); - numRemoved++; - } - } - - return numRemoved; -} - -// Function: svgCanvasToString -// Main function to set up the SVG content for output -// -// Returns: -// String containing the SVG image for output -this.svgCanvasToString = function() { - // keep calling it until there are none to remove - while (removeUnusedDefElems() > 0) {}; - - pathActions.clear(true); - - // Keep SVG-Edit comment on top - $.each(svgcontent.childNodes, function(i, node) { - if(i && node.nodeType === 8 && node.data.indexOf('Created with') >= 0) { - svgcontent.insertBefore(node, svgcontent.firstChild); - } - }); - - // Move out of in-group editing mode - if(current_group) { - leaveContext(); - selectOnly([current_group]); - } - - var naked_svgs = []; - - // Unwrap gsvg if it has no special attributes (only id and style) - $(svgcontent).find('g:data(gsvg)').each(function() { - var attrs = this.attributes; - var len = attrs.length; - for(var i=0; i<len; i++) { - if(attrs[i].nodeName == 'id' || attrs[i].nodeName == 'style') { - len--; - } - } - // No significant attributes, so ungroup - if(len <= 0) { - var svg = this.firstChild; - naked_svgs.push(svg); - $(this).replaceWith(svg); - } - }); - var output = this.svgToString(svgcontent, 0); - - // Rewrap gsvg - if(naked_svgs.length) { - $(naked_svgs).each(function() { - groupSvgElem(this); - }); - } - - return output; -}; - -// Function: svgToString -// Sub function ran on each SVG element to convert it to a string as desired -// -// Parameters: -// elem - The SVG element to convert -// indent - Integer with the amount of spaces to indent this tag -// -// Returns: -// String with the given element as an SVG tag -this.svgToString = function(elem, indent) { - var out = new Array(), toXml = svgedit.utilities.toXml; - var unit = curConfig.baseUnit; - var unit_re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - - if (elem) { - cleanupElement(elem); - var attrs = elem.attributes, - attr, - i, - childs = elem.childNodes; - - for (var i=0; i<indent; i++) out.push(" "); - out.push("<"); out.push(elem.nodeName); - if(elem.id === 'svgcontent') { - // Process root element separately - var res = getResolution(); - - var vb = ""; - // TODO: Allow this by dividing all values by current baseVal - // Note that this also means we should properly deal with this on import -// if(curConfig.baseUnit !== "px") { -// var unit = curConfig.baseUnit; -// var unit_m = svgedit.units.getTypeMap()[unit]; -// res.w = svgedit.units.shortFloat(res.w / unit_m) -// res.h = svgedit.units.shortFloat(res.h / unit_m) -// vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"'; -// res.w += unit; -// res.h += unit; -// } - - if(unit !== "px") { - res.w = svgedit.units.convertUnit(res.w, unit) + unit; - res.h = svgedit.units.convertUnit(res.h, unit) + unit; - } - - out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="'+svgns+'"'); - - var nsuris = {}; - - // Check elements for namespaces, add if found - $(elem).find('*').andSelf().each(function() { - var el = this; - $.each(this.attributes, function(i, attr) { - var uri = attr.namespaceURI; - if(uri && !nsuris[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml' ) { - nsuris[uri] = true; - out.push(" xmlns:" + nsMap[uri] + '="' + uri +'"'); - } - }); - }); - - var i = attrs.length; - var attr_names = ['width','height','xmlns','x','y','viewBox','id','overflow']; - while (i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - - // Namespaces have already been dealt with, so skip - if(attr.nodeName.indexOf('xmlns:') === 0) continue; - - // only serialize attributes we don't use internally - if (attrVal != "" && attr_names.indexOf(attr.localName) == -1) - { - - if(!attr.namespaceURI || nsMap[attr.namespaceURI]) { - out.push(' '); - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } else { - // Skip empty defs - if(elem.nodeName === 'defs' && !elem.firstChild) return; - - var moz_attrs = ['-moz-math-font-style', '_moz-math-font-style']; - for (var i=attrs.length-1; i>=0; i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - //remove bogus attributes added by Gecko - if (moz_attrs.indexOf(attr.localName) >= 0) continue; - if (attrVal != "") { - if(attrVal.indexOf('pointer-events') === 0) continue; - if(attr.localName === "class" && attrVal.indexOf('se_') === 0) continue; - out.push(" "); - if(attr.localName === 'd') attrVal = pathActions.convertPath(elem, true); - if(!isNaN(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal); - } else if(unit_re.test(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal) + unit; - } - - // Embed images when saving - if(save_options.apply - && elem.nodeName === 'image' - && attr.localName === 'href' - && save_options.images - && save_options.images === 'embed') - { - var img = encodableImages[attrVal]; - if(img) attrVal = img; - } - - // map various namespaces to our fixed namespace prefixes - // (the default xmlns attribute itself does not get a prefix) - if(!attr.namespaceURI || attr.namespaceURI == svgns || nsMap[attr.namespaceURI]) { - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } - - if (elem.hasChildNodes()) { - out.push(">"); - indent++; - var bOneLine = false; - - for (var i=0; i<childs.length; i++) - { - var child = childs.item(i); - switch(child.nodeType) { - case 1: // element node - out.push("\n"); - out.push(this.svgToString(childs.item(i), indent)); - break; - case 3: // text node - var str = child.nodeValue.replace(/^\s+|\s+$/g, ""); - if (str != "") { - bOneLine = true; - out.push(toXml(str) + ""); - } - break; - case 4: // cdata node - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<![CDATA["); - out.push(child.nodeValue); - out.push("]]>"); - break; - case 8: // comment - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<!--"); - out.push(child.data); - out.push("-->"); - break; - } // switch on node type - } - indent--; - if (!bOneLine) { - out.push("\n"); - for (var i=0; i<indent; i++) out.push(" "); - } - out.push("</"); out.push(elem.nodeName); out.push(">"); - } else { - out.push("/>"); - } - } - return out.join(''); -}; // end svgToString() - -// Function: embedImage -// Converts a given image file to a data URL when possible, then runs a given callback -// -// Parameters: -// val - String with the path/URL of the image -// callback - Optional function to run when image data is found, supplies the -// result (data URL or false) as first parameter. -this.embedImage = function(val, callback) { - - // load in the image and once it's loaded, get the dimensions - $(new Image()).load(function() { - // create a canvas the same size as the raster image - var canvas = document.createElement("canvas"); - canvas.width = this.width; - canvas.height = this.height; - // load the raster image into the canvas - canvas.getContext("2d").drawImage(this,0,0); - // retrieve the data: URL - try { - var urldata = ';svgedit_url=' + encodeURIComponent(val); - urldata = canvas.toDataURL().replace(';base64',urldata+';base64'); - encodableImages[val] = urldata; - } catch(e) { - encodableImages[val] = false; - } - last_good_img_url = val; - if(callback) callback(encodableImages[val]); - }).attr('src',val); -} - -// Function: setGoodImage -// Sets a given URL to be a "last good image" URL -this.setGoodImage = function(val) { - last_good_img_url = val; -} - -this.open = function() { - // Nothing by default, handled by optional widget/extension -}; - -// Function: save -// Serializes the current drawing into SVG XML text and returns it to the 'saved' handler. -// This function also includes the XML prolog. Clients of the SvgCanvas bind their save -// function to the 'saved' event. -// -// Returns: -// Nothing -this.save = function(opts) { - // remove the selected outline before serializing - clearSelection(); - // Update save options if provided - if(opts) $.extend(save_options, opts); - save_options.apply = true; - - // no need for doctype, see http://jwatt.org/svg/authoring/#doctype-declaration - var str = this.svgCanvasToString(); - call("saved", str); -}; - -// Function: rasterExport -// Generates a PNG Data URL based on the current image, then calls "exported" -// with an object including the string and any issues found -this.rasterExport = function() { - // remove the selected outline before serializing - clearSelection(); - - // Check for known CanVG issues - var issues = []; - - // Selector and notice - var issue_list = { - 'feGaussianBlur': uiStrings.exportNoBlur, - 'foreignObject': uiStrings.exportNoforeignObject, - '[stroke-dasharray]': uiStrings.exportNoDashArray - }; - var content = $(svgcontent); - - // Add font/text check if Canvas Text API is not implemented - if(!("font" in $('<canvas>')[0].getContext('2d'))) { - issue_list['text'] = uiStrings.exportNoText; - } - - $.each(issue_list, function(sel, descr) { - if(content.find(sel).length) { - issues.push(descr); - } - }); - - var str = this.svgCanvasToString(); - call("exported", {svg: str, issues: issues}); -}; - -// Function: getSvgString -// Returns the current drawing as raw SVG XML text. -// -// Returns: -// The current drawing as raw SVG XML text. -this.getSvgString = function() { - save_options.apply = false; - return this.svgCanvasToString(); -}; - -// Function: randomizeIds -// This function determines whether to use a nonce in the prefix, when -// generating IDs for future documents in SVG-Edit. -// -// Parameters: -// an opional boolean, which, if true, adds a nonce to the prefix. Thus -// svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true) -// -// if you're controlling SVG-Edit externally, and want randomized IDs, call -// this BEFORE calling svgCanvas.setSvgString -// -this.randomizeIds = function() { - if (arguments.length > 0 && arguments[0] == false) { - svgedit.draw.randomizeIds(false, getCurrentDrawing()); - } else { - svgedit.draw.randomizeIds(true, getCurrentDrawing()); - } -}; - -// Function: uniquifyElems -// Ensure each element has a unique ID -// -// Parameters: -// g - The parent element of the tree to give unique IDs -var uniquifyElems = this.uniquifyElems = function(g) { - var ids = {}; - // TODO: Handle markers and connectors. These are not yet re-identified properly - // as their referring elements do not get remapped. - // - // <marker id='se_marker_end_svg_7'/> - // <polyline id='svg_7' se:connector='svg_1 svg_6' marker-end='url(#se_marker_end_svg_7)'/> - // - // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute - // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute - var ref_elems = ["filter", "linearGradient", "pattern", "radialGradient", "symbol", "textPath", "use"]; - - svgedit.utilities.walkTree(g, function(n) { - // if it's an element node - if (n.nodeType == 1) { - // and the element has an ID - if (n.id) { - // and we haven't tracked this ID yet - if (!(n.id in ids)) { - // add this id to our map - ids[n.id] = {elem:null, attrs:[], hrefs:[]}; - } - ids[n.id]["elem"] = n; - } - - // now search for all attributes on this element that might refer - // to other elements - $.each(ref_attrs,function(i,attr) { - var attrnode = n.getAttributeNode(attr); - if (attrnode) { - // the incoming file has been sanitized, so we should be able to safely just strip off the leading # - var url = svgedit.utilities.getUrlFromAttr(attrnode.value), - refid = url ? url.substr(1) : null; - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["attrs"].push(attrnode); - } - } - }); - - // check xlink:href now - var href = svgedit.utilities.getHref(n); - // TODO: what if an <image> or <a> element refers to an element internally? - if(href && ref_elems.indexOf(n.nodeName) >= 0) - { - var refid = href.substr(1); - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["hrefs"].push(n); - } - } - } - }); - - // in ids, we now have a map of ids, elements and attributes, let's re-identify - for (var oldid in ids) { - if (!oldid) continue; - var elem = ids[oldid]["elem"]; - if (elem) { - var newid = getNextId(); - - // assign element its new id - elem.id = newid; - - // remap all url() attributes - var attrs = ids[oldid]["attrs"]; - var j = attrs.length; - while (j--) { - var attr = attrs[j]; - attr.ownerElement.setAttribute(attr.name, "url(#" + newid + ")"); - } - - // remap all href attributes - var hreffers = ids[oldid]["hrefs"]; - var k = hreffers.length; - while (k--) { - var hreffer = hreffers[k]; - svgedit.utilities.setHref(hreffer, "#"+newid); - } - } - } -} - -// Function setUseData -// Assigns reference data for each use element -var setUseData = this.setUseData = function(parent) { - var elems = $(parent); - - if(parent.tagName !== 'use') { - elems = elems.find('use'); - } - - elems.each(function() { - var id = getHref(this).substr(1); - var ref_elem = getElem(id); - if(!ref_elem) return; - $(this).data('ref', ref_elem); - if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') { - $(this).data('symbol', ref_elem).data('ref', ref_elem); - } - }); -} - -// Function convertGradients -// Converts gradients from userSpaceOnUse to objectBoundingBox -var convertGradients = this.convertGradients = function(elem) { - var elems = $(elem).find('linearGradient, radialGradient'); - if(!elems.length && svgedit.browser.isWebkit()) { - // Bug in webkit prevents regular *Gradient selector search - elems = $(elem).find('*').filter(function() { - return (this.tagName.indexOf('Gradient') >= 0); - }); - } - - elems.each(function() { - var grad = this; - if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { - // TODO: Support more than one element with this ref by duplicating parent grad - var elems = $(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - if(!elems.length) return; - - // get object's bounding box - var bb = svgedit.utilities.getBBox(elems[0]); - - // This will occur if the element is inside a <defs> or a <symbol>, - // in which we shouldn't need to convert anyway. - if(!bb) return; - - if(grad.tagName === 'linearGradient') { - var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); - - // If has transform, convert - var tlist = grad.gradientTransform.baseVal; - if(tlist && tlist.numberOfItems > 0) { - var m = transformListToTransform(tlist).matrix; - var pt1 = transformPoint(g_coords.x1, g_coords.y1, m); - var pt2 = transformPoint(g_coords.x2, g_coords.y2, m); - - g_coords.x1 = pt1.x; - g_coords.y1 = pt1.y; - g_coords.x2 = pt2.x; - g_coords.y2 = pt2.y; - grad.removeAttribute('gradientTransform'); - } - - $(grad).attr({ - x1: (g_coords.x1 - bb.x) / bb.width, - y1: (g_coords.y1 - bb.y) / bb.height, - x2: (g_coords.x2 - bb.x) / bb.width, - y2: (g_coords.y2 - bb.y) / bb.height - }); - grad.removeAttribute('gradientUnits'); - } else { - // Note: radialGradient elements cannot be easily converted - // because userSpaceOnUse will keep circular gradients, while - // objectBoundingBox will x/y scale the gradient according to - // its bbox. - - // For now we'll do nothing, though we should probably have - // the gradient be updated as the element is moved, as - // inkscape/illustrator do. - -// var g_coords = $(grad).attr(['cx', 'cy', 'r']); -// -// $(grad).attr({ -// cx: (g_coords.cx - bb.x) / bb.width, -// cy: (g_coords.cy - bb.y) / bb.height, -// r: g_coords.r -// }); -// -// grad.removeAttribute('gradientUnits'); - } - - - } - }); -} - -// Function: convertToGroup -// Converts selected/given <use> 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']); - - var vb = elem.getAttribute('viewBox'); - - if(vb) { - var nums = vb.split(' '); - pos.x -= +nums[0]; - pos.y -= +nums[1]; - } - - // Not ideal, but works - ts += " translate(" + (pos.x || 0) + "," + (pos.y || 0) + ")"; - - var prev = $elem.prev(); - - // Remove <use> element - batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].nextSibling, $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)); - } - - // Duplicate the gradients for Gecko, since they weren't included in the <symbol> - if(svgedit.browser.isGecko()) { - var dupeGrads = $(findDefs()).children('linearGradient,radialGradient,pattern').clone(); - $(g).append(dupeGrads); - } - - if (ts) { - g.setAttribute("transform", ts); - } - - var parent = elem.parentNode; - - uniquifyElems(g); - - // Put the dupe gradients back into <defs> (after uniquifying them) - if(svgedit.browser.isGecko()) { - $(findDefs()).append( $(g).find('linearGradient,radialGradient,pattern') ); - } - - // now give the g itself a new id - g.id = getNextId(); - - prev.after(g); - - if(parent) { - if(!has_more) { - // remove symbol/svg element - var nextSibling = elem.nextSibling; - parent.removeChild(elem); - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - } - - setUseData(g); - - if(svgedit.browser.isGecko()) { - convertGradients(findDefs()); - } else { - convertGradients(g); - } - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - // Give ID for any visible element missing one - $(g).find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - selectOnly([g]); - - var cm = pushGroupProperties(g, true); - if(cm) { - batchCmd.addSubCommand(cm); - } - - addCommandToHistory(batchCmd); - - } else { - console.log('Unexpected element to ungroup:', elem); - } -} - -// -// Function: setSvgString -// This function sets the current drawing as the input SVG XML. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the set was unsuccessful, true otherwise. -this.setSvgString = function(xmlString) { - try { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - var batchCmd = new BatchCommand("Change Source"); - - // remove old svg document - var nextSibling = svgcontent.nextSibling; - var oldzoom = svgroot.removeChild(svgcontent); - batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgroot)); - - // set new svg document - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svgcontent = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svgcontent = svgdoc.importNode(newDoc.documentElement, true); - } - - svgroot.appendChild(svgcontent); - var content = $(svgcontent); - - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - - // retrieve or set the nonce - var nonce = getCurrentDrawing().getNonce(); - if (nonce) { - call("setnonce", nonce); - } else { - call("unsetnonce"); - } - - // change image href vals if possible - content.find('image').each(function() { - var image = this; - preventClickDefault(image); - var val = getHref(this); - 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); - }); - - // Wrap child SVGs in group elements - content.find('svg').each(function() { - // Skip if it's in a <defs> - if($(this).closest('defs').length) return; - - uniquifyElems(this); - - // Check if it already has a gsvg group - var pa = this.parentNode; - if(pa.childNodes.length === 1 && pa.nodeName === 'g') { - $(pa).data('gsvg', this); - pa.id = pa.id || getNextId(); - } else { - groupSvgElem(this); - } - }); - - // For Firefox: Put all paint elems in defs - if(svgedit.browser.isGecko()) { - content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); - } - - - // Set ref element for <use> elements - - // TODO: This should also be done if the object is re-added through "redo" - setUseData(content); - - convertGradients(content[0]); - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - var attrs = { - id: 'svgcontent', - overflow: curConfig.show_outside_canvas?'visible':'hidden' - }; - - var percs = false; - - // determine proper size - if (content.attr("viewBox")) { - var vb = content.attr("viewBox").split(' '); - attrs.width = vb[2]; - attrs.height = vb[3]; - } - // handle content that doesn't have a viewBox - else { - $.each(['width', 'height'], function(i, dim) { - // Set to 100 if not given - var val = content.attr(dim); - - if(!val) val = '100%'; - - if((val+'').substr(-1) === "%") { - // Use user units if percentage given - percs = true; - } else { - attrs[dim] = convertToNum(dim, val); - } - }); - } - - // identify layers - identifyLayers(); - - // Give ID for any visible layer children missing one - content.children().find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - // Percentage width/height, so let's base it on visible elements - if(percs) { - var bb = getStrokedBBox(); - attrs.width = bb.width + bb.x; - attrs.height = bb.height + bb.y; - } - - // Just in case negative numbers are given or - // result from the percs calculation - if(attrs.width <= 0) attrs.width = 100; - if(attrs.height <= 0) attrs.height = 100; - - content.attr(attrs); - this.contentW = attrs['width']; - this.contentH = attrs['height']; - - batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); - // update root to the correct size - var changes = content.attr(["width", "height"]); - batchCmd.addSubCommand(new ChangeElementCommand(svgroot, changes)); - - // reset zoom - current_zoom = 1; - - // reset transform lists - svgedit.transformlist.resetListMap(); - clearSelection(); - svgedit.path.clearData(); - svgroot.appendChild(selectorManager.selectorParentGroup); - - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// Function: importSvgString -// This function imports the input SVG XML as a <symbol> in the <defs>, then adds a -// <use> to the current layer. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the import was unsuccessful, true otherwise. -// TODO: -// * properly handle if namespace is introduced by imported content (must add to svgcontent -// and update all prefixes in the imported node) -// * properly handle recalculating dimensions, recalculateDimensions() doesn't handle -// arbitrary transform lists, but makes some assumptions about how the transform list -// was obtained -// * import should happen in top-left of current zoomed viewport -this.importSvgString = function(xmlString) { - - try { - // Get unique ID - var uid = svgedit.utilities.encode64(xmlString.length + xmlString).substr(0,32); - - var useExisting = false; - - // Look for symbol and make sure symbol exists in image - if(import_ids[uid]) { - if( $(import_ids[uid].symbol).parents('#svgroot').length ) { - useExisting = true; - } - } - - var batchCmd = new BatchCommand("Import SVG"); - - if(useExisting) { - var symbol = import_ids[uid].symbol; - var ts = import_ids[uid].xform; - } else { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - // import new svg document into our document - var svg; - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svg = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svg = svgdoc.importNode(newDoc.documentElement, true); - } - - uniquifyElems(svg); - - 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) - vb[j] = +(vb[j]); - - // TODO: properly handle preserveAspectRatio - var canvasw = +svgcontent.getAttribute("width"), - canvash = +svgcontent.getAttribute("height"); - // imported content should be 1/3 of the canvas on its largest dimension - - if (innerh > innerw) { - var ts = "scale(" + (canvash/3)/vb[3] + ")"; - } - else { - var ts = "scale(" + (canvash/3)/vb[2] + ")"; - } - - // Hack to make recalculateDimensions understand how to scale - ts = "translate(0) " + ts + " translate(0)"; - - var symbol = svgdoc.createElementNS(svgns, "symbol"); - var defs = findDefs(); - - if(svgedit.browser.isGecko()) { - // Move all gradients into root for Firefox, workaround for this bug: - // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 - // TODO: Make this properly undo-able. - $(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); - } - - while (svg.firstChild) { - var first = svg.firstChild; - symbol.appendChild(first); - } - var attrs = svg.attributes; - for(var i=0; i < attrs.length; i++) { - var attr = attrs[i]; - symbol.setAttribute(attr.nodeName, attr.nodeValue); - } - symbol.id = getNextId(); - - // Store data - import_ids[uid] = { - symbol: symbol, - xform: ts - } - - findDefs().appendChild(symbol); - batchCmd.addSubCommand(new InsertElementCommand(symbol)); - } - - - var use_el = svgdoc.createElementNS(svgns, "use"); - use_el.id = getNextId(); - setHref(use_el, "#" + symbol.id); - - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(use_el); - batchCmd.addSubCommand(new InsertElementCommand(use_el)); - clearSelection(); - - use_el.setAttribute("transform", ts); - recalculateDimensions(use_el); - $(use_el).data('symbol', symbol).data('ref', symbol); - addToSelection([use_el]); - - // 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; - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// TODO(codedread): Move all layer/context functions in draw.js -// Layer API Functions - -// Group: Layers - -// Function: identifyLayers -// Updates layer system -var identifyLayers = canvas.identifyLayers = function() { - leaveContext(); - getCurrentDrawing().identifyLayers(); -}; - -// Function: createLayer -// Creates a new top-level layer in the drawing with the given name, sets the current layer -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.createLayer = function(name) { - var batchCmd = new BatchCommand("Create Layer"); - var new_layer = getCurrentDrawing().createLayer(name); - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [new_layer]); -}; - -// Function: cloneLayer -// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.cloneLayer = function(name) { - var batchCmd = new BatchCommand("Duplicate Layer"); - var new_layer = svgdoc.createElementNS(svgns, "g"); - var layer_title = svgdoc.createElementNS(svgns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - var current_layer = getCurrentDrawing().getCurrentLayer(); - $(current_layer).after(new_layer); - var childs = current_layer.childNodes; - for(var i = 0; i < childs.length; i++) { - var ch = childs[i]; - if(ch.localName == 'title') continue; - new_layer.appendChild(copyElem(ch)); - } - - clearSelection(); - identifyLayers(); - - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - canvas.setCurrentLayer(name); - call("changed", [new_layer]); -}; - -// Function: deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -this.deleteCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - var nextSibling = current_layer.nextSibling; - var parent = current_layer.parentNode; - current_layer = getCurrentDrawing().deleteCurrentLayer(); - if (current_layer) { - var batchCmd = new BatchCommand("Delete Layer"); - // store in our Undo History - batchCmd.addSubCommand(new RemoveElementCommand(current_layer, nextSibling, parent)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [parent]); - return true; - } - return false; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -this.setCurrentLayer = function(name) { - var result = getCurrentDrawing().setCurrentLayer(svgedit.utilities.toXml(name)); - if (result) { - clearSelection(); - } - return result; -}; - -// Function: renameCurrentLayer -// Renames the current layer. If the layer name is not valid (i.e. unique), then this function -// does nothing and returns false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// newname - the new name you want to give the current layer. This name must be unique -// among all layer names. -// -// Returns: -// true if the rename succeeded, false otherwise. -this.renameCurrentLayer = function(newname) { - 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 batchCmd = new BatchCommand("Rename Layer"); - // find the index of the layer - for (var 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 (var 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 ChangeElementCommand(child, {"#text":oldname})); - addCommandToHistory(batchCmd); - call("changed", [oldLayer]); - return true; - } - } - } - drawing.current_layer = oldLayer; - } - return false; -}; - -// Function: setCurrentLayerPosition -// Changes the position of the current layer to the new value. If the new index is not valid, -// this function does nothing and returns false, otherwise it returns true. This is an -// undo-able action. -// -// Parameters: -// newpos - The zero-based index of the new position of the layer. This should be between -// 0 and (number of layers - 1) -// -// Returns: -// true if the current layer position was changed, false otherwise. -this.setCurrentLayerPosition = function(newpos) { - var drawing = getCurrentDrawing(); - if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) { - for (var 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 MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent)); - - identifyLayers(); - canvas.setCurrentLayer(drawing.getLayerName(newpos)); - - return true; - } - } - - return false; -}; - -// Function: setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// true if the layer's visibility was set, false otherwise -this.setLayerVisibility = function(layername, bVisible) { - var drawing = getCurrentDrawing(); - var prevVisibility = drawing.getLayerVisibility(layername); - var layer = drawing.setLayerVisibility(layername, bVisible); - if (layer) { - var oldDisplay = prevVisibility ? 'inline' : 'none'; - addCommandToHistory(new ChangeElementCommand(layer, {'display':oldDisplay}, 'Layer Visibility')); - } else { - return false; - } - - if (layer == drawing.getCurrentLayer()) { - clearSelection(); - pathActions.clear(); - } -// call("changed", [selected]); - return true; -}; - -// Function: moveSelectedToLayer -// Moves the selected elements to layername. If the name is not a valid layer name, then false -// is returned. Otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer you want to which you want to move the selected elements -// -// Returns: -// true if the selected elements were moved to the layer, false otherwise. -this.moveSelectedToLayer = function(layername) { - // find the layer - var layer = null; - var drawing = getCurrentDrawing(); - for (var i = 0; i < drawing.getNumLayers(); ++i) { - if (drawing.getLayerName(i) == layername) { - layer = drawing.all_layers[i][1]; - break; - } - } - if (!layer) return false; - - var batchCmd = new BatchCommand("Move Elements to Layer"); - - // loop for each selected element and move it - var selElems = selectedElements; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (!elem) continue; - var oldNextSibling = elem.nextSibling; - // TODO: this is pretty brittle! - var oldLayer = elem.parentNode; - layer.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); - } - - addCommandToHistory(batchCmd); - - return true; -}; - -this.mergeLayer = function(skipHistory) { - var batchCmd = new 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 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 RemoveElementCommand(ch, chNextSibling, drawing.current_layer)); - drawing.current_layer.removeChild(ch); - continue; - } - var oldNextSibling = ch.nextSibling; - prev.appendChild(ch); - batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, drawing.current_layer)); - } - - // Remove current layer - svgcontent.removeChild(drawing.current_layer); - - if(!skipHistory) { - clearSelection(); - identifyLayers(); - - call("changed", [svgcontent]); - - addCommandToHistory(batchCmd); - } - - drawing.current_layer = prev; - return batchCmd; -} - -this.mergeAllLayers = function() { - var batchCmd = new 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)); - } - - clearSelection(); - identifyLayers(); - call("changed", [svgcontent]); - addCommandToHistory(batchCmd); -} - -// Function: leaveContext -// Return from a group context to the regular kind, make any previously -// disabled elements enabled again -var leaveContext = this.leaveContext = function() { - var len = disabled_elems.length; - if(len) { - for(var i = 0; i < len; i++) { - var elem = disabled_elems[i]; - - var orig = elData(elem, 'orig_opac'); - if(orig !== 1) { - elem.setAttribute('opacity', orig); - } else { - elem.removeAttribute('opacity'); - } - elem.setAttribute('style', 'pointer-events: inherit'); - } - disabled_elems = []; - clearSelection(true); - call("contextset", null); - } - current_group = null; -} - -// Function: setContext -// Set the current context (for in-group editing) -var setContext = this.setContext = function(elem) { - leaveContext(); - if(typeof elem === 'string') { - elem = getElem(elem); - } - - // Edit inside this group - current_group = elem; - - // Disable other elements - $(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function() { - var opac = this.getAttribute('opacity') || 1; - // Store the original's opacity - elData(this, 'orig_opac', opac); - this.setAttribute('opacity', opac * .33); - this.setAttribute('style', 'pointer-events: none'); - disabled_elems.push(this); - }); - - clearSelection(); - call("contextset", current_group); -} - -// Group: Document functions - -// Function: clear -// Clears the current document. This is not an undoable action. -this.clear = function() { - pathActions.clear(); - - clearSelection(); - - // clear the svgcontent node - canvas.clearSvgContentElement(); - - // create new document - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent); - - // create empty first layer - canvas.createLayer("Layer 1"); - - // clear the undo stack - canvas.undoMgr.resetUndoStack(); - - // reset the selector manager - selectorManager.initGroup(); - - // reset the rubber band box - rubberBox = selectorManager.getRubberBandBox(); - - call("cleared"); -}; - -// Function: linkControlPoints -// Alias function -this.linkControlPoints = pathActions.linkControlPoints; - -// Function: getContentElem -// Returns the content DOM element -this.getContentElem = function() { return svgcontent; }; - -// Function: getRootElem -// Returns the root DOM element -this.getRootElem = function() { return svgroot; }; - -// Function: getSelectedElems -// Returns the array with selected DOM elements -this.getSelectedElems = function() { return selectedElements; }; - -// Function: getResolution -// Returns the current dimensions and zoom level in an object -var getResolution = this.getResolution = function() { -// var vb = svgcontent.getAttribute("viewBox").split(' '); -// return {'w':vb[2], 'h':vb[3], 'zoom': current_zoom}; - - var width = svgcontent.getAttribute("width")/current_zoom; - var height = svgcontent.getAttribute("height")/current_zoom; - - return { - 'w': width, - 'h': height, - 'zoom': current_zoom - }; -}; - -// Function: getZoom -// Returns the current zoom level -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: 2082 $)"; -}; - -// Function: setUiStrings -// Update interface strings with given values -// -// Parameters: -// strs - Object with strings (see uiStrings for examples) -this.setUiStrings = function(strs) { - $.extend(uiStrings, strs.notification); -} - -// Function: setConfig -// Update configuration options with given values -// -// Parameters: -// opts - Object with options (see curConfig for examples) -this.setConfig = function(opts) { - $.extend(curConfig, opts); -} - -// Function: getTitle -// 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<childs.length; i++) { - if(childs[i].nodeName == 'title') { - return childs[i].textContent; - } - } - return ''; -} - -// Function: setGroupTitle -// Sets the group/SVG's title content -// TODO: Combine this with setDocumentTitle -this.setGroupTitle = function(val) { - var elem = selectedElements[0]; - elem = $(elem).data('gsvg') || elem; - - var ts = $(elem).children('title'); - - var batchCmd = new BatchCommand("Set Label"); - - if(!val.length) { - // Remove title element - var tsNextSibling = ts.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)); - ts.remove(); - } else if(ts.length) { - // Change title contents - var title = ts[0]; - batchCmd.addSubCommand(new ChangeElementCommand(title, {'#text': title.textContent})); - title.textContent = val; - } else { - // Add title element - title = svgdoc.createElementNS(svgns, "title"); - title.textContent = val; - $(elem).prepend(title); - batchCmd.addSubCommand(new InsertElementCommand(title)); - } - - addCommandToHistory(batchCmd); -} - -// Function: getDocumentTitle -// Returns the current document title or an empty string if not found -this.getDocumentTitle = function() { - return canvas.getTitle(svgcontent); -} - -// Function: setDocumentTitle -// Adds/updates a title element for the document with the given name. -// This is an undoable action -// -// Parameters: -// newtitle - String with the new title -this.setDocumentTitle = function(newtitle) { - var childs = svgcontent.childNodes, doc_title = false, old_title = ''; - - var batchCmd = new BatchCommand("Change Image Title"); - - for (var i=0; i<childs.length; i++) { - if(childs[i].nodeName == 'title') { - doc_title = childs[i]; - old_title = doc_title.textContent; - break; - } - } - if(!doc_title) { - doc_title = svgdoc.createElementNS(svgns, "title"); - svgcontent.insertBefore(doc_title, svgcontent.firstChild); - } - - if(newtitle.length) { - doc_title.textContent = newtitle; - } else { - // No title given, so element is not necessary - doc_title.parentNode.removeChild(doc_title); - } - batchCmd.addSubCommand(new ChangeElementCommand(doc_title, {'#text': old_title})); - addCommandToHistory(batchCmd); -} - -// Function: getEditorNS -// Returns the editor's namespace URL, optionally adds it to root element -// -// Parameters: -// add - Boolean to indicate whether or not to add the namespace value -this.getEditorNS = function(add) { - if(add) { - svgcontent.setAttribute('xmlns:se', se_ns); - } - return se_ns; -} - -// Function: setResolution -// Changes the document's dimensions to the given size -// -// Parameters: -// x - Number with the width of the new dimensions in user units. -// Can also be the string "fit" to indicate "fit to content" -// y - Number with the height of the new dimensions in user units. -// -// Returns: -// Boolean to indicate if resolution change was succesful. -// It will fail on "fit to content" option with no content to fit to. -this.setResolution = function(x, y) { - var res = getResolution(); - var w = res.w, h = res.h; - var batchCmd; - - if(x == 'fit') { - // Get bounding box - var bbox = getStrokedBBox(); - - if(bbox) { - batchCmd = new BatchCommand("Fit Canvas to Content"); - var visEls = getVisibleElements(); - addToSelection(visEls); - var dx = [], dy = []; - $.each(visEls, function(i, item) { - dx.push(bbox.x*-1); - dy.push(bbox.y*-1); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - clearSelection(); - - x = Math.round(bbox.width); - y = Math.round(bbox.height); - } else { - return false; - } - } - if (x != w || y != h) { - var handle = svgroot.suspendRedraw(1000); - if(!batchCmd) { - batchCmd = new BatchCommand("Change Image Dimensions"); - } - - x = convertToNum('width', x); - y = convertToNum('height', y); - - svgcontent.setAttribute('width', x); - svgcontent.setAttribute('height', y); - - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"width":w, "height":h})); - - svgcontent.setAttribute("viewBox", [0, 0, x/current_zoom, y/current_zoom].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"viewBox": ["0 0", w, h].join(' ')})); - - addCommandToHistory(batchCmd); - svgroot.unsuspendRedraw(handle); - call("changed", [svgcontent]); - } - return true; -}; - -// Function: getOffset -// Returns an object with x, y values indicating the svgcontent element's -// position in the editor's canvas. -this.getOffset = function() { - return $(svgcontent).attr(['x', 'y']); -} - -// Function: setBBoxZoom -// Sets the zoom level on the canvas-side based on the given value -// -// Parameters: -// val - Bounding box object to zoom to or string indicating zoom option -// editor_w - Integer with the editor's workarea box's width -// editor_h - Integer with the editor's workarea box's height -this.setBBoxZoom = function(val, editor_w, editor_h) { - var spacer = .85; - var bb; - var calcZoom = function(bb) { - if(!bb) return false; - var w_zoom = Math.round((editor_w / bb.width)*100 * spacer)/100; - var h_zoom = Math.round((editor_h / bb.height)*100 * spacer)/100; - var zoomlevel = Math.min(w_zoom,h_zoom); - canvas.setZoom(zoomlevel); - return {'zoom': zoomlevel, 'bbox': bb}; - } - - if(typeof val == 'object') { - bb = val; - if(bb.width == 0 || bb.height == 0) { - var newzoom = bb.zoom?bb.zoom:current_zoom * bb.factor; - canvas.setZoom(newzoom); - return {'zoom': current_zoom, 'bbox': bb}; - } - return calcZoom(bb); - } - - switch (val) { - case 'selection': - if(!selectedElements[0]) return; - var sel_elems = $.map(selectedElements, function(n){ if(n) return n; }); - bb = getStrokedBBox(sel_elems); - break; - case 'canvas': - var res = getResolution(); - spacer = .95; - bb = {width:res.w, height:res.h ,x:0, y:0}; - break; - case 'content': - bb = getStrokedBBox(); - break; - case 'layer': - bb = getStrokedBBox(getVisibleElements(getCurrentDrawing().getCurrentLayer())); - break; - default: - return; - } - return calcZoom(bb); -} - -// Function: setZoom -// Sets the zoom to the given level -// -// Parameters: -// zoomlevel - Float indicating the zoom level to change to -this.setZoom = function(zoomlevel) { - var res = getResolution(); - svgcontent.setAttribute("viewBox", "0 0 " + res.w/zoomlevel + " " + res.h/zoomlevel); - current_zoom = zoomlevel; - $.each(selectedElements, function(i, elem) { - if(!elem) return; - selectorManager.requestSelector(elem).resize(); - }); - pathActions.zoomChange(); - runExtensions("zoomChanged", zoomlevel); -} - -// Function: getMode -// Returns the current editor mode string -this.getMode = function() { - return current_mode; -}; - -// Function: setMode -// Sets the editor's mode to the given string -// -// Parameters: -// name - String with the new mode to change to -this.setMode = function(name) { - pathActions.clear(true); - textActions.clear(); - $("#workarea").attr("class", name); - cur_properties = (selectedElements[0] && selectedElements[0].nodeName == 'text') ? cur_text : cur_shape; - current_mode = name; -}; - -// Group: Element Styling - -// Function: getColor -// Returns the current fill/stroke option -this.getColor = function(type) { - return cur_properties[type]; -}; - -// Function: setColor -// Change the current stroke/fill color/gradient value -// -// Parameters: -// type - String indicating fill or stroke -// val - The value to set the stroke attribute to -// preventUndo - Boolean indicating whether or not this should be and undoable option -this.setColor = function(type, val, preventUndo) { - cur_shape[type] = val; - cur_properties[type + '_paint'] = {type:"solidColor"}; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else { - if(type == 'fill') { - if(elem.tagName != "polyline" && elem.tagName != "line") { - elems.push(elem); - } - } else { - elems.push(elem); - } - } - } - } - if (elems.length > 0) { - if (!preventUndo) { - changeSelectedAttribute(type, val, elems); - call("changed", elems); - } else - changeSelectedAttributeNoUndo(type, val, elems); - } -} - - -// Function: findDefs -// Return the document's <defs> element, create it first if necessary -var findDefs = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - defs = svgdoc.createElementNS(svgns, "defs" ); - if(svgcontent.firstChild) { - // first child is a comment, so call nextSibling - svgcontent.insertBefore( defs, svgcontent.firstChild.nextSibling); - } else { - svgcontent.appendChild(defs); - } - } - return defs; -}; - -// Function: setGradient -// Apply the current gradient to selected element's fill or stroke -// -// Parameters -// type - String indicating "fill" or "stroke" to apply to an element -var setGradient = this.setGradient = function(type) { - if(!cur_properties[type + '_paint'] || cur_properties[type + '_paint'].type == "solidColor") return; - var grad = canvas[type + 'Grad']; - // find out if there is a duplicate gradient already in the defs - var duplicate_grad = findDuplicateGradient(grad); - var defs = findDefs(); - // no duplicate found, so import gradient into defs - if (!duplicate_grad) { - var orig_grad = grad; - grad = defs.appendChild( svgdoc.importNode(grad, true) ); - // get next id and set it on the grad - grad.id = getNextId(); - } - else { // use existing gradient - grad = duplicate_grad; - } - canvas.setColor(type, "url(#" + grad.id + ")"); -} - -// Function: findDuplicateGradient -// Check if exact gradient already exists -// -// Parameters: -// grad - The gradient DOM element to compare to others -// -// Returns: -// The existing gradient if found, null if not -var findDuplicateGradient = function(grad) { - var defs = findDefs(); - var existing_grads = $(defs).find("linearGradient, radialGradient"); - var i = existing_grads.length; - var rad_attrs = ['r','cx','cy','fx','fy']; - while (i--) { - var og = existing_grads[i]; - if(grad.tagName == "linearGradient") { - if (grad.getAttribute('x1') != og.getAttribute('x1') || - grad.getAttribute('y1') != og.getAttribute('y1') || - grad.getAttribute('x2') != og.getAttribute('x2') || - grad.getAttribute('y2') != og.getAttribute('y2')) - { - continue; - } - } else { - var grad_attrs = $(grad).attr(rad_attrs); - var og_attrs = $(og).attr(rad_attrs); - - var diff = false; - $.each(rad_attrs, function(i, attr) { - if(grad_attrs[attr] != og_attrs[attr]) diff = true; - }); - - if(diff) continue; - } - - // else could be a duplicate, iterate through stops - var stops = grad.getElementsByTagNameNS(svgns, "stop"); - var ostops = og.getElementsByTagNameNS(svgns, "stop"); - - if (stops.length != ostops.length) { - continue; - } - - var j = stops.length; - while(j--) { - var stop = stops[j]; - var ostop = ostops[j]; - - if (stop.getAttribute('offset') != ostop.getAttribute('offset') || - stop.getAttribute('stop-opacity') != ostop.getAttribute('stop-opacity') || - stop.getAttribute('stop-color') != ostop.getAttribute('stop-color')) - { - break; - } - } - - if (j == -1) { - return og; - } - } // for each gradient in defs - - return null; -}; - -function reorientGrads(elem, m) { - var bb = svgedit.utilities.getBBox(elem); - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = elem.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - var grad = getRefElem(attrVal); - if(grad.tagName === 'linearGradient') { - var x1 = grad.getAttribute('x1') || 0; - var y1 = grad.getAttribute('y1') || 0; - var x2 = grad.getAttribute('x2') || 1; - var y2 = grad.getAttribute('y2') || 0; - - // Convert to USOU points - x1 = (bb.width * x1) + bb.x; - y1 = (bb.height * y1) + bb.y; - x2 = (bb.width * x2) + bb.x; - y2 = (bb.height * y2) + bb.y; - - // Transform those points - var pt1 = transformPoint(x1, y1, m); - var pt2 = transformPoint(x2, y2, m); - - // Convert back to BB points - var g_coords = {}; - - g_coords.x1 = (pt1.x - bb.x) / bb.width; - g_coords.y1 = (pt1.y - bb.y) / bb.height; - g_coords.x2 = (pt2.x - bb.x) / bb.width; - g_coords.y2 = (pt2.y - bb.y) / bb.height; - - var newgrad = grad.cloneNode(true); - $(newgrad).attr(g_coords); - - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - elem.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - } - } -} - -// Function: setPaint -// Set a color/gradient to a fill/stroke -// -// Parameters: -// type - String with "fill" or "stroke" -// paint - The jGraduate paint object to apply -this.setPaint = function(type, paint) { - // make a copy - var p = new $.jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha/100, true); - - // now set the current paint object - cur_properties[type + '_paint'] = p; - switch ( p.type ) { - case "solidColor": - - if (p.solidColor != "none") { - this.setColor(type, "#"+p.solidColor) - } - else { - this.setColor(type, "none"); - var selector = (type == "fill") ? "#fill_color rect" : "#stroke_color rect" - document.querySelector(selector).setAttribute('fill', 'transparent'); - } - break; - case "linearGradient": - case "radialGradient": - canvas[type + 'Grad'] = p[p.type]; - setGradient(type); - break; - default: -// console.log("none!"); - } -}; - - -// this.setStrokePaint = function(p) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setStrokeOpacity(p.alpha/100); -// -// // now set the current paint object -// cur_properties.stroke_paint = p; -// switch ( p.type ) { -// case "solidColor": -// this.setColor('stroke', p.solidColor != "none" ? "#"+p.solidColor : "none");; -// break; -// case "linearGradient" -// case "radialGradient" -// canvas.strokeGrad = p[p.type]; -// setGradient(type); -// default: -// // console.log("none!"); -// } -// }; -// -// this.setFillPaint = function(p, addGrad) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setFillOpacity(p.alpha/100, true); -// -// // now set the current paint object -// cur_properties.fill_paint = p; -// if (p.type == "solidColor") { -// this.setColor('fill', p.solidColor != "none" ? "#"+p.solidColor : "none"); -// } -// else if(p.type == "linearGradient") { -// canvas.fillGrad = p.linearGradient; -// if(addGrad) setGradient(); -// } -// else if(p.type == "radialGradient") { -// canvas.fillGrad = p.radialGradient; -// if(addGrad) setGradient(); -// } -// else { -// // console.log("none!"); -// } -// }; - -// Function: getStrokeWidth -// Returns the current stroke-width value -this.getStrokeWidth = function() { - return cur_properties.stroke_width; -}; - -// Function: setStrokeWidth -// Sets the stroke width for the current selected elements -// When attempting to set a line's width to 0, this changes it to 1 instead -// -// Parameters: -// val - A Float indicating the new stroke width value -this.setStrokeWidth = function(val) { - if(val == 0 && ['line', 'path'].indexOf(current_mode) >= 0) { - canvas.setStrokeWidth(1); - return; - } - cur_properties.stroke_width = val; - - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute("stroke-width", val, elems); - call("changed", selectedElements); - } -}; - -// Function: setStrokeAttr -// Set the given stroke-related attribute the given value for selected elements -// -// Parameters: -// attr - String with the attribute name -// val - String or number with the attribute value -this.setStrokeAttr = function(attr, val) { - cur_shape[attr.replace('-','_')] = val; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute(attr, val, elems); - call("changed", selectedElements); - } -}; - -// Function: getStyle -// Returns current style options -this.getStyle = function() { - return cur_shape; -} - -// Function: getOpacity -// Returns the current opacity -this.getOpacity = function() { - return cur_shape.opacity; -}; - -// Function: setOpacity -// Sets the given opacity to the current selected elements -this.setOpacity = function(val) { - cur_shape.opacity = val; - changeSelectedAttribute("opacity", val); -}; - -// Function: getOpacity -// Returns the current fill opacity -this.getFillOpacity = function() { - return cur_shape.fill_opacity; -}; - -// Function: getStrokeOpacity -// Returns the current stroke opacity -this.getStrokeOpacity = function() { - return cur_shape.stroke_opacity; -}; - -// Function: setPaintOpacity -// Sets the current fill/stroke opacity -// -// Parameters: -// type - String with "fill" or "stroke" -// val - Float with the new opacity value -// preventUndo - Boolean indicating whether or not this should be an undoable action -this.setPaintOpacity = function(type, val, preventUndo) { - cur_shape[type + '_opacity'] = val; - if (!preventUndo) - changeSelectedAttribute(type + "-opacity", val); - else - changeSelectedAttributeNoUndo(type + "-opacity", val); -}; - -// Function: getBlur -// Gets the stdDeviation blur value of the given element -// -// Parameters: -// elem - The element to check the blur value for -this.getBlur = function(elem) { - var val = 0; -// var elem = selectedElements[0]; - - if(elem) { - var filter_url = elem.getAttribute('filter'); - if(filter_url) { - var blur = getElem(elem.id + '_blur'); - if(blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } - } - } - return val; -}; - -(function() { - var cur_command = null; - var filter = null; - var filterHidden = false; - - // Function: setBlurNoUndo - // Sets the stdDeviation blur value on the selected element without being undoable - // - // Parameters: - // val - The new stdDeviation value - canvas.setBlurNoUndo = function(val) { - if(!filter) { - canvas.setBlur(val); - return; - } - if(val === 0) { - // Don't change the StdDev, as that will hide the element. - // Instead, just remove the value for "filter" - changeSelectedAttributeNoUndo("filter", ""); - filterHidden = true; - } else { - var elem = selectedElements[0]; - if(filterHidden) { - changeSelectedAttributeNoUndo("filter", 'url(#' + elem.id + '_blur)'); - } - if(svgedit.browser.isWebkit()) { - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); - } - changeSelectedAttributeNoUndo("stdDeviation", val, [filter.firstChild]); - canvas.setBlurOffsets(filter, val); - } - } - - function finishChange() { - var bCmd = canvas.undoMgr.finishUndoableChange(); - cur_command.addSubCommand(bCmd); - addCommandToHistory(cur_command); - cur_command = null; - filter = null; - } - - // Function: setBlurOffsets - // Sets the x, y, with, height values of the filter element in order to - // make the blur not be clipped. Removes them if not neeeded - // - // Parameters: - // filter - The filter DOM element to update - // stdDev - The standard deviation value on which to base the offset size - canvas.setBlurOffsets = function(filter, stdDev) { - if(stdDev > 3) { - // TODO: Create algorithm here where size is based on expected blur - assignAttributes(filter, { - x: '-50%', - y: '-50%', - width: '200%', - height: '200%' - }, 100); - } else { - // Removing these attributes hides text in Chrome (see Issue 579) - if(!svgedit.browser.isWebkit()) { - filter.removeAttribute('x'); - filter.removeAttribute('y'); - filter.removeAttribute('width'); - filter.removeAttribute('height'); - } - } - } - - // Function: setBlur - // Adds/updates the blur filter to the selected element - // - // Parameters: - // val - Float with the new stdDeviation blur value - // complete - Boolean indicating whether or not the action should be completed (to add to the undo manager) - canvas.setBlur = function(val, complete) { - if(cur_command) { - finishChange(); - return; - } - - // Looks for associated blur, creates one if not found - var elem = selectedElements[0]; - var elem_id = elem.id; - filter = getElem(elem_id + '_blur'); - - val -= 0; - - var batchCmd = new BatchCommand(); - - // Blur found! - if(filter) { - if(val === 0) { - filter = null; - } - } else { - // Not found, so create - var newblur = addSvgElementFromJson({ "element": "feGaussianBlur", - "attr": { - "in": 'SourceGraphic', - "stdDeviation": val - } - }); - - filter = addSvgElementFromJson({ "element": "filter", - "attr": { - "id": elem_id + '_blur' - } - }); - - filter.appendChild(newblur); - findDefs().appendChild(filter); - - batchCmd.addSubCommand(new InsertElementCommand(filter)); - } - - var changes = {filter: elem.getAttribute('filter')}; - - if(val === 0) { - elem.removeAttribute("filter"); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - return; - } else { - changeSelectedAttribute("filter", 'url(#' + elem_id + '_blur)'); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - - canvas.setBlurOffsets(filter, val); - } - - cur_command = batchCmd; - canvas.undoMgr.beginUndoableChange("stdDeviation", [filter?filter.firstChild:null]); - if(complete) { - canvas.setBlurNoUndo(val); - finishChange(); - } - }; -}()); - -// Function: getBold -// Check whether selected element is bold or not -// -// Returns: -// Boolean indicating whether or not element is bold -this.getBold = function() { - // should only have one element selected - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-weight") == "bold"); - } - return false; -}; - -// Function: setBold -// Make the selected element bold or normal -// -// Parameters: -// b - Boolean indicating bold (true) or normal (false) -this.setBold = function(b) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-weight", b ? "bold" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getItalic -// Check whether selected element is italic or not -// -// Returns: -// Boolean indicating whether or not element is italic -this.getItalic = function() { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-style") == "italic"); - } - return false; -}; - -// Function: setItalic -// Make the selected element italic or normal -// -// Parameters: -// b - Boolean indicating italic (true) or normal (false) -this.setItalic = function(i) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-style", i ? "italic" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getFontFamily -// Returns the current font family -this.getFontFamily = function() { - return cur_text.font_family; -}; - -// Function: setFontFamily -// Set the new font family -// -// Parameters: -// val - String with the new font family -this.setFontFamily = function(val) { - cur_text.font_family = val; - changeSelectedAttribute("font-family", val); - if(selectedElements[0] && !selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - - -// Function: setFontColor -// Set the new font color -// -// Parameters: -// val - String with the new font color -this.setFontColor = function(val) { - cur_text.fill = val; - changeSelectedAttribute("fill", val); -}; - -// Function: getFontColor -// Returns the current font color -this.getFontSize = function() { - return cur_text.fill; -}; - -// Function: getFontSize -// Returns the current font size -this.getFontSize = function() { - return cur_text.font_size; -}; - -// Function: setFontSize -// Applies the given font size to the selected element -// -// Parameters: -// val - Float with the new font size -this.setFontSize = function(val) { - cur_text.font_size = val; - changeSelectedAttribute("font-size", val); - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getText -// Returns the current text (textContent) of the selected element -this.getText = function() { - var selected = selectedElements[0]; - if (selected == null) { return ""; } - return selected.textContent; -}; - -// Function: setTextContent -// Updates the text element with the given string -// -// Parameters: -// val - String with the new text -this.setTextContent = function(val) { - changeSelectedAttribute("#text", val); - textActions.init(val); - textActions.setCursor(); -}; - -// Function: setImageURL -// Sets the new image URL for the selected image element. Updates its size if -// a new URL is given -// -// Parameters: -// val - String with the image URL/path -this.setImageURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - - var attrs = $(elem).attr(['width', 'height']); - var setsize = (!attrs.width || !attrs.height); - - var cur_href = getHref(elem); - - // Do nothing if no URL change or size change - if(cur_href !== val) { - setsize = true; - } else if(!setsize) return; - - var batchCmd = new BatchCommand("Change Image URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - if(setsize) { - $(new Image()).load(function() { - var changes = $(elem).attr(['width', 'height']); - - $(elem).attr({ - width: this.width, - height: this.height - }); - - selectorManager.requestSelector(elem).resize(); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - addCommandToHistory(batchCmd); - call("changed", [elem]); - }).attr('src',val); - } else { - addCommandToHistory(batchCmd); - } -}; - -// Function: setLinkURL -// Sets the new link URL for the selected anchor element. -// -// Parameters: -// val - String with the link URL/path -this.setLinkURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - if(elem.tagName !== 'a') { - // See if parent is an anchor - var parents_a = $(elem).parents('a'); - if(parents_a.length) { - elem = parents_a[0]; - } else { - return; - } - } - - var cur_href = getHref(elem); - - if(cur_href === val) return; - - var batchCmd = new BatchCommand("Change Link URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - addCommandToHistory(batchCmd); -}; - - -// Function: setRectRadius -// Sets the rx & ry values to the selected rect element to change its corner radius -// -// Parameters: -// val - The new radius -this.setRectRadius = function(val) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "rect") { - var r = selected.getAttribute("rx"); - if (r != val) { - selected.setAttribute("rx", val); - selected.setAttribute("ry", val); - addCommandToHistory(new ChangeElementCommand(selected, {"rx":r, "ry":r}, "Radius")); - call("changed", [selected]); - } - } -}; - -// Function: makeHyperlink -// Wraps the selected element(s) in an anchor element or converts group to one -this.makeHyperlink = function(url) { - canvas.groupSelectedElements('a', url); - - // TODO: If element is a single "g", convert to "a" - // if(selectedElements.length > 1 && selectedElements[1]) { - -} - -// Function: removeHyperlink -this.removeHyperlink = function() { - canvas.ungroupSelectedElement(); -} - -// Group: Element manipulation - -// Function: setSegType -// Sets the new segment type to the selected segment(s). -// -// Parameters: -// new_type - Integer with the new segment type -// See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list -this.setSegType = function(new_type) { - pathActions.setSegType(new_type); -} - -// TODO(codedread): Remove the getBBox argument and split this function into two. -// Function: convertToPath -// Convert selected element to a path, or get the BBox of an element-as-path -// -// Parameters: -// elem - The DOM element to be converted -// getBBox - Boolean on whether or not to only return the path's BBox -// -// Returns: -// If the getBBox flag is true, the resulting path's bounding box object. -// Otherwise the resulting path element is returned. -this.convertToPath = function(elem, getBBox) { - if(elem == null) { - var elems = selectedElements; - $.each(selectedElements, function(i, elem) { - if(elem) canvas.convertToPath(elem); - }); - return; - } - - if(!getBBox) { - var batchCmd = new BatchCommand("Convert element to Path"); - } - - var attrs = getBBox?{}:{ - "fill": cur_shape.fill, - "fill-opacity": cur_shape.fill_opacity, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "opacity": cur_shape.opacity, - "visibility":"hidden" - }; - - // any attribute on the element not covered by the above - // TODO: make this list global so that we can properly maintain it - // TODO: what about @transform, @clip-rule, @fill-rule, etc? - $.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function() { - if (elem.getAttribute(this)) { - attrs[this] = elem.getAttribute(this); - } - }); - - var path = addSvgElementFromJson({ - "element": "path", - "attr": attrs - }); - - var eltrans = elem.getAttribute("transform"); - if(eltrans) { - path.setAttribute("transform",eltrans); - } - - var id = elem.id; - var parent = elem.parentNode; - if(elem.nextSibling) { - parent.insertBefore(path, elem); - } else { - parent.appendChild(path); - } - - var d = ''; - - var joinSegs = function(segs) { - $.each(segs, function(j, seg) { - var l = seg[0], pts = seg[1]; - d += l; - for(var i=0; i < pts.length; i+=2) { - d += (pts[i] +','+pts[i+1]) + ' '; - } - }); - } - - // Possibly the cubed root of 6, but 1.81 works best - var num = 1.81; - - switch (elem.tagName) { - case 'ellipse': - case 'circle': - var a = $(elem).attr(['rx', 'ry', 'cx', 'cy']); - var cx = a.cx, cy = a.cy, rx = a.rx, ry = a.ry; - if(elem.tagName == 'circle') { - rx = ry = $(elem).attr('r'); - } - - joinSegs([ - ['M',[(cx-rx),(cy)]], - ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]], - ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]], - ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]], - ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]], - ['Z',[]] - ]); - break; - case 'path': - d = elem.getAttribute('d'); - break; - case 'line': - var a = $(elem).attr(["x1", "y1", "x2", "y2"]); - d = "M"+a.x1+","+a.y1+"L"+a.x2+","+a.y2; - break; - case 'polyline': - case 'polygon': - d = "M" + elem.getAttribute('points'); - break; - case 'rect': - var r = $(elem).attr(['rx', 'ry']); - var rx = r.rx, ry = r.ry; - var b = elem.getBBox(); - var x = b.x, y = b.y, w = b.width, h = b.height; - var num = 4-num; // Why? Because! - - if(!rx && !ry) { - // Regular rect - joinSegs([ - ['M',[x, y]], - ['L',[x+w, y]], - ['L',[x+w, y+h]], - ['L',[x, y+h]], - ['L',[x, y]], - ['Z',[]] - ]); - } else { - joinSegs([ - ['M',[x, y+ry]], - ['C',[x,y+ry/num, x+rx/num,y, x+rx,y]], - ['L',[x+w-rx, y]], - ['C',[x+w-rx/num,y, x+w,y+ry/num, x+w,y+ry]], - ['L',[x+w, y+h-ry]], - ['C',[x+w, y+h-ry/num, x+w-rx/num,y+h, x+w-rx,y+h]], - ['L',[x+rx, y+h]], - ['C',[x+rx/num, y+h, x,y+h-ry/num, x,y+h-ry]], - ['L',[x, y+ry]], - ['Z',[]] - ]); - } - break; - default: - path.parentNode.removeChild(path); - break; - } - - if(d) { - path.setAttribute('d',d); - } - - if(!getBBox) { - // Replace the current element with the converted one - - // Reorient if it has a matrix - if(eltrans) { - var tlist = getTransformList(path); - if(hasMatrixTransform(tlist)) { - pathActions.resetOrientation(path); - } - } - - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - batchCmd.addSubCommand(new InsertElementCommand(path)); - - clearSelection(); - elem.parentNode.removeChild(elem) - path.setAttribute('id', id); - path.removeAttribute("visibility"); - addToSelection([path], true); - - addCommandToHistory(batchCmd); - - } else { - // Get the correct BBox of the new path, then discard it - pathActions.resetOrientation(path); - var bb = false; - try { - bb = path.getBBox(); - } catch(e) { - // Firefox fails - } - path.parentNode.removeChild(path); - return bb; - } -}; - - -// Function: changeSelectedAttributeNoUndo -// This function makes the changes to the elements. It does not add the change -// to the history stack. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttributeNoUndo = function(attr, newValue, elems) { - var handle = svgroot.suspendRedraw(1000); - if(current_mode == 'pathedit') { - // Editing node - pathActions.moveNode(attr, newValue); - } - var elems = elems || selectedElements; - var i = elems.length; - var no_xy_elems = ['g', 'polyline', 'path']; - var good_g_attrs = ['transform', 'opacity', 'filter']; - - while (i--) { - var elem = elems[i]; - if (elem == null) continue; - - // Go into "select" mode for text changes - if(current_mode === "textedit" && attr !== "#text" && elem.textContent.length) { - textActions.toSelectMode(elem); - } - - // Set x,y vals on elements that don't have them - if((attr === 'x' || attr === 'y') && no_xy_elems.indexOf(elem.tagName) >= 0) { - var bbox = getStrokedBBox([elem]); - var diff_x = attr === 'x' ? newValue - bbox.x : 0; - var diff_y = attr === 'y' ? newValue - bbox.y : 0; - canvas.moveSelectedElements(diff_x*current_zoom, diff_y*current_zoom, true); - continue; - } - - // only allow the transform/opacity/filter attribute to change on <g> elements, slightly hacky - // TODO: FIXME: This doesn't seem right. Where's the body of this if statement? - if (elem.tagName === "g" && good_g_attrs.indexOf(attr) >= 0); - var oldval = attr === "#text" ? elem.textContent : elem.getAttribute(attr); - if (oldval == null) oldval = ""; - if (oldval !== String(newValue)) { - if (attr == "#text") { - var old_w = svgedit.utilities.getBBox(elem).width; - elem.textContent = newValue; - - // FF bug occurs on on rotated elements - if(/rotate/.test(elem.getAttribute('transform'))) { - elem = ffClone(elem); - } - - // Hoped to solve the issue of moving text with text-anchor="start", - // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd - -// var box=getBBox(elem), left=box.x, top=box.y, width=box.width, -// height=box.height, dx = width - old_w, dy=0; -// var angle = getRotationAngle(elem, true); -// if (angle) { -// var r = Math.sqrt( dx*dx + dy*dy ); -// var theta = Math.atan2(dy,dx) - angle; -// dx = r * Math.cos(theta); -// dy = r * Math.sin(theta); -// -// elem.setAttribute('x', elem.getAttribute('x')-dx); -// elem.setAttribute('y', elem.getAttribute('y')-dy); -// } - - } else if (attr == "#href") { - setHref(elem, newValue); - } - else elem.setAttribute(attr, newValue); -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - // Use the Firefox ffClone hack for text elements with gradients or - // where other text attributes are changed. - if(svgedit.browser.isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) { - if((newValue+'').indexOf('url') === 0 || ['font-size','font-family','x','y'].indexOf(attr) >= 0 && elem.textContent) { - elem = ffClone(elem); - } - } - // Timeout needed for Opera & Firefox - // codedread: it is now possible for this function to be called with elements - // that are not in the selectedElements array, we need to only request a - // selector if the element is in that array - if (selectedElements.indexOf(elem) >= 0) { - setTimeout(function() { - // Due to element replacement, this element may no longer - // be part of the DOM - if(!elem.parentNode) return; - selectorManager.requestSelector(elem).resize(); - },0); - } - // if this element was rotated, and we changed the position of this element - // we need to update the rotational transform attribute - var angle = getRotationAngle(elem); - if (angle != 0 && attr != "transform") { - var tlist = getTransformList(elem); - var n = tlist.numberOfItems; - while (n--) { - var xform = tlist.getItem(n); - if (xform.type == 4) { - // remove old rotate - tlist.removeItem(n); - - var box = svgedit.utilities.getBBox(elem); - var center = transformPoint(box.x+box.width/2, box.y+box.height/2, transformListToTransform(tlist).matrix); - var cx = center.x, - cy = center.y; - var newrot = svgroot.createSVGTransform(); - newrot.setRotate(angle, cx, cy); - tlist.insertItemBefore(newrot, n); - break; - } - } - } - } // if oldValue != newValue - } // for each elem - svgroot.unsuspendRedraw(handle); -}; - -// Function: changeSelectedAttribute -// Change the given/selected element and add the original value to the history stack -// If you want to change all selectedElements, ignore the elems argument. -// If you want to change only a subset of selectedElements, then send the -// subset to this function in the elems argument. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttribute = this.changeSelectedAttribute = function(attr, val, elems) { - var elems = elems || selectedElements; - canvas.undoMgr.beginUndoableChange(attr, elems); - var i = elems.length; - - changeSelectedAttributeNoUndo(attr, val, elems); - - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } -}; - -// Function: deleteSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack -this.deleteSelectedElements = function() { - var batchCmd = new BatchCommand("Delete Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - // Get the parent if it's a single-child anchor - if(parent.tagName === 'a' && parent.childNodes.length === 1) { - t = parent; - parent = parent.parentNode; - } - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); -}; - -// Function: cutSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack. Remembers removed elements on the clipboard - -// TODO: Combine similar code with deleteSelectedElements -this.cutSelectedElements = function() { - var batchCmd = new BatchCommand("Cut Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); - - canvas.clipBoard = selectedCopy; -}; - -// Function: copySelectedElements -// Remembers the current selected elements on the clipboard -this.copySelectedElements = function() { - canvas.clipBoard = $.merge([], selectedElements); -}; - -this.pasteElements = function(type, x, y) { - var cb = canvas.clipBoard; - var len = cb.length; - if(!len) return; - - var pasted = []; - var batchCmd = new BatchCommand('Paste elements'); - - // Move elements to lastClickPoint - - while (len--) { - var elem = cb[len]; - if(!elem) continue; - var copy = copyElem(elem); - - // See if elem with elem ID is in the DOM already - if(!getElem(elem.id)) copy.id = elem.id; - pasted.push(copy); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(copy); - batchCmd.addSubCommand(new InsertElementCommand(copy)); - } - - selectOnly(pasted); - if(type != 'in_place') { - if(lastClickPoint == null) { - lastClickPoint.x = 0; - lastClickPoint.y = 0; - } - var ctr_x, ctr_y; - if(!type) { - ctr_x = lastClickPoint.x; - ctr_y = lastClickPoint.y; - } else if(type === 'point') { - ctr_x = x; - ctr_y = y; - } - - var bbox = getStrokedBBox(pasted); - var cx = ctr_x - (bbox.x + bbox.width/2), - cy = ctr_y - (bbox.y + bbox.height/2), - dx = [], - dy = []; - - $.each(pasted, function(i, item) { - dx.push(cx); - dy.push(cy); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, false); - batchCmd.addSubCommand(cmd); - } - - - - addCommandToHistory(batchCmd); - call("changed", pasted); -} - -// Function: groupSelectedElements -// Wraps all the selected elements in a group (g) element - -// Parameters: -// type - type of element to group into, defaults to <g> -this.groupSelectedElements = function(type) { - if(!type) type = 'g'; - var cmd_str = ''; - - switch ( type ) { - case "a": - cmd_str = "Make hyperlink"; - var url = ''; - if(arguments.length > 1) { - url = arguments[1]; - } - break; - default: - type = 'g'; - cmd_str = "Group Elements"; - break; - } - - var batchCmd = new BatchCommand(cmd_str); - - // create and insert the group element - var g = addSvgElementFromJson({ - "element": type, - "attr": { - "id": getNextId() - } - }); - if(type === 'a') { - setHref(g, url); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - - // now move all children into the group - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem == null) continue; - - if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { - elem = elem.parentNode; - } - - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - g.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - selectOnly([g], true); -}; - - -// Function: pushGroupProperties -// Pushes all appropriate parent group properties down to its children, then -// removes them from the group -var pushGroupProperties = this.pushGroupProperties = function(g, undoable) { - - var children = g.childNodes; - var len = children.length; - var xform = g.getAttribute("transform"); - - var glist = getTransformList(g); - var m = transformListToTransform(glist).matrix; - - var batchCmd = new BatchCommand("Push group properties"); - - // TODO: get all fill/stroke properties from the group that we are about to destroy - // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", - // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", - // "stroke-width" - // and then for each child, if they do not have the attribute (or the value is 'inherit') - // then set the child's attribute - - var i = 0; - var gangle = getRotationAngle(g); - - var gattrs = $(g).attr(['filter', 'opacity']); - var gfilter, gblur; - - for(var i = 0; i < len; i++) { - var elem = children[i]; - - if(elem.nodeType !== 1) continue; - - if(gattrs.opacity !== null && gattrs.opacity !== 1) { - var c_opac = elem.getAttribute('opacity') || 1; - var new_opac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100)/100; - changeSelectedAttribute('opacity', new_opac, [elem]); - } - - if(gattrs.filter) { - var cblur = this.getBlur(elem); - var orig_cblur = cblur; - if(!gblur) gblur = this.getBlur(g); - if(cblur) { - // Is this formula correct? - cblur = (gblur-0) + (cblur-0); - } else if(cblur === 0) { - cblur = gblur; - } - - // If child has no current filter, get group's filter or clone it. - if(!orig_cblur) { - // Set group's filter to use first child's ID - if(!gfilter) { - gfilter = getRefElem(gattrs.filter); - } else { - // Clone the group's filter - gfilter = copyElem(gfilter); - findDefs().appendChild(gfilter); - } - } else { - gfilter = getRefElem(elem.getAttribute('filter')); - } - - // Change this in future for different filters - var suffix = (gfilter.firstChild.tagName === 'feGaussianBlur')?'blur':'filter'; - gfilter.id = elem.id + '_' + suffix; - changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); - - // Update blur value - if(cblur) { - changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); - canvas.setBlurOffsets(gfilter, cblur); - } - } - - var chtlist = getTransformList(elem); - - // Don't process gradient transforms - if(~elem.tagName.indexOf('Gradient')) chtlist = null; - - // Hopefully not a problem to add this. Necessary for elements like <desc/> - if(!chtlist) continue; - - // Apparently <defs> can get get a transformlist, but we don't want it to have one! - if(elem.tagName === 'defs') 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 - // out any translates) - if (gangle && glist.numberOfItems == 1) { - // [Rg] [Rc] [Mc] - // we want [Tr] [Rc2] [Mc] where: - // - [Rc2] is at the child's current center but has the - // sum of the group and child's rotation angles - // - [Tr] is the equivalent translation that this child - // undergoes if the group wasn't there - - // [Tr] = [Rg] [Rc] [Rc2_inv] - - // get group's rotation matrix (Rg) - var rgm = glist.getItem(0).matrix; - - // get child's rotation matrix (Rc) - var rcm = svgroot.createSVGMatrix(); - var cangle = getRotationAngle(elem); - if (cangle) { - rcm = chtlist.getItem(0).matrix; - } - - // get child's old center of rotation - var cbox = svgedit.utilities.getBBox(elem); - var ceqm = transformListToTransform(chtlist).matrix; - var coldc = transformPoint(cbox.x+cbox.width/2, cbox.y+cbox.height/2,ceqm); - - // sum group and child's angles - var sangle = gangle + cangle; - - // get child's rotation at the old center (Rc2_inv) - var r2 = svgroot.createSVGTransform(); - r2.setRotate(sangle, coldc.x, coldc.y); - - // calculate equivalent translate - var trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); - - // set up tlist - if (cangle) { - chtlist.removeItem(0); - } - - if (sangle) { - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(r2, 0); - } else { - chtlist.appendItem(r2); - } - } - - if (trm.e || trm.f) { - var tr = svgroot.createSVGTransform(); - tr.setTranslate(trm.e, trm.f); - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(tr, 0); - } else { - chtlist.appendItem(tr); - } - } - } - else { // more complicated than just a rotate - - // transfer the group's transform down to each child and then - // call recalculateDimensions() - var oldxform = elem.getAttribute("transform"); - var changes = {}; - changes["transform"] = oldxform ? oldxform : ""; - - var newxform = svgroot.createSVGTransform(); - - // [ gm ] [ chm ] = [ chm ] [ gm' ] - // [ gm' ] = [ chm_inv ] [ gm ] [ chm ] - var chm = transformListToTransform(chtlist).matrix, - chm_inv = chm.inverse(); - var gm = matrixMultiply( chm_inv, m, chm ); - newxform.setMatrix(gm); - chtlist.appendItem(newxform); - } - var cmd = recalculateDimensions(elem); - if(cmd) batchCmd.addSubCommand(cmd); - } - } - - - // remove transform and make it undo-able - if (xform) { - var changes = {}; - changes["transform"] = xform; - g.setAttribute("transform", ""); - g.removeAttribute("transform"); - batchCmd.addSubCommand(new ChangeElementCommand(g, changes)); - } - - if (undoable && !batchCmd.isEmpty()) { - return batchCmd; - } -} - - -// Function: ungroupSelectedElement -// Unwraps all the elements in a selected group (g) element. This requires -// significant recalculations to apply group's transforms, etc to its children -this.ungroupSelectedElement = function() { - var g = selectedElements[0]; - if($(g).data('gsvg') || $(g).data('symbol')) { - // Is svg, so actually convert to group - - convertToGroup(g); - return; - } else if(g.tagName === 'use') { - // Somehow doesn't have data set, so retrieve - var symbol = getElem(getHref(g).substr(1)); - $(g).data('symbol', symbol).data('ref', symbol); - convertToGroup(g); - return; - } - var parents_a = $(g).parents('a'); - if(parents_a.length) { - g = parents_a[0]; - } - - // Look for parent "a" - if (g.tagName === "g" || g.tagName === "a") { - - var batchCmd = new BatchCommand("Ungroup Elements"); - var cmd = pushGroupProperties(g, true); - if(cmd) batchCmd.addSubCommand(cmd); - - var parent = g.parentNode; - var anchor = g.nextSibling; - var children = new Array(g.childNodes.length); - - var i = 0; - - while (g.firstChild) { - var elem = g.firstChild; - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - - // Remove child title elements - if(elem.tagName === 'title') { - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent)); - oldParent.removeChild(elem); - continue; - } - - children[i++] = elem = parent.insertBefore(elem, anchor); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - - // remove the group from the selection - clearSelection(); - - // delete the group element (but make undo-able) - var gNextSibling = g.nextSibling; - g = parent.removeChild(g); - batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)); - - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - addToSelection(children); - } -}; - -// Function: moveToTopSelectedElement -// Repositions the selected element to the bottom in the DOM to appear on top of -// other elements -this.moveToTopSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - t = t.parentNode.appendChild(t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "top")); - call("changed", [t]); - } - } -}; - -// Function: moveToBottomSelectedElement -// Repositions the selected element to the top in the DOM to appear under -// other elements -this.moveToBottomSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - var firstChild = t.parentNode.firstChild; - if (firstChild.tagName == 'title') { - firstChild = firstChild.nextSibling; - } - // This can probably be removed, as the defs should not ever apppear - // inside a layer group - if (firstChild.tagName == 'defs') { - firstChild = firstChild.nextSibling; - } - t = t.parentNode.insertBefore(t, firstChild); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "bottom")); - call("changed", [t]); - } - } -}; - -// Function: moveUpDownSelected -// Moves the select element up or down the stack, based on the visibly -// intersecting elements -// -// Parameters: -// dir - String that's either 'Up' or 'Down' -this.moveUpDownSelected = function(dir) { - var selected = selectedElements[0]; - if (!selected) return; - - curBBoxes = []; - var closest, found_cur; - // jQuery sorts this list - var list = $(getIntersectionList(getStrokedBBox([selected]))).toArray(); - if(dir == 'Down') list.reverse(); - - $.each(list, function() { - if(!found_cur) { - if(this == selected) { - found_cur = true; - } - return; - } - closest = this; - return false; - }); - if(!closest) return; - - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - $(closest)[dir == 'Down'?'before':'after'](t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "Move " + dir)); - call("changed", [t]); - } -}; - -// Function: moveSelectedElements -// Moves selected elements on the X/Y axis -// -// Parameters: -// dx - Float with the distance to move on the x-axis -// dy - Float with the distance to move on the y-axis -// undoable - Boolean indicating whether or not the action should be undoable -// -// Returns: -// Batch command for the move -this.moveSelectedElements = function(dx, dy, undoable) { - // if undoable is not sent, default to true - // if single values, scale them to the zoom - if (dx.constructor != Array) { - dx /= current_zoom; - dy /= current_zoom; - } - var undoable = undoable || true; - var batchCmd = new BatchCommand("position"); - var i = selectedElements.length; - while (i--) { - var selected = selectedElements[i]; - if (selected != null) { -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(selected); - -// var b = {}; -// for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; -// selectedBBoxes[i] = b; - - var xform = svgroot.createSVGTransform(); - var tlist = getTransformList(selected); - - // dx and dy could be arrays - if (dx.constructor == Array) { -// if (i==0) { -// selectedBBoxes[0].x += dx[0]; -// selectedBBoxes[0].y += dy[0]; -// } - xform.setTranslate(dx[i],dy[i]); - } else { -// if (i==0) { -// selectedBBoxes[0].x += dx; -// selectedBBoxes[0].y += dy; -// } - xform.setTranslate(dx,dy); - } - - if(tlist.numberOfItems) { - tlist.insertItemBefore(xform, 0); - } else { - tlist.appendItem(xform); - } - - var cmd = recalculateDimensions(selected); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - - selectorManager.requestSelector(selected).resize(); - } - } - if (!batchCmd.isEmpty()) { - if (undoable) - addCommandToHistory(batchCmd); - call("changed", selectedElements); - return batchCmd; - } -}; - -// Function: cloneSelectedElements -// Create deep DOM copies (clones) of all selected elements and move them slightly -// from their originals -this.cloneSelectedElements = function(x,y) { - var batchCmd = new BatchCommand("Clone Elements"); - // find all the elements selected (stop at first null) - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - } - // use slice to quickly get the subset of elements we need - var copiedElements = selectedElements.slice(0,i); - this.clearSelection(true); - // note that we loop in the reverse way because of the way elements are added - // to the selectedElements array (top-first) - var i = copiedElements.length; - while (i--) { - // clone each element and replace it within copiedElements - var elem = copiedElements[i] = copyElem(copiedElements[i]); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(elem); - batchCmd.addSubCommand(new InsertElementCommand(elem)); - } - - if (!batchCmd.isEmpty()) { - addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - this.moveSelectedElements(x,y,false); - addCommandToHistory(batchCmd); - } -}; - -// Function: alignSelectedElements -// Aligns selected elements -// -// Parameters: -// type - String with single character indicating the alignment type -// relative_to - String that must be one of the following: -// "selected", "largest", "smallest", "page" -this.alignSelectedElements = function(type, relative_to) { - var bboxes = [], angles = []; - var minx = Number.MAX_VALUE, maxx = Number.MIN_VALUE, miny = Number.MAX_VALUE, maxy = Number.MIN_VALUE; - var curwidth = Number.MIN_VALUE, curheight = Number.MIN_VALUE; - var len = selectedElements.length; - if (!len) return; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - bboxes[i] = getStrokedBBox([elem]); - - // now bbox is axis-aligned and handles rotation - switch (relative_to) { - case 'smallest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth > bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight > bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - case 'largest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth < bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight < bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - default: // 'selected' - if (bboxes[i].x < minx) minx = bboxes[i].x; - if (bboxes[i].y < miny) miny = bboxes[i].y; - if (bboxes[i].x + bboxes[i].width > maxx) maxx = bboxes[i].x + bboxes[i].width; - if (bboxes[i].y + bboxes[i].height > maxy) maxy = bboxes[i].y + bboxes[i].height; - break; - } - } // loop for each element to find the bbox and adjust min/max - - if (relative_to == 'page') { - minx = 0; - miny = 0; - maxx = canvas.contentW; - maxy = canvas.contentH; - } - - var dx = new Array(len); - var dy = new Array(len); - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - var bbox = bboxes[i]; - dx[i] = 0; - dy[i] = 0; - switch (type) { - case 'l': // left (horizontal) - dx[i] = minx - bbox.x; - break; - case 'c': // center (horizontal) - dx[i] = (minx+maxx)/2 - (bbox.x + bbox.width/2); - break; - case 'r': // right (horizontal) - dx[i] = maxx - (bbox.x + bbox.width); - break; - case 't': // top (vertical) - dy[i] = miny - bbox.y; - break; - case 'm': // middle (vertical) - dy[i] = (miny+maxy)/2 - (bbox.y + bbox.height/2); - break; - case 'b': // bottom (vertical) - dy[i] = maxy - (bbox.y + bbox.height); - break; - } - } - this.moveSelectedElements(dx,dy); -}; - -// Group: Additional editor tools - -this.contentW = getResolution().w; -this.contentH = getResolution().h; - -// Function: updateCanvas -// Updates the editor canvas width/height/position after a zoom has occurred -// -// Parameters: -// w - Float with the new width -// h - Float with the new height -// -// Returns: -// Object with the following values: -// * x - The canvas' new x coordinate -// * y - The canvas' new y coordinate -// * old_x - The canvas' old x coordinate -// * old_y - The canvas' old y coordinate -// * d_x - The x position difference -// * d_y - The y position difference -this.updateCanvas = function(w, h) { - svgroot.setAttribute("width", w); - svgroot.setAttribute("height", h); - var bg = $('#canvasBackground')[0]; - var old_x = svgcontent.getAttribute('x'); - var old_y = svgcontent.getAttribute('y'); - var x = (w/2 - this.contentW*current_zoom/2); - var y = (h/2 - this.contentH*current_zoom/2); - - assignAttributes(svgcontent, { - width: this.contentW*current_zoom, - height: this.contentH*current_zoom, - 'x': x, - 'y': y, - "viewBox" : "0 0 " + this.contentW + " " + this.contentH - }); - - assignAttributes(bg, { - width: svgcontent.getAttribute('width'), - height: svgcontent.getAttribute('height'), - x: x, - y: y - }); - - var bg_img = getElem('background_image'); - if (bg_img) { - assignAttributes(bg_img, { - 'width': '100%', - 'height': '100%' - }); - } - - selectorManager.selectorParentGroup.setAttribute("transform","translate(" + x + "," + y + ")"); - - return {x:x, y:y, old_x:old_x, old_y:old_y, d_x:x - old_x, d_y:y - old_y}; -} - -// Function: setBackground -// Set the background of the editor (NOT the actual document) -// -// Parameters: -// color - String with fill color to apply -// url - URL or path to image to use -this.setBackground = function(color, url) { - var bg = getElem('canvasBackground'); - var border = $(bg).find('rect')[0]; - var bg_img = getElem('background_image'); - border.setAttribute('fill',color); - if(url) { - if(!bg_img) { - bg_img = svgdoc.createElementNS(svgns, "image"); - assignAttributes(bg_img, { - 'id': 'background_image', - 'width': '100%', - 'height': '100%', - 'preserveAspectRatio': 'xMinYMin', - 'style':'pointer-events:none' - }); - } - setHref(bg_img, url); - bg.appendChild(bg_img); - } else if(bg_img) { - bg_img.parentNode.removeChild(bg_img); - } -} - -// Function: cycleElement -// Select the next/previous element within the current layer -// -// Parameters: -// next - Boolean where true = next and false = previous element -this.cycleElement = function(next) { - var cur_elem = selectedElements[0]; - var elem = false; - var all_elems = getVisibleElements(current_group || getCurrentDrawing().getCurrentLayer()); - if(!all_elems.length) return; - if (cur_elem == null) { - var num = next?all_elems.length-1:0; - elem = all_elems[num]; - } else { - var i = all_elems.length; - while(i--) { - if(all_elems[i] == cur_elem) { - var num = next?i-1:i+1; - if(num >= all_elems.length) { - num = 0; - } else if(num < 0) { - num = all_elems.length-1; - } - elem = all_elems[num]; - break; - } - } - } - selectOnly([elem], true); - call("selected", selectedElements); -} - -this.clear(); - - -// DEPRECATED: getPrivateMethods -// Since all methods are/should be public somehow, this function should be removed - -// Being able to access private methods publicly seems wrong somehow, -// but currently appears to be the best way to allow testing and provide -// access to them to plugins. -this.getPrivateMethods = function() { - var obj = { - addCommandToHistory: addCommandToHistory, - setGradient: setGradient, - addSvgElementFromJson: addSvgElementFromJson, - assignAttributes: assignAttributes, - BatchCommand: BatchCommand, - call: call, - ChangeElementCommand: ChangeElementCommand, - copyElem: copyElem, - ffClone: ffClone, - findDefs: findDefs, - findDuplicateGradient: findDuplicateGradient, - getElem: getElem, - getId: getId, - getIntersectionList: getIntersectionList, - getMouseTarget: getMouseTarget, - getNextId: getNextId, - getPathBBox: getPathBBox, - getUrlFromAttr: getUrlFromAttr, - hasMatrixTransform: hasMatrixTransform, - identifyLayers: identifyLayers, - InsertElementCommand: InsertElementCommand, - isIdentity: svgedit.math.isIdentity, - logMatrix: logMatrix, - matrixMultiply: matrixMultiply, - MoveElementCommand: MoveElementCommand, - preventClickDefault: preventClickDefault, - recalculateAllSelectedDimensions: recalculateAllSelectedDimensions, - recalculateDimensions: recalculateDimensions, - remapElement: remapElement, - RemoveElementCommand: RemoveElementCommand, - removeUnusedDefElems: removeUnusedDefElems, - round: round, - runExtensions: runExtensions, - sanitizeSvg: sanitizeSvg, - SVGEditTransformList: svgedit.transformlist.SVGTransformList, - toString: toString, - transformBox: svgedit.math.transformBox, - transformListToTransform: transformListToTransform, - transformPoint: transformPoint, - walkTree: svgedit.utilities.walkTree - } - return obj; -}; - -} diff --git a/build/svg-edit-2.6-src/editor/svgedit.compiled.js b/build/svg-edit-2.6-src/editor/svgedit.compiled.js deleted file mode 100644 index e69de29..0000000 diff --git a/build/svg-edit-2.6-src/editor/svgicons/jquery.svgicons.js b/build/svg-edit-2.6-src/editor/svgicons/jquery.svgicons.js deleted file mode 100644 index 1f7ef67..0000000 --- a/build/svg-edit-2.6-src/editor/svgicons/jquery.svgicons.js +++ /dev/null @@ -1,485 +0,0 @@ -/* - * SVG Icon Loader 2.0 - * - * jQuery Plugin for loading SVG icons from a single file - * - * Copyright (c) 2009 Alexis Deveria - * http://a.deveria.com - * - * Apache 2 License - -How to use: - -1. Create the SVG master file that includes all icons: - -The master SVG icon-containing file is an SVG file that contains -<g> elements. Each <g> element should contain the markup of an SVG -icon. The <g> element has an ID that should -correspond with the ID of the HTML element used on the page that should contain -or optionally be replaced by the icon. Additionally, one empty element should be -added at the end with id "svg_eof". - -2. Optionally create fallback raster images for each SVG icon. - -3. Include the jQuery and the SVG Icon Loader scripts on your page. - -4. Run $.svgIcons() when the document is ready: - -$.svgIcons( file [string], options [object literal]); - -File is the location of a local SVG or SVGz file. - -All options are optional and can include: - -- 'w (number)': The icon widths - -- 'h (number)': The icon heights - -- 'fallback (object literal)': List of raster images with each - key being the SVG icon ID to replace, and the value the image file name. - -- 'fallback_path (string)': The path to use for all images - listed under "fallback" - -- 'replace (boolean)': If set to true, HTML elements will be replaced by, - rather than include the SVG icon. - -- 'placement (object literal)': List with selectors for keys and SVG icon ids - as values. This provides a custom method of adding icons. - -- 'resize (object literal)': List with selectors for keys and numbers - as values. This allows an easy way to resize specific icons. - -- 'callback (function)': A function to call when all icons have been loaded. - Includes an object literal as its argument with as keys all icon IDs and the - icon as a jQuery object as its value. - -- 'id_match (boolean)': Automatically attempt to match SVG icon ids with - corresponding HTML id (default: true) - -- 'no_img (boolean)': Prevent attempting to convert the icon into an <img> - element (may be faster, help for browser consistency) - -- 'svgz (boolean)': Indicate that the file is an SVGZ file, and thus not to - parse as XML. SVGZ files add compression benefits, but getting data from - them fails in Firefox 2 and older. - -5. To access an icon at a later point without using the callback, use this: - $.getSvgIcon(id (string)); - -This will return the icon (as jQuery object) with a given ID. - -6. To resize icons at a later point without using the callback, use this: - $.resizeSvgIcons(resizeOptions) (use the same way as the "resize" parameter) - - -Example usage #1: - -$(function() { - $.svgIcons('my_icon_set.svg'); // The SVG file that contains all icons - // No options have been set, so all icons will automatically be inserted - // into HTML elements that match the same IDs. -}); - -Example usage #2: - -$(function() { - $.svgIcons('my_icon_set.svg', { // The SVG file that contains all icons - callback: function(icons) { // Custom callback function that sets click - // events for each icon - $.each(icons, function(id, icon) { - icon.click(function() { - alert('You clicked on the icon with id ' + id); - }); - }); - } - }); //The SVG file that contains all icons -}); - -Example usage #3: - -$(function() { - $.svgIcons('my_icon_set.svgz', { // The SVGZ file that contains all icons - w: 32, // All icons will be 32px wide - h: 32, // All icons will be 32px high - fallback_path: 'icons/', // All fallback files can be found here - fallback: { - '#open_icon': 'open.png', // The "open.png" will be appended to the - // HTML element with ID "open_icon" - '#close_icon': 'close.png', - '#save_icon': 'save.png' - }, - placement: {'.open_icon','open'}, // The "open" icon will be added - // to all elements with class "open_icon" - resize: function() { - '#save_icon .svg_icon': 64 // The "save" icon will be resized to 64 x 64px - }, - - callback: function(icons) { // Sets background color for "close" icon - icons['close'].css('background','red'); - }, - - svgz: true // Indicates that an SVGZ file is being used - - }) -}); - -*/ - - -(function($) { - var svg_icons = {}, fixIDs; - - $.svgIcons = function(file, opts) { - var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - icon_w = opts.w?opts.w : 24, - icon_h = opts.h?opts.h : 24, - elems, svgdoc, testImg, - icons_made = false, data_loaded = false, load_attempts = 0, - ua = navigator.userAgent, isOpera = !!window.opera, isSafari = (ua.indexOf('Safari/') > -1 && ua.indexOf('Chrome/')==-1), - data_pre = 'data:image/svg+xml;charset=utf-8;base64,'; - - if(opts.svgz) { - var data_el = $('<object data="' + file + '" type=image/svg+xml>').appendTo('body').hide(); - try { - svgdoc = data_el[0].contentDocument; - data_el.load(getIcons); - getIcons(0, true); // Opera will not run "load" event if file is already cached - } catch(err1) { - useFallback(); - } - } else { - var parser = new DOMParser(); - $.ajax({ - url: file, - dataType: 'string', - success: function(data) { - if(!data) { - $(useFallback); - return; - } - svgdoc = parser.parseFromString(data, "text/xml"); - $(function() { - getIcons('ajax'); - }); - }, - error: function(err) { - // TODO: Fix Opera widget icon bug - if(window.opera) { - $(function() { - useFallback(); - }); - } else { - if(err.responseText) { - svgdoc = parser.parseFromString(err.responseText, "text/xml"); - - if(!svgdoc.childNodes.length) { - $(useFallback); - } - $(function() { - getIcons('ajax'); - }); - } else { - $(useFallback); - } - } - } - }); - } - - function getIcons(evt, no_wait) { - if(evt !== 'ajax') { - if(data_loaded) return; - // Webkit sometimes says svgdoc is undefined, other times - // it fails to load all nodes. Thus we must make sure the "eof" - // element is loaded. - svgdoc = data_el[0].contentDocument; // Needed again for Webkit - var isReady = (svgdoc && svgdoc.getElementById('svg_eof')); - if(!isReady && !(no_wait && isReady)) { - load_attempts++; - if(load_attempts < 50) { - setTimeout(getIcons, 20); - } else { - useFallback(); - data_loaded = true; - } - return; - } - data_loaded = true; - } - - elems = $(svgdoc.firstChild).children(); //.getElementsByTagName('foreignContent'); - - if(!opts.no_img) { - var testSrc = data_pre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; - - testImg = $(new Image()).attr({ - src: testSrc, - width: 0, - height: 0 - }).appendTo('body') - .load(function () { - // Safari 4 crashes, Opera and Chrome don't - makeIcons(true); - }).error(function () { - makeIcons(); - }); - } else { - setTimeout(function() { - if(!icons_made) makeIcons(); - },500); - } - } - - var setIcon = function(target, icon, id, setID) { - if(isOpera) icon.css('visibility','hidden'); - if(opts.replace) { - if(setID) icon.attr('id',id); - var cl = target.attr('class'); - if(cl) icon.attr('class','svg_icon '+cl); - target.replaceWith(icon); - } else { - - target.append(icon); - } - if(isOpera) { - setTimeout(function() { - icon.removeAttr('style'); - },1); - } - } - - var addIcon = function(icon, id) { - if(opts.id_match === undefined || opts.id_match !== false) { - setIcon(holder, icon, id, true); - } - svg_icons[id] = icon; - } - - function makeIcons(toImage, fallback) { - if(icons_made) return; - if(opts.no_img) toImage = false; - var holder; - - if(toImage) { - var temp_holder = $(document.createElement('div')); - temp_holder.hide().appendTo('body'); - } - if(fallback) { - var path = opts.fallback_path?opts.fallback_path:''; - $.each(fallback, function(id, imgsrc) { - holder = $('#' + id); - var icon = $(new Image()) - .attr({ - 'class':'svg_icon', - src: path + imgsrc, - 'width': icon_w, - 'height': icon_h, - 'alt': 'icon' - }); - - addIcon(icon, id); - }); - } else { - var len = elems.length; - for(var i = 0; i < len; i++) { - var elem = elems[i]; - var id = elem.id; - if(id === 'svg_eof') break; - holder = $('#' + id); - var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; - var svgroot = document.createElementNS(svgns, "svg"); - svgroot.setAttributeNS(svgns, 'viewBox', [0,0,icon_w,icon_h].join(' ')); - // Make flexible by converting width/height to viewBox - var w = svg.getAttribute('width'); - var h = svg.getAttribute('height'); - svg.removeAttribute('width'); - svg.removeAttribute('height'); - - var vb = svg.getAttribute('viewBox'); - if(!vb) { - svg.setAttribute('viewBox', [0,0,w,h].join(' ')); - } - - // Not using jQuery to be a bit faster - svgroot.setAttribute('xmlns', svgns); - svgroot.setAttribute('width', icon_w); - svgroot.setAttribute('height', icon_h); - svgroot.setAttribute("xmlns:xlink", xlinkns); - svgroot.setAttribute("class", 'svg_icon'); - - // Without cloning, Firefox will make another GET request. - // With cloning, causes issue in Opera/Win/Non-EN - if(!isOpera) svg = svg.cloneNode(true); - - svgroot.appendChild(svg); - - if(toImage) { - // Without cloning, Safari will crash - // With cloning, causes issue in Opera/Win/Non-EN - var svgcontent = isOpera?svgroot:svgroot.cloneNode(true); - temp_holder.empty().append(svgroot); - var str = data_pre + encode64(temp_holder.html()); - var icon = $(new Image()) - .attr({'class':'svg_icon', src:str}); - } else { - var icon = fixIDs($(svgroot), i); - } - addIcon(icon, id); - } - - } - - if(opts.placement) { - $.each(opts.placement, function(sel, id) { - if(!svg_icons[id]) return; - $(sel).each(function(i) { - var copy = svg_icons[id].clone(); - if(i > 0 && !toImage) copy = fixIDs(copy, i, true); - setIcon($(this), copy, id); - }) - }); - } - if(!fallback) { - if(toImage) temp_holder.remove(); - if(data_el) data_el.remove(); - if(testImg) testImg.remove(); - } - if(opts.resize) $.resizeSvgIcons(opts.resize); - icons_made = true; - - if(opts.callback) opts.callback(svg_icons); - } - - fixIDs = function(svg_el, svg_num, force) { - var defs = svg_el.find('defs'); - if(!defs.length) return svg_el; - - if(isOpera) { - var id_elems = defs.find('*').filter(function() { - return !!this.id; - }); - } else { - var id_elems = defs.find('[id]'); - } - - var all_elems = svg_el[0].getElementsByTagName('*'), len = all_elems.length; - - id_elems.each(function(i) { - var id = this.id; - var no_dupes = ($(svgdoc).find('#' + id).length <= 1); - if(isOpera) no_dupes = false; // Opera didn't clone svg_el, so not reliable - // if(!force && no_dupes) return; - var new_id = 'x' + id + svg_num + i; - this.id = new_id; - - var old_val = 'url(#' + id + ')'; - var new_val = 'url(#' + new_id + ')'; - - // Selector method, possibly faster but fails in Opera / jQuery 1.4.3 -// svg_el.find('[fill="url(#' + id + ')"]').each(function() { -// this.setAttribute('fill', 'url(#' + new_id + ')'); -// }).end().find('[stroke="url(#' + id + ')"]').each(function() { -// this.setAttribute('stroke', 'url(#' + new_id + ')'); -// }).end().find('use').each(function() { -// if(this.getAttribute('xlink:href') == '#' + id) { -// this.setAttributeNS(xlinkns,'href','#' + new_id); -// } -// }).end().find('[filter="url(#' + id + ')"]').each(function() { -// this.setAttribute('filter', 'url(#' + new_id + ')'); -// }); - - for(var i = 0; i < len; i++) { - var elem = all_elems[i]; - if(elem.getAttribute('fill') === old_val) { - elem.setAttribute('fill', new_val); - } - if(elem.getAttribute('stroke') === old_val) { - elem.setAttribute('stroke', new_val); - } - if(elem.getAttribute('filter') === old_val) { - elem.setAttribute('filter', new_val); - } - } - }); - return svg_el; - } - - function useFallback() { - if(file.indexOf('.svgz') != -1) { - var reg_file = file.replace('.svgz','.svg'); - if(window.console) { - console.log('.svgz failed, trying with .svg'); - } - $.svgIcons(reg_file, opts); - } else if(opts.fallback) { - makeIcons(false, opts.fallback); - } - } - - function encode64(input) { - // base64 strings are 4/3 larger than the original string - if(window.btoa) return window.btoa(input); - var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0, p = 0; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = _keyStr.charAt(enc1); - output[p++] = _keyStr.charAt(enc2); - output[p++] = _keyStr.charAt(enc3); - output[p++] = _keyStr.charAt(enc4); - } while (i < input.length); - - return output.join(''); - } - } - - $.getSvgIcon = function(id, uniqueClone) { - var icon = svg_icons[id]; - if(uniqueClone && icon) { - icon = fixIDs(icon, 0, true).clone(true); - } - return icon; - } - - $.resizeSvgIcons = function(obj) { - // FF2 and older don't detect .svg_icon, so we change it detect svg elems instead - var change_sel = !$('.svg_icon:first').length; - $.each(obj, function(sel, size) { - var arr = $.isArray(size); - var w = arr?size[0]:size, - h = arr?size[1]:size; - if(change_sel) { - sel = sel.replace(/\.svg_icon/g,'svg'); - } - $(sel).each(function() { - this.setAttribute('width', w); - this.setAttribute('height', h); - if(window.opera && window.widget) { - this.parentNode.style.width = w + 'px'; - this.parentNode.style.height = h + 'px'; - } - }); - }); - } - -})(jQuery); \ No newline at end of file diff --git a/build/svg-edit-2.6-src/editor/svgtransformlist.js b/build/svg-edit-2.6-src/editor/svgtransformlist.js deleted file mode 100644 index 5c291ca..0000000 --- a/build/svg-edit-2.6-src/editor/svgtransformlist.js +++ /dev/null @@ -1,291 +0,0 @@ -/** - * SVGTransformList - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) browser.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.transformlist) { - svgedit.transformlist = {}; -} - -var svgroot = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - -// Helper function. -function transformToString(xform) { - var m = xform.matrix, - text = ""; - switch(xform.type) { - case 1: // MATRIX - text = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - break; - case 2: // TRANSLATE - text = "translate(" + m.e + "," + m.f + ")"; - break; - case 3: // SCALE - if (m.a == m.d) text = "scale(" + m.a + ")"; - else text = "scale(" + m.a + "," + m.d + ")"; - break; - case 4: // ROTATE - var cx = 0, cy = 0; - // this prevents divide by zero - if (xform.angle != 0) { - var K = 1 - m.a; - cy = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b ); - cx = ( m.e - m.b * cy ) / K; - } - text = "rotate(" + xform.angle + " " + cx + "," + cy + ")"; - break; - } - return text; -}; - - -/** - * Map of SVGTransformList objects. - */ -var listMap_ = {}; - - -// ************************************************************************************** -// SVGTransformList implementation for Webkit -// These methods do not currently raise any exceptions. -// These methods also do not check that transforms are being inserted. This is basically -// implementing as much of SVGTransformList that we need to get the job done. -// -// interface SVGEditTransformList { -// attribute unsigned long numberOfItems; -// void clear ( ) -// SVGTransform initialize ( in SVGTransform newItem ) -// SVGTransform getItem ( in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform insertItemBefore ( in SVGTransform newItem, in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform replaceItem ( in SVGTransform newItem, in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform removeItem ( in unsigned long index ) (DOES NOT THROW DOMException, INDEX_SIZE_ERR) -// SVGTransform appendItem ( in SVGTransform newItem ) -// NOT IMPLEMENTED: SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix ); -// NOT IMPLEMENTED: SVGTransform consolidate ( ); -// } -// ************************************************************************************** -svgedit.transformlist.SVGTransformList = function(elem) { - this._elem = elem || null; - this._xforms = []; - // TODO: how do we capture the undo-ability in the changed transform list? - this._update = function() { - var tstr = ""; - var concatMatrix = svgroot.createSVGMatrix(); - for (var i = 0; i < this.numberOfItems; ++i) { - var xform = this._list.getItem(i); - tstr += transformToString(xform) + " "; - } - this._elem.setAttribute("transform", tstr); - }; - this._list = this; - this._init = function() { - // Transform attribute parser - var str = this._elem.getAttribute("transform"); - if(!str) return; - - // TODO: Add skew support in future - var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; - var arr = []; - var m = true; - while(m) { - m = str.match(re); - str = str.replace(re,''); - if(m && m[1]) { - var x = m[1]; - var bits = x.split(/\s*\(/); - var name = bits[0]; - var val_bits = bits[1].match(/\s*(.*?)\s*\)/); - val_bits[1] = val_bits[1].replace(/(\d)-/g, "$1 -"); - var val_arr = val_bits[1].split(/[, ]+/); - var letters = 'abcdef'.split(''); - var mtx = svgroot.createSVGMatrix(); - $.each(val_arr, function(i, item) { - val_arr[i] = parseFloat(item); - if(name == 'matrix') { - mtx[letters[i]] = val_arr[i]; - } - }); - var xform = svgroot.createSVGTransform(); - var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1); - var values = name=='matrix'?[mtx]:val_arr; - - if (name == 'scale' && values.length == 1) { - values.push(values[0]); - } else if (name == 'translate' && values.length == 1) { - values.push(0); - } else if (name == 'rotate' && values.length == 1) { - values.push(0); - values.push(0); - } - xform[fname].apply(xform, values); - this._list.appendItem(xform); - } - } - }; - this._removeFromOtherLists = function(item) { - if (item) { - // Check if this transform is already in a transformlist, and - // remove it if so. - var found = false; - for (var id in listMap_) { - var tl = listMap_[id]; - for (var i = 0, len = tl._xforms.length; i < len; ++i) { - if(tl._xforms[i] == item) { - found = true; - tl.removeItem(i); - break; - } - } - if (found) { - break; - } - } - } - }; - - this.numberOfItems = 0; - this.clear = function() { - this.numberOfItems = 0; - this._xforms = []; - }; - - this.initialize = function(newItem) { - this.numberOfItems = 1; - this._removeFromOtherLists(newItem); - this._xforms = [newItem]; - }; - - this.getItem = function(index) { - if (index < this.numberOfItems && index >= 0) { - return this._xforms[index]; - } - throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR - }; - - this.insertItemBefore = function(newItem, index) { - var retValue = null; - if (index >= 0) { - if (index < this.numberOfItems) { - this._removeFromOtherLists(newItem); - var newxforms = new Array(this.numberOfItems + 1); - // TODO: use array copying and slicing - for ( var i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - newxforms[i] = newItem; - for ( var j = i+1; i < this.numberOfItems; ++j, ++i) { - newxforms[j] = this._xforms[i]; - } - this.numberOfItems++; - this._xforms = newxforms; - retValue = newItem; - this._list._update(); - } - else { - retValue = this._list.appendItem(newItem); - } - } - return retValue; - }; - - this.replaceItem = function(newItem, index) { - var retValue = null; - if (index < this.numberOfItems && index >= 0) { - this._removeFromOtherLists(newItem); - this._xforms[index] = newItem; - retValue = newItem; - this._list._update(); - } - return retValue; - }; - - this.removeItem = function(index) { - if (index < this.numberOfItems && index >= 0) { - var retValue = this._xforms[index]; - var newxforms = new Array(this.numberOfItems - 1); - for (var i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - for (var j = i; j < this.numberOfItems-1; ++j, ++i) { - newxforms[j] = this._xforms[i+1]; - } - this.numberOfItems--; - this._xforms = newxforms; - this._list._update(); - return retValue; - } else { - throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR - } - }; - - this.appendItem = function(newItem) { - this._removeFromOtherLists(newItem); - this._xforms.push(newItem); - this.numberOfItems++; - this._list._update(); - return newItem; - }; -}; - - -svgedit.transformlist.resetListMap = function() { - listMap_ = {}; -}; - -/** - * Removes transforms of the given element from the map. - * Parameters: - * elem - a DOM Element - */ -svgedit.transformlist.removeElementFromListMap = function(elem) { - if (elem.id && listMap_[elem.id]) { - delete listMap_[elem.id]; - } -}; - -// Function: getTransformList -// Returns an object that behaves like a SVGTransformList for the given DOM element -// -// Parameters: -// elem - DOM element to get a transformlist from -svgedit.transformlist.getTransformList = function(elem) { - if (!svgedit.browser.supportsNativeTransformLists()) { - var id = elem.id; - if(!id) { - // Get unique ID for temporary element - id = 'temp'; - } - var t = listMap_[id]; - if (!t || id == 'temp') { - listMap_[id] = new svgedit.transformlist.SVGTransformList(elem); - listMap_[id]._init(); - t = listMap_[id]; - } - return t; - } - else if (elem.transform) { - return elem.transform.baseVal; - } - else if (elem.gradientTransform) { - return elem.gradientTransform.baseVal; - } - else if (elem.patternTransform) { - return elem.patternTransform.baseVal; - } - - return null; -}; - - -})(); \ No newline at end of file diff --git a/build/svg-edit-2.6-src/editor/svgutils.js b/build/svg-edit-2.6-src/editor/svgutils.js deleted file mode 100644 index a3a6b49..0000000 --- a/build/svg-edit-2.6-src/editor/svgutils.js +++ /dev/null @@ -1,648 +0,0 @@ -/** - * Package: svgedit.utilities - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.utilities) { - svgedit.utilities = {}; -} - -// Constants - -// String used to encode base64. -var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; -var SVGNS = 'http://www.w3.org/2000/svg'; -var XLINKNS = 'http://www.w3.org/1999/xlink'; -var XMLNS = "http://www.w3.org/XML/1998/namespace"; - -// Much faster than running getBBox() every time -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); -//var hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath'; - -var editorContext_ = null; -var domdoc_ = null; -var domcontainer_ = null; -var svgroot_ = null; - -svgedit.utilities.init = function(editorContext) { - editorContext_ = editorContext; - domdoc_ = editorContext.getDOMDocument(); - domcontainer_ = editorContext.getDOMContainer(); - svgroot_ = editorContext.getSVGRoot(); -}; - -// Function: svgedit.utilities.toXml -// Converts characters in a string to XML-friendly entities. -// -// Example: "&" becomes "&" -// -// Parameters: -// str - The string to be converted -// -// Returns: -// The converted string -svgedit.utilities.toXml = function(str) { - return $('<p/>').text(str).html(); -}; - -// Function: svgedit.utilities.fromXml -// Converts XML entities in a string to single characters. -// Example: "&" becomes "&" -// -// Parameters: -// str - The string to be converted -// -// Returns: -// The converted string -svgedit.utilities.fromXml = function(str) { - return $('<p/>').html(str).text(); -}; - -// This code was written by Tyler Akins and has been placed in the -// public domain. It would be nice if you left this header intact. -// Base64 code from Tyler Akins -- http://rumkin.com - -// schiller: Removed string concatenation in favour of Array.join() optimization, -// also precalculate the size of the array needed. - -// Function: svgedit.utilities.encode64 -// Converts a string to base64 -svgedit.utilities.encode64 = function(input) { - // base64 strings are 4/3 larger than the original string -// input = svgedit.utilities.encodeUTF8(input); // convert non-ASCII characters - input = svgedit.utilities.convertToXMLReferences(input); - if(window.btoa) return window.btoa(input); // Use native if available - var output = new Array( Math.floor( (input.length + 2) / 3 ) * 4 ); - var chr1, chr2, chr3; - var enc1, enc2, enc3, enc4; - var i = 0, p = 0; - - do { - chr1 = input.charCodeAt(i++); - chr2 = input.charCodeAt(i++); - chr3 = input.charCodeAt(i++); - - enc1 = chr1 >> 2; - enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); - enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); - enc4 = chr3 & 63; - - if (isNaN(chr2)) { - enc3 = enc4 = 64; - } else if (isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = KEYSTR.charAt(enc1); - output[p++] = KEYSTR.charAt(enc2); - output[p++] = KEYSTR.charAt(enc3); - output[p++] = KEYSTR.charAt(enc4); - } while (i < input.length); - - return output.join(''); -}; - -// Function: svgedit.utilities.decode64 -// Converts a string from base64 -svgedit.utilities.decode64 = function(input) { - if(window.atob) return window.atob(input); - var output = ""; - var chr1, chr2, chr3 = ""; - var enc1, enc2, enc3, enc4 = ""; - var i = 0; - - // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); - - do { - enc1 = KEYSTR.indexOf(input.charAt(i++)); - enc2 = KEYSTR.indexOf(input.charAt(i++)); - enc3 = KEYSTR.indexOf(input.charAt(i++)); - enc4 = KEYSTR.indexOf(input.charAt(i++)); - - chr1 = (enc1 << 2) | (enc2 >> 4); - chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); - chr3 = ((enc3 & 3) << 6) | enc4; - - output = output + String.fromCharCode(chr1); - - if (enc3 != 64) { - output = output + String.fromCharCode(chr2); - } - if (enc4 != 64) { - output = output + String.fromCharCode(chr3); - } - - chr1 = chr2 = chr3 = ""; - enc1 = enc2 = enc3 = enc4 = ""; - - } while (i < input.length); - return unescape(output); -}; - -// Currently not being used, so commented out for now -// based on http://phpjs.org/functions/utf8_encode:577 -// codedread:does not seem to work with webkit-based browsers on OSX -// "encodeUTF8": function(input) { -// //return unescape(encodeURIComponent(input)); //may or may not work -// var output = ''; -// for (var n = 0; n < input.length; n++){ -// var c = input.charCodeAt(n); -// if (c < 128) { -// output += input[n]; -// } -// else if (c > 127) { -// if (c < 2048){ -// output += String.fromCharCode((c >> 6) | 192); -// } -// else { -// output += String.fromCharCode((c >> 12) | 224) + String.fromCharCode((c >> 6) & 63 | 128); -// } -// output += String.fromCharCode((c & 63) | 128); -// } -// } -// return output; -// }, - -// Function: svgedit.utilities.convertToXMLReferences -// Converts a string to use XML references -svgedit.utilities.convertToXMLReferences = function(input) { - var output = ''; - for (var n = 0; n < input.length; n++){ - var c = input.charCodeAt(n); - if (c < 128) { - output += input[n]; - } else if(c > 127) { - output += ("&#" + c + ";"); - } - } - return output; -}; - -// Function: svgedit.utilities.text2xml -// Cross-browser compatible method of converting a string to an XML tree -// found this function here: http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f -svgedit.utilities.text2xml = function(sXML) { - if(sXML.indexOf('<svg:svg') >= 0) { - sXML = sXML.replace(/<(\/?)svg:/g, '<$1').replace('xmlns:svg', 'xmlns'); - } - - var out; - try{ - var dXML = (window.DOMParser)?new DOMParser():new ActiveXObject("Microsoft.XMLDOM"); - dXML.async = false; - } catch(e){ - throw new Error("XML Parser could not be instantiated"); - }; - try{ - if(dXML.loadXML) out = (dXML.loadXML(sXML))?dXML:false; - else out = dXML.parseFromString(sXML, "text/xml"); - } - catch(e){ throw new Error("Error parsing XML string"); }; - return out; -}; - -// Function: svgedit.utilities.bboxToObj -// Converts a SVGRect into an object. -// -// Parameters: -// bbox - a SVGRect -// -// Returns: -// An object with properties names x, y, width, height. -svgedit.utilities.bboxToObj = function(bbox) { - return { - x: bbox.x, - y: bbox.y, - width: bbox.width, - height: bbox.height - } -}; - -// Function: svgedit.utilities.walkTree -// Walks the tree and executes the callback on each element in a top-down fashion -// -// Parameters: -// elem - DOM element to traverse -// cbFn - Callback function to run on each element -svgedit.utilities.walkTree = function(elem, cbFn){ - if (elem && elem.nodeType == 1) { - cbFn(elem); - var i = elem.childNodes.length; - while (i--) { - svgedit.utilities.walkTree(elem.childNodes.item(i), cbFn); - } - } -}; - -// Function: svgedit.utilities.walkTreePost -// Walks the tree and executes the callback on each element in a depth-first fashion -// TODO: FIXME: Shouldn't this be calling walkTreePost? -// -// Parameters: -// elem - DOM element to traverse -// cbFn - Callback function to run on each element -svgedit.utilities.walkTreePost = function(elem, cbFn) { - if (elem && elem.nodeType == 1) { - var i = elem.childNodes.length; - while (i--) { - svgedit.utilities.walkTree(elem.childNodes.item(i), cbFn); - } - cbFn(elem); - } -}; - -// Function: svgedit.utilities.getUrlFromAttr -// Extracts the URL from the url(...) syntax of some attributes. -// Three variants: -// * <circle fill="url(someFile.svg#foo)" /> -// * <circle fill="url('someFile.svg#foo')" /> -// * <circle fill='url("someFile.svg#foo")' /> -// -// Parameters: -// attrVal - The attribute value as a string -// -// Returns: -// String with just the URL, like someFile.svg#foo -svgedit.utilities.getUrlFromAttr = function(attrVal) { - if (attrVal) { - // url("#somegrad") - if (attrVal.indexOf('url("') === 0) { - return attrVal.substring(5,attrVal.indexOf('"',6)); - } - // url('#somegrad') - else if (attrVal.indexOf("url('") === 0) { - return attrVal.substring(5,attrVal.indexOf("'",6)); - } - else if (attrVal.indexOf("url(") === 0) { - return attrVal.substring(4,attrVal.indexOf(')')); - } - } - return null; -}; - -// Function: svgedit.utilities.getHref -// Returns the given element's xlink:href value -svgedit.utilities.getHref = function(elem) { - return elem.getAttributeNS(XLINKNS, "href"); -} - -// Function: svgedit.utilities.setHref -// Sets the given element's xlink:href value -svgedit.utilities.setHref = function(elem, val) { - elem.setAttributeNS(XLINKNS, "xlink:href", val); -} - -// Function: findDefs -// Parameters: -// svgElement - The <svg> element. -// -// Returns: -// The document's <defs> element, create it first if necessary -svgedit.utilities.findDefs = function(svgElement) { - var svgElement = editorContext_.getSVGContent().documentElement; - var defs = svgElement.getElementsByTagNameNS(SVGNS, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - // first child is a comment, so call nextSibling - defs = svgElement.insertBefore( svgElement.ownerDocument.createElementNS(SVGNS, "defs" ), svgElement.firstChild.nextSibling); - } - return defs; -}; - -// TODO(codedread): Consider moving the next to functions to bbox.js - -// Function: svgedit.utilities.getPathBBox -// Get correct BBox for a path in Webkit -// Converted from code found here: -// http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html -// -// Parameters: -// path - The path DOM element to get the BBox for -// -// Returns: -// A BBox-like object -svgedit.utilities.getPathBBox = function(path) { - var seglist = path.pathSegList; - var tot = seglist.numberOfItems; - - var bounds = [[], []]; - var start = seglist.getItem(0); - var P0 = [start.x, start.y]; - - for(var i=0; i < tot; i++) { - var seg = seglist.getItem(i); - - if(typeof seg.x == 'undefined') continue; - - // Add actual points to limits - bounds[0].push(P0[0]); - bounds[1].push(P0[1]); - - if(seg.x1) { - var P1 = [seg.x1, seg.y1], - P2 = [seg.x2, seg.y2], - P3 = [seg.x, seg.y]; - - for(var j=0; j < 2; j++) { - - var calc = function(t) { - return Math.pow(1-t,3) * P0[j] - + 3 * Math.pow(1-t,2) * t * P1[j] - + 3 * (1-t) * Math.pow(t,2) * P2[j] - + Math.pow(t,3) * P3[j]; - }; - - var b = 6 * P0[j] - 12 * P1[j] + 6 * P2[j]; - var a = -3 * P0[j] + 9 * P1[j] - 9 * P2[j] + 3 * P3[j]; - var c = 3 * P1[j] - 3 * P0[j]; - - if(a == 0) { - if(b == 0) { - continue; - } - var t = -c / b; - if(0 < t && t < 1) { - bounds[j].push(calc(t)); - } - continue; - } - - var b2ac = Math.pow(b,2) - 4 * c * a; - if(b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac))/(2 * a); - if(0 < t1 && t1 < 1) bounds[j].push(calc(t1)); - var t2 = (-b - Math.sqrt(b2ac))/(2 * a); - if(0 < t2 && t2 < 1) bounds[j].push(calc(t2)); - } - P0 = P3; - } else { - bounds[0].push(seg.x); - bounds[1].push(seg.y); - } - } - - var x = Math.min.apply(null, bounds[0]); - var w = Math.max.apply(null, bounds[0]) - x; - var y = Math.min.apply(null, bounds[1]); - var h = Math.max.apply(null, bounds[1]) - y; - return { - 'x': x, - 'y': y, - 'width': w, - 'height': h - }; -}; - -// Function: groupBBFix -// Get the given/selected element's bounding box object, checking for -// horizontal/vertical lines (see issue 717) -// Note that performance is currently terrible, so some way to improve would -// be great. -// -// Parameters: -// selected - Container or <use> DOM element -function groupBBFix(selected) { - if(svgedit.browser.supportsHVLineContainerBBox()) { - try { return selected.getBBox();} catch(e){} - } - var ref = $.data(selected, 'ref'); - var matched = null; - - if(ref) { - var copy = $(ref).children().clone().attr('visibility', 'hidden'); - $(svgroot_).append(copy); - matched = copy.filter('line, path'); - } else { - matched = $(selected).find('line, path'); - } - - var issue = false; - if(matched.length) { - matched.each(function() { - var bb = this.getBBox(); - if(!bb.width || !bb.height) { - issue = true; - } - }); - if(issue) { - var elems = ref ? copy : $(selected).children(); - ret = getStrokedBBox(elems); - } else { - ret = selected.getBBox(); - } - } else { - ret = selected.getBBox(); - } - if(ref) { - copy.remove(); - } - return ret; -} - -// Function: svgedit.utilities.getBBox -// Get the given/selected element's bounding box object, convert it to be more -// usable when necessary -// -// Parameters: -// elem - Optional DOM element to get the BBox for -svgedit.utilities.getBBox = function(elem) { - var selected = elem || editorContext_.geSelectedElements()[0]; - if (elem.nodeType != 1) return null; - var ret = null; - var elname = selected.nodeName; - - switch ( elname ) { - case 'text': - if(selected.textContent === '') { - selected.textContent = 'a'; // Some character needed for the selector to use. - ret = selected.getBBox(); - selected.textContent = ''; - } else { - try { ret = selected.getBBox();} catch(e){} - } - break; - case 'path': - if(!svgedit.browser.supportsPathBBox()) { - ret = svgedit.utilities.getPathBBox(selected); - } else { - try { ret = selected.getBBox();} catch(e){} - } - break; - case 'g': - case 'a': - ret = groupBBFix(selected); - break; - default: - - if(elname === 'use') { - ret = groupBBFix(selected, true); - } - - if(elname === 'use') { - if(!ret) ret = selected.getBBox(); - if(!svgedit.browser.isWebkit()) { - var bb = {}; - bb.width = ret.width; - bb.height = ret.height; - bb.x = ret.x + parseFloat(selected.getAttribute('x')||0); - bb.y = ret.y + parseFloat(selected.getAttribute('y')||0); - ret = bb; - } - } else if(~visElems_arr.indexOf(elname)) { - try { ret = selected.getBBox();} - 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; - } - } - } - } - - if(ret) { - ret = svgedit.utilities.bboxToObj(ret); - } - - // get the bounding box from the DOM (which is in that element's coordinate system) - return ret; -}; - -// Function: svgedit.utilities.getRotationAngle -// Get the rotation angle of the given/selected DOM element -// -// Parameters: -// elem - Optional DOM element to get the angle for -// to_rad - Boolean that when true returns the value in radians rather than degrees -// -// Returns: -// Float with the angle in degrees or radians -svgedit.utilities.getRotationAngle = function(elem, to_rad) { - var selected = elem || editorContext_.getSelectedElements()[0]; - // find the rotation transform (if any) and set it - var tlist = svgedit.transformlist.getTransformList(selected); - if(!tlist) return 0; // <svg> elements have no tlist - var N = tlist.numberOfItems; - for (var i = 0; i < N; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - return to_rad ? xform.angle * Math.PI / 180.0 : xform.angle; - } - } - return 0.0; -}; - -// Function: getElem -// Get a DOM element by ID within the SVG root element. -// -// Parameters: -// id - String with the element's new ID -if (svgedit.browser.supportsSelectors()) { - svgedit.utilities.getElem = function(id) { - // querySelector lookup - return svgroot_.querySelector('#'+id); - }; -} else if (svgedit.browser.supportsXpath()) { - svgedit.utilities.getElem = function(id) { - // xpath lookup - return domdoc_.evaluate( - 'svg:svg[@id="svgroot"]//svg:*[@id="'+id+'"]', - domcontainer_, - function() { return "http://www.w3.org/2000/svg"; }, - 9, - null).singleNodeValue; - }; -} else { - svgedit.utilities.getElem = function(id) { - // jQuery lookup: twice as slow as xpath in FF - return $(svgroot_).find('[id=' + id + ']')[0]; - }; -} - -// Function: assignAttributes -// Assigns multiple attributes to an element. -// -// Parameters: -// node - DOM element to apply new attribute values to -// attrs - Object with attribute keys/values -// suspendLength - Optional integer of milliseconds to suspend redraw -// unitCheck - Boolean to indicate the need to use svgedit.units.setUnitAttr -svgedit.utilities.assignAttributes = function(node, attrs, suspendLength, unitCheck) { - if(!suspendLength) suspendLength = 0; - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!svgedit.browser.isOpera()) svgroot_.suspendRedraw(suspendLength); - - for (var i in attrs) { - var ns = (i.substr(0,4) === "xml:" ? XMLNS : - i.substr(0,6) === "xlink:" ? XLINKNS : null); - - if(ns) { - node.setAttributeNS(ns, i, attrs[i]); - } else if(!unitCheck) { - node.setAttribute(i, attrs[i]); - } else { - svgedit.units.setUnitAttr(node, i, attrs[i]); - } - - } - - if (!svgedit.browser.isOpera()) svgroot_.unsuspendRedraw(handle); -}; - -// Function: cleanupElement -// Remove unneeded (default) attributes, makes resulting SVG smaller -// -// Parameters: -// element - DOM element to clean up -svgedit.utilities.cleanupElement = function(element) { - var handle = svgroot_.suspendRedraw(60); - var defaults = { - 'fill-opacity':1, - 'stop-opacity':1, - 'opacity':1, - 'stroke':'none', - 'stroke-dasharray':'none', - 'stroke-linejoin':'miter', - 'stroke-linecap':'butt', - 'stroke-opacity':1, - 'stroke-width':1, - 'rx':0, - 'ry':0 - } - - for(var attr in defaults) { - var val = defaults[attr]; - if(element.getAttribute(attr) == val) { - element.removeAttribute(attr); - } - } - - svgroot_.unsuspendRedraw(handle); -}; - - -})(); diff --git a/build/svg-edit-2.6-src/editor/touch.js b/build/svg-edit-2.6-src/editor/touch.js deleted file mode 100644 index 7db1544..0000000 --- a/build/svg-edit-2.6-src/editor/touch.js +++ /dev/null @@ -1,28 +0,0 @@ -function touchHandler(event) -{ - - var touches = event.changedTouches, - first = touches[0], - type = ""; - switch(event.type) - { - case "touchstart": type="mousedown"; break; - case "touchmove": type="mousemove"; break; - case "touchend": type="mouseup"; break; - default: return; - } - - //initMouseEvent(type, canBubble, cancelable, view, clickCount, - // screenX, screenY, clientX, clientY, ctrlKey, - // altKey, shiftKey, metaKey, button, relatedTarget); - - var simulatedEvent = document.createEvent("MouseEvent"); - simulatedEvent.initMouseEvent(type, true, true, window, 1, - first.screenX, first.screenY, - first.clientX, first.clientY, false, - false, false, false, 0/*left*/, null); - if(touches.length < 2) { - first.target.dispatchEvent(simulatedEvent); - event.preventDefault(); - } -} diff --git a/build/svg-edit-2.6-src/editor/units.js b/build/svg-edit-2.6-src/editor/units.js deleted file mode 100644 index f2b30e7..0000000 --- a/build/svg-edit-2.6-src/editor/units.js +++ /dev/null @@ -1,281 +0,0 @@ -/** - * Package: svgedit.units - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.units) { - svgedit.units = {}; -} - -var w_attrs = ['x', 'x1', 'cx', 'rx', 'width']; -var h_attrs = ['y', 'y1', 'cy', 'ry', 'height']; -var unit_attrs = $.merge(['r','radius'], w_attrs); - -var unitNumMap = { - '%': 2, - 'em': 3, - 'ex': 4, - 'px': 5, - 'cm': 6, - 'mm': 7, - 'in': 8, - 'pt': 9, - 'pc': 10 -}; - -$.merge(unit_attrs, h_attrs); - -// Container of elements. -var elementContainer_; - -/** - * Stores mapping of unit type to user coordinates. - */ -var typeMap_ = {px: 1}; - -/** - * ElementContainer interface - * - * function getBaseUnit() - returns a string of the base unit type of the container ("em") - * function getElement() - returns an element in the container given an id - * function getHeight() - returns the container's height - * function getWidth() - returns the container's width - * function getRoundDigits() - returns the number of digits number should be rounded to - */ - -/** - * Function: svgedit.units.init() - * Initializes this module. - * - * Parameters: - * elementContainer - an object implementing the ElementContainer interface. - */ -svgedit.units.init = function(elementContainer) { - elementContainer_ = elementContainer; - - var svgns = 'http://www.w3.org/2000/svg'; - - // Get correct em/ex values by creating a temporary SVG. - var svg = document.createElementNS(svgns, 'svg'); - document.body.appendChild(svg); - var rect = document.createElementNS(svgns,'rect'); - rect.setAttribute('width',"1em"); - rect.setAttribute('height',"1ex"); - rect.setAttribute('x',"1in"); - svg.appendChild(rect); - var bb = rect.getBBox(); - document.body.removeChild(svg); - - var inch = bb.x; - typeMap_['em'] = bb.width; - typeMap_['ex'] = bb.height; - typeMap_['in'] = inch; - typeMap_['cm'] = inch / 2.54; - typeMap_['mm'] = inch / 25.4; - typeMap_['pt'] = inch / 72; - typeMap_['pc'] = inch / 6; - typeMap_['%'] = 0; -}; - -// Group: Unit conversion functions - -// Function: svgedit.units.getTypeMap -// Returns the unit object with values for each unit -svgedit.units.getTypeMap = function() { - return typeMap_; -}; - -// Function: svgedit.units.shortFloat -// Rounds a given value to a float with number of digits defined in save_options -// -// Parameters: -// val - The value as a String, Number or Array of two numbers to be rounded -// -// Returns: -// If a string/number was given, returns a Float. If an array, return a string -// with comma-seperated floats -svgedit.units.shortFloat = function(val) { - var digits = elementContainer_.getRoundDigits(); - if(!isNaN(val)) { - // Note that + converts to Number - return +((+val).toFixed(digits)); - } else if($.isArray(val)) { - return svgedit.units.shortFloat(val[0]) + ',' + svgedit.units.shortFloat(val[1]); - } - return parseFloat(val).toFixed(digits) - 0; -}; - -// Function: svgedit.units.convertUnit -// Converts the number to given unit or baseUnit -svgedit.units.convertUnit = function(val, unit) { - unit = unit || elementContainer_.getBaseUnit(); -// baseVal.convertToSpecifiedUnits(unitNumMap[unit]); -// var val = baseVal.valueInSpecifiedUnits; -// baseVal.convertToSpecifiedUnits(1); - return svgedit.unit.shortFloat(val / typeMap_[unit]); -}; - -// Function: svgedit.units.setUnitAttr -// Sets an element's attribute based on the unit in its current value. -// -// Parameters: -// elem - DOM element to be changed -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to convert -svgedit.units.setUnitAttr = function(elem, attr, val) { - if(!isNaN(val)) { - // New value is a number, so check currently used unit - var old_val = elem.getAttribute(attr); - - // Enable this for alternate mode -// if(old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) { -// // Old value was a number, so get unit, then convert -// var unit; -// if(old_val.substr(-1) === '%') { -// var res = getResolution(); -// unit = '%'; -// val *= 100; -// if(w_attrs.indexOf(attr) >= 0) { -// val = val / res.w; -// } else if(h_attrs.indexOf(attr) >= 0) { -// val = val / res.h; -// } else { -// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2); -// } -// } else { -// if(elementContainer_.getBaseUnit() !== 'px') { -// unit = elementContainer_.getBaseUnit(); -// } else { -// unit = old_val.substr(-2); -// } -// val = val / typeMap_[unit]; -// } -// -// val += unit; -// } - } - elem.setAttribute(attr, val); -}; - -var attrsToConvert = { - "line": ['x1', 'x2', 'y1', 'y2'], - "circle": ['cx', 'cy', 'r'], - "ellipse": ['cx', 'cy', 'rx', 'ry'], - "foreignObject": ['x', 'y', 'width', 'height'], - "rect": ['x', 'y', 'width', 'height'], - "image": ['x', 'y', 'width', 'height'], - "use": ['x', 'y', 'width', 'height'], - "text": ['x', 'y'] -}; - -// Function: svgedit.units.convertAttrs -// Converts all applicable attributes to the configured baseUnit -// -// Parameters: -// element - a DOM element whose attributes should be converted -svgedit.units.convertAttrs = function(element) { - var elName = element.tagName; - var unit = elementContainer_.getBaseUnit(); - var attrs = attrsToConvert[elName]; - if(!attrs) return; - var len = attrs.length - for(var i = 0; i < len; i++) { - var attr = attrs[i]; - var cur = element.getAttribute(attr); - if(cur) { - if(!isNaN(cur)) { - element.setAttribute(attr, (cur / typeMap_[unit]) + unit); - } else { - // Convert existing? - } - } - } -}; - -// Function: svgedit.units.convertToNum -// Converts given values to numbers. Attributes must be supplied in -// case a percentage is given -// -// Parameters: -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to convert -svgedit.units.convertToNum = function(attr, val) { - // Return a number if that's what it already is - if(!isNaN(val)) return val-0; - - if(val.substr(-1) === '%') { - // Deal with percentage, depends on attribute - var num = val.substr(0, val.length-1)/100; - var width = elementContainer_.getWidth(); - var height = elementContainer_.getHeight(); - - if(w_attrs.indexOf(attr) >= 0) { - return num * width; - } else if(h_attrs.indexOf(attr) >= 0) { - return num * height; - } else { - return num * Math.sqrt((width*width) + (height*height))/Math.sqrt(2); - } - } else { - var unit = val.substr(-2); - var num = val.substr(0, val.length-2); - // Note that this multiplication turns the string into a number - return num * typeMap_[unit]; - } -}; - -// Function: svgedit.units.isValidUnit -// Check if an attribute's value is in a valid format -// -// Parameters: -// attr - String with the name of the attribute associated with the value -// val - String with the attribute value to check -svgedit.units.isValidUnit = function(attr, val, selectedElement) { - var valid = false; - if(unit_attrs.indexOf(attr) >= 0) { - // True if it's just a number - if(!isNaN(val)) { - valid = true; - } else { - // Not a number, check if it has a valid unit - val = val.toLowerCase(); - $.each(typeMap_, function(unit) { - if(valid) return; - var re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - if(re.test(val)) valid = true; - }); - } - } else if (attr == "id") { - // if we're trying to change the id, make sure it's not already present in the doc - // and the id value is valid. - - var result = false; - // because getElem() can throw an exception in the case of an invalid id - // (according to http://www.w3.org/TR/xml-id/ IDs must be a NCName) - // we wrap it in an exception and only return true if the ID was valid and - // not already present - try { - var elem = elementContainer_.getElement(val); - result = (elem == null || elem === selectedElement); - } catch(e) {} - return result; - } else { - valid = true; - } - - return valid; -}; - - -})(); \ No newline at end of file diff --git a/build/svg-edit-2.6-src/examples/arbelos.svg b/build/svg-edit-2.6-src/examples/arbelos.svg deleted file mode 100644 index c9cc18a..0000000 --- a/build/svg-edit-2.6-src/examples/arbelos.svg +++ /dev/null @@ -1,197 +0,0 @@ -<?xml version="1.0" standalone="no"?> -<svg width="800" height="600" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"> - <!-- Created with SVG-edit - http://svg-edit.googlecode.com/ --> - <defs> - <linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_10"> - <stop stop-opacity="1" stop-color="#ff00ff" offset="0"/> - <stop stop-opacity="0" stop-color="#ff00ff" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_11"> - <stop stop-opacity="1" stop-color="#7f007f" offset="0"/> - <stop stop-opacity="0" stop-color="#7f007f" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_17"> - <stop stop-opacity="1" stop-color="#cccccc" offset="0"/> - <stop stop-opacity="1" stop-color="#0b3535" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_26"> - <stop stop-opacity="1" stop-color="#bf005f" offset="0"/> - <stop stop-opacity="1" stop-color="#aaffff" offset="1"/> - </linearGradient> - <linearGradient y2="0.65234" x2="0.74609" y1="0" x1="0" id="svg_27"> - <stop stop-opacity="1" stop-color="#bf005f" offset="0"/> - <stop stop-opacity="1" stop-color="#aaffff" offset="1"/> - </linearGradient> - <linearGradient y2="0.51953" x2="0.61719" y1="0" x1="0" id="svg_28"> - <stop stop-opacity="1" stop-color="#bf005f" offset="0"/> - <stop stop-opacity="1" stop-color="#aaffff" offset="1"/> - </linearGradient> - <linearGradient y2="0.34766" x2="0.42188" y1="0" x1="0" id="svg_29"> - <stop stop-opacity="1" stop-color="#bf005f" offset="0"/> - <stop stop-opacity="1" stop-color="#aaffff" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_43"> - <stop stop-opacity="1" stop-color="#0000ff" offset="0"/> - <stop stop-opacity="1" stop-color="#333333" offset="1"/> - </linearGradient> - <linearGradient y2="0.94141" x2="0.42578" y1="0.17188" x1="0.80859" id="svg_31"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="1" stop-color="#626784" offset="1"/> - </linearGradient> - <linearGradient y2="0.95703" x2="0.98828" y1="0.38281" x1="0.46484" id="svg_38"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="1" stop-color="#626784" offset="1"/> - </linearGradient> - <linearGradient y2="0.03125" x2="0.98438" y1="0.90234" x1="0.11719" id="svg_39"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="1" stop-color="#626784" offset="1"/> - </linearGradient> - <linearGradient y2="0.125" x2="0.69922" y1="0.75781" x1="0.48828" id="svg_40"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="1" stop-color="#626784" offset="1"/> - </linearGradient> - <linearGradient y2="0.46094" x2="0.66016" y1="0.77734" x1="0.09766" id="svg_106"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="1" stop-color="#626784" offset="1"/> - </linearGradient> - <linearGradient y2="0.10156" x2="0.88672" y1="0.33984" x1="0.40625" id="svg_116"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="0.82" stop-color="#626784" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0" x1="0" id="svg_125"> - <stop stop-opacity="1" stop-color="#060649" offset="0"/> - <stop stop-opacity="0.77" stop-color="#3b5b7a" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0.18359" x1="0.23438" id="svg_126"> - <stop stop-opacity="1" stop-color="#c7eaea" offset="0"/> - <stop stop-opacity="1" stop-color="#e5e5e5" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0.18359" x1="0.23438" id="svg_132"> - <stop stop-opacity="1" stop-color="#a1c6c6" offset="0"/> - <stop stop-opacity="1" stop-color="#e5e5e5" offset="1"/> - </linearGradient> - <linearGradient y2="0.85938" x2="0.22266" y1="0.07813" x1="0.875" id="svg_134"> - <stop stop-opacity="1" stop-color="#333333" offset="0"/> - <stop stop-opacity="1" stop-color="#5b5b93" offset="1"/> - </linearGradient> - <linearGradient y2="1" x2="1" y1="0.18359" x1="0.23438" id="svg_135"> - <stop stop-opacity="1" stop-color="#ffffff" offset="0"/> - <stop stop-opacity="1" stop-color="#e5e5e5" offset="1"/> - </linearGradient> - <linearGradient id="svg_58" x1="0.60938" y1="0.62891" x2="1" y2="0.01953"> - <stop offset="0" stop-color="#0b0b28" stop-opacity="1"/> - <stop offset="1" stop-color="#0b0b28" stop-opacity="0.5"/> - </linearGradient> - <linearGradient id="svg_60" x1="0.96094" y1="0" x2="0.60938" y2="0.29297"> - <stop offset="0" stop-color="#00ccff" stop-opacity="1"/> - <stop offset="1" stop-color="#00ccff" stop-opacity="0.42"/> - </linearGradient> - <linearGradient id="svg_71" x1="0.48047" y1="0.01172" x2="0.49609" y2="0.22656"> - <stop offset="0" stop-color="#ffffff" stop-opacity="1"/> - <stop offset="1" stop-color="#ffffff" stop-opacity="0"/> - </linearGradient> - <linearGradient id="svg_76" x1="0.46094" y1="0.75391" x2="0.46094" y2="0.37891"> - <stop offset="0" stop-color="#ffffff" stop-opacity="1"/> - <stop offset="1" stop-color="#ffffff" stop-opacity="0"/> - </linearGradient> - <linearGradient id="svg_80" x1="0.48828" y1="0.88672" x2="0.5" y2="0.00391"> - <stop offset="0" stop-color="#ffffff" stop-opacity="1"/> - <stop offset="1" stop-color="#ffffff" stop-opacity="0"/> - </linearGradient> - <linearGradient id="svg_83" x1="0" y1="0" x2="1" y2="1"> - <stop offset="0" stop-color="#ffffff" stop-opacity="1"/> - <stop offset="1" stop-color="#ffffff" stop-opacity="0"/> - </linearGradient> - <linearGradient id="svg_84" x1="0.48828" y1="0.97266" x2="0.54297" y2="0.28516"> - <stop offset="0" stop-color="#871187" stop-opacity="1"/> - <stop offset="1" stop-color="#871187" stop-opacity="0.46"/> - </linearGradient> - </defs> - <title>SVG-edit 2.4 Arbelos - - Layer 2 - - - - - - Layer 3 - - - - - - - Layer 4 - - - - Background - - - - - Arbelos - - - - - - - - - - - Manta Ray - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Text - Link - - - SVG-edit - SVG-edit - - - - - - SVG-edit - - 2.4 Arbelos - 2.4 Arbelos - 2.4 Arbelos - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/examples/mickey.svg b/build/svg-edit-2.6-src/examples/mickey.svg deleted file mode 100644 index 72bcde5..0000000 --- a/build/svg-edit-2.6-src/examples/mickey.svg +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - SVG-edit - SVG-edit - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/extras/server-save/README b/build/svg-edit-2.6-src/extras/server-save/README deleted file mode 100644 index e94370b..0000000 --- a/build/svg-edit-2.6-src/extras/server-save/README +++ /dev/null @@ -1,8 +0,0 @@ -Usage: - -1) copy file svg-editor-save.php into the directory - -2) edit the end of the svgcanvas.js and change this.saveHandler method - into the method described in svg-editor-save.js - -3) now the drawings will be saved into the file named saved.svg diff --git a/build/svg-edit-2.6-src/extras/server-save/svg-editor-save.js b/build/svg-edit-2.6-src/extras/server-save/svg-editor-save.js deleted file mode 100644 index ea6a089..0000000 --- a/build/svg-edit-2.6-src/extras/server-save/svg-editor-save.js +++ /dev/null @@ -1,3 +0,0 @@ -this.saveHandler = function(svg) { - $.post("svg-editor-save.php", { svg_data: escape(svg) } ); -}); diff --git a/build/svg-edit-2.6-src/extras/server-save/svg-editor-save.php b/build/svg-edit-2.6-src/extras/server-save/svg-editor-save.php deleted file mode 100644 index 10617b9..0000000 --- a/build/svg-edit-2.6-src/extras/server-save/svg-editor-save.php +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/build/svg-edit-2.6-src/extras/tojson.py b/build/svg-edit-2.6-src/extras/tojson.py deleted file mode 100644 index 5feea1d..0000000 --- a/build/svg-edit-2.6-src/extras/tojson.py +++ /dev/null @@ -1,52 +0,0 @@ -import sys, json, codecs -infile = codecs.open(sys.argv[1], "r", "utf-8") -outfile = codecs.open(sys.argv[1][:-3], "w", "utf-8") -indata = infile.readlines() -look = False -out = "[\n" -js = [] -jss = "" - -def readfrompos(pos): - global out - global js - - if (indata[pos].startswith("#, -x-svg-edit-title")) or (indata[pos].startswith("#, -x-svg-edit-textContent")): - out += '{' - out += '"id": ' - out += " ".join(indata[pos+1].split()[1:]) + ", " - out += '"' + line[15:].strip() + '": ' - out += " ".join(indata[pos+2].split()[1:]) - out += '}' - elif (indata[pos].startswith("#, -x-svg-edit-both")): - out += '{' - out += '"id": ' - out += " ".join(indata[pos+1].split()[1:]) + ", " - out += '"textContent": ' - out += '"' + " ".join(indata[pos+2].split()[1:]).split('|')[1] + ', ' - out += '"title": ' - out += " ".join(indata[pos+2].split()[1:]).split('|')[0] + '"' - out += '}' - elif (indata[pos].startswith("#, -x-svg-edit-js_strings")): - js.append((" ".join(indata[pos+1].split()[1:]), " ".join(indata[pos+2].split()[1:]))) - -for pos, line in enumerate(indata): - if (not look) and (line.startswith('# ---')): - look = True - marker = pos - elif (look) and (line.startswith('#, -x-svg-edit')): - readfrompos(pos) - -js.sort() - -for j in js: - jss += " %s: %s,\n" % (j[0], j[1]) - -out += '{\n "js_strings": {\n' -out += str(jss) -out += ' "": ""\n }' -out += "\n}" -out += "\n]" -out = out.replace('}{', '},\n{') - -outfile.write(out) \ No newline at end of file diff --git a/build/svg-edit-2.6-src/extras/topo.py b/build/svg-edit-2.6-src/extras/topo.py deleted file mode 100644 index 592cbee..0000000 --- a/build/svg-edit-2.6-src/extras/topo.py +++ /dev/null @@ -1,39 +0,0 @@ -import sys, json, codecs -infile = json.load(codecs.open(sys.argv[1], "r", "utf-8")) -outfile = codecs.open(sys.argv[1] + ".po", "w", "utf-8") -out = [] - -out.append("""# LANGUAGE FILE FOR SVG-EDIT, AUTOGENERATED BY TOPO.PY - -msgid "" -msgstr "" -"Content-Type: text/plain; charset=utf-8\\n" -"Content-Transfer-Encoding: 8bit\\n" - -# --- - -""") - -def printstr(flag, i, s): - out.append('\n') - if flag == '-x-svg-edit-both': - out.append("# Enter the title first, then the contents, seperated by a pipe char (|)\n") - out.append("#, " + flag + '\n') - out.append("msgid \"" + i + "\"" + '\n') - out.append("msgstr \"" + s.replace('\n', '\\n') + "\"" + '\n') - -for line in infile: - if line.has_key('title') and line.has_key('textContent'): - printstr('-x-svg-edit-both', line['id'], "|".join(((line['title'], line['textContent'])))) - elif line.has_key('title'): - printstr('-x-svg-edit-title', line['id'], line['title']) - elif line.has_key('textContent'): - printstr('-x-svg-edit-textContent', line['id'], line['textContent']) - elif line.has_key('js_strings'): - for i, s in line['js_strings'].items(): - printstr('-x-svg-edit-js_strings', i, s) - else: - pass # The line wasn't really a string - -outfile.writelines(out) -outfile.close() \ No newline at end of file diff --git a/build/svg-edit-2.6-src/extras/update-langs.py b/build/svg-edit-2.6-src/extras/update-langs.py deleted file mode 100755 index 0a33dae..0000000 --- a/build/svg-edit-2.6-src/extras/update-langs.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -# -*- coding: iso-8859-15 -*- -""" -This is a helper script for the svg-edit project, useful for managing -all the language files - -Licensed under the Apache 2 License as is the rest of the project -Requires Python 2.6 - -Copyright (c) 2010 Jeff Schiller -""" -import os -import json -from types import DictType - -def changeTooltipTarget(j): - """ - Moves the tooltip target for some tools - """ - tools = ['rect_width', 'rect_height'] - for row in j: - try: - id = row['id'] - if id in tools: - row['id'] = row['id'] + '_tool' - except KeyError: - pass - -def updateMainMenu(j): - """ - Converts title into textContent for items in the main menu - """ - tools = ['tool_clear', 'tool_open', 'tool_save', 'tool_docprops'] - for row in j: - try: - ids = row['id'] - if ids in tools: - row[u'textContent'] = row.pop('title') - except KeyError: - pass - -def ourPrettyPrint(j): - """ - Outputs a string representation of the JSON object passed in - formatted properly for our lang.XX.js files. - """ - s = '[' + os.linesep - js_strings = None - j.sort() - for row in j: - try: - ids = row['id'] - row_string = json.dumps(row, sort_keys=True, ensure_ascii=False) - s += row_string + ',' + os.linesep - except KeyError: - if type(row) is DictType: - js_strings = row - - s += json.dumps(js_strings, sort_keys=True, ensure_ascii=False, indent=1) + os.linesep - s += ']' - return s - -def processFile(filename): - """ - Loads the given lang.XX.js file, processes it and saves it - back to the file system - """ - in_string = open('../editor/locale/' + filename, 'r').read() - - try: - j = json.loads(in_string) - - # process the JSON object here - changeTooltipTarget(j) - - # now write it out back to the file - s = ourPrettyPrint(j).encode("UTF-8") - open('../editor/locale/' + filename, 'w').write(s) - - print "Updated " + filename - except ValueError: - print "ERROR! " + filename + " was not valid JSON, please fix it!" - -if __name__ == '__main__': - # get list of all lang files and process them - for file_name in os.listdir('../editor/locale/'): - if file_name[:4] == "lang": - processFile(file_name) diff --git a/build/svg-edit-2.6-src/firefox-extension/.DS_Store b/build/svg-edit-2.6-src/firefox-extension/.DS_Store deleted file mode 100644 index 506beb4..0000000 Binary files a/build/svg-edit-2.6-src/firefox-extension/.DS_Store and /dev/null differ diff --git a/build/svg-edit-2.6-src/firefox-extension/chrome.manifest b/build/svg-edit-2.6-src/firefox-extension/chrome.manifest deleted file mode 100644 index 3e98b2d..0000000 --- a/build/svg-edit-2.6-src/firefox-extension/chrome.manifest +++ /dev/null @@ -1,2 +0,0 @@ -content svg-edit content/ -overlay chrome://browser/content/browser.xul chrome://svg-edit/content/svg-edit-overlay.xul diff --git a/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.css b/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.css deleted file mode 100644 index 4b7e9b5..0000000 --- a/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.css +++ /dev/null @@ -1,21 +0,0 @@ -#svg-edit-statusbar-button { - list-style-image: url("chrome://svg-edit/content/editor/images/logo.png"); - display: -moz-box; - /*-moz-image-region: rect(16px, 16px, 32px, 0px);*/ - padding-left: 0px; - padding-right: 0px; - width: 16px; - height: 16px; - -} - -#svg-edit-statusbar-button[state="active"] { - list-style-image: url("chrome://svg-edit/content/editor/images/logo.png"); - -moz-image-region: rect(32px, 16px, 48px, 0px); -} - -#svg-edit-statusbar-button[state="error"] { - list-style-image: url("chrome://svg-edit/content/editor/images/logo.png"); - -moz-image-region: rect(0px, 16px, 16px, 0px); -} - diff --git a/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.js b/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.js deleted file mode 100644 index 8d1600d..0000000 --- a/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.js +++ /dev/null @@ -1,4 +0,0 @@ -function start_svg_edit() { - var url = "chrome://svg-edit/content/editor/svg-editor.html"; - window.openDialog(url, "SVG Editor", "width=1024,height=700,menubar=no,toolbar=no"); -} diff --git a/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.xul b/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.xul deleted file mode 100644 index 08fdd88..0000000 --- a/build/svg-edit-2.6-src/firefox-extension/content/svg-edit-overlay.xul +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - Failed to load for some reason. - - - diff --git a/build/svg-edit-2.6-src/opera-widget/style.css b/build/svg-edit-2.6-src/opera-widget/style.css deleted file mode 100644 index b4e8ae6..0000000 --- a/build/svg-edit-2.6-src/opera-widget/style.css +++ /dev/null @@ -1,2 +0,0 @@ -body { margin: 0px; padding: 0px; } -#container { width: 100%; height: 100%; border: none; } diff --git a/build/svg-edit-2.6-src/screencasts/svgedit-screencast-1.txt b/build/svg-edit-2.6-src/screencasts/svgedit-screencast-1.txt deleted file mode 100644 index 316c474..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgedit-screencast-1.txt +++ /dev/null @@ -1,27 +0,0 @@ -Hello, my name is Jeff Schiller and I'll be giving you a brief introduction to SVG-edit. In this video, I'll describe what SVG-edit is, what it can do and I'll demonstrate some of its features. - -SVG-edit is a new, open-source, lightweight vector graphics editor similar in nature to Adobe Illustrator or Inkscape. But what's exciting about SVG-edit is that it runs directly in the browser and is powered only by open web technologies such as HTML, CSS, JavaScript and SVG. SVG-edit runs in any modern browser including Firefox, Opera, Safari and Chrome. - -So here is SVG-edit. What we're looking at is a small collection of tools, a color palette at the bottom and a white canvas on which you can draw your masterpiece. We'll see that drawing simple shapes is as simple as clicking the tool you want, I'll choose a simple rectangle here, and then dragging and lifting on the canvas. - -We can draw many types of shapes: rectangles, circles [draw one large one for sun], ellipses [draw two small ones], lines [draw three for sun radiation], or even freehand drawing [draw a smile]. - -If we want to move the elements around, we click on the Select Tool and then drag the element to the correct position. We can click to select one shape or we can drag on the canvas to select multiple shapes. We can use the resizing grips to change the size of the element to our hearts content. [arrange sun, beams, eyes, rectangle floor, and text] - -If we want to change the interior color of a particular shape, we first select the shape using the Select Tool, and then either click on a palette box or we can click on the Fill Paint box and choose the color we want from the standard picker. We can also set the opacity or alpha of the paint. - -Changing the border color of the shape can be done in a similar manner by using the color picker for the Stroke. We can also shift-click on the palette to change the stroke color or to clear the Stroke color. We can also change the thickness of the stroke or the dash-style of the stroke using controls near the bottom of the window. - -A simple Text tool is also included [set stroke to None, set fill to Red, then create a text element that says "Vector Graphics are powerful"] - -I'd like to talk a bit about the tool panel near the top of the window. Apart from some standard buttons on the left, which I'll go over in a minute, the rest of the panel is dedicated to context-sensitive tools. This means that you only see controls on this toolbar for the tool and element you have selected. For instance, when I select a Text element, I see controls to change the text contents, font family, font size and whether the text should be bold or italic. If I select a rectangle, I see controls to change the rectangle's position, size and whether the rectangle should have rounded corners. - -You may have noticed that some buttons were available in both cases. These controls manipulate the selected element. For instance, you can delete an element or move it to the top of the stack. - -The final thing I'd like to talk about is the controls on the left. These controls are always present. There are the standard Undo/Redo buttons. And there are the standard New Document or Save Document buttons. Clicking New will wipe out all existing work. Clicking Save will open a new tab in the browser containing your document. You can then save this document to your desktop, publish it to a website or whatever. - -One final thing to mention: because SVG-edit is a web application, it's quite trivial to embed the editor in a web page using nothing more than an HTML iframe element. Here we see an entry on my blog in which I've done this very thing. - -SVG-edit is still in the beginning stages of development, there are a lot of features missing, but I hope this video has given you a sense of SVG-edit's capabilities and its ease of use. - -Thanks for watching! \ No newline at end of file diff --git a/build/svg-edit-2.6-src/screencasts/svgedit-screencast-2.txt b/build/svg-edit-2.6-src/screencasts/svgedit-screencast-2.txt deleted file mode 100644 index 251c443..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgedit-screencast-2.txt +++ /dev/null @@ -1,23 +0,0 @@ -Hi, this is Jeff Schiller and I'll be describing the new features in the latest release of SVG-edit, version 2.3. - -For those of you who didn't watch the first screencast, SVG-edit is an open source vector graphics editor that works in any modern browser that natively supports SVG. This includes Firefox, Opera, Safari, and Chrome. - -The latest release of SVG-edit sports more than just a new logo, this release brings some powerful new features. Features that you would expect of a first-class vector editor on your desktop. So let's launch the 2.3 Demo [click] - -Probably the most significant new capability that SVG-edit brings is the ability to actually save and reload your work. SVG-edit now comes with a source editor [click on editor], which means you can save your SVG files to your hard disk and then copy and paste them back into SVG-edit and continue your work. You can also fine-tune the source of your drawing if there's something you want to do that isn't yet supported by the editor [add Jeff Schiller to comment and delete -->, show dialog]. - -Another important addition in 2.3 is the ability to construct arbitrary polygons or connected line segments. Once the shape is complete, click on the first point to close the shape or any other point if you want to leave it open. Polys can be dragged and resized just like any other shape. Click the shape again to edit the position of the points. [draw an arrow and position the points] - -Rotation is now supported on shapes. There are a variety of ways to do this: by drag-rotating the handle, by holding shift and pressing the left/right arrow keys or by adjusting the spinner control at the top. [rotate the arrow] - -The final major feature in SVG-edit 2.3 is the ability to pick linear gradients as fill/stroke paints instead of just solid colors. The color picker now has two tabs, one for solid colors and one for gradients. You choose the position of the begin and end stops and the color/opacity of each stop. [set fill on the black ellipse to a vert gradient from white to transparent] - -There are also several minor features worthy of note: - -Elements can now be copy-pasted using the Clone Tool. Select any number of elements and click Clone (or press C) to get the copied elements. - -If you want fine-grained element navigation, you can use the keyboard shortcuts Shift-O and Shift-P to cycle forward or backward through elements on the canvas. - -Compared to desktop vector graphics editors, SVG-edit still has a long ways to go, but already pretty sophisticated artwork can be achieved [open mickey.svg]. It's also important to remember that SVG-edit runs directly in the browser, with no plugins required. This means zero install hassle for users. You don't even need a bleeding edge browser, any SVG-capable browser released for the last few years will just work. - -Thanks for watching. diff --git a/build/svg-edit-2.6-src/screencasts/svgedit-screencast-3.txt b/build/svg-edit-2.6-src/screencasts/svgedit-screencast-3.txt deleted file mode 100644 index 88c98c1..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgedit-screencast-3.txt +++ /dev/null @@ -1,50 +0,0 @@ -SVG-edit 2.4 ------------- - -Hi, this is Jeff Schiller and this is part one of two videos in which I'll be describing the new features in the latest release of SVG-edit 2.4. - -First, some background: SVG-edit is a web-based vector graphics editor that runs in any modern browser that supports SVG. This includes Firefox, Opera, Safari and Chrome. SVG-edit also runs in Internet Explorer with the Google Chrome Frame plugin installed. - -So Version 2.4, code-named Arbelos, is a significant improvement over the previous release: SVG-edit has now evolved from a proof-of-concept demo into a full-featured application. - -In this video I'll talk about the new path tool and the concept of zooming, I'll also cover some of the improvements to the user interface. - -First up is the new path tool. In SVG-edit 2.3, the user had the ability to create a connected series of line segments and polygons [Draw a polyline]. In 2.4, the Poly Tool has evolved into a general purpose Path tool that draw straight lines or curves. To change a line segment into a curve, double-click on the starting point of that segment. Users can also manipulate the look of the curve by moving control points. Curves can be configured to be symmetrical by a push-button in the context panel. As you can see, when I change the position of a control point, the opposite control point also moves. The user also has the ability to add/delete segments to an existing path element. One final note on paths: most graphical elements (rectangles, ellipses, etc) can now be converted into paths for finer editing. This conversion is a one-way process, though it can be undone. - -So next I'm going to talk about zooming. In 2.4, it is now possible to zoom in and out of a graphic. Zooming can be achieved in a variety of ways: Using the zoom control at the bottom left, you can type in a zoom percentage, use the spinner or pick a zoom level from the popup. Also included in the popup are things like "Fit to selection", which can be quite handy. Zooming is also possible via the Zoom tool on the left. Select it, then drag the area you wish to zoom in on. A final option is to just use the mousewheel to zoom the canvas quickly around the mouse pointer. - -From a usability perspective, we've created a Document Properties dialog, available by clicking on the button in the top panel. This dialog box serves as housing for image and editor properties that are seldom accessed, but still important. - -In terms of image properties: - - * Give the image a title - * Change the canvas size, or pick one of several options - (* You can choose to have all local raster images referenced via URL or embedded inline as a data: URL. This will make your SVG image larger, but self-contained and thus, more portable.) - -In terms of editor properties: - - * SVG-edit's entire user interface (tooltips, labels) is fully localizable, and SVG-edit has now been translated into 8 languages. If you would like to contribute translation for a language, please contact us on the mailing list. - * Another nice feature is the ability to set the icon size of the editor, which can help with adapting SVG-edit to different environments (mobile devices, smaller netbooks, widescreen displays). - (* One final editor preference that can be changed is the canvas' colour. For most situations, a white canvas might be fine for creating your graphic, but if you are trying to draw an image with a lot of white in it, you might find this option useful.) - -So that's it for this video. In the next video I'll talk about grouping, layers and a few other features of SVG-edit 2.4. - - --------------------- - -Hi, this is Jeff Schiller and this is the second of two videos describing the new features in the latest release of SVG-edit 2.4, code-named Arbelos. - -If you missed the first video, SVG-edit is a web-based vector graphics editor that runs in any modern browser that supports SVG. This includes Firefox, Opera, Safari and Chrome. SVG-edit also runs in Internet Explorer with the Google Chrome Frame plugin installed. - -In the first video I gave an overview of the Path tool, Zooming and the new Document Properties dialog. In this video I'll talk about grouping, layers and a couple other features that round out the release. - -So first is grouping. In SVG-edit 2.3 one could draw graphical primitives such as ellipses, rectangles, lines and polygons - and those elements could be moved, resized, and rotated. In 2.4 we've added the ability to arrange any number of elements together into a group. Groups behave just like other element types: they can be moved, resized and rotated - and they can be added to larger groups to create even more complex objects. You can copy/delete groups just like any other element. Ungrouping a group allows you to manipulate the elements individually again. - -The next thing I'll talk about is Layers. The Layers panel lies tucked to the side but can be clicked or dragged open at any time. Layers work very much like they do in other drawing programs: you can create new layers, rename them, change the order and delete them. Elements not on the current layer are not selectable, so it's an excellent way to separate elements in your drawing so that you can work on them without interfering with other parts of the drawing. If you want to move elements between layers, select them, then select the layer you want to move them to. - -There are a couple of other minor features that round out SVG-edit 2.4: - * It is now possible to embed raster images (via URL) into the canvas using the Image tool on the left - * It is also possible to keep the ratio of any element fixed when resizing by holding down the shift key. - * Finally, if the canvas is starting to become obscured, you can turn on 'wireframe mode' which shows the outline of all shapes in your drawing, but none of the fill or stroke properties. - -There are several minor features that I didn't have time to talk about, but feel free to browse to the project page and try out the demo. Thanks for your time. \ No newline at end of file diff --git a/build/svg-edit-2.6-src/screencasts/svgopen2010/index.html b/build/svg-edit-2.6-src/screencasts/svgopen2010/index.html deleted file mode 100644 index 59881ee..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgopen2010/index.html +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - - - - - SVG-edit, Pavol Rusnák, SVG Open 2010, Paris - - - - - -

          -
          -
          - -
          -
          -

          SVG-edit

          -

          logo

          -

          Pavol Rusnák

          -

          SVG Open 2010, Paris

          -
          -
          - -
          -
          -
          -

          SVG-edit is ...

          -
          -
            -
          • a web-based, JavaScript-driven SVG editor that works in any modern browser
          • -
          • not a full replacement for Inkscape (yet :-P)
          • -
          • licensed under very liberal open source license (Apache License 2.0)
          • -
          • platform for other projects which need to edit SVG documents
          • -
          • pushing browsers to find their limits
          • -
          • always up-to-date
          • -
          -
          -
          - -
          -
          -
          -

          History: 1.0 (13th Feb 2009)

          -
          -
            -
          • draw path, line, freehand-circle, rectangle
          • -
          • clear drawn image
          • -
          • delete element
          • -
          • save image
          • -
          • → Narendra Sisodiya
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          History: 2.0 (3rd June 2009)

          -
          -
            -
          • draw ellipse, square
          • -
          • change line style (stroke-dasharray)
          • -
          • rearranged whole code to utilize OOP
          • -
          • GUI enhancement
          • -
          • → Pavol Rusnák
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          History: 2.1 (17th June 2009)

          -
          -
            -
          • tooltips added to all UI elements
          • -
          • edit of fill opacity, stroke opacity, group opacity
          • -
          • selection of elements
          • -
          • move/drag of elements
          • -
          • save SVG file to separate tab
          • -
          • create and edit text elements
          • -
          • contextual panel of tools
          • -
          • change rect radius, font-family, font-size
          • -
          • keystroke handling
          • -
          • → Jeff Schiller
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          History: 2.2 (8th July 2009)

          -
          -
            -
          • multiselect mode
          • -
          • undo/redo actions
          • -
          • resize elements
          • -
          • contextual tools for rect, circle, ellipse, line, text elements
          • -
          • some updated button images
          • -
          • stretched the UI to fit the browser window
          • -
          • resizing of the SVG canvas
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          History: 2.3 (8th Sept 2009)

          -
          -
            -
          • align objects
          • -
          • rotate objects
          • -
          • clone objects
          • -
          • select next/prev object
          • -
          • edit SVG source
          • -
          • gradient picking
          • -
          • polygon mode
          • -
          • → Alexis Deveria
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          History: 2.4 Arbelos (11th Jan 2010)

          -
          -
            -
          • include raster images
          • -
          • select non-adjacent elements
          • -
          • group/ungroup
          • -
          • zoom
          • -
          • layers
          • -
          • curve segments in paths
          • -
          • UI localization
          • -
          • wireframe mode
          • -
          • change background
          • -
          • convert shapes to path
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          History: 2.5 Bicorn (15th June 2010)

          -
          -
            -
          • open local files (Firefox 3.6+, Chrome 6+ only)
          • -
          • import SVG into drawing (Firefox 3.6+, Chrome 6+ only)
          • -
          • connector lines and arrows
          • -
          • smoother freehand paths
          • -
          • editing outside the canvas
          • -
          • increased support for SVG elements
          • -
          • add/edit sub-paths
          • -
          • multiple path segment selection
          • -
          • support for foreign markup (MathML)
          • -
          • radial gradients
          • -
          • eye-dropper tool
          • -
          • stroke linejoin and linecap
          • -
          • export to PNG
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          Plugin Architecture

          -
          -
          -svgEditor.addExtension("Hello World", function() {
          -
          -        return {
          -                svgicons: "extensions/helloworld-icon.xml",
          -                buttons: [{...}],
          -                mouseDown: function() {
          -                        ...
          -                },
          -
          -                mouseUp: function(opts) {
          -                        ...
          -                }
          -        };
          -});
          -
          -
          - -
          -
          -
          -

          Features in progress (for 2.6 Cycloid)

          -
          -
            -
          • IE9 support
          • -
          • context menus
          • -
          • path clipping
          • -
          • support for <a> element
          • -
          • advanced gradient editor (more stops, elliptic fills)
          • -
          • shape library tool
          • -
          • linking off to clipart/image library sites
          • -
          -

          _

          -
          -
          - -
          -
          -
          -

          Projects based on SVG-edit

          -
          -
            -
          • Firefox add-on
          • -
          • Opera widget
          • -
          • Google Wave gadget
          • -
          • Wiki extensions (Dokuwiki, Instiki, MoinMoin, XWiki)
          • -
          • Cloud Canvas
          • -
          • Eduvid
          • -
          • Sesame
          • -
          -
          -
          - -
          -
          -
          -

          Resources

          -
          - -
          -
          - -
          -
          -

          Thank you!

          -

          Questions?

          -
          -
          - -
          - -
          - - - - - - - diff --git a/build/svg-edit-2.6-src/screencasts/svgopen2010/logo.svg b/build/svg-edit-2.6-src/screencasts/svgopen2010/logo.svg deleted file mode 100644 index e71308b..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgopen2010/logo.svg +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - Layer 2 - - - diff --git a/build/svg-edit-2.6-src/screencasts/svgopen2010/script.js b/build/svg-edit-2.6-src/screencasts/svgopen2010/script.js deleted file mode 100644 index 28f9f90..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgopen2010/script.js +++ /dev/null @@ -1,390 +0,0 @@ - (function() { - var doc = document; - var disableBuilds = true; - - var ctr = 0; - var spaces = /\s+/, a1 = ['']; - - var toArray = function(list) { - return Array.prototype.slice.call(list || [], 0); - }; - - var byId = function(id) { - if (typeof id == 'string') { return doc.getElementById(id); } - return id; - }; - - var query = function(query, root) { - if (!query) { return []; } - if (typeof query != 'string') { return toArray(query); } - if (typeof root == 'string') { - root = byId(root); - if(!root){ return []; } - } - - root = root || document; - var rootIsDoc = (root.nodeType == 9); - var doc = rootIsDoc ? root : (root.ownerDocument || document); - - // rewrite the query to be ID rooted - if (!rootIsDoc || ('>~+'.indexOf(query.charAt(0)) >= 0)) { - root.id = root.id || ('qUnique' + (ctr++)); - query = '#' + root.id + ' ' + query; - } - // don't choke on something like ".yada.yada >" - if ('>~+'.indexOf(query.slice(-1)) >= 0) { query += ' *'; } - - return toArray(doc.querySelectorAll(query)); - }; - - var strToArray = function(s) { - if (typeof s == 'string' || s instanceof String) { - if (s.indexOf(' ') < 0) { - a1[0] = s; - return a1; - } else { - return s.split(spaces); - } - } - return s; - }; - - var addClass = function(node, classStr) { - classStr = strToArray(classStr); - var cls = ' ' + node.className + ' '; - for (var i = 0, len = classStr.length, c; i < len; ++i) { - c = classStr[i]; - if (c && cls.indexOf(' ' + c + ' ') < 0) { - cls += c + ' '; - } - } - node.className = cls.trim(); - }; - - var removeClass = function(node, classStr) { - var cls; - if (classStr !== undefined) { - classStr = strToArray(classStr); - cls = ' ' + node.className + ' '; - for (var i = 0, len = classStr.length; i < len; ++i) { - cls = cls.replace(' ' + classStr[i] + ' ', ' '); - } - cls = cls.trim(); - } else { - cls = ''; - } - if (node.className != cls) { - node.className = cls; - } - }; - - var toggleClass = function(node, classStr) { - var cls = ' ' + node.className + ' '; - if (cls.indexOf(' ' + classStr.trim() + ' ') >= 0) { - removeClass(node, classStr); - } else { - addClass(node, classStr); - } - }; - - var ua = navigator.userAgent; - var isFF = parseFloat(ua.split('Firefox/')[1]) || undefined; - var isWK = parseFloat(ua.split('WebKit/')[1]) || undefined; - var isOpera = parseFloat(ua.split('Opera/')[1]) || undefined; - - var canTransition = (function() { - var ver = parseFloat(ua.split('Version/')[1]) || undefined; - // test to determine if this browser can handle CSS transitions. - var cachedCanTransition = - (isWK || (isFF && isFF > 3.6 ) || (isOpera && ver >= 10.5)); - return function() { return cachedCanTransition; } - })(); - - // - // Slide class - // - var Slide = function(node, idx) { - this._node = node; - if (idx >= 0) { - this._count = idx + 1; - } - if (this._node) { - addClass(this._node, 'slide distant-slide'); - } - this._makeCounter(); - this._makeBuildList(); - }; - - Slide.prototype = { - _node: null, - _count: 0, - _buildList: [], - _visited: false, - _currentState: '', - _states: [ 'distant-slide', 'far-past', - 'past', 'current', 'future', - 'far-future', 'distant-slide' ], - setState: function(state) { - if (typeof state != 'string') { - state = this._states[state]; - } - if (state == 'current' && !this._visited) { - this._visited = true; - this._makeBuildList(); - } - removeClass(this._node, this._states); - addClass(this._node, state); - this._currentState = state; - - // delay first auto run. Really wish this were in CSS. - /* - this._runAutos(); - */ - var _t = this; - setTimeout(function(){ _t._runAutos(); } , 400); - }, - _makeCounter: function() { - if(!this._count || !this._node) { return; } - var c = doc.createElement('span'); - c.innerHTML = this._count; - c.className = 'counter'; - this._node.appendChild(c); - }, - _makeBuildList: function() { - this._buildList = []; - if (disableBuilds) { return; } - if (this._node) { - this._buildList = query('[data-build] > *', this._node); - } - this._buildList.forEach(function(el) { - addClass(el, 'to-build'); - }); - }, - _runAutos: function() { - if (this._currentState != 'current') { - return; - } - // find the next auto, slice it out of the list, and run it - var idx = -1; - this._buildList.some(function(n, i) { - if (n.hasAttribute('data-auto')) { - idx = i; - return true; - } - return false; - }); - if (idx >= 0) { - var elem = this._buildList.splice(idx, 1)[0]; - var transitionEnd = isWK ? 'webkitTransitionEnd' : (isFF ? 'mozTransitionEnd' : 'oTransitionEnd'); - var _t = this; - if (canTransition()) { - var l = function(evt) { - elem.parentNode.removeEventListener(transitionEnd, l, false); - _t._runAutos(); - }; - elem.parentNode.addEventListener(transitionEnd, l, false); - removeClass(elem, 'to-build'); - } else { - setTimeout(function() { - removeClass(elem, 'to-build'); - _t._runAutos(); - }, 400); - } - } - }, - buildNext: function() { - if (!this._buildList.length) { - return false; - } - removeClass(this._buildList.shift(), 'to-build'); - return true; - }, - }; - - // - // SlideShow class - // - var SlideShow = function(slides) { - this._slides = (slides || []).map(function(el, idx) { - return new Slide(el, idx); - }); - - var h = window.location.hash; - try { - this.current = parseInt(h.split('#slide')[1], 10); - }catch (e) { /* squeltch */ } - this.current = isNaN(this.current) ? 1 : this.current; - var _t = this; - doc.addEventListener('keydown', - function(e) { _t.handleKeys(e); }, false); - doc.addEventListener('mousewheel', - function(e) { _t.handleWheel(e); }, false); - doc.addEventListener('DOMMouseScroll', - function(e) { _t.handleWheel(e); }, false); - doc.addEventListener('touchstart', - function(e) { _t.handleTouchStart(e); }, false); - doc.addEventListener('touchend', - function(e) { _t.handleTouchEnd(e); }, false); - window.addEventListener('popstate', - function(e) { _t.go(e.state); }, false); - this._update(); - }; - - SlideShow.prototype = { - _slides: [], - _update: function(dontPush) { - document.querySelector('#presentation-counter').innerText = this.current; - if (history.pushState) { - if (!dontPush) { - history.pushState(this.current, 'Slide ' + this.current, '#slide' + this.current); - } - } else { - window.location.hash = 'slide' + this.current; - } - for (var x = this.current-1; x < this.current + 7; x++) { - if (this._slides[x-4]) { - this._slides[x-4].setState(Math.max(0, x-this.current)); - } - } - }, - - current: 0, - next: function() { - if (!this._slides[this.current-1].buildNext()) { - this.current = Math.min(this.current + 1, this._slides.length); - this._update(); - } - }, - prev: function() { - this.current = Math.max(this.current-1, 1); - this._update(); - }, - go: function(num) { - if (history.pushState && this.current != num) { - history.replaceState(this.current, 'Slide ' + this.current, '#slide' + this.current); - } - this.current = num; - this._update(true); - }, - - _notesOn: false, - showNotes: function() { - var isOn = this._notesOn = !this._notesOn; - query('.notes').forEach(function(el) { - el.style.display = (notesOn) ? 'block' : 'none'; - }); - }, - switch3D: function() { - toggleClass(document.body, 'three-d'); - }, - handleWheel: function(e) { - var delta = 0; - if (e.wheelDelta) { - delta = e.wheelDelta/120; - if (isOpera) { - delta = -delta; - } - } else if (e.detail) { - delta = -e.detail/3; - } - - if (delta > 0 ) { - this.prev(); - return; - } - if (delta < 0 ) { - this.next(); - return; - } - }, - handleKeys: function(e) { - - if (/^(input|textarea)$/i.test(e.target.nodeName)) return; - - switch (e.keyCode) { - case 37: // left arrow - this.prev(); break; - case 39: // right arrow - case 32: // space - this.next(); break; - case 50: // 2 - this.showNotes(); break; - case 51: // 3 - this.switch3D(); break; - } - }, - _touchStartX: 0, - handleTouchStart: function(e) { - this._touchStartX = e.touches[0].pageX; - }, - handleTouchEnd: function(e) { - var delta = this._touchStartX - e.changedTouches[0].pageX; - var SWIPE_SIZE = 150; - if (delta > SWIPE_SIZE) { - this.next(); - } else if (delta< -SWIPE_SIZE) { - this.prev(); - } - }, - }; - - // Initialize - var slideshow = new SlideShow(query('.slide')); - - - - - - document.querySelector('#toggle-counter').addEventListener('click', toggleCounter, false); - document.querySelector('#toggle-size').addEventListener('click', toggleSize, false); - document.querySelector('#toggle-transitions').addEventListener('click', toggleTransitions, false); - document.querySelector('#toggle-gradients').addEventListener('click', toggleGradients, false); - - - var counters = document.querySelectorAll('.counter'); - var slides = document.querySelectorAll('.slide'); - - function toggleCounter() { - toArray(counters).forEach(function(el) { - el.style.display = (el.offsetHeight) ? 'none' : 'block'; - }); - } - - function toggleSize() { - toArray(slides).forEach(function(el) { - if (!/reduced/.test(el.className)) { - addClass(el, 'reduced'); - } - else { - removeClass(el, 'reduced'); - } - }); - } - - function toggleTransitions() { - toArray(slides).forEach(function(el) { - if (!/no-transitions/.test(el.className)) { - addClass(el, 'no-transitions'); - } - else { - removeClass(el, 'no-transitions'); - } - }); - } - - function toggleGradients() { - toArray(slides).forEach(function(el) { - if (!/no-gradients/.test(el.className)) { - addClass(el, 'no-gradients'); - } - else { - removeClass(el, 'no-gradients'); - } - }); - } - - - - - - })(); diff --git a/build/svg-edit-2.6-src/screencasts/svgopen2010/style.css b/build/svg-edit-2.6-src/screencasts/svgopen2010/style.css deleted file mode 100644 index 04b571c..0000000 --- a/build/svg-edit-2.6-src/screencasts/svgopen2010/style.css +++ /dev/null @@ -1,395 +0,0 @@ - body { - font: 20px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; - padding: 0; - margin: 0; - width: 100%; - height: 100%; - position: absolute; - left: 0px; top: 0px; - } - - .presentation { - position: absolute; - height: 100%; - width: 100%; - left: 0px; - top: 0px; - display: block; - overflow: hidden; - background: #778; - } - - .slides { - width: 100%; - height: 100%; - left: 0; - top: 0; - position: absolute; - display: block; - -webkit-transition: -webkit-transform 1s ease-in-out; - -moz-transition: -moz-transform 1s ease-in-out; - -o-transition: -o-transform 1s ease-in-out; - transition: transform 1s ease-in-out; - - /* so it's visible in the iframe. */ - -webkit-transform: scale(0.8); - -moz-transform: scale(0.8); - -o-transform: scale(0.8); - transform: scale(0.8); - - } - - .slide { - display: none; - position: absolute; - overflow: hidden; - width: 900px; - height: 700px; - left: 50%; - top: 50%; - margin-top: -350px; - background-color: #eee; - background: -webkit-gradient(linear, left bottom, left top, from(#bbd), to(#fff)); - background: -moz-linear-gradient(bottom, #bbd, #fff); - background: linear-gradient(bottom, #bbd, #fff); - -webkit-transition: all 0.25s ease-in-out; - -moz-transition: all 0.25s ease-in-out; - -o-transition: all 0.25s ease-in-out; - transition: all 0.25s ease-in-out; - -webkit-transform: scale(1); - -moz-transform: scale(1); - -o-transform: scale(1); - transform: scale(1); - } - - .slide:nth-child(even) { - -moz-border-radius: 20px 0; - -khtml-border-radius: 20px 0; - border-radius: 20px 0; /* includes Opera 10.5+ */ - -webkit-border-top-left-radius: 20px; - -webkit-border-bottom-right-radius: 20px; - } - - .slide:nth-child(odd) { - -moz-border-radius: 0 20px; - -khtml-border-radius: 0 20px; - border-radius: 0 20px; - -webkit-border-top-right-radius: 20px; - -webkit-border-bottom-left-radius: 20px; - } - - .slide p, .slide textarea { - font-size: 120%; - } - - .slide .counter { - color: #999999; - position: absolute; - left: 20px; - bottom: 20px; - display: block; - font-size: 70%; - } - - .slide.title > .counter, - .slide.segue > .counter, - .slide.mainTitle > .counter { - display: none; - } - - .force-render { - display: block; - visibility: hidden; - } - - .slide.far-past { - display: block; - margin-left: -2400px; - } - - .slide.past { - visibility: visible; - display: block; - margin-left: -1400px; - } - - .slide.current { - visibility: visible; - display: block; - margin-left: -450px; - } - - .slide.future { - visibility: visible; - display: block; - margin-left: 500px; - } - - .slide.far-future { - display: block; - margin-left: 1500px; - } - - body.three-d div.slides { - -webkit-transform: translateX(50px) scale(0.8) rotateY(10deg); - -moz-transform: translateX(50px) scale(0.8) rotateY(10deg); - -o-transform: translateX(50px) scale(0.8) rotateY(10deg); - transform: translateX(50px) scale(0.8) rotateY(10deg); - } - - /* Content */ - - @font-face { font-family: 'Junction'; src: url(src/Junction02.otf); } - @font-face { font-family: 'LeagueGothic'; src: url(src/LeagueGothic.otf); } - - header { - font-family: 'Droid Sans'; - font-weight: normal; - letter-spacing: -.05em; - text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px; - left: 30px; - top: 25px; - margin: 0; - padding: 0; - font-size: 140%; - } - - h1 { - font-size: 140%; - display: inline; - font-weight: normal; - padding: 0; - margin: 0; - } - - h2 { - font-family: 'Droid Sans'; - color: black; - font-size: 120%; - padding: 0; - margin: 20px 0; - } - - h2:first-child { - margin-top: 0; - } - - section, footer { - font-family: 'Droid Sans'; - color: #3f3f3f; - text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px; - margin: 100px 30px 0; - display: block; - overflow: hidden; - } - - footer { - font-size: 100%; - margin: 20px 0 0 30px; - } - - a { - color: inherit; - display: inline-block; - text-decoration: none; - line-height: 110%; - border-bottom: 2px solid #3f3f3f; - } - - ul { - margin: 0; - padding: 0; - } - - li { - margin: 2%; - } - - button { - font-size: 100%; - } - - pre button { - margin: 2px; - } - - section.left { - float: left; - width: 390px; - } - - section.small { - font-size: 24px; - } - - section.small ul { - margin: 0 0 0 15px; - padding: 0; - } - - section.small li { - padding-bottom: 0; - } - - section.middle { - line-height: 2em; - text-align: center; - display: table-cell; - vertical-align: middle; - height: 700px; - width: 900px; - } - - pre { - text-align: left; - font-family: 'Droid Sans Mono', Courier; - font-size: 80%; - padding: 10px 20px; - background: rgba(255, 0, 0, 0.05); - -webkit-border-radius: 8px; - -khtml-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; - border: 1px solid rgba(255, 0, 0, 0.2); - } - - pre select { - font-family: Monaco, Courier; - border: 1px solid #c61800; - } - - input { - font-size: 100%; - margin-right: 10px; - font-family: Helvetica; - padding: 3px; - } - input[type="range"] { - width: 100%; - } - - button { - margin: 20px 10px 0 0; - font-family: Verdana; - } - - button.large { - font-size: 32px; - } - - pre b { - font-weight: normal; - color: #c61800; - text-shadow: #c61800 0 0 1px; - /*letter-spacing: -1px;*/ - } - pre em { - font-weight: normal; - font-style: normal; - color: #18a600; - text-shadow: #18a600 0 0 1px; - } - pre input[type="range"] { - height: 6px; - cursor: pointer; - width: auto; - } - - div.example { - display: block; - padding: 10px 20px; - color: black; - background: rgba(255, 255, 255, 0.4); - -webkit-border-radius: 8px; - -khtml-border-radius: 8px; - -moz-border-radius: 8px; - border-radius: 8px; - margin-bottom: 10px; - border: 1px solid rgba(0, 0, 0, 0.2); - } - - video { - -moz-border-radius: 8px; - -khtml-border-radius: 8px; - -webkit-border-radius: 8px; - border-radius: 8px; - border: 1px solid rgba(0, 0, 0, 0.2); - } - - .key { - font-family: 'Droid Sans'; - color: black; - display: inline-block; - padding: 6px 10px 3px 10px; - font-size: 100%; - line-height: 30px; - text-shadow: none; - letter-spacing: 0; - bottom: 10px; - position: relative; - -moz-border-radius: 10px; - -khtml-border-radius: 10px; - -webkit-border-radius: 10px; - border-radius: 10px; - background: white; - box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; - -webkit-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; - -moz-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; - -o-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; - } - - .key { font-family: Arial; } - - :not(header) > .key { - margin: 0 5px; - bottom: 4px; - } - - .two-column { - -webkit-column-count: 2; - -moz-column-count: 2; - column-count: 2; - } - - .stroke { - -webkit-text-stroke-color: red; - -webkit-text-stroke-width: 1px; - } /* currently webkit-only */ - - .center { - text-align: center; - } - - #presentation-counter { - color: #ccc; - font-size: 70%; - letter-spacing: 1px; - position: absolute; - top: 40%; - left: 0; - width: 100%; - text-align: center; - } - - div:not(.current).reduced { - -webkit-transform: scale(0.8); - -moz-transform: scale(0.8); - -o-transform: scale(0.8); - transform: scale(0.8); - } - - .no-transitions { - -webkit-transition: none; - -moz-transition: none; - -o-transition: none; - transition: none; - } - - .no-gradients { - background: none; - background-color: #fff; - } - - ul.bulleted { - padding-left: 30px; - } diff --git a/build/svg-edit-2.6-src/test/all_tests.html b/build/svg-edit-2.6-src/test/all_tests.html deleted file mode 100644 index 86f517f..0000000 --- a/build/svg-edit-2.6-src/test/all_tests.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - All SVG-edit Tests - - -

          All SVG-edit Tests

          -

          This file frames all SVG-edit test pages. This should only include tests known to work. These tests are known to pass 100% in the following: Firefox 3.6, Chrome 7, IE9 Preview 6 (1.9.8006.6000), Opera 10.63. If a test is broken in this page, it is possible that YOU broke it. Please do not submit code that breaks any of these tests.

          - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/test/contextmenu_test.html b/build/svg-edit-2.6-src/test/contextmenu_test.html deleted file mode 100644 index c32f4e8..0000000 --- a/build/svg-edit-2.6-src/test/contextmenu_test.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - - - - - - -

          Unit Tests for contextmenu.js

          -

          -

          -
            -
          - - - diff --git a/build/svg-edit-2.6-src/test/draw_test.html b/build/svg-edit-2.6-src/test/draw_test.html deleted file mode 100644 index f104a18..0000000 --- a/build/svg-edit-2.6-src/test/draw_test.html +++ /dev/null @@ -1,539 +0,0 @@ - - - - - - - - - - - - -

          Unit Tests for draw.js

          -

          -

          -
            -
          - - - diff --git a/build/svg-edit-2.6-src/test/history_test.html b/build/svg-edit-2.6-src/test/history_test.html deleted file mode 100644 index 15bc3b1..0000000 --- a/build/svg-edit-2.6-src/test/history_test.html +++ /dev/null @@ -1,591 +0,0 @@ - - - - - - - - - - -

          Unit Tests for history.js

          -

          -

          -
            -
          - - - - - diff --git a/build/svg-edit-2.6-src/test/math_test.html b/build/svg-edit-2.6-src/test/math_test.html deleted file mode 100644 index 408f5c8..0000000 --- a/build/svg-edit-2.6-src/test/math_test.html +++ /dev/null @@ -1,114 +0,0 @@ - - - - - - - - - - -

          Unit Tests for math.js

          -

          -

          -
            -
          - - diff --git a/build/svg-edit-2.6-src/test/path_test.html b/build/svg-edit-2.6-src/test/path_test.html deleted file mode 100644 index 6d5872b..0000000 --- a/build/svg-edit-2.6-src/test/path_test.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - -

          Unit Tests for path.js

          -

          -

          -
            -
          - - - diff --git a/build/svg-edit-2.6-src/test/qunit/qunit.css b/build/svg-edit-2.6-src/test/qunit/qunit.css deleted file mode 100644 index a6a831c..0000000 --- a/build/svg-edit-2.6-src/test/qunit/qunit.css +++ /dev/null @@ -1,197 +0,0 @@ -/** Font Family and Sizes */ - -#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; -} - -#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } -#qunit-tests { font-size: smaller; } - - -/** Resets */ - -#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { - margin: 0; - padding: 0; -} - - -/** Header */ - -#qunit-header { - padding: 0.5em 0 0.5em 1em; - - color: #8699a4; - background-color: #0d3349; - - font-size: 1.5em; - line-height: 1em; - font-weight: normal; - - border-radius: 15px 15px 0 0; - -moz-border-radius: 15px 15px 0 0; - -webkit-border-top-right-radius: 15px; - -webkit-border-top-left-radius: 15px; -} - -#qunit-header a { - text-decoration: none; - color: #c2ccd1; -} - -#qunit-header a:hover, -#qunit-header a:focus { - color: #fff; -} - -#qunit-banner { - height: 5px; -} - -#qunit-testrunner-toolbar { - padding: 0.5em 0 0.5em 2em; - color: #5E740B; - background-color: #eee; -} - -#qunit-userAgent { - padding: 0.5em 0 0.5em 2.5em; - background-color: #2b81af; - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; -} - - -/** Tests: Pass/Fail */ - -#qunit-tests { - list-style-position: inside; -} - -#qunit-tests li { - padding: 0.4em 0.5em 0.4em 2.5em; - border-bottom: 1px solid #fff; - list-style-position: inside; -} - -#qunit-tests li strong { - cursor: pointer; -} - -#qunit-tests ol { - margin-top: 0.5em; - padding: 0.5em; - - background-color: #fff; - - border-radius: 15px; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - - box-shadow: inset 0px 2px 13px #999; - -moz-box-shadow: inset 0px 2px 13px #999; - -webkit-box-shadow: inset 0px 2px 13px #999; -} - -#qunit-tests table { - border-collapse: collapse; - margin-top: .2em; -} - -#qunit-tests th { - text-align: right; - vertical-align: top; - padding: 0 .5em 0 0; -} - -#qunit-tests td { - vertical-align: top; -} - -#qunit-tests pre { - margin: 0; - white-space: pre-wrap; - word-wrap: break-word; -} - -#qunit-tests del { - background-color: #e0f2be; - color: #374e0c; - text-decoration: none; -} - -#qunit-tests ins { - background-color: #ffcaca; - color: #500; - text-decoration: none; -} - -/*** Test Counts */ - -#qunit-tests b.counts { color: black; } -#qunit-tests b.passed { color: #5E740B; } -#qunit-tests b.failed { color: #710909; } - -#qunit-tests li li { - margin: 0.5em; - padding: 0.4em 0.5em 0.4em 0.5em; - background-color: #fff; - border-bottom: none; - list-style-position: inside; -} - -/*** Passing Styles */ - -#qunit-tests li li.pass { - color: #5E740B; - background-color: #fff; - border-left: 26px solid #C6E746; -} - -#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } -#qunit-tests .pass .test-name { color: #366097; } - -#qunit-tests .pass .test-actual, -#qunit-tests .pass .test-expected { color: #999999; } - -#qunit-banner.qunit-pass { background-color: #C6E746; } - -/*** Failing Styles */ - -#qunit-tests li li.fail { - color: #710909; - background-color: #fff; - border-left: 26px solid #EE5757; -} - -#qunit-tests .fail { color: #000000; background-color: #EE5757; } -#qunit-tests .fail .test-name, -#qunit-tests .fail .module-name { color: #000000; } - -#qunit-tests .fail .test-actual { color: #EE5757; } -#qunit-tests .fail .test-expected { color: green; } - -#qunit-banner.qunit-fail { background-color: #EE5757; } - - -/** Footer */ - -#qunit-testresult { - padding: 0.5em 0.5em 0.5em 2.5em; - - color: #2b81af; - background-color: #D2E0E6; - - border-radius: 0 0 15px 15px; - -moz-border-radius: 0 0 15px 15px; - -webkit-border-bottom-right-radius: 15px; - -webkit-border-bottom-left-radius: 15px; -} - -/** Fixture */ - -#qunit-fixture { - position: absolute; - top: -10000px; - left: -10000px; -} diff --git a/build/svg-edit-2.6-src/test/qunit/qunit.js b/build/svg-edit-2.6-src/test/qunit/qunit.js deleted file mode 100644 index 30e0395..0000000 --- a/build/svg-edit-2.6-src/test/qunit/qunit.js +++ /dev/null @@ -1,1415 +0,0 @@ -/* - * QUnit - A JavaScript Unit Testing Framework - * - * http://docs.jquery.com/QUnit - * - * Copyright (c) 2011 John Resig, Jörn Zaefferer - * Dual licensed under the MIT (MIT-LICENSE.txt) - * or GPL (GPL-LICENSE.txt) licenses. - */ - -(function(window) { - -var defined = { - setTimeout: typeof window.setTimeout !== "undefined", - sessionStorage: (function() { - try { - return !!sessionStorage.getItem; - } catch(e){ - return false; - } - })() -} - -var testId = 0; - -var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { - this.name = name; - this.testName = testName; - this.expected = expected; - this.testEnvironmentArg = testEnvironmentArg; - this.async = async; - this.callback = callback; - this.assertions = []; -}; -Test.prototype = { - init: function() { - var tests = id("qunit-tests"); - if (tests) { - var b = document.createElement("strong"); - b.innerHTML = "Running " + this.name; - var li = document.createElement("li"); - li.appendChild( b ); - li.id = this.id = "test-output" + testId++; - tests.appendChild( li ); - } - }, - setup: function() { - if (this.module != config.previousModule) { - if ( config.previousModule ) { - QUnit.moduleDone( { - name: config.previousModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - } ); - } - config.previousModule = this.module; - config.moduleStats = { all: 0, bad: 0 }; - QUnit.moduleStart( { - name: this.module - } ); - } - - config.current = this; - this.testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, this.moduleTestEnvironment); - if (this.testEnvironmentArg) { - extend(this.testEnvironment, this.testEnvironmentArg); - } - - QUnit.testStart( { - name: this.testName - } ); - - // allow utility functions to access the current test environment - // TODO why?? - QUnit.current_testEnvironment = this.testEnvironment; - - try { - if ( !config.pollution ) { - saveGlobal(); - } - - this.testEnvironment.setup.call(this.testEnvironment); - } catch(e) { - QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); - } - }, - run: function() { - if ( this.async ) { - QUnit.stop(); - } - - if ( config.notrycatch ) { - this.callback.call(this.testEnvironment); - return; - } - try { - this.callback.call(this.testEnvironment); - } catch(e) { - fail("Test " + this.testName + " died, exception and test follows", e, this.callback); - QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - start(); - } - } - }, - teardown: function() { - try { - checkPollution(); - this.testEnvironment.teardown.call(this.testEnvironment); - } catch(e) { - QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); - } - }, - finish: function() { - if ( this.expected && this.expected != this.assertions.length ) { - QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); - } - - var good = 0, bad = 0, - tests = id("qunit-tests"); - - config.stats.all += this.assertions.length; - config.moduleStats.all += this.assertions.length; - - if ( tests ) { - var ol = document.createElement("ol"); - - for ( var i = 0; i < this.assertions.length; i++ ) { - var assertion = this.assertions[i]; - - var li = document.createElement("li"); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - - // store result when possible - defined.sessionStorage && sessionStorage.setItem("qunit-" + this.testName, bad); - - if (bad == 0) { - ol.style.display = "none"; - } - - var b = document.createElement("strong"); - b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.nextSibling, display = next.style.display; - next.style.display = display === "none" ? "block" : "none"; - }); - - addEvent(b, "dblclick", function(e) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "")); - } - }); - - var li = id(this.id); - li.className = bad ? "fail" : "pass"; - li.style.display = resultDisplayStyle(!bad); - li.removeChild( li.firstChild ); - li.appendChild( b ); - li.appendChild( ol ); - - } else { - for ( var i = 0; i < this.assertions.length; i++ ) { - if ( !this.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - try { - QUnit.reset(); - } catch(e) { - fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); - } - - QUnit.testDone( { - name: this.testName, - failed: bad, - passed: this.assertions.length - bad, - total: this.assertions.length - } ); - }, - - queue: function() { - var test = this; - synchronize(function() { - test.init(); - }); - function run() { - // each of these can by async - synchronize(function() { - test.setup(); - }); - synchronize(function() { - test.run(); - }); - synchronize(function() { - test.teardown(); - }); - synchronize(function() { - test.finish(); - }); - } - // defer when previous test run passed, if storage is available - var bad = defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.testName); - if (bad) { - run(); - } else { - synchronize(run); - }; - } - -} - -var QUnit = { - - // call on start of module test to prepend name to all tests - module: function(name, testEnvironment) { - config.currentModule = name; - config.currentModuleTestEnviroment = testEnvironment; - }, - - asyncTest: function(testName, expected, callback) { - if ( arguments.length === 2 ) { - callback = expected; - expected = 0; - } - - QUnit.test(testName, expected, callback, true); - }, - - test: function(testName, expected, callback, async) { - var name = '' + testName + '', testEnvironmentArg; - - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - // is 2nd argument a testEnvironment? - if ( expected && typeof expected === 'object') { - testEnvironmentArg = expected; - expected = null; - } - - if ( config.currentModule ) { - name = '' + config.currentModule + ": " + name; - } - - if ( !validTest(config.currentModule + ": " + testName) ) { - return; - } - - var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); - test.module = config.currentModule; - test.moduleTestEnvironment = config.currentModuleTestEnviroment; - test.queue(); - }, - - /** - * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. - */ - expect: function(asserts) { - config.current.expected = asserts; - }, - - /** - * Asserts true. - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ - ok: function(a, msg) { - a = !!a; - var details = { - result: a, - message: msg - }; - msg = escapeHtml(msg); - QUnit.log(details); - config.current.assertions.push({ - result: a, - message: msg - }); - }, - - /** - * Checks that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * - * Prefered to ok( actual == expected, message ) - * - * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); - * - * @param Object actual - * @param Object expected - * @param String message (optional) - */ - equal: function(actual, expected, message) { - QUnit.push(expected == actual, actual, expected, message); - }, - - notEqual: function(actual, expected, message) { - QUnit.push(expected != actual, actual, expected, message); - }, - - deepEqual: function(actual, expected, message) { - QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); - }, - - notDeepEqual: function(actual, expected, message) { - QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); - }, - - strictEqual: function(actual, expected, message) { - QUnit.push(expected === actual, actual, expected, message); - }, - - notStrictEqual: function(actual, expected, message) { - QUnit.push(expected !== actual, actual, expected, message); - }, - - raises: function(block, expected, message) { - var actual, ok = false; - - if (typeof expected === 'string') { - message = expected; - expected = null; - } - - try { - block(); - } catch (e) { - actual = e; - } - - if (actual) { - // we don't want to validate thrown error - if (!expected) { - ok = true; - // expected is a regexp - } else if (QUnit.objectType(expected) === "regexp") { - ok = expected.test(actual); - // expected is a constructor - } else if (actual instanceof expected) { - ok = true; - // expected is a validation function which returns true is validation passed - } else if (expected.call({}, actual) === true) { - ok = true; - } - } - - QUnit.ok(ok, message); - }, - - start: function() { - config.semaphore--; - if (config.semaphore > 0) { - // don't start until equal number of stop-calls - return; - } - if (config.semaphore < 0) { - // ignore if start is called more often then stop - config.semaphore = 0; - } - // A slight delay, to avoid any current callbacks - if ( defined.setTimeout ) { - window.setTimeout(function() { - if ( config.timeout ) { - clearTimeout(config.timeout); - } - - config.blocking = false; - process(); - }, 13); - } else { - config.blocking = false; - process(); - } - }, - - stop: function(timeout) { - config.semaphore++; - config.blocking = true; - - if ( timeout && defined.setTimeout ) { - clearTimeout(config.timeout); - config.timeout = window.setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - QUnit.start(); - }, timeout); - } - } - -}; - -// Backwards compatibility, deprecated -QUnit.equals = QUnit.equal; -QUnit.same = QUnit.deepEqual; - -// Maintain internal state -var config = { - // The queue of tests to run - queue: [], - - // block until document ready - blocking: true -}; - -// Load paramaters -(function() { - var location = window.location || { search: "", protocol: "file:" }, - GETParams = location.search.slice(1).split('&'); - - for ( var i = 0; i < GETParams.length; i++ ) { - GETParams[i] = decodeURIComponent( GETParams[i] ); - if ( GETParams[i] === "noglobals" ) { - GETParams.splice( i, 1 ); - i--; - config.noglobals = true; - } else if ( GETParams[i] === "notrycatch" ) { - GETParams.splice( i, 1 ); - i--; - config.notrycatch = true; - } else if ( GETParams[i].search('=') > -1 ) { - GETParams.splice( i, 1 ); - i--; - } - } - - // restrict modules/tests by get parameters - config.filters = GETParams; - - // Figure out if we're running the tests from a server or not - QUnit.isLocal = !!(location.protocol === 'file:'); -})(); - -// Expose the API as global variables, unless an 'exports' -// object exists, in that case we assume we're in CommonJS -if ( typeof exports === "undefined" || typeof require === "undefined" ) { - extend(window, QUnit); - window.QUnit = QUnit; -} else { - extend(exports, QUnit); - exports.QUnit = QUnit; -} - -// define these after exposing globals to keep them in these QUnit namespace only -extend(QUnit, { - config: config, - - // Initialize the configuration options - init: function() { - extend(config, { - stats: { all: 0, bad: 0 }, - moduleStats: { all: 0, bad: 0 }, - started: +new Date, - updateRate: 1000, - blocking: false, - autostart: true, - autorun: false, - filters: [], - queue: [], - semaphore: 0 - }); - - var tests = id("qunit-tests"), - banner = id("qunit-banner"), - result = id("qunit-testresult"); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - }, - - /** - * Resets the test setup. Useful for tests that modify the DOM. - * - * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. - */ - reset: function() { - if ( window.jQuery ) { - jQuery( "#main, #qunit-fixture" ).html( config.fixture ); - } else { - var main = id( 'main' ) || id( 'qunit-fixture' ); - if ( main ) { - main.innerHTML = config.fixture; - } - } - }, - - /** - * Trigger an event on an element. - * - * @example triggerEvent( document.body, "click" ); - * - * @param DOMElement elem - * @param String type - */ - triggerEvent: function( elem, type, event ) { - if ( document.createEvent ) { - event = document.createEvent("MouseEvents"); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - elem.dispatchEvent( event ); - - } else if ( elem.fireEvent ) { - elem.fireEvent("on"+type); - } - }, - - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) == type; - }, - - objectType: function( obj ) { - if (typeof obj === "undefined") { - return "undefined"; - - // consider: typeof null === object - } - if (obj === null) { - return "null"; - } - - var type = Object.prototype.toString.call( obj ) - .match(/^\[object\s(.*)\]$/)[1] || ''; - - switch (type) { - case 'Number': - if (isNaN(obj)) { - return "nan"; - } else { - return "number"; - } - case 'String': - case 'Boolean': - case 'Array': - case 'Date': - case 'RegExp': - case 'Function': - return type.toLowerCase(); - } - if (typeof obj === "object") { - return "object"; - } - return undefined; - }, - - push: function(result, actual, expected, message) { - var details = { - result: result, - message: message, - actual: actual, - expected: expected - }; - - message = escapeHtml(message) || (result ? "okay" : "failed"); - message = '' + message + ""; - expected = escapeHtml(QUnit.jsDump.parse(expected)); - actual = escapeHtml(QUnit.jsDump.parse(actual)); - var output = message + ''; - if (actual != expected) { - output += ''; - output += ''; - } - if (!result) { - var source = sourceFromStacktrace(); - if (source) { - details.source = source; - output += ''; - } - } - output += "
          Expected:
          ' + expected + '
          Result:
          ' + actual + '
          Diff:
          ' + QUnit.diff(expected, actual) +'
          Source:
          ' + source +'
          "; - - QUnit.log(details); - - config.current.assertions.push({ - result: !!result, - message: output - }); - }, - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: function() {}, - // done: { failed, passed, total, runtime } - done: function() {}, - // log: { result, actual, expected, message } - log: function() {}, - // testStart: { name } - testStart: function() {}, - // testDone: { name, failed, passed, total } - testDone: function() {}, - // moduleStart: { name } - moduleStart: function() {}, - // moduleDone: { name, failed, passed, total } - moduleDone: function() {} -}); - -if ( typeof document === "undefined" || document.readyState === "complete" ) { - config.autorun = true; -} - -addEvent(window, "load", function() { - QUnit.begin({}); - - // Initialize the config, saving the execution queue - var oldconfig = extend({}, config); - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - var userAgent = id("qunit-userAgent"); - if ( userAgent ) { - userAgent.innerHTML = navigator.userAgent; - } - var banner = id("qunit-header"); - if ( banner ) { - var paramsIndex = location.href.lastIndexOf(location.search); - if ( paramsIndex > -1 ) { - var mainPageLocation = location.href.slice(0, paramsIndex); - if ( mainPageLocation == location.href ) { - banner.innerHTML = ' ' + banner.innerHTML + ' '; - } else { - var testName = decodeURIComponent(location.search.slice(1)); - banner.innerHTML = '' + banner.innerHTML + '' + testName + ''; - } - } - } - - var toolbar = id("qunit-testrunner-toolbar"); - if ( toolbar ) { - var filter = document.createElement("input"); - filter.type = "checkbox"; - filter.id = "qunit-filter-pass"; - addEvent( filter, "click", function() { - var li = document.getElementsByTagName("li"); - for ( var i = 0; i < li.length; i++ ) { - if ( li[i].className.indexOf("pass") > -1 ) { - li[i].style.display = filter.checked ? "none" : ""; - } - } - if ( defined.sessionStorage ) { - sessionStorage.setItem("qunit-filter-passed-tests", filter.checked ? "true" : ""); - } - }); - if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { - filter.checked = true; - } - toolbar.appendChild( filter ); - - var label = document.createElement("label"); - label.setAttribute("for", "qunit-filter-pass"); - label.innerHTML = "Hide passed tests"; - toolbar.appendChild( label ); - } - - var main = id('main') || id('qunit-fixture'); - if ( main ) { - config.fixture = main.innerHTML; - } - - if (config.autostart) { - QUnit.start(); - } -}); - -function done() { - config.autorun = true; - - // Log the last module results - if ( config.currentModule ) { - QUnit.moduleDone( { - name: config.currentModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - } ); - } - - var banner = id("qunit-banner"), - tests = id("qunit-tests"), - runtime = +new Date - config.started, - passed = config.stats.all - config.stats.bad, - html = [ - 'Tests completed in ', - runtime, - ' milliseconds.
          ', - '', - passed, - ' tests of ', - config.stats.all, - ' passed, ', - config.stats.bad, - ' failed.' - ].join(''); - - if ( banner ) { - banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); - } - - if ( tests ) { - var result = id("qunit-testresult"); - - if ( !result ) { - result = document.createElement("p"); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests.nextSibling ); - } - - result.innerHTML = html; - } - - QUnit.done( { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - } ); -} - -function validTest( name ) { - var i = config.filters.length, - run = false; - - if ( !i ) { - return true; - } - - while ( i-- ) { - var filter = config.filters[i], - not = filter.charAt(0) == '!'; - - if ( not ) { - filter = filter.slice(1); - } - - if ( name.indexOf(filter) !== -1 ) { - return !not; - } - - if ( not ) { - run = true; - } - } - - return run; -} - -// so far supports only Firefox, Chrome and Opera (buggy) -// could be extended in the future to use something like https://github.com/csnover/TraceKit -function sourceFromStacktrace() { - try { - throw new Error(); - } catch ( e ) { - if (e.stacktrace) { - // Opera - return e.stacktrace.split("\n")[6]; - } else if (e.stack) { - // Firefox, Chrome - return e.stack.split("\n")[4]; - } - } -} - -function resultDisplayStyle(passed) { - return passed && id("qunit-filter-pass") && id("qunit-filter-pass").checked ? 'none' : ''; -} - -function escapeHtml(s) { - if (!s) { - return ""; - } - s = s + ""; - return s.replace(/[\&"<>\\]/g, function(s) { - switch(s) { - case "&": return "&"; - case "\\": return "\\\\"; - case '"': return '\"'; - case "<": return "<"; - case ">": return ">"; - default: return s; - } - }); -} - -function synchronize( callback ) { - config.queue.push( callback ); - - if ( config.autorun && !config.blocking ) { - process(); - } -} - -function process() { - var start = (new Date()).getTime(); - - while ( config.queue.length && !config.blocking ) { - if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { - config.queue.shift()(); - } else { - window.setTimeout( process, 13 ); - break; - } - } - if (!config.blocking && !config.queue.length) { - done(); - } -} - -function saveGlobal() { - config.pollution = []; - - if ( config.noglobals ) { - for ( var key in window ) { - config.pollution.push( key ); - } - } -} - -function checkPollution( name ) { - var old = config.pollution; - saveGlobal(); - - var newGlobals = diff( old, config.pollution ); - if ( newGlobals.length > 0 ) { - ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); - config.current.expected++; - } - - var deletedGlobals = diff( config.pollution, old ); - if ( deletedGlobals.length > 0 ) { - ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); - config.current.expected++; - } -} - -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var result = a.slice(); - for ( var i = 0; i < result.length; i++ ) { - for ( var j = 0; j < b.length; j++ ) { - if ( result[i] === b[j] ) { - result.splice(i, 1); - i--; - break; - } - } - } - return result; -} - -function fail(message, exception, callback) { - if ( typeof console !== "undefined" && console.error && console.warn ) { - console.error(message); - console.error(exception); - console.warn(callback.toString()); - - } else if ( window.opera && opera.postError ) { - opera.postError(message, exception, callback.toString); - } -} - -function extend(a, b) { - for ( var prop in b ) { - a[prop] = b[prop]; - } - - return a; -} - -function addEvent(elem, type, fn) { - if ( elem.addEventListener ) { - elem.addEventListener( type, fn, false ); - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, fn ); - } else { - fn(); - } -} - -function id(name) { - return !!(typeof document !== "undefined" && document && document.getElementById) && - document.getElementById( name ); -} - -// Test for equality any JavaScript type. -// Discussions and reference: http://philrathe.com/articles/equiv -// Test suites: http://philrathe.com/tests/equiv -// Author: Philippe Rathé -QUnit.equiv = function () { - - var innerEquiv; // the real equiv function - var callers = []; // stack to decide between skip/abort functions - var parents = []; // stack to avoiding loops from circular referencing - - // Call the o related callback with the given arguments. - function bindCallbacks(o, callbacks, args) { - var prop = QUnit.objectType(o); - if (prop) { - if (QUnit.objectType(callbacks[prop]) === "function") { - return callbacks[prop].apply(callbacks, args); - } else { - return callbacks[prop]; // or undefined - } - } - } - - var callbacks = function () { - - // for string, boolean, number and null - function useStrictEquality(b, a) { - if (b instanceof a.constructor || a instanceof b.constructor) { - // to catch short annotaion VS 'new' annotation of a declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function (b) { - return isNaN(b); - }, - - "date": function (b, a) { - return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function (b, a) { - return QUnit.objectType(b) === "regexp" && - a.source === b.source && // the regex itself - a.global === b.global && // and its modifers (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function () { - var caller = callers[callers.length - 1]; - return caller !== Object && - typeof caller !== "undefined"; - }, - - "array": function (b, a) { - var i, j, loop; - var len; - - // b could be an object literal here - if ( ! (QUnit.objectType(b) === "array")) { - return false; - } - - len = a.length; - if (len !== b.length) { // safe and faster - return false; - } - - //track reference to avoid circular references - parents.push(a); - for (i = 0; i < len; i++) { - loop = false; - for(j=0;j= 0) { - type = "array"; - } else { - type = typeof obj; - } - return type; - }, - separator:function() { - return this.multiline ? this.HTML ? '
          ' : '\n' : this.HTML ? ' ' : ' '; - }, - indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing - if ( !this.multiline ) - return ''; - var chr = this.indentChar; - if ( this.HTML ) - chr = chr.replace(/\t/g,' ').replace(/ /g,' '); - return Array( this._depth_ + (extra||0) ).join(chr); - }, - up:function( a ) { - this._depth_ += a || 1; - }, - down:function( a ) { - this._depth_ -= a || 1; - }, - setParser:function( name, parser ) { - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote:quote, - literal:literal, - join:join, - // - _depth_: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers:{ - window: '[Window]', - document: '[Document]', - error:'[ERROR]', //when no parser is found, shouldn't happen - unknown: '[Unknown]', - 'null':'null', - undefined:'undefined', - 'function':function( fn ) { - var ret = 'function', - name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE - if ( name ) - ret += ' ' + name; - ret += '('; - - ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); - return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); - }, - array: array, - nodelist: array, - arguments: array, - object:function( map ) { - var ret = [ ]; - QUnit.jsDump.up(); - for ( var key in map ) - ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); - QUnit.jsDump.down(); - return join( '{', ret, '}' ); - }, - node:function( node ) { - var open = QUnit.jsDump.HTML ? '<' : '<', - close = QUnit.jsDump.HTML ? '>' : '>'; - - var tag = node.nodeName.toLowerCase(), - ret = open + tag; - - for ( var a in QUnit.jsDump.DOMAttrs ) { - var val = node[QUnit.jsDump.DOMAttrs[a]]; - if ( val ) - ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); - } - return ret + close + open + '/' + tag + close; - }, - functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function - var l = fn.length; - if ( !l ) return ''; - - var args = Array(l); - while ( l-- ) - args[l] = String.fromCharCode(97+l);//97 is 'a' - return ' ' + args.join(', ') + ' '; - }, - key:quote, //object calls it internally, the key part of an item in a map - functionCode:'[code]', //function calls it internally, it's the content of the function - attribute:quote, //node calls it internally, it's an html attribute value - string:quote, - date:quote, - regexp:literal, //regex - number:literal, - 'boolean':literal - }, - DOMAttrs:{//attributes to dump from nodes, name=>realName - id:'id', - name:'name', - 'class':'className' - }, - HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) - indentChar:' ',//indentation unit - multiline:true //if true, items in a collection, are separated by a \n, else just a space. - }; - - return jsDump; -})(); - -// from Sizzle.js -function getText( elems ) { - var ret = "", elem; - - for ( var i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -}; - -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - function diff(o, n){ - var ns = new Object(); - var os = new Object(); - - for (var i = 0; i < n.length; i++) { - if (ns[n[i]] == null) - ns[n[i]] = { - rows: new Array(), - o: null - }; - ns[n[i]].rows.push(i); - } - - for (var i = 0; i < o.length; i++) { - if (os[o[i]] == null) - os[o[i]] = { - rows: new Array(), - n: null - }; - os[o[i]].rows.push(i); - } - - for (var i in ns) { - if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { - n[ns[i].rows[0]] = { - text: n[ns[i].rows[0]], - row: os[i].rows[0] - }; - o[os[i].rows[0]] = { - text: o[os[i].rows[0]], - row: ns[i].rows[0] - }; - } - } - - for (var i = 0; i < n.length - 1; i++) { - if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && - n[i + 1] == o[n[i].row + 1]) { - n[i + 1] = { - text: n[i + 1], - row: n[i].row + 1 - }; - o[n[i].row + 1] = { - text: o[n[i].row + 1], - row: i + 1 - }; - } - } - - for (var i = n.length - 1; i > 0; i--) { - if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && - n[i - 1] == o[n[i].row - 1]) { - n[i - 1] = { - text: n[i - 1], - row: n[i].row - 1 - }; - o[n[i].row - 1] = { - text: o[n[i].row - 1], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function(o, n){ - o = o.replace(/\s+$/, ''); - n = n.replace(/\s+$/, ''); - var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); - - var str = ""; - - var oSpace = o.match(/\s+/g); - if (oSpace == null) { - oSpace = [" "]; - } - else { - oSpace.push(" "); - } - var nSpace = n.match(/\s+/g); - if (nSpace == null) { - nSpace = [" "]; - } - else { - nSpace.push(" "); - } - - if (out.n.length == 0) { - for (var i = 0; i < out.o.length; i++) { - str += '' + out.o[i] + oSpace[i] + ""; - } - } - else { - if (out.n[0].text == null) { - for (n = 0; n < out.o.length && out.o[n].text == null; n++) { - str += '' + out.o[n] + oSpace[n] + ""; - } - } - - for (var i = 0; i < out.n.length; i++) { - if (out.n[i].text == null) { - str += '' + out.n[i] + nSpace[i] + ""; - } - else { - var pre = ""; - - for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { - pre += '' + out.o[n] + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; -})(); - -})(this); diff --git a/build/svg-edit-2.6-src/test/select_test.html b/build/svg-edit-2.6-src/test/select_test.html deleted file mode 100644 index 22bf338..0000000 --- a/build/svg-edit-2.6-src/test/select_test.html +++ /dev/null @@ -1,154 +0,0 @@ - - - - - - - - - - - - - -

          Unit Tests for select.js

          -

          -

          -
            -
          -
          - - diff --git a/build/svg-edit-2.6-src/test/svgtransformlist_test.html b/build/svg-edit-2.6-src/test/svgtransformlist_test.html deleted file mode 100644 index df697cf..0000000 --- a/build/svg-edit-2.6-src/test/svgtransformlist_test.html +++ /dev/null @@ -1,418 +0,0 @@ - - - - - - - - - - - -

          Unit Tests for svgtransformlist.js

          -

          -

          -
            -
          - - - diff --git a/build/svg-edit-2.6-src/test/svgutils_test.html b/build/svg-edit-2.6-src/test/svgutils_test.html deleted file mode 100644 index b04a07f..0000000 --- a/build/svg-edit-2.6-src/test/svgutils_test.html +++ /dev/null @@ -1,134 +0,0 @@ - - - - - - - - - - - - - -

          Unit Tests for svgutils.js

          -

          -

          -
            -
          - - diff --git a/build/svg-edit-2.6-src/test/test1.html b/build/svg-edit-2.6-src/test/test1.html deleted file mode 100644 index 33b297b..0000000 --- a/build/svg-edit-2.6-src/test/test1.html +++ /dev/null @@ -1,283 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - -

          Unit Tests for SvgCanvas

          -

          -

          -
            -
          -
          -
          - -
          -
          -
          -
          - - \ No newline at end of file diff --git a/build/svg-edit-2.6-src/test/units_test.html b/build/svg-edit-2.6-src/test/units_test.html deleted file mode 100644 index 116f20e..0000000 --- a/build/svg-edit-2.6-src/test/units_test.html +++ /dev/null @@ -1,95 +0,0 @@ - - - - - - - - - - -

          Unit Tests for units.js

          -

          -

          -
            -
          - -
          - - -
          - -
          - - diff --git a/build/svg-edit-2.6-src/tspan_move.patch b/build/svg-edit-2.6-src/tspan_move.patch deleted file mode 100644 index 3b1893e..0000000 --- a/build/svg-edit-2.6-src/tspan_move.patch +++ /dev/null @@ -1,24 +0,0 @@ -Index: editor/svgcanvas.js -=================================================================== ---- editor/svgcanvas.js (revision 2067) -+++ editor/svgcanvas.js (working copy) -@@ -1227,6 +1227,19 @@ - changes.y2 = pt2.y; - - case "text": -+ var tspan = selected.querySelectorAll('tspan'); -+ var i = tspan.length -+ while(i--) { -+ var offsetX = selected.getAttribute('x') - tspan[i].getAttribute('x'); -+ var offsetY = selected.getAttribute('y') - tspan[i].getAttribute('y'); -+ var offset = { -+ x: changes.x - offsetX, -+ y: changes.y - offsetY, -+ } -+ assignAttributes(tspan[i], offset, 1000, true); -+ } -+ finishUp(); -+ break; - case "use": - finishUp(); - break; diff --git a/build/svg-edit-2.6-src/wave/json2.js b/build/svg-edit-2.6-src/wave/json2.js deleted file mode 100644 index 8a7793b..0000000 --- a/build/svg-edit-2.6-src/wave/json2.js +++ /dev/null @@ -1,481 +0,0 @@ -/* - http://www.JSON.org/json2.js - 2009-08-17 - - Public Domain. - - NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. - - See http://www.JSON.org/js.html - - This file creates a global JSON object containing two methods: stringify - and parse. - - JSON.stringify(value, replacer, space) - value any JavaScript value, usually an object or array. - - replacer an optional parameter that determines how object - values are stringified for objects. It can be a - function or an array of strings. - - space an optional parameter that specifies the indentation - of nested structures. If it is omitted, the text will - be packed without extra whitespace. If it is a number, - it will specify the number of spaces to indent at each - level. If it is a string (such as '\t' or ' '), - it contains the characters used to indent at each level. - - This method produces a JSON text from a JavaScript value. - - When an object value is found, if the object contains a toJSON - method, its toJSON method will be called and the result will be - stringified. A toJSON method does not serialize: it returns the - value represented by the name/value pair that should be serialized, - or undefined if nothing should be serialized. The toJSON method - will be passed the key associated with the value, and this will be - bound to the value - - For example, this would serialize Dates as ISO strings. - - Date.prototype.toJSON = function (key) { - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - return this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z'; - }; - - You can provide an optional replacer method. It will be passed the - key and value of each member, with this bound to the containing - object. The value that is returned from your method will be - serialized. If your method returns undefined, then the member will - be excluded from the serialization. - - If the replacer parameter is an array of strings, then it will be - used to select the members to be serialized. It filters the results - such that only members with keys listed in the replacer array are - stringified. - - Values that do not have JSON representations, such as undefined or - functions, will not be serialized. Such values in objects will be - dropped; in arrays they will be replaced with null. You can use - a replacer function to replace those with JSON values. - JSON.stringify(undefined) returns undefined. - - The optional space parameter produces a stringification of the - value that is filled with line breaks and indentation to make it - easier to read. - - If the space parameter is a non-empty string, then that string will - be used for indentation. If the space parameter is a number, then - the indentation will be that many spaces. - - Example: - - text = JSON.stringify(['e', {pluribus: 'unum'}]); - // text is '["e",{"pluribus":"unum"}]' - - - text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); - // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' - - text = JSON.stringify([new Date()], function (key, value) { - return this[key] instanceof Date ? - 'Date(' + this[key] + ')' : value; - }); - // text is '["Date(---current time---)"]' - - - JSON.parse(text, reviver) - This method parses a JSON text to produce an object or array. - It can throw a SyntaxError exception. - - The optional reviver parameter is a function that can filter and - transform the results. It receives each of the keys and values, - and its return value is used instead of the original value. - If it returns what it received, then the structure is not modified. - If it returns undefined then the member is deleted. - - Example: - - // Parse the text. Values that look like ISO date strings will - // be converted to Date objects. - - myData = JSON.parse(text, function (key, value) { - var a; - if (typeof value === 'string') { - a = -/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); - if (a) { - return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], - +a[5], +a[6])); - } - } - return value; - }); - - myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { - var d; - if (typeof value === 'string' && - value.slice(0, 5) === 'Date(' && - value.slice(-1) === ')') { - d = new Date(value.slice(5, -1)); - if (d) { - return d; - } - } - return value; - }); - - - This is a reference implementation. You are free to copy, modify, or - redistribute. - - This code should be minified before deployment. - See http://javascript.crockford.com/jsmin.html - - USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO - NOT CONTROL. -*/ - -/*jslint evil: true */ - -/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, - call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, - getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, - lastIndex, length, parse, prototype, push, replace, slice, stringify, - test, toJSON, toString, valueOf -*/ - -"use strict"; - -// Create a JSON object only if one does not already exist. We create the -// methods in a closure to avoid creating global variables. - -if (!this.JSON) { - this.JSON = {}; -} - -(function () { - - function f(n) { - // Format integers to have at least two digits. - return n < 10 ? '0' + n : n; - } - - if (typeof Date.prototype.toJSON !== 'function') { - - Date.prototype.toJSON = function (key) { - - return isFinite(this.valueOf()) ? - this.getUTCFullYear() + '-' + - f(this.getUTCMonth() + 1) + '-' + - f(this.getUTCDate()) + 'T' + - f(this.getUTCHours()) + ':' + - f(this.getUTCMinutes()) + ':' + - f(this.getUTCSeconds()) + 'Z' : null; - }; - - String.prototype.toJSON = - Number.prototype.toJSON = - Boolean.prototype.toJSON = function (key) { - return this.valueOf(); - }; - } - - var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, - gap, - indent, - meta = { // table of character substitutions - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' - }, - rep; - - - function quote(string) { - -// If the string contains no control characters, no quote characters, and no -// backslash characters, then we can safely slap some quotes around it. -// Otherwise we must also replace the offending characters with safe escape -// sequences. - - escapable.lastIndex = 0; - return escapable.test(string) ? - '"' + string.replace(escapable, function (a) { - var c = meta[a]; - return typeof c === 'string' ? c : - '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) + '"' : - '"' + string + '"'; - } - - - function str(key, holder) { - -// Produce a string from holder[key]. - - var i, // The loop counter. - k, // The member key. - v, // The member value. - length, - mind = gap, - partial, - value = holder[key]; - -// If the value has a toJSON method, call it to obtain a replacement value. - - if (value && typeof value === 'object' && - typeof value.toJSON === 'function') { - value = value.toJSON(key); - } - -// If we were called with a replacer function, then call the replacer to -// obtain a replacement value. - - if (typeof rep === 'function') { - value = rep.call(holder, key, value); - } - -// What happens next depends on the value's type. - - switch (typeof value) { - case 'string': - return quote(value); - - case 'number': - -// JSON numbers must be finite. Encode non-finite numbers as null. - - return isFinite(value) ? String(value) : 'null'; - - case 'boolean': - case 'null': - -// If the value is a boolean or null, convert it to a string. Note: -// typeof null does not produce 'null'. The case is included here in -// the remote chance that this gets fixed someday. - - return String(value); - -// If the type is 'object', we might be dealing with an object or an array or -// null. - - case 'object': - -// Due to a specification blunder in ECMAScript, typeof null is 'object', -// so watch out for that case. - - if (!value) { - return 'null'; - } - -// Make an array to hold the partial results of stringifying this object value. - - gap += indent; - partial = []; - -// Is the value an array? - - if (Object.prototype.toString.apply(value) === '[object Array]') { - -// The value is an array. Stringify every element. Use null as a placeholder -// for non-JSON values. - - length = value.length; - for (i = 0; i < length; i += 1) { - partial[i] = str(i, value) || 'null'; - } - -// Join all of the elements together, separated with commas, and wrap them in -// brackets. - - v = partial.length === 0 ? '[]' : - gap ? '[\n' + gap + - partial.join(',\n' + gap) + '\n' + - mind + ']' : - '[' + partial.join(',') + ']'; - gap = mind; - return v; - } - -// If the replacer is an array, use it to select the members to be stringified. - - if (rep && typeof rep === 'object') { - length = rep.length; - for (i = 0; i < length; i += 1) { - k = rep[i]; - if (typeof k === 'string') { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } else { - -// Otherwise, iterate through all of the keys in the object. - - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = str(k, value); - if (v) { - partial.push(quote(k) + (gap ? ': ' : ':') + v); - } - } - } - } - -// Join all of the member texts together, separated with commas, -// and wrap them in braces. - - v = partial.length === 0 ? '{}' : - gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + - mind + '}' : '{' + partial.join(',') + '}'; - gap = mind; - return v; - } - } - -// If the JSON object does not yet have a stringify method, give it one. - - if (typeof JSON.stringify !== 'function') { - JSON.stringify = function (value, replacer, space) { - -// The stringify method takes a value and an optional replacer, and an optional -// space parameter, and returns a JSON text. The replacer can be a function -// that can replace values, or an array of strings that will select the keys. -// A default replacer method can be provided. Use of the space parameter can -// produce text that is more easily readable. - - var i; - gap = ''; - indent = ''; - -// If the space parameter is a number, make an indent string containing that -// many spaces. - - if (typeof space === 'number') { - for (i = 0; i < space; i += 1) { - indent += ' '; - } - -// If the space parameter is a string, it will be used as the indent string. - - } else if (typeof space === 'string') { - indent = space; - } - -// If there is a replacer, it must be a function or an array. -// Otherwise, throw an error. - - rep = replacer; - if (replacer && typeof replacer !== 'function' && - (typeof replacer !== 'object' || - typeof replacer.length !== 'number')) { - throw new Error('JSON.stringify'); - } - -// Make a fake root object containing our value under the key of ''. -// Return the result of stringifying the value. - - return str('', {'': value}); - }; - } - - -// If the JSON object does not yet have a parse method, give it one. - - if (typeof JSON.parse !== 'function') { - JSON.parse = function (text, reviver) { - -// The parse method takes a text and an optional reviver function, and returns -// a JavaScript value if the text is a valid JSON text. - - var j; - - function walk(holder, key) { - -// The walk method is used to recursively walk the resulting structure so -// that modifications can be made. - - var k, v, value = holder[key]; - if (value && typeof value === 'object') { - for (k in value) { - if (Object.hasOwnProperty.call(value, k)) { - v = walk(value, k); - if (v !== undefined) { - value[k] = v; - } else { - delete value[k]; - } - } - } - } - return reviver.call(holder, key, value); - } - - -// Parsing happens in four stages. In the first stage, we replace certain -// Unicode characters with escape sequences. JavaScript handles many characters -// incorrectly, either silently deleting them, or treating them as line endings. - - cx.lastIndex = 0; - if (cx.test(text)) { - text = text.replace(cx, function (a) { - return '\\u' + - ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }); - } - -// In the second stage, we run the text against regular expressions that look -// for non-JSON patterns. We are especially concerned with '()' and 'new' -// because they can cause invocation, and '=' because it can cause mutation. -// But just to be safe, we want to reject all unexpected forms. - -// We split the second stage into 4 regexp operations in order to work around -// crippling inefficiencies in IE's and Safari's regexp engines. First we -// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we -// replace all simple value tokens with ']' characters. Third, we delete all -// open brackets that follow a colon or comma or that begin the text. Finally, -// we look to see that the remaining characters are only whitespace or ']' or -// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. - - if (/^[\],:{}\s]*$/. -test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). -replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). -replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { - -// In the third stage we use the eval function to compile the text into a -// JavaScript structure. The '{' operator is subject to a syntactic ambiguity -// in JavaScript: it can begin a block or an object literal. We wrap the text -// in parens to eliminate the ambiguity. - - j = eval('(' + text + ')'); - -// In the optional fourth stage, we recursively walk the new structure, passing -// each name/value pair to a reviver function for possible transformation. - - return typeof reviver === 'function' ? - walk({'': j}, '') : j; - } - -// If the text is not JSON parseable, then a SyntaxError is thrown. - - throw new SyntaxError('JSON.parse'); - }; - } -}()); - diff --git a/build/svg-edit-2.6-src/wave/manifest.xml b/build/svg-edit-2.6-src/wave/manifest.xml deleted file mode 100644 index e85a2b9..0000000 --- a/build/svg-edit-2.6-src/wave/manifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/build/svg-edit-2.6-src/wave/svg-edit.xml b/build/svg-edit-2.6-src/wave/svg-edit.xml deleted file mode 100644 index e16ea7b..0000000 --- a/build/svg-edit-2.6-src/wave/svg-edit.xml +++ /dev/null @@ -1,484 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
          - -
          - -
          -
          - -
          -
          -

          Layers

          -
          -
          -
          -
          -
          -
          -
          - - - - - - -
          Layer 1
          - Move elements to: - -
          -
          L a y e r s
          -
          - - - -
          - - -
          -
          - -
          -
          -
          -
          -
          - - -
          -
          -
          -
          -
          - - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - - - -
          -
          - - -
          -
          - - - - -
          -
          - - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - relative to: - -
          - -
          - -
          -
          -
          -
          - -
          -
          - - - - -
          -
          - - -
          -
          - -
          -
          - - - - -
          -
          - - - -
          -
          -
          - -
          -
          - - - - -
          -
          - - -
          -
          - -
          -
          - - - - -
          -
          - - - - -
          -
          - -
          -
          - - - - -
          -
          - - - - -
          -
          - -
          -
          B
          -
          i
          - -
          - - -
          - -
          - - -
          - -
          - -
          -
          - -
          - - - - - -
          -
          -
          - -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          - - -
          - zoom: - - -
          -
          - -
          - - - - - - - - - - - - -
          fill:
          100%
          stroke:
          100 %
          - - - -
          -
          - -
          -
          -
          - -
          - - -
          - -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          - -
          - -
          -
          -
          -
          - - -
          -
          - -
          -
          -
          - -
          -
          -
          -
          - - -
          - - -
          - Image Properties - - -
          - Canvas Dimensions - - - - - - -
          - -
          - Included Images - - -
          - - -
          - -
          - Editor Preferences - - - - - -
          - Editor Background -
          - -

          Note: Background will not be saved with image.

          -
          - -
          - -
          -
          - -
          -
          -
          -
          - Test message -
          -
          -
          -
          - - ]]> -
          -
          diff --git a/build/svg-edit-2.6-src/wave/wave.js b/build/svg-edit-2.6-src/wave/wave.js deleted file mode 100644 index c3723f7..0000000 --- a/build/svg-edit-2.6-src/wave/wave.js +++ /dev/null @@ -1,147 +0,0 @@ -var shapetime = {}; -var nodelete = false; - -function stateUpdated() { - - // 'state' is an object of key-value pairs that map ids to JSON serialization of SVG elements - // 'keys' is an array of all the keys in the state - var state = wave.getState(); - var keys = state.getKeys(); - svgCanvas.each(function(e) { - // 'this' is the SVG DOM element node (ellipse, rect, etc) - // 'e' is an integer describing the position within the document - var k = this.id; - var v = state.get(k); - if(k == "selectorParentGroup" || k == "svgcontent"){ - //meh - }else if (v) { - var ob = JSON.parse(v); - if (ob) { - // do nothing - } else { - //var node = document.getElementById(k); - //if (node) node.parentNode.removeChild(node); - } - //keys.remove(k); - - } else if(!nodelete){ - - this.parentNode.removeChild(this); - } - }); - - // New nodes - for (var k in keys) { - var v = state.get(keys[k]); - var ob = JSON.parse(v); - if (ob){ - if(!shapetime[k] || ob.time > shapetime[k]){ - var a; - if(a = document.getElementById(k)){ - var attrs = get_attrs(a); - if(JSON.stringify(attrs) != JSON.stringify(ob.attr)){ - shapetime[k] = ob.time - svgCanvas.updateElementFromJson(ob) - } - }else{ - shapetime[k] = ob.time - svgCanvas.updateElementFromJson(ob) - } - - } - } - } -} - - -function getId(canvas, objnum) { - var id = wave.getViewer().getId().split("@")[0]; - var extra = SHA256(wave.getViewer().getId()); //in case the next step kills all the characters - for(var i = 0, l = id.length, n = ""; i < l; i++){ - if("abcdefghijklmnopqrstuvwxyz0123456789".indexOf(id[i]) != -1){ - n+=id[i]; - } - } - return "svg_"+n+"_"+extra.substr(0,5)+"_"+objnum; -} - -function get_attrs(a){ - var attrs = {}; - for(var i = a.length; i--;){ - var attr = a.item(i).nodeName; - if(",style,".indexOf(","+attr+",") == -1){ - attrs[attr] = a.item(i).nodeValue; - } - } - return attrs -} - -function main() { - $(document).ready(function(){ - if (wave && wave.isInWaveContainer()) { - wave.setStateCallback(function(){setTimeout(stateUpdated,10)}); - } - - var oldchanged = svgCanvas.bind("changed", function(canvas, elem){ - if(oldchanged)oldchanged.apply(this, [canvas,elem]); - - var delta = {} - $.each(elem, function(){ - - var attrs = {}; - var a = this.attributes; - if(a){ - var attrs = get_attrs(a) - var ob = {element: this.nodeName, attr: attrs}; - - ob.time = shapetime[this.id] = (new Date).getTime() - delta[this.id] = JSON.stringify(ob); - } - }) - - wave.getState().submitDelta(delta) - //sendDelta(canvas, elem) - - }); - //* - - var oldselected = svgCanvas.bind("selected", function(canvas, elem){ - - if(oldselected)oldselected.apply(this, [canvas,elem]); - - - var delta = {} - var deletions = 0; - $.each(elem, function(){ - if(!this.parentNode && this != window){ - delta[this.id] = null; - deletions ++ - } - }); - if(deletions > 0){ - wave.getState().submitDelta(delta) - } - }); - /// - svgCanvas.bind("cleared", function(){ - //alert("cleared") - var state = {}, keys = wave.getState().getKeys() - for(var i = 0; i < keys.length; i++){ - state[keys[i]] = null; - } - wave.getState().submitDelta(state) - }); - //*/ - svgCanvas.bind("getid", getId); - }) -} - - - -if(window.gadgets) gadgets.util.registerOnLoadHandler(main); - -//$(main) - -//and why not use my stuff? -function SHA256(b){function h(j,k){return(j>>e)+(k>>e)+((p=(j&o)+(k&o))>>e)<>>k|j<<32-k}var g=[],d,c=3,l=[2],p,i,q,a,m=[],n=[];i=b.length*8;for(var e=16,o=65535,r="";c<312;c++){for(d=l.length;d--&&c%l[d]!=0;);d<0&&l.push(c)}b+="\u0080";for(c=0;c<=i;c+=8)n[c>>5]|=(b.charCodeAt(c/8)&255)<<24-c%32;n[(i+64>>9<<4)+15]=i;for(c=8;c--;)m[c]=parseInt(Math.pow(l[c],0.5).toString(e).substr(2,8),e);for(c=0;c>>10,g[b-7]),f(g[b-15],7)^f(g[b-15],18)^g[b-15]>>>3),g[b-e]);i=h(h(h(h(a[7],f(a[4],6)^f(a[4],11)^f(a[4],25)),a[4]&a[5]^~a[4]&a[6]),parseInt(Math.pow(l[b],1/3).toString(e).substr(2,8),e)),g[b]);q=(f(a[0],2)^f(a[0],13)^f(a[0],22))+(a[0]&a[1]^a[0]&a[2]^a[1]&a[2]);for(d=8;--d;)a[d]=d==4?h(a[3],i):a[d-1];a[0]=h(i,q)}for(d=8;d--;)m[d]+=a[d]}for(c=0;c<8;c++)for(b=8;b--;)r+=(m[c]>>>b*4&15).toString(e);return r} - diff --git a/build/svg-edit-2.6.wgt b/build/svg-edit-2.6.wgt deleted file mode 100644 index 15af21a..0000000 Binary files a/build/svg-edit-2.6.wgt and /dev/null differ diff --git a/build/svg-edit-2.6.xpi b/build/svg-edit-2.6.xpi deleted file mode 100644 index cd1438f..0000000 Binary files a/build/svg-edit-2.6.xpi and /dev/null differ diff --git a/build/svg-edit-2.6.zip b/build/svg-edit-2.6.zip deleted file mode 100644 index b3a935a..0000000 Binary files a/build/svg-edit-2.6.zip and /dev/null differ diff --git a/build/svg-edit-2.6/browser-not-supported.html b/build/svg-edit-2.6/browser-not-supported.html deleted file mode 100644 index 3010fcf..0000000 --- a/build/svg-edit-2.6/browser-not-supported.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - -Browser does not support SVG | SVG-edit - - - -
          -SVG-edit logo
          -

          Sorry, but your browser does not support SVG. Below is a list of alternate browsers and versions that support SVG and SVG-edit (from caniuse.com).

          -

          Try the latest version of Firefox, Google Chrome, Safari, Opera or Internet Explorer.

          -

          If you are unable to install one of these and must use an old version of Internet Explorer, you can install the Google Chrome Frame plugin.

          - - - -
          - - - diff --git a/build/svg-edit-2.6/browser.js b/build/svg-edit-2.6/browser.js deleted file mode 100644 index edfba7b..0000000 --- a/build/svg-edit-2.6/browser.js +++ /dev/null @@ -1,180 +0,0 @@ -/** - * Package: svgedit.browser - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Alexis Deveria - */ - -// Dependencies: -// 1) jQuery (for $.alert()) - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.browser) { - svgedit.browser = {}; -} -var supportsSvg_ = (function() { - return !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect; -})(); -svgedit.browser.supportsSvg = function() { return supportsSvg_; } -if(!svgedit.browser.supportsSvg()) { - window.location = "browser-not-supported.html"; -} -else{ - -var svgns = 'http://www.w3.org/2000/svg'; -var userAgent = navigator.userAgent; -var svg = document.createElementNS(svgns, 'svg'); - -// Note: Browser sniffing should only be used if no other detection method is possible -var isOpera_ = !!window.opera; -var isWebkit_ = userAgent.indexOf("AppleWebKit") >= 0; -var isGecko_ = userAgent.indexOf('Gecko/') >= 0; -var isIE_ = userAgent.indexOf('MSIE') >= 0; -var isChrome_ = userAgent.indexOf('Chrome/') >= 0; -var isWindows_ = userAgent.indexOf('Windows') >= 0; -var isMac_ = userAgent.indexOf('Macintosh') >= 0; -var isTouch_ = 'ontouchstart' in window; - -var supportsSelectors_ = (function() { - return !!svg.querySelector; -})(); - -var supportsXpath_ = (function() { - return !!document.evaluate; -})(); - -// segList functions (for FF1.5 and 2.0) -var supportsPathReplaceItem_ = (function() { - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.replaceItem(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -var supportsPathInsertItemBefore_ = (function() { - var path = document.createElementNS(svgns,'path'); - path.setAttribute('d','M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5,5); - try { - seglist.insertItemBefore(seg, 0); - return true; - } catch(err) {} - return false; -})(); - -// text character positioning (for IE9) -var supportsGoodTextCharPos_ = (function() { - var retValue = false; - var svgroot = document.createElementNS(svgns, 'svg'); - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgroot); - svgcontent.setAttribute('x', 5); - svgroot.appendChild(svgcontent); - var text = document.createElementNS(svgns,'text'); - text.textContent = 'a'; - svgcontent.appendChild(text); - var pos = text.getStartPositionOfChar(0).x; - document.documentElement.removeChild(svgroot); - return (pos === 0); -})(); - -var supportsPathBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 C0,0 10,10 10,0'); - svgcontent.appendChild(path); - var bbox = path.getBBox(); - document.documentElement.removeChild(svgcontent); - return (bbox.height > 4 && bbox.height < 5); -})(); - -// Support for correct bbox sizing on groups with horizontal/vertical lines -var supportsHVLineContainerBBox_ = (function() { - var svgcontent = document.createElementNS(svgns, 'svg'); - document.documentElement.appendChild(svgcontent); - var path = document.createElementNS(svgns, 'path'); - path.setAttribute('d','M0,0 10,0'); - var path2 = document.createElementNS(svgns, 'path'); - path2.setAttribute('d','M5,0 15,0'); - var g = document.createElementNS(svgns, 'g'); - g.appendChild(path); - g.appendChild(path2); - svgcontent.appendChild(g); - var bbox = g.getBBox(); - document.documentElement.removeChild(svgcontent); - // Webkit gives 0, FF gives 10, Opera (correctly) gives 15 - return (bbox.width == 15); -})(); - -var supportsEditableText_ = (function() { - // TODO: Find better way to check support for this - return isOpera_; -})(); - -var supportsGoodDecimals_ = (function() { - // Correct decimals on clone attributes (Opera < 10.5/win/non-en) - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('x',.1); - var crect = rect.cloneNode(false); - var retValue = (crect.getAttribute('x').indexOf(',') == -1); - if(!retValue) { - $.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\ - Please upgrade to the latest version in which the problems have been fixed."); - } - return retValue; -})(); - -var supportsNonScalingStroke_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - rect.setAttribute('style','vector-effect:non-scaling-stroke'); - return rect.style.vectorEffect === 'non-scaling-stroke'; -})(); - -var supportsNativeSVGTransformLists_ = (function() { - var rect = document.createElementNS(svgns, 'rect'); - var rxform = rect.transform.baseVal; - - var t1 = svg.createSVGTransform(); - rxform.appendItem(t1); - return rxform.getItem(0) == t1; -})(); - -// Public API - -svgedit.browser.isOpera = function() { return isOpera_; } -svgedit.browser.isWebkit = function() { return isWebkit_; } -svgedit.browser.isGecko = function() { return isGecko_; } -svgedit.browser.isIE = function() { return isIE_; } -svgedit.browser.isChrome = function() { return isChrome_; } -svgedit.browser.isWindows = function() { return isWindows_; } -svgedit.browser.isMac = function() { return isMac_; } -svgedit.browser.isTouch = function() { return isTouch_; } - -svgedit.browser.supportsSelectors = function() { return supportsSelectors_; } -svgedit.browser.supportsXpath = function() { return supportsXpath_; } - -svgedit.browser.supportsPathReplaceItem = function() { return supportsPathReplaceItem_; } -svgedit.browser.supportsPathInsertItemBefore = function() { return supportsPathInsertItemBefore_; } -svgedit.browser.supportsPathBBox = function() { return supportsPathBBox_; } -svgedit.browser.supportsHVLineContainerBBox = function() { return supportsHVLineContainerBBox_; } -svgedit.browser.supportsGoodTextCharPos = function() { return supportsGoodTextCharPos_; } -svgedit.browser.supportsEditableText = function() { return supportsEditableText_; } -svgedit.browser.supportsGoodDecimals = function() { return supportsGoodDecimals_; } -svgedit.browser.supportsNonScalingStroke = function() { return supportsNonScalingStroke_; } -svgedit.browser.supportsNativeTransformLists = function() { return supportsNativeSVGTransformLists_; } - -} - -})(); diff --git a/build/svg-edit-2.6/canvg/canvg.js b/build/svg-edit-2.6/canvg/canvg.js deleted file mode 100644 index 7b24a38..0000000 --- a/build/svg-edit-2.6/canvg/canvg.js +++ /dev/null @@ -1,2620 +0,0 @@ -/* - * canvg.js - Javascript SVG parser and renderer on Canvas - * MIT Licensed - * Gabe Lerner (gabelerner@gmail.com) - * http://code.google.com/p/canvg/ - * - * Requires: rgbcolor.js - http://www.phpied.com/rgb-color-parser-in-javascript/ - */ -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(!Array.prototype.indexOf){ - Array.prototype.indexOf = function(obj){ - for(var i=0; i ignore mouse events - // ignoreAnimation: true => ignore animations - // ignoreDimensions: true => does not try to resize canvas - // ignoreClear: true => does not clear canvas - // offsetX: int => draws at a x offset - // offsetY: int => draws at a y offset - // scaleWidth: int => scales horizontally to width - // scaleHeight: int => scales vertically to height - // renderCallback: function => will call the function after the first render is completed - // forceRedraw: function => will call the function on every frame, if it returns true, will redraw - this.canvg = function (target, s, opts) { - // no parameters - if (target == null && s == null && opts == null) { - var svgTags = document.getElementsByTagName('svg'); - for (var i=0; i]*>/, ''); - var xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); - xmlDoc.async = 'false'; - xmlDoc.loadXML(xml); - return xmlDoc; - } - } - - svg.Property = function(name, value) { - this.name = name; - this.value = value; - - this.hasValue = function() { - return (this.value != null && this.value !== ''); - } - - // return the numerical value of the property - this.numValue = function() { - if (!this.hasValue()) return 0; - - var n = parseFloat(this.value); - if ((this.value + '').match(/%$/)) { - n = n / 100.0; - } - return n; - } - - this.valueOrDefault = function(def) { - if (this.hasValue()) return this.value; - return def; - } - - this.numValueOrDefault = function(def) { - if (this.hasValue()) return this.numValue(); - return def; - } - - /* EXTENSIONS */ - var that = this; - - // color extensions - this.Color = { - // augment the current color value with the opacity - addOpacity: function(opacity) { - var newValue = that.value; - if (opacity != null && opacity != '') { - var color = new RGBColor(that.value); - if (color.ok) { - newValue = 'rgba(' + color.r + ', ' + color.g + ', ' + color.b + ', ' + opacity + ')'; - } - } - return new svg.Property(that.name, newValue); - } - } - - // definition extensions - this.Definition = { - // get the definition from the definitions table - getDefinition: function() { - var name = that.value.replace(/^(url\()?#([^\)]+)\)?$/, '$2'); - return svg.Definitions[name]; - }, - - isUrl: function() { - return that.value.indexOf('url(') == 0 - }, - - getFillStyle: function(e) { - var def = this.getDefinition(); - - // gradient - if (def != null && def.createGradient) { - return def.createGradient(svg.ctx, e); - } - - // pattern - if (def != null && def.createPattern) { - return def.createPattern(svg.ctx, e); - } - - return null; - } - } - - // length extensions - this.Length = { - DPI: function(viewPort) { - return 96.0; // TODO: compute? - }, - - EM: function(viewPort) { - var em = 12; - - var fontSize = new svg.Property('fontSize', svg.Font.Parse(svg.ctx.font).fontSize); - if (fontSize.hasValue()) em = fontSize.Length.toPixels(viewPort); - - return em; - }, - - // get the length as pixels - toPixels: function(viewPort) { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/em$/)) return that.numValue() * this.EM(viewPort); - if (s.match(/ex$/)) return that.numValue() * this.EM(viewPort) / 2.0; - if (s.match(/px$/)) return that.numValue(); - if (s.match(/pt$/)) return that.numValue() * 1.25; - if (s.match(/pc$/)) return that.numValue() * 15; - if (s.match(/cm$/)) return that.numValue() * this.DPI(viewPort) / 2.54; - if (s.match(/mm$/)) return that.numValue() * this.DPI(viewPort) / 25.4; - if (s.match(/in$/)) return that.numValue() * this.DPI(viewPort); - if (s.match(/%$/)) return that.numValue() * svg.ViewPort.ComputeSize(viewPort); - return that.numValue(); - } - } - - // time extensions - this.Time = { - // get the time as milliseconds - toMilliseconds: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/s$/)) return that.numValue() * 1000; - if (s.match(/ms$/)) return that.numValue(); - return that.numValue(); - } - } - - // angle extensions - this.Angle = { - // get the angle as radians - toRadians: function() { - if (!that.hasValue()) return 0; - var s = that.value+''; - if (s.match(/deg$/)) return that.numValue() * (Math.PI / 180.0); - if (s.match(/grad$/)) return that.numValue() * (Math.PI / 200.0); - if (s.match(/rad$/)) return that.numValue(); - return that.numValue() * (Math.PI / 180.0); - } - } - } - - // fonts - svg.Font = new (function() { - this.Styles = ['normal','italic','oblique','inherit']; - this.Variants = ['normal','small-caps','inherit']; - this.Weights = ['normal','bold','bolder','lighter','100','200','300','400','500','600','700','800','900','inherit']; - - this.CreateFont = function(fontStyle, fontVariant, fontWeight, fontSize, fontFamily, inherit) { - var f = inherit != null ? this.Parse(inherit) : this.CreateFont('', '', '', '', '', svg.ctx.font); - return { - fontFamily: fontFamily || f.fontFamily, - fontSize: fontSize || f.fontSize, - fontStyle: fontStyle || f.fontStyle, - fontWeight: fontWeight || f.fontWeight, - fontVariant: fontVariant || f.fontVariant, - toString: function () { return [this.fontStyle, this.fontVariant, this.fontWeight, this.fontSize, this.fontFamily].join(' ') } - } - } - - var that = this; - this.Parse = function(s) { - var f = {}; - var d = svg.trim(svg.compressSpaces(s || '')).split(' '); - var set = { fontSize: false, fontStyle: false, fontWeight: false, fontVariant: false } - var ff = ''; - for (var i=0; i this.x2) this.x2 = x; - } - - if (y != null) { - if (isNaN(this.y1) || isNaN(this.y2)) { - this.y1 = y; - this.y2 = y; - } - if (y < this.y1) this.y1 = y; - if (y > this.y2) this.y2 = y; - } - } - this.addX = function(x) { this.addPoint(x, null); } - this.addY = function(y) { this.addPoint(null, y); } - - this.addBoundingBox = function(bb) { - this.addPoint(bb.x1, bb.y1); - this.addPoint(bb.x2, bb.y2); - } - - this.addQuadraticCurve = function(p0x, p0y, p1x, p1y, p2x, p2y) { - var cp1x = p0x + 2/3 * (p1x - p0x); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp1y = p0y + 2/3 * (p1y - p0y); // CP1 = QP0 + 2/3 *(QP1-QP0) - var cp2x = cp1x + 1/3 * (p2x - p0x); // CP2 = CP1 + 1/3 *(QP2-QP0) - var cp2y = cp1y + 1/3 * (p2y - p0y); // CP2 = CP1 + 1/3 *(QP2-QP0) - this.addBezierCurve(p0x, p0y, cp1x, cp2x, cp1y, cp2y, p2x, p2y); - } - - this.addBezierCurve = function(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y) { - // from http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - var p0 = [p0x, p0y], p1 = [p1x, p1y], p2 = [p2x, p2y], p3 = [p3x, p3y]; - this.addPoint(p0[0], p0[1]); - this.addPoint(p3[0], p3[1]); - - for (i=0; i<=1; i++) { - var f = function(t) { - return Math.pow(1-t, 3) * p0[i] - + 3 * Math.pow(1-t, 2) * t * p1[i] - + 3 * (1-t) * Math.pow(t, 2) * p2[i] - + Math.pow(t, 3) * p3[i]; - } - - var b = 6 * p0[i] - 12 * p1[i] + 6 * p2[i]; - var a = -3 * p0[i] + 9 * p1[i] - 9 * p2[i] + 3 * p3[i]; - var c = 3 * p1[i] - 3 * p0[i]; - - if (a == 0) { - if (b == 0) continue; - var t = -c / b; - if (0 < t && t < 1) { - if (i == 0) this.addX(f(t)); - if (i == 1) this.addY(f(t)); - } - continue; - } - - var b2ac = Math.pow(b, 2) - 4 * c * a; - if (b2ac < 0) continue; - var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); - if (0 < t1 && t1 < 1) { - if (i == 0) this.addX(f(t1)); - if (i == 1) this.addY(f(t1)); - } - var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); - if (0 < t2 && t2 < 1) { - if (i == 0) this.addX(f(t2)); - if (i == 1) this.addY(f(t2)); - } - } - } - - this.isPointInBox = function(x, y) { - return (this.x1 <= x && x <= this.x2 && this.y1 <= y && y <= this.y2); - } - - this.addPoint(x1, y1); - this.addPoint(x2, y2); - } - - // transforms - svg.Transform = function(v) { - var that = this; - this.Type = {} - - // translate - this.Type.translate = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.translate(this.p.x || 0.0, this.p.y || 0.0); - } - this.applyToPoint = function(p) { - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - } - } - - // rotate - this.Type.rotate = function(s) { - var a = svg.ToNumberArray(s); - this.angle = new svg.Property('angle', a[0]); - this.cx = a[1] || 0; - this.cy = a[2] || 0; - this.apply = function(ctx) { - ctx.translate(this.cx, this.cy); - ctx.rotate(this.angle.Angle.toRadians()); - ctx.translate(-this.cx, -this.cy); - } - this.applyToPoint = function(p) { - var a = this.angle.Angle.toRadians(); - p.applyTransform([1, 0, 0, 1, this.p.x || 0.0, this.p.y || 0.0]); - p.applyTransform([Math.cos(a), Math.sin(a), -Math.sin(a), Math.cos(a), 0, 0]); - p.applyTransform([1, 0, 0, 1, -this.p.x || 0.0, -this.p.y || 0.0]); - } - } - - this.Type.scale = function(s) { - this.p = svg.CreatePoint(s); - this.apply = function(ctx) { - ctx.scale(this.p.x || 1.0, this.p.y || this.p.x || 1.0); - } - this.applyToPoint = function(p) { - p.applyTransform([this.p.x || 0.0, 0, 0, this.p.y || 0.0, 0, 0]); - } - } - - this.Type.matrix = function(s) { - this.m = svg.ToNumberArray(s); - this.apply = function(ctx) { - ctx.transform(this.m[0], this.m[1], this.m[2], this.m[3], this.m[4], this.m[5]); - } - this.applyToPoint = function(p) { - p.applyTransform(this.m); - } - } - - this.Type.SkewBase = function(s) { - this.base = that.Type.matrix; - this.base(s); - this.angle = new svg.Property('angle', s); - } - this.Type.SkewBase.prototype = new this.Type.matrix; - - this.Type.skewX = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, 0, Math.tan(this.angle.Angle.toRadians()), 1, 0, 0]; - } - this.Type.skewX.prototype = new this.Type.SkewBase; - - this.Type.skewY = function(s) { - this.base = that.Type.SkewBase; - this.base(s); - this.m = [1, Math.tan(this.angle.Angle.toRadians()), 0, 1, 0, 0]; - } - this.Type.skewY.prototype = new this.Type.SkewBase; - - this.transforms = []; - - this.apply = function(ctx) { - for (var i=0; i= this.tokens.length - 1; - } - - this.isCommandOrEnd = function() { - if (this.isEnd()) return true; - return this.tokens[this.i + 1].match(/^[A-Za-z]$/) != null; - } - - this.isRelativeCommand = function() { - return this.command == this.command.toLowerCase(); - } - - this.getToken = function() { - this.i = this.i + 1; - return this.tokens[this.i]; - } - - this.getScalar = function() { - return parseFloat(this.getToken()); - } - - this.nextCommand = function() { - this.previousCommand = this.command; - this.command = this.getToken(); - } - - this.getPoint = function() { - var p = new svg.Point(this.getScalar(), this.getScalar()); - return this.makeAbsolute(p); - } - - this.getAsControlPoint = function() { - var p = this.getPoint(); - this.control = p; - return p; - } - - this.getAsCurrentPoint = function() { - var p = this.getPoint(); - this.current = p; - return p; - } - - this.getReflectedControlPoint = function() { - if (this.previousCommand.toLowerCase() != 'c' && this.previousCommand.toLowerCase() != 's') { - return this.current; - } - - // reflect point - var p = new svg.Point(2 * this.current.x - this.control.x, 2 * this.current.y - this.control.y); - return p; - } - - this.makeAbsolute = function(p) { - if (this.isRelativeCommand()) { - p.x = this.current.x + p.x; - p.y = this.current.y + p.y; - } - return p; - } - - this.addMarker = function(p, from, priorTo) { - // if the last angle isn't filled in because we didn't have this point yet ... - if (priorTo != null && this.angles.length > 0 && this.angles[this.angles.length-1] == null) { - this.angles[this.angles.length-1] = this.points[this.points.length-1].angleTo(priorTo); - } - this.addMarkerAngle(p, from == null ? null : from.angleTo(p)); - } - - this.addMarkerAngle = function(p, a) { - this.points.push(p); - this.angles.push(a); - } - - this.getMarkerPoints = function() { return this.points; } - this.getMarkerAngles = function() { - for (var i=0; i 1) { - rx *= Math.sqrt(l); - ry *= Math.sqrt(l); - } - // cx', cy' - var s = (largeArcFlag == sweepFlag ? -1 : 1) * Math.sqrt( - ((Math.pow(rx,2)*Math.pow(ry,2))-(Math.pow(rx,2)*Math.pow(currp.y,2))-(Math.pow(ry,2)*Math.pow(currp.x,2))) / - (Math.pow(rx,2)*Math.pow(currp.y,2)+Math.pow(ry,2)*Math.pow(currp.x,2)) - ); - if (isNaN(s)) s = 0; - var cpp = new svg.Point(s * rx * currp.y / ry, s * -ry * currp.x / rx); - // cx, cy - var centp = new svg.Point( - (curr.x + cp.x) / 2.0 + Math.cos(xAxisRotation) * cpp.x - Math.sin(xAxisRotation) * cpp.y, - (curr.y + cp.y) / 2.0 + Math.sin(xAxisRotation) * cpp.x + Math.cos(xAxisRotation) * cpp.y - ); - // vector magnitude - var m = function(v) { return Math.sqrt(Math.pow(v[0],2) + Math.pow(v[1],2)); } - // ratio between two vectors - var r = function(u, v) { return (u[0]*v[0]+u[1]*v[1]) / (m(u)*m(v)) } - // angle between two vectors - var a = function(u, v) { return (u[0]*v[1] < u[1]*v[0] ? -1 : 1) * Math.acos(r(u,v)); } - // initial angle - var a1 = a([1,0], [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]); - // angle delta - var u = [(currp.x-cpp.x)/rx,(currp.y-cpp.y)/ry]; - var v = [(-currp.x-cpp.x)/rx,(-currp.y-cpp.y)/ry]; - var ad = a(u, v); - if (r(u,v) <= -1) ad = Math.PI; - if (r(u,v) >= 1) ad = 0; - - if (sweepFlag == 0 && ad > 0) ad = ad - 2 * Math.PI; - if (sweepFlag == 1 && ad < 0) ad = ad + 2 * Math.PI; - - // for markers - var halfWay = new svg.Point( - centp.x - rx * Math.cos((a1 + ad) / 2), - centp.y - ry * Math.sin((a1 + ad) / 2) - ); - pp.addMarkerAngle(halfWay, (a1 + ad) / 2 + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - pp.addMarkerAngle(cp, ad + (sweepFlag == 0 ? 1 : -1) * Math.PI / 2); - - bb.addPoint(cp.x, cp.y); // TODO: this is too naive, make it better - if (ctx != null) { - var r = rx > ry ? rx : ry; - var sx = rx > ry ? 1 : rx / ry; - var sy = rx > ry ? ry / rx : 1; - - ctx.translate(centp.x, centp.y); - ctx.rotate(xAxisRotation); - ctx.scale(sx, sy); - ctx.arc(0, 0, r, a1, a1 + ad, 1 - sweepFlag); - ctx.scale(1/sx, 1/sy); - ctx.rotate(-xAxisRotation); - ctx.translate(-centp.x, -centp.y); - } - } - break; - case 'Z': - if (ctx != null) ctx.closePath(); - pp.current = pp.start; - } - } - - return bb; - } - - this.getMarkers = function() { - var points = this.PathParser.getMarkerPoints(); - var angles = this.PathParser.getMarkerAngles(); - - var markers = []; - for (var i=0; i this.maxDuration) { - // loop for indefinitely repeating animations - if (this.attribute('repeatCount').value == 'indefinite') { - this.duration = 0.0 - } - else if (this.attribute('fill').valueOrDefault('remove') == 'remove' && !this.removed) { - this.removed = true; - this.getProperty().value = this.initialValue; - return true; - } - else { - return false; // no updates made - } - } - this.duration = this.duration + delta; - - // if we're past the begin time - var updated = false; - if (this.begin < this.duration) { - var newValue = this.calcValue(); // tween - - if (this.attribute('type').hasValue()) { - // for transform, etc. - var type = this.attribute('type').value; - newValue = type + '(' + newValue + ')'; - } - - this.getProperty().value = newValue; - updated = true; - } - - return updated; - } - - // fraction of duration we've covered - this.progress = function() { - return ((this.duration - this.begin) / (this.maxDuration - this.begin)); - } - } - svg.Element.AnimateBase.prototype = new svg.Element.ElementBase; - - // animate element - svg.Element.animate = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = this.attribute('from').numValue(); - var to = this.attribute('to').numValue(); - - // tween value linearly - return from + (to - from) * this.progress(); - }; - } - svg.Element.animate.prototype = new svg.Element.AnimateBase; - - // animate color element - svg.Element.animateColor = function(node) { - this.base = svg.Element.AnimateBase; - this.base(node); - - this.calcValue = function() { - var from = new RGBColor(this.attribute('from').value); - var to = new RGBColor(this.attribute('to').value); - - if (from.ok && to.ok) { - // tween color linearly - var r = from.r + (to.r - from.r) * this.progress(); - var g = from.g + (to.g - from.g) * this.progress(); - var b = from.b + (to.b - from.b) * this.progress(); - return 'rgb('+parseInt(r,10)+','+parseInt(g,10)+','+parseInt(b,10)+')'; - } - return this.attribute('from').value; - }; - } - svg.Element.animateColor.prototype = new svg.Element.AnimateBase; - - // animate transform element - svg.Element.animateTransform = function(node) { - this.base = svg.Element.animate; - this.base(node); - } - svg.Element.animateTransform.prototype = new svg.Element.animate; - - // font element - svg.Element.font = function(node) { - this.base = svg.Element.ElementBase; - this.base(node); - - this.horizAdvX = this.attribute('horiz-adv-x').numValue(); - - this.isRTL = false; - this.isArabic = false; - this.fontFace = null; - this.missingGlyph = null; - this.glyphs = []; - for (var i=0; i0 && text[i-1]!=' ' && i0 && text[i-1]!=' ' && (i == text.length-1 || text[i+1]==' ')) arabicForm = 'initial'; - if (typeof(font.glyphs[c]) != 'undefined') { - glyph = font.glyphs[c][arabicForm]; - if (glyph == null && font.glyphs[c].type == 'glyph') glyph = font.glyphs[c]; - } - } - else { - glyph = font.glyphs[c]; - } - if (glyph == null) glyph = font.missingGlyph; - return glyph; - } - - this.renderChildren = function(ctx) { - var customFont = this.parent.style('font-family').Definition.getDefinition(); - if (customFont != null) { - var fontSize = this.parent.style('font-size').numValueOrDefault(svg.Font.Parse(svg.ctx.font).fontSize); - var fontStyle = this.parent.style('font-style').valueOrDefault(svg.Font.Parse(svg.ctx.font).fontStyle); - var text = this.getText(); - if (customFont.isRTL) text = text.split("").reverse().join(""); - - var dx = svg.ToNumberArray(this.parent.attribute('dx').value); - for (var i=0; i 0 ? node.childNodes[0].nodeValue : // element - node.text; - this.getText = function() { - return this.text; - } - } - svg.Element.tspan.prototype = new svg.Element.TextElementBase; - - // tref - svg.Element.tref = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.getText = function() { - var element = this.attribute('xlink:href').Definition.getDefinition(); - if (element != null) return element.children[0].getText(); - } - } - svg.Element.tref.prototype = new svg.Element.TextElementBase; - - // a element - svg.Element.a = function(node) { - this.base = svg.Element.TextElementBase; - this.base(node); - - this.hasText = true; - for (var i=0; i 1 ? node.childNodes[1].nodeValue : ''); - css = css.replace(/(\/\*([^*]|[\r\n]|(\*+([^*\/]|[\r\n])))*\*+\/)|(^[\s]*\/\/.*)/gm, ''); // remove comments - css = svg.compressSpaces(css); // replace whitespace - var cssDefs = css.split('}'); - for (var i=0; i 0) { - var urlStart = srcs[s].indexOf('url'); - var urlEnd = srcs[s].indexOf(')', urlStart); - var url = srcs[s].substr(urlStart + 5, urlEnd - urlStart - 6); - var doc = svg.parseXml(svg.ajax(url)); - var fonts = doc.getElementsByTagName('font'); - for (var f=0; f - * @link http://www.phpied.com/rgb-color-parser-in-javascript/ - * @license Use it if you like it - */ -function RGBColor(color_string) -{ - this.ok = false; - - // strip any leading # - if (color_string.charAt(0) == '#') { // remove # if any - color_string = color_string.substr(1,6); - } - - color_string = color_string.replace(/ /g,''); - color_string = color_string.toLowerCase(); - - // before getting into regexps, try simple matches - // and overwrite the input - var simple_colors = { - aliceblue: 'f0f8ff', - antiquewhite: 'faebd7', - aqua: '00ffff', - aquamarine: '7fffd4', - azure: 'f0ffff', - beige: 'f5f5dc', - bisque: 'ffe4c4', - black: '000000', - blanchedalmond: 'ffebcd', - blue: '0000ff', - blueviolet: '8a2be2', - brown: 'a52a2a', - burlywood: 'deb887', - cadetblue: '5f9ea0', - chartreuse: '7fff00', - chocolate: 'd2691e', - coral: 'ff7f50', - cornflowerblue: '6495ed', - cornsilk: 'fff8dc', - crimson: 'dc143c', - cyan: '00ffff', - darkblue: '00008b', - darkcyan: '008b8b', - darkgoldenrod: 'b8860b', - darkgray: 'a9a9a9', - darkgreen: '006400', - darkkhaki: 'bdb76b', - darkmagenta: '8b008b', - darkolivegreen: '556b2f', - darkorange: 'ff8c00', - darkorchid: '9932cc', - darkred: '8b0000', - darksalmon: 'e9967a', - darkseagreen: '8fbc8f', - darkslateblue: '483d8b', - darkslategray: '2f4f4f', - darkturquoise: '00ced1', - darkviolet: '9400d3', - deeppink: 'ff1493', - deepskyblue: '00bfff', - dimgray: '696969', - dodgerblue: '1e90ff', - feldspar: 'd19275', - firebrick: 'b22222', - floralwhite: 'fffaf0', - forestgreen: '228b22', - fuchsia: 'ff00ff', - gainsboro: 'dcdcdc', - ghostwhite: 'f8f8ff', - gold: 'ffd700', - goldenrod: 'daa520', - gray: '808080', - green: '008000', - greenyellow: 'adff2f', - honeydew: 'f0fff0', - hotpink: 'ff69b4', - indianred : 'cd5c5c', - indigo : '4b0082', - ivory: 'fffff0', - khaki: 'f0e68c', - lavender: 'e6e6fa', - lavenderblush: 'fff0f5', - lawngreen: '7cfc00', - lemonchiffon: 'fffacd', - lightblue: 'add8e6', - lightcoral: 'f08080', - lightcyan: 'e0ffff', - lightgoldenrodyellow: 'fafad2', - lightgrey: 'd3d3d3', - lightgreen: '90ee90', - lightpink: 'ffb6c1', - lightsalmon: 'ffa07a', - lightseagreen: '20b2aa', - lightskyblue: '87cefa', - lightslateblue: '8470ff', - lightslategray: '778899', - lightsteelblue: 'b0c4de', - lightyellow: 'ffffe0', - lime: '00ff00', - limegreen: '32cd32', - linen: 'faf0e6', - magenta: 'ff00ff', - maroon: '800000', - mediumaquamarine: '66cdaa', - mediumblue: '0000cd', - mediumorchid: 'ba55d3', - mediumpurple: '9370d8', - mediumseagreen: '3cb371', - mediumslateblue: '7b68ee', - mediumspringgreen: '00fa9a', - mediumturquoise: '48d1cc', - mediumvioletred: 'c71585', - midnightblue: '191970', - mintcream: 'f5fffa', - mistyrose: 'ffe4e1', - moccasin: 'ffe4b5', - navajowhite: 'ffdead', - navy: '000080', - oldlace: 'fdf5e6', - olive: '808000', - olivedrab: '6b8e23', - orange: 'ffa500', - orangered: 'ff4500', - orchid: 'da70d6', - palegoldenrod: 'eee8aa', - palegreen: '98fb98', - paleturquoise: 'afeeee', - palevioletred: 'd87093', - papayawhip: 'ffefd5', - peachpuff: 'ffdab9', - peru: 'cd853f', - pink: 'ffc0cb', - plum: 'dda0dd', - powderblue: 'b0e0e6', - purple: '800080', - red: 'ff0000', - rosybrown: 'bc8f8f', - royalblue: '4169e1', - saddlebrown: '8b4513', - salmon: 'fa8072', - sandybrown: 'f4a460', - seagreen: '2e8b57', - seashell: 'fff5ee', - sienna: 'a0522d', - silver: 'c0c0c0', - skyblue: '87ceeb', - slateblue: '6a5acd', - slategray: '708090', - snow: 'fffafa', - springgreen: '00ff7f', - steelblue: '4682b4', - tan: 'd2b48c', - teal: '008080', - thistle: 'd8bfd8', - tomato: 'ff6347', - turquoise: '40e0d0', - violet: 'ee82ee', - violetred: 'd02090', - wheat: 'f5deb3', - white: 'ffffff', - whitesmoke: 'f5f5f5', - yellow: 'ffff00', - yellowgreen: '9acd32' - }; - for (var key in simple_colors) { - if (color_string == key) { - color_string = simple_colors[key]; - } - } - // emd of simple type-in colors - - // array of color definition objects - var color_defs = [ - { - re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, - example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], - process: function (bits){ - return [ - parseInt(bits[1]), - parseInt(bits[2]), - parseInt(bits[3]) - ]; - } - }, - { - re: /^(\w{2})(\w{2})(\w{2})$/, - example: ['#00ff00', '336699'], - process: function (bits){ - return [ - parseInt(bits[1], 16), - parseInt(bits[2], 16), - parseInt(bits[3], 16) - ]; - } - }, - { - re: /^(\w{1})(\w{1})(\w{1})$/, - example: ['#fb0', 'f0f'], - process: function (bits){ - return [ - parseInt(bits[1] + bits[1], 16), - parseInt(bits[2] + bits[2], 16), - parseInt(bits[3] + bits[3], 16) - ]; - } - } - ]; - - // search through the definitions to find a match - for (var i = 0; i < color_defs.length; i++) { - var re = color_defs[i].re; - var processor = color_defs[i].process; - var bits = re.exec(color_string); - if (bits) { - channels = processor(bits); - this.r = channels[0]; - this.g = channels[1]; - this.b = channels[2]; - this.ok = true; - } - - } - - // validate/cleanup values - this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); - this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); - this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); - - // some getters - this.toRGB = function () { - return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; - } - this.toHex = function () { - var r = this.r.toString(16); - var g = this.g.toString(16); - var b = this.b.toString(16); - if (r.length == 1) r = '0' + r; - if (g.length == 1) g = '0' + g; - if (b.length == 1) b = '0' + b; - return '#' + r + g + b; - } - - // help - this.getHelpXML = function () { - - var examples = new Array(); - // add regexps - for (var i = 0; i < color_defs.length; i++) { - var example = color_defs[i].example; - for (var j = 0; j < example.length; j++) { - examples[examples.length] = example[j]; - } - } - // add type-in colors - for (var sc in simple_colors) { - examples[examples.length] = sc; - } - - var xml = document.createElement('ul'); - xml.setAttribute('id', 'rgbcolor-examples'); - for (var i = 0; i < examples.length; i++) { - try { - var list_item = document.createElement('li'); - var list_color = new RGBColor(examples[i]); - var example_div = document.createElement('div'); - example_div.style.cssText = - 'margin: 3px; ' - + 'border: 1px solid black; ' - + 'background:' + list_color.toHex() + '; ' - + 'color:' + list_color.toHex() - ; - example_div.appendChild(document.createTextNode('test')); - var list_item_value = document.createTextNode( - ' ' + examples[i] + ' -> ' + list_color.toRGB() + ' -> ' + list_color.toHex() - ); - list_item.appendChild(example_div); - list_item.appendChild(list_item_value); - xml.appendChild(list_item); - - } catch(e){} - } - return xml; - - } - -} diff --git a/build/svg-edit-2.6/contextmenu.js b/build/svg-edit-2.6/contextmenu.js deleted file mode 100644 index afa4318..0000000 --- a/build/svg-edit-2.6/contextmenu.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Package: svgedit.contextmenu - * - * Licensed under the Apache License, Version 2 - * - * Author: Adam Bender - */ -// Dependencies: -// 1) jQuery (for dom injection of context menus)\ - -var svgedit = svgedit || {}; -(function() { - var self = this; - if (!svgedit.contextmenu) { - svgedit.contextmenu = {}; - } - self.contextMenuExtensions = {} - var addContextMenuItem = function(menuItem) { - // menuItem: {id, label, shortcut, action} - if (!menuItemIsValid(menuItem)) { - console - .error("Menu items must be defined and have at least properties: id, label, action, where action must be a function"); - return; - } - if (menuItem.id in self.contextMenuExtensions) { - console.error('Cannot add extension "' + menuItem.id - + '", an extension by that name already exists"'); - return; - } - // Register menuItem action, see below for deferred menu dom injection - console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}"); - self.contextMenuExtensions[menuItem.id] = menuItem; - //TODO: Need to consider how to handle custom enable/disable behavior - } - var hasCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey] && true; - } - var getCustomHandler = function(handlerKey) { - return self.contextMenuExtensions[handlerKey].action; - } - var injectExtendedContextMenuItemIntoDom = function(menuItem) { - if (Object.keys(self.contextMenuExtensions).length == 0) { - // all menuItems appear at the bottom of the menu in their own container. - // if this is the first extension menu we need to add the separator. - $("#cmenu_canvas").append("
        • "); - } - var shortcut = menuItem.shortcut || ""; - $("#cmenu_canvas").append("
        • " - + menuItem.label + "" - + shortcut + "
        • "); - } - - var menuItemIsValid = function(menuItem) { - return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function'; - } - - // Defer injection to wait out initial menu processing. This probably goes away once all context - // menu behavior is brought here. - svgEditor.ready(function() { - for (menuItem in contextMenuExtensions) { - injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]); - } - }); - svgedit.contextmenu.resetCustomMenus = function(){self.contextMenuExtensions = {}} - svgedit.contextmenu.add = addContextMenuItem; - svgedit.contextmenu.hasCustomHandler = hasCustomHandler; - svgedit.contextmenu.getCustomHandler = getCustomHandler; -})(); diff --git a/build/svg-edit-2.6/contextmenu/jquery.contextMenu.js b/build/svg-edit-2.6/contextmenu/jquery.contextMenu.js deleted file mode 100755 index 009d6cd..0000000 --- a/build/svg-edit-2.6/contextmenu/jquery.contextMenu.js +++ /dev/null @@ -1,203 +0,0 @@ -// jQuery Context Menu Plugin -// -// Version 1.01 -// -// Cory S.N. LaViska -// A Beautiful Site (http://abeautifulsite.net/) -// Modified by Alexis Deveria -// -// More info: http://abeautifulsite.net/2008/09/jquery-context-menu-plugin/ -// -// Terms of Use -// -// This plugin is dual-licensed under the GNU General Public License -// and the MIT License and is copyright A Beautiful Site, LLC. -// -if(jQuery)( function() { - var win = $(window); - var doc = $(document); - - $.extend($.fn, { - - contextMenu: function(o, callback) { - // Defaults - if( o.menu == undefined ) return false; - if( o.inSpeed == undefined ) o.inSpeed = 150; - if( o.outSpeed == undefined ) o.outSpeed = 75; - // 0 needs to be -1 for expected results (no fade) - if( o.inSpeed == 0 ) o.inSpeed = -1; - if( o.outSpeed == 0 ) o.outSpeed = -1; - // Loop each context menu - $(this).each( function() { - var el = $(this); - var offset = $(el).offset(); - - var menu = $('#' + o.menu); - - // Add contextMenu class - menu.addClass('contextMenu'); - // Simulate a true right click - $(this).bind( "mousedown", function(e) { - var evt = e; - $(this).mouseup( function(e) { - var srcElement = $(this); - srcElement.unbind('mouseup'); - $(".contextMenu").hide(); - if( evt.button === 2 || o.allowLeft || (evt.ctrlKey && svgedit.browser.isMac()) ) { - e.stopPropagation(); - - // Get this context menu - - if( el.hasClass('disabled') ) return false; - - // Detect mouse position - var d = {}, x = e.pageX, y = e.pageY; - - var x_off = win.width() - menu.width(), - y_off = win.height() - menu.height(); - - if(x > x_off - 15) x = x_off-15; - if(y > y_off - 30) y = y_off-30; // 30 is needed to prevent scrollbars in FF - - // Show the menu - doc.unbind('click'); - menu.css({ top: y, left: x }).fadeIn(o.inSpeed); - // Hover events - menu.find('A').mouseover( function() { - menu.find('LI.hover').removeClass('hover'); - $(this).parent().addClass('hover'); - }).mouseout( function() { - menu.find('LI.hover').removeClass('hover'); - }); - - // Keyboard - doc.keypress( function(e) { - switch( e.keyCode ) { - case 38: // up - if( !menu.find('LI.hover').length ) { - menu.find('LI:last').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').prevAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:last').addClass('hover'); - } - break; - case 40: // down - if( menu.find('LI.hover').length == 0 ) { - menu.find('LI:first').addClass('hover'); - } else { - menu.find('LI.hover').removeClass('hover').nextAll('LI:not(.disabled)').eq(0).addClass('hover'); - if( !menu.find('LI.hover').length ) menu.find('LI:first').addClass('hover'); - } - break; - case 13: // enter - menu.find('LI.hover A').trigger('click'); - break; - case 27: // esc - doc.trigger('click'); - break - } - }); - - // When items are selected - menu.find('A').unbind('mouseup'); - menu.find('LI:not(.disabled) A').mouseup( function() { - doc.unbind('click').unbind('keypress'); - $(".contextMenu").hide(); - // Callback - if( callback ) callback( $(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y} ); - return false; - }); - - // Hide bindings - setTimeout( function() { // Delay for Mozilla - doc.click( function() { - doc.unbind('click').unbind('keypress'); - menu.fadeOut(o.outSpeed); - return false; - }); - }, 0); - } - }); - }); - - // Disable text selection - if( $.browser.mozilla ) { - $('#' + o.menu).each( function() { $(this).css({ 'MozUserSelect' : 'none' }); }); - } else if( $.browser.msie ) { - $('#' + o.menu).each( function() { $(this).bind('selectstart.disableTextSelect', function() { return false; }); }); - } else { - $('#' + o.menu).each(function() { $(this).bind('mousedown.disableTextSelect', function() { return false; }); }); - } - // Disable browser context menu (requires both selectors to work in IE/Safari + FF/Chrome) - $(el).add($('UL.contextMenu')).bind('contextmenu', function() { return false; }); - - }); - return $(this); - }, - - // Disable context menu items on the fly - disableContextMenuItems: function(o) { - if( o == undefined ) { - // Disable all - $(this).find('LI').addClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().addClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Enable context menu items on the fly - enableContextMenuItems: function(o) { - if( o == undefined ) { - // Enable all - $(this).find('LI.disabled').removeClass('disabled'); - return( $(this) ); - } - $(this).each( function() { - if( o != undefined ) { - var d = o.split(','); - for( var i = 0; i < d.length; i++ ) { - $(this).find('A[href="' + d[i] + '"]').parent().removeClass('disabled'); - - } - } - }); - return( $(this) ); - }, - - // Disable context menu(s) - disableContextMenu: function() { - $(this).each( function() { - $(this).addClass('disabled'); - }); - return( $(this) ); - }, - - // Enable context menu(s) - enableContextMenu: function() { - $(this).each( function() { - $(this).removeClass('disabled'); - }); - return( $(this) ); - }, - - // Destroy context menu(s) - destroyContextMenu: function() { - // Destroy specified context menus - $(this).each( function() { - // Disable action - $(this).unbind('mousedown').unbind('mouseup'); - }); - return( $(this) ); - } - - }); -})(jQuery); \ No newline at end of file diff --git a/build/svg-edit-2.6/draginput.js b/build/svg-edit-2.6/draginput.js deleted file mode 100644 index 0c172b1..0000000 --- a/build/svg-edit-2.6/draginput.js +++ /dev/null @@ -1,47 +0,0 @@ -;(function($) { - - var methods = { - - init : function(options) { - - return this.each(function() { - - var settings = { - }; - - if(options) { - $.extend(settings, options); - } - - var plugin = this; - var $plugin = $(this); - - $plugin.settings = settings; - - this.privateMethod = function() { - } - - $plugin.data("example", {}); - - // Plug-in code here... - }); - - }, - - publicFunction : function() { - } - }; - - $.fn.example = function(method) { - if(methods[method]) { - return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); - } - else if(typeof method === 'object' || !method) { - return methods.init.apply(this, arguments); - } - else { - $.error("Method " + method + " does not exist on jQuery.example"); - } - }; - -})(jQuery); \ No newline at end of file diff --git a/build/svg-edit-2.6/draw.js b/build/svg-edit-2.6/draw.js deleted file mode 100644 index 8db3138..0000000 --- a/build/svg-edit-2.6/draw.js +++ /dev/null @@ -1,528 +0,0 @@ -/** - * Package: svgedit.draw - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2011 Jeff Schiller - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgutils.js - -var svgedit = svgedit || {}; - -(function() { - -if (!svgedit.draw) { - svgedit.draw = {}; -} - -var svg_ns = "http://www.w3.org/2000/svg"; -var se_ns = "http://svg-edit.googlecode.com"; -var xmlns_ns = "http://www.w3.org/2000/xmlns/"; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var visElems_arr = visElems.split(','); - -var RandomizeModes = { - LET_DOCUMENT_DECIDE: 0, - ALWAYS_RANDOMIZE: 1, - NEVER_RANDOMIZE: 2 -}; -var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE; - -/** - * This class encapsulates the concept of a layer in the drawing - * @param name {String} Layer name - * @param child {SVGGElement} Layer SVG group. - */ -svgedit.draw.Layer = function(name, group) { - this.name_ = name; - this.group_ = group; -}; - -svgedit.draw.Layer.prototype.getName = function() { - return this.name_; -}; - -svgedit.draw.Layer.prototype.getGroup = function() { - return this.group_; -}; - - -// Called to ensure that drawings will or will not have randomized ids. -// The current_drawing will have its nonce set if it doesn't already. -// -// Params: -// enableRandomization - flag indicating if documents should have randomized ids -svgedit.draw.randomizeIds = function(enableRandomization, current_drawing) { - randomize_ids = enableRandomization == false ? - RandomizeModes.NEVER_RANDOMIZE : - RandomizeModes.ALWAYS_RANDOMIZE; - - if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !current_drawing.getNonce()) { - current_drawing.setNonce(Math.floor(Math.random() * 100001)); - } else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && current_drawing.getNonce()) { - current_drawing.clearNonce(); - } -}; - -/** - * This class encapsulates the concept of a SVG-edit drawing - * - * @param svgElem {SVGSVGElement} The SVG DOM Element that this JS object - * encapsulates. If the svgElem has a se:nonce attribute on it, then - * IDs will use the nonce as they are generated. - * @param opt_idPrefix {String} The ID prefix to use. Defaults to "svg_" - * if not specified. - */ -svgedit.draw.Drawing = function(svgElem, opt_idPrefix) { - if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI || - svgElem.tagName != 'svg' || svgElem.namespaceURI != svg_ns) { - throw "Error: svgedit.draw.Drawing instance initialized without a element"; - } - - /** - * The SVG DOM Element that represents this drawing. - * @type {SVGSVGElement} - */ - this.svgElem_ = svgElem; - - /** - * The latest object number used in this drawing. - * @type {number} - */ - this.obj_num = 0; - - /** - * The prefix to prepend to each element id in the drawing. - * @type {String} - */ - this.idPrefix = opt_idPrefix || "svg_"; - - /** - * An array of released element ids to immediately reuse. - * @type {Array.} - */ - this.releasedNums = []; - - /** - * The z-ordered array of tuples containing layer names and elements. - * The first layer is the one at the bottom of the rendering. - * TODO: Turn this into an Array. - * @type {Array.>} - */ - this.all_layers = []; - - /** - * The current layer being used. - * TODO: Make this a {Layer}. - * @type {SVGGElement} - */ - this.current_layer = null; - - /** - * The nonce to use to uniquely identify elements across drawings. - * @type {!String} - */ - this.nonce_ = ""; - var n = this.svgElem_.getAttributeNS(se_ns, 'nonce'); - // If already set in the DOM, use the nonce throughout the document - // else, if randomizeIds(true) has been called, create and set the nonce. - if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) { - this.nonce_ = n; - } else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) { - this.setNonce(Math.floor(Math.random() * 100001)); - } -}; - -svgedit.draw.Drawing.prototype.getElem_ = function(id) { - if(this.svgElem_.querySelector) { - // querySelector lookup - return this.svgElem_.querySelector('#'+id); - } else { - // jQuery lookup: twice as slow as xpath in FF - return $(this.svgElem_).find('[id=' + id + ']')[0]; - } -}; - -svgedit.draw.Drawing.prototype.getSvgElem = function() { - return this.svgElem_; -}; - -svgedit.draw.Drawing.prototype.getNonce = function() { - return this.nonce_; -}; - -svgedit.draw.Drawing.prototype.setNonce = function(n) { - this.svgElem_.setAttributeNS(xmlns_ns, 'xmlns:se', se_ns); - this.svgElem_.setAttributeNS(se_ns, 'se:nonce', n); - this.nonce_ = n; -}; - -svgedit.draw.Drawing.prototype.clearNonce = function() { - // We deliberately leave any se:nonce attributes alone, - // we just don't use it to randomize ids. - this.nonce_ = ""; -}; - -/** - * Returns the latest object id as a string. - * @return {String} The latest object Id. - */ -svgedit.draw.Drawing.prototype.getId = function() { - return this.nonce_ ? - this.idPrefix + this.nonce_ +'_' + this.obj_num : - this.idPrefix + this.obj_num; -}; - -/** - * Returns the next object Id as a string. - * @return {String} The next object Id to use. - */ -svgedit.draw.Drawing.prototype.getNextId = function() { - var oldObjNum = this.obj_num; - var restoreOldObjNum = false; - - // If there are any released numbers in the release stack, - // use the last one instead of the next obj_num. - // We need to temporarily use obj_num as that is what getId() depends on. - if (this.releasedNums.length > 0) { - this.obj_num = this.releasedNums.pop(); - restoreOldObjNum = true; - } else { - // If we are not using a released id, then increment the obj_num. - this.obj_num++; - } - - // Ensure the ID does not exist. - var id = this.getId(); - while (this.getElem_(id)) { - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - restoreOldObjNum = false; - } - this.obj_num++; - id = this.getId(); - } - // Restore the old object number if required. - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - } - return id; -}; - -// Function: svgedit.draw.Drawing.releaseId -// Releases the object Id, letting it be used as the next id in getNextId(). -// This method DOES NOT remove any elements from the DOM, it is expected -// that client code will do this. -// -// Parameters: -// id - The id to release. -// -// Returns: -// True if the id was valid to be released, false otherwise. -svgedit.draw.Drawing.prototype.releaseId = function(id) { - // confirm if this is a valid id for this Document, else return false - var front = this.idPrefix + (this.nonce_ ? this.nonce_ +'_' : ''); - if (typeof id != typeof '' || id.indexOf(front) != 0) { - return false; - } - // extract the obj_num of this id - var num = parseInt(id.substr(front.length)); - - // if we didn't get a positive number or we already released this number - // then return false. - if (typeof num != typeof 1 || num <= 0 || this.releasedNums.indexOf(num) != -1) { - return false; - } - - // push the released number into the released queue - this.releasedNums.push(num); - - return true; -}; - -// Function: svgedit.draw.Drawing.getNumLayers -// Returns the number of layers in the current drawing. -// -// Returns: -// The number of layers in the current drawing. -svgedit.draw.Drawing.prototype.getNumLayers = function() { - return this.all_layers.length; -}; - -// Function: svgedit.draw.Drawing.hasLayer -// Check if layer with given name already exists -svgedit.draw.Drawing.prototype.hasLayer = function(name) { - for(var i = 0; i < this.getNumLayers(); i++) { - if(this.all_layers[i][0] == name) return true; - } - return false; -}; - - -// Function: svgedit.draw.Drawing.getLayerName -// Returns the name of the ith layer. If the index is out of range, an empty string is returned. -// -// Parameters: -// i - the zero-based index of the layer you are querying. -// -// Returns: -// The name of the ith layer -svgedit.draw.Drawing.prototype.getLayerName = function(i) { - if (i >= 0 && i < this.getNumLayers()) { - return this.all_layers[i][0]; - } - return ""; -}; - -// Function: svgedit.draw.Drawing.getCurrentLayer -// Returns: -// The SVGGElement representing the current layer. -svgedit.draw.Drawing.prototype.getCurrentLayer = function() { - return this.current_layer; -}; - -// Function: getCurrentLayerName -// Returns the name of the currently selected layer. If an error occurs, an empty string -// is returned. -// -// Returns: -// The name of the currently active layer. -svgedit.draw.Drawing.prototype.getCurrentLayerName = function() { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.all_layers[i][1] == this.current_layer) { - return this.getLayerName(i); - } - } - return ""; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (name == this.getLayerName(i)) { - if (this.current_layer != this.all_layers[i][1]) { - this.current_layer.setAttribute("style", "pointer-events:none"); - this.current_layer = this.all_layers[i][1]; - this.current_layer.setAttribute("style", "pointer-events:all"); - } - return true; - } - } - return false; -}; - - -// Function: svgedit.draw.Drawing.deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -// Returns: -// The SVGGElement of the layer removed or null. -svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() { - if (this.current_layer && this.getNumLayers() > 1) { - // actually delete from the DOM and return it - var parent = this.current_layer.parentNode; - var nextSibling = this.current_layer.nextSibling; - var oldLayerGroup = parent.removeChild(this.current_layer); - this.identifyLayers(); - return oldLayerGroup; - } - return null; -}; - -// Function: svgedit.draw.Drawing.identifyLayers -// Updates layer system and sets the current layer to the -// top-most layer (last child of this drawing). -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 a_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] ); - a_layer = child; - svgedit.utilities.walkTree(child, function(e){e.setAttribute("style", "pointer-events:inherit");}); - a_layer.setAttribute("style", "pointer-events:none"); - } - // if group did not have a name, it is an orphan - else { - orphans.push(child); - } - } - // if child has is "visible" (i.e. not a or element), then it is an orphan - else if(~visElems_arr.indexOf(child.nodeName)) { - 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; - a_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = newname; - a_layer.appendChild(layer_title); - for (var j = 0; j < orphans.length; ++j) { - a_layer.appendChild(orphans[j]); - } - this.svgElem_.appendChild(a_layer); - this.all_layers.push( [newname, a_layer] ); - } - svgedit.utilities.walkTree(a_layer, function(e){e.setAttribute("style","pointer-events:inherit");}); - this.current_layer = a_layer; - this.current_layer.setAttribute("style","pointer-events:all"); -}; - -// Function: svgedit.draw.Drawing.createLayer -// Creates a new top-level layer in the drawing with the given name and -// sets the current layer to it. -// -// Parameters: -// name - The given name -// -// Returns: -// The SVGGElement of the new layer, which is also the current layer -// of this drawing. -svgedit.draw.Drawing.prototype.createLayer = function(name) { - var svgdoc = this.svgElem_.ownerDocument; - var new_layer = svgdoc.createElementNS(svg_ns, "g"); - var layer_title = svgdoc.createElementNS(svg_ns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - this.svgElem_.appendChild(new_layer); - this.identifyLayers(); - return new_layer; -}; - -// Function: svgedit.draw.Drawing.getLayerVisibility -// Returns whether the layer is visible. If the layer name is not valid, then this function -// returns false. -// -// Parameters: -// layername - the name of the layer which you want to query. -// -// Returns: -// The visibility state of the layer, or false if the layer name was invalid. -svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) { - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return false; - return (layer.getAttribute('display') != 'none'); -}; - -// Function: svgedit.draw.Drawing.setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// The SVGGElement representing the layer if the layername was valid, otherwise null. -svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) { - if (typeof bVisible != typeof true) { - return null; - } - // find the layer - var layer = null; - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - layer = this.all_layers[i][1]; - break; - } - } - if (!layer) return null; - - var oldDisplay = layer.getAttribute("display"); - if (!oldDisplay) oldDisplay = "inline"; - layer.setAttribute("display", bVisible ? "inline" : "none"); - return layer; -}; - - -// Function: svgedit.draw.Drawing.getLayerOpacity -// Returns the opacity of the given layer. If the input name is not a layer, null is returned. -// -// Parameters: -// layername - name of the layer on which to get the opacity -// -// Returns: -// The opacity value of the given layer. This will be a value between 0.0 and 1.0, or null -// if layername is not a valid layer -svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) { - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - var opacity = g.getAttribute('opacity'); - if (!opacity) { - opacity = '1.0'; - } - return parseFloat(opacity); - } - } - return null; -}; - -// Function: svgedit.draw.Drawing.setLayerOpacity -// Sets the opacity of the given layer. If the input name is not a layer, nothing happens. -// If opacity is not a value between 0.0 and 1.0, then nothing happens. -// -// Parameters: -// layername - name of the layer on which to set the opacity -// opacity - a float value in the range 0.0-1.0 -svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) { - if (typeof opacity != typeof 1.0 || opacity < 0.0 || opacity > 1.0) { - return; - } - for (var i = 0; i < this.getNumLayers(); ++i) { - if (this.getLayerName(i) == layername) { - var g = this.all_layers[i][1]; - g.setAttribute("opacity", opacity); - break; - } - } -}; - -})(); diff --git a/build/svg-edit-2.6/embedapi.html b/build/svg-edit-2.6/embedapi.html deleted file mode 100644 index 3db0364..0000000 --- a/build/svg-edit-2.6/embedapi.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - -
          - - - - diff --git a/build/svg-edit-2.6/embedapi.js b/build/svg-edit-2.6/embedapi.js deleted file mode 100644 index 8debfd6..0000000 --- a/build/svg-edit-2.6/embedapi.js +++ /dev/null @@ -1,173 +0,0 @@ -/* -function embedded_svg_edit(frame){ - //initialize communication - this.frame = frame; - this.stack = []; //callback stack - - var editapi = this; - - window.addEventListener("message", function(e){ - if(e.data.substr(0,5) == "ERROR"){ - editapi.stack.splice(0,1)[0](e.data,"error") - }else{ - editapi.stack.splice(0,1)[0](e.data) - } - }, false) -} - -embedded_svg_edit.prototype.call = function(code, callback){ - this.stack.push(callback); - this.frame.contentWindow.postMessage(code,"*"); -} - -embedded_svg_edit.prototype.getSvgString = function(callback){ - this.call("svgCanvas.getSvgString()",callback) -} - -embedded_svg_edit.prototype.setSvgString = function(svg){ - this.call("svgCanvas.setSvgString('"+svg.replace(/'/g, "\\'")+"')"); -} -*/ - - -/* -Embedded SVG-edit API - -General usage: -- Have an iframe somewhere pointing to a version of svg-edit > r1000 -- Initialize the magic with: -var svgCanvas = new embedded_svg_edit(window.frames['svgedit']); -- Pass functions in this format: -svgCanvas.setSvgString("string") -- Or if a callback is needed: -svgCanvas.setSvgString("string")(function(data, error){ - if(error){ - //there was an error - }else{ - //handle data - } -}) - -Everything is done with the same API as the real svg-edit, -and all documentation is unchanged. The only difference is -when handling returns, the callback notation is used instead. - -var blah = new embedded_svg_edit(window.frames['svgedit']); -blah.clearSelection("woot","blah",1337,[1,2,3,4,5,"moo"],-42,{a: "tree",b:6, c: 9})(function(){console.log("GET DATA",arguments)}) -*/ - -function embedded_svg_edit(frame){ - //initialize communication - this.frame = frame; - //this.stack = [] //callback stack - this.callbacks = {}; //successor to stack - this.encode = embedded_svg_edit.encode; - //List of functions extracted with this: - //Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html - - //for(var i=0,q=[],f = document.querySelectorAll("div.CFunction h3.CTitle a");i - - - - Layer 1 - - - - - - - - - - - - - - - - - Layer 1 - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/svg-edit-2.6/extensions/ext-arrows.js b/build/svg-edit-2.6/extensions/ext-arrows.js deleted file mode 100644 index 4bb5cd2..0000000 --- a/build/svg-edit-2.6/extensions/ext-arrows.js +++ /dev/null @@ -1,298 +0,0 @@ -/* - * ext-arrows.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - - -svgEditor.addExtension("Arrows", function(S) { - var svgcontent = S.svgcontent, - addElem = S.addSvgElementFromJson, - nonce = S.nonce, - randomize_ids = S.randomize_ids, - selElems; - - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); - - var lang_list = { - "en":[ - {"id": "arrow_none", "textContent": "No arrow" } - ], - "fr":[ - {"id": "arrow_none", "textContent": "Sans flèche" } - ] - }; - - var prefix = 'se_arrow_'; - if (randomize_ids) { - var arrowprefix = prefix + nonce + '_'; - } else { - var arrowprefix = prefix; - } - - var pathdata = { - fw: {d:"m0,0l10,5l-10,5l5,-5l-5,-5z", refx:8, id: arrowprefix + 'fw'}, - bk: {d:"m10,0l-10,5l10,5l-5,-5l5,-5z", refx:2, id: arrowprefix + 'bk'} - } - - function setArrowNonce(window, n) { - randomize_ids = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function unsetArrowNonce(window) { - randomize_ids = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } - - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if(!str) return null; - var m = str.match(/\(\#(.*)\)/); - if(!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } - - function showPanel(on) { - $('#arrow_panel').toggle(on); - - if(on) { - var el = selElems[0]; - var end = el.getAttribute("marker-end"); - var start = el.getAttribute("marker-start"); - var mid = el.getAttribute("marker-mid"); - var val; - - if(end && start) { - val = "both"; - } else if(end) { - val = "end"; - } else if(start) { - val = "start"; - } else if(mid) { - val = "mid"; - if(mid.indexOf("bk") != -1) { - val = "mid_bk"; - } - } - - if(!start && !mid && !end) { - val = "none"; - } - - $("#arrow_list").val(val); - } - } - - function resetMarker() { - var el = selElems[0]; - el.removeAttribute("marker-start"); - el.removeAttribute("marker-mid"); - el.removeAttribute("marker-end"); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var marker = S.getElem(id); - - var data = pathdata[dir]; - - if(type == "mid") { - data.refx = 5; - } - - if(!marker) { - marker = addElem({ - "element": "marker", - "attr": { - "viewBox": "0 0 10 10", - "id": id, - "refY": 5, - "markerUnits": "strokeWidth", - "markerWidth": 5, - "markerHeight": 5, - "orient": "auto", - "style": "pointer-events:none" // Currently needed for Opera - } - }); - var arrow = addElem({ - "element": "path", - "attr": { - "d": data.d, - "fill": "#000000" - } - }); - marker.appendChild(arrow); - S.findDefs().appendChild(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - var type = this.value; - resetMarker(); - - if(type == "none") { - return; - } - - // Set marker on element - var dir = "fw"; - if(type == "mid_bk") { - type = "mid"; - dir = "bk"; - } else if(type == "both") { - addMarker("bk", type); - svgCanvas.changeSelectedAttribute("marker-start", "url(#" + pathdata.bk.id + ")"); - type = "end"; - dir = "fw"; - } else if (type == "start") { - dir = "bk"; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute("marker-"+type, "url(#" + pathdata[dir].id + ")"); - S.call("changed", selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - - var mtypes = ['start','mid','end']; - var defs = S.findDefs(); - - $.each(mtypes, function(i, type) { - var marker = getLinked(elem, 'marker-'+type); - if(!marker) return; - - var cur_color = $(marker).children().attr('fill'); - var cur_d = $(marker).children().attr('d'); - var new_marker = null; - if(cur_color === color) return; - - var all_markers = $(defs).find('marker'); - // Different color, check if already made - all_markers.each(function() { - var attrs = $(this).children().attr(['fill', 'd']); - if(attrs.fill === color && attrs.d === cur_d) { - // Found another marker with this color and this path - new_marker = this; - } - }); - - if(!new_marker) { - // Create a new marker with this color - var last_id = marker.id; - var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; - - new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); - - $(new_marker).children().attr('fill', color); - } - - $(elem).attr('marker-'+type, "url(#" + new_marker.id + ")"); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function() { - var elem = this; - $.each(mtypes, function(j, mtype) { - if($(elem).attr('marker-' + mtype) === "url(#" + marker.id + ")") { - return remove = false; - } - }); - if(!remove) return false; - }); - - // Not found, so can safely remove - if(remove) { - $(marker).remove(); - } - - }); - - } - - return { - name: "Arrows", - context_tools: [{ - type: "select", - panel: "arrow_panel", - title: "Select arrow type", - id: "arrow_list", - options: { - none: "No arrow", - end: "---->", - start: "<----", - both: "<--->", - mid: "-->--", - mid_bk: "--<--" - }, - defval: "none", - events: { - change: setArrow - } - }], - callback: function() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function(lang) { - return { - data: lang_list[lang] - }; - }, - selectedChanged: function(opts) { - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - var marker_elems = ['line','path','polyline','polygon']; - - while(i--) { - var elem = selElems[i]; - if(elem && $.inArray(elem.tagName, marker_elems) != -1) { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function(opts) { - var elem = opts.elems[0]; - if(elem && ( - elem.getAttribute("marker-start") || - elem.getAttribute("marker-mid") || - elem.getAttribute("marker-end") - )) { - // var start = elem.getAttribute("marker-start"); - // var mid = elem.getAttribute("marker-mid"); - // var end = elem.getAttribute("marker-end"); - // Has marker, so see if it should match color - colorChanged(elem); - } - - } - }; -}); diff --git a/build/svg-edit-2.6/extensions/ext-closepath.js b/build/svg-edit-2.6/extensions/ext-closepath.js deleted file mode 100644 index bf8e72c..0000000 --- a/build/svg-edit-2.6/extensions/ext-closepath.js +++ /dev/null @@ -1,92 +0,0 @@ -/* - * ext-closepath.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Jeff Schiller - * - */ - -// This extension adds a simple button to the contextual panel for paths -// The button toggles whether the path is open or closed -svgEditor.addExtension("ClosePath", function(S) { - var selElems, - updateButton = function(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType==1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }, - showPanel = function(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) updateButton(path); - } - }, - - toggleClosed = function() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if(seglist.getItem(last).pathSegType == 1) { - seglist.removeItem(last); - } - else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; - - return { - name: "ClosePath", - svgicons: "extensions/closepath_icons.svg", - buttons: [{ - id: "tool_openpath", - type: "context", - panel: "closepath_panel", - title: "Open path", - events: { - 'click': function() { - toggleClosed(); - } - } - }, - { - id: "tool_closepath", - type: "context", - panel: "closepath_panel", - title: "Close path", - events: { - 'click': function() { - toggleClosed(); - } - } - }], - callback: function() { - $('#closepath_panel').hide(); - }, - selectedChanged: function(opts) { - selElems = opts.elems; - var i = selElems.length; - - while(i--) { - var elem = selElems[i]; - if(elem && elem.tagName == 'path') { - if(opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; -}); diff --git a/build/svg-edit-2.6/extensions/ext-connector.js b/build/svg-edit-2.6/extensions/ext-connector.js deleted file mode 100644 index 3498c7f..0000000 --- a/build/svg-edit-2.6/extensions/ext-connector.js +++ /dev/null @@ -1,587 +0,0 @@ -/* - * ext-connector.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * - */ - -svgEditor.addExtension("Connector", function(S) { - var svgcontent = S.svgcontent, - svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - curConfig = svgEditor.curConfig, - started = false, - start_x, - start_y, - cur_line, - start_elem, - end_elem, - connections = [], - conn_sel = ".se_connector", - se_ns, -// connect_str = "-SE_CONNECT-", - selElems = []; - - elData = $.data; - - var lang_list = { - "en":[ - {"id": "mode_connect", "title": "Connect two objects" } - ], - "fr":[ - {"id": "mode_connect", "title": "Connecter deux objets"} - ] - }; - - function getOffset(side, line) { - var give_offset = !!line.getAttribute('marker-' + side); -// var give_offset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return give_offset ? size : 0; - } - - function showPanel(on) { - var conn_rules = $('#connector_rules'); - if(!conn_rules.length) { - conn_rules = $(' -
          - -
          - - -
          -
          -

          Layers

          -
          -
          -
          -
          -
          -
          -
          -
          - - - - - - -
          Layer 1
          - Move elements to: - -
          -
          L a y e r s
          -
          - - - - - -
          - -
          - -
          -

          Canvas

          - - -
          - -
          - -
          -

          Rectangle

          -
          - - -
          - -
          - -
          -

          Path

          -
          - -
          -

          Image

          -
          - - -
          -
          - - -
          -
          - -
          -
          - - -
          -
          - -
          -
          - -
          -

          Ellipse

          -
          - - -
          -
          - - -
          -
          - -
          -

          Line

          -
          - - -
          -
          - - -
          -
          - -
          -

          Text

          - -
          - - - - -
          - -
          -
          B
          -
          i
          -
          - - - - - -
          - - -
          - - - - -
          - -
          - -
          - -
          -

          Group

          -
          - - -
          - -
          - -
          -

          Edit Path

          -
          - - - - - - - -
          Add Node
          -
          Delete Node
          -
          Open Path
          - -
          - - -
          - - - - - - - - -

          Stroke

          -
          - -
          - - - - - - -

          Align

          -
          - -
          -
          -

          Position

          - - -
          -
          - - -
          -

          Multiple Elements

          - - - - - - -
          -

          Align

          - -
          - -
          - -
          - -
          -
          - -
          - - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          -
          -
          - -
          -
          -
          -
          -
          - -
          - -
          -
          -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          -
          -
          -
          - -
          - - -
          - -
          - -
          - -
          - -
          -
          -
          -
          - - - - - -
          - - - -
          -
          -
          -
          -

          Copy the contents of this box into a text editor, then save the file with a .svg extension.

          - -
          -
          - -
          -
          - - -
          -
          -
          - - -
          -
          -
          - -
          - Canvas Dimensions - - - - - - -
          -
          - - -
          -
          -
          - -
          -
          -
          - -
          - Editor Preferences - - - - - - - - - - - - - - - - - -
          -
          - - -
          -
          -
          - -
          -
          -
          -
          -
          -
          -
          - - - - - - - - - diff --git a/build/svg-edit-2.6/svg-editor.js b/build/svg-edit-2.6/svg-editor.js deleted file mode 100644 index 87d3070..0000000 --- a/build/svg-edit-2.6/svg-editor.js +++ /dev/null @@ -1,4891 +0,0 @@ -/* - * svg-editor.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * Copyright(c) 2010 Narendra Sisodiya - * - */ - -// Dependencies: -// 1) units.js -// 2) browser.js -// 3) svgcanvas.js - -(function() { - - document.addEventListener("touchstart", touchHandler, true); - document.addEventListener("touchmove", touchHandler, true); - document.addEventListener("touchend", touchHandler, true); - document.addEventListener("touchcancel", touchHandler, true); - if(!window.svgEditor) window.svgEditor = function($) { - var svgCanvas; - var Editor = {}; - var is_ready = false; - - var defaultPrefs = { - lang:'en', - iconsize:'m', - bkgd_color:'FFF', - bkgd_url:'', - img_save:'embed' - }, - curPrefs = {}, - - // Note: Difference between Prefs and Config is that Prefs can be - // changed in the UI and are stored in the browser, config can not - - curConfig = { - canvas_expansion: 1, - dimensions: [640,480], - initFill: { - color: 'fff', // solid red - opacity: 1 - }, - initStroke: { - width: 1.5, - color: '000', // solid black - opacity: 1 - }, - initOpacity: 1, - imgPath: 'images/', - langPath: 'locale/', - extPath: 'extensions/', - jGraduatePath: 'jgraduate/images/', - extensions: ['ext-markers.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-grid.js'], - initTool: 'select', - wireframe: false, - colorPickerCSS: false, - gridSnapping: false, - gridColor: "#000", - baseUnit: 'px', - snappingStep: 10, - showRulers: true, - show_outside_canvas: false - }, - uiStrings = Editor.uiStrings = { - common: { - "ok":"OK", - "cancel":"Cancel", - "key_up":"Up", - "key_down":"Down", - "key_backspace":"Backspace", - "key_del":"Del" - - }, - // This is needed if the locale is English, since the locale strings are not read in that instance. - layers: { - "layer":"Layer" - }, - notification: { - "invalidAttrValGiven":"Invalid value given", - "noContentToFitTo":"No content to fit to", - "dupeLayerName":"There is already a layer named that!", - "enterUniqueLayerName":"Please enter a unique layer name", - "enterNewLayerName":"Please enter the new layer name", - "layerHasThatName":"Layer already has that name", - "QmoveElemsToLayer":"Move selected elements to layer \"%s\"?", - "QwantToClear":"Do you want to clear the drawing?\nThis will also erase your undo history!", - "QwantToOpen":"Do you want to open a new file?\nThis will also erase your undo history!", - "QerrorsRevertToSource":"There were parsing errors in your SVG source.\nRevert back to original SVG source?", - "QignoreSourceChanges":"Ignore changes made to SVG source?", - "featNotSupported":"Feature not supported", - "enterNewImgURL":"Enter the new image URL", - "defsFailOnSave": "NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.", - "loadingImage":"Loading image, please wait...", - "saveFromBrowser": "Select \"Save As...\" in your browser to save this image as a %s file.", - "noteTheseIssues": "Also note the following issues: ", - "unsavedChanges": "There are unsaved changes.", - "enterNewLinkURL": "Enter the new hyperlink URL", - "errorLoadingSVG": "Error: Unable to load SVG data", - "URLloadFail": "Unable to load from URL", - "retrieving": 'Retrieving "%s" ...' - } - }; - - var curPrefs = {}; //$.extend({}, defaultPrefs); - - var customHandlers = {}; - - Editor.curConfig = curConfig; - - Editor.tool_scale = 1; - -// window.ontouchmove = function(e) { -// e.stopPropagation(); -// }; -// -// $(document).bind("touchmove", function(evt) { -// if (evt.target.tagName.toLowerCase() !== "path" && evt.target.tagName.toLowerCase() !== "a") { -// return evt.preventDefault(); -// } -// }); - - // Store and retrieve preferences - $.pref = function(key, val) { - if(val) curPrefs[key] = val; - key = 'svg-edit-'+key; - var host = location.hostname, - onweb = host && host.indexOf('.') >= 0, - store = (val != undefined), - storage = false; - // Some FF versions throw security errors here - try { - if(window.localStorage) { // && onweb removed so Webkit works locally - storage = localStorage; - } - } catch(e) {} - try { - if(window.globalStorage && onweb) { - storage = globalStorage[host]; - } - } catch(e) {} - - if(storage) { - if(store) storage.setItem(key, val); - else if (storage.getItem(key)) return storage.getItem(key) + ''; // Convert to string for FF (.value fails in Webkit) - } else if(window.widget) { - if(store) widget.setPreferenceForKey(val, key); - else return widget.preferenceForKey(key); - } else { - if(store) { - var d = new Date(); - d.setTime(d.getTime() + 31536000000); - val = encodeURIComponent(val); - document.cookie = key+'='+val+'; expires='+d.toUTCString(); - } else { - var result = document.cookie.match(new RegExp(key + "=([^;]+)")); - return result?decodeURIComponent(result[1]):''; - } - } - } - - Editor.setConfig = function(opts) { - $.each(opts, function(key, val) { - // Only allow prefs defined in defaultPrefs - if(key in defaultPrefs) { - $.pref(key, val); - } - }); - $.extend(true, curConfig, opts); - if(opts.extensions) { - curConfig.extensions = opts.extensions; - } - - } - - // Extension mechanisms must call setCustomHandlers with two functions: opts.open and opts.save - // opts.open's responsibilities are: - // - invoke a file chooser dialog in 'open' mode - // - let user pick a SVG file - // - calls setCanvas.setSvgString() with the string contents of that file - // opts.save's responsibilities are: - // - accept the string contents of the current document - // - invoke a file chooser dialog in 'save' mode - // - save the file to location chosen by the user - Editor.setCustomHandlers = function(opts) { - Editor.ready(function() { - if(opts.open) { - $('#tool_open > input[type="file"]').remove(); - $('#tool_open').show(); - svgCanvas.open = opts.open; - } - if(opts.save) { - Editor.show_save_warning = false; - svgCanvas.bind("saved", opts.save); - } - if(opts.pngsave) { - svgCanvas.bind("exported", opts.pngsave); - } - customHandlers = opts; - }); - } - - Editor.randomizeIds = function() { - svgCanvas.randomizeIds(arguments) - } - - Editor.init = function() { - // For external openers - (function() { - // let the opener know SVG Edit is ready - var w = window.opener; - if (w) { - try { - var svgEditorReadyEvent = w.document.createEvent("Event"); - svgEditorReadyEvent.initEvent("svgEditorReady", true, true); - w.document.documentElement.dispatchEvent(svgEditorReadyEvent); - } - catch(e) {} - } - })(); - - (function() { - // Load config/data from URL if given - var urldata = $.deparam.querystring(true); - if(!$.isEmptyObject(urldata)) { - if(urldata.dimensions) { - urldata.dimensions = urldata.dimensions.split(','); - } - - if(urldata.extensions) { - urldata.extensions = urldata.extensions.split(','); - } - - if(urldata.bkgd_color) { - urldata.bkgd_color = '#' + urldata.bkgd_color; - } - - svgEditor.setConfig(urldata); - - var src = urldata.source; - var qstr = $.param.querystring(); - - if(!src) { // urldata.source may have been null if it ended with '=' - if(qstr.indexOf('source=data:') >= 0) { - src = qstr.match(/source=(data:[^&]*)/)[1]; - } - } - - if(src) { - if(src.indexOf("data:") === 0) { - // plusses get replaced by spaces, so re-insert - src = src.replace(/ /g, "+"); - Editor.loadFromDataURI(src); - } else { - Editor.loadFromString(src); - } - } else if(qstr.indexOf('paramurl=') !== -1) { - // Get paramater URL (use full length of remaining location.href) - svgEditor.loadFromURL(qstr.substr(9)); - } else if(urldata.url) { - svgEditor.loadFromURL(urldata.url); - } - } - })(); - - var extFunc = function() { - $.each(curConfig.extensions, function() { - 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); - } - }); - }); - - var good_langs = []; - - $('#lang_select option').each(function() { - good_langs.push(this.value); - }); - - // var lang = ('lang' in curPrefs) ? curPrefs.lang : null; - Editor.putLocale(null, good_langs); - } - - // Load extensions - // Bit of a hack to run extensions in local Opera/IE9 - if(document.location.protocol === 'file:') { - setTimeout(extFunc, 100); - } else { - extFunc(); - } - $.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { - w:24, h:24, - id_match: false, - no_img: !svgedit.browser.isWebkit(), // Opera & Firefox 4 gives odd behavior w/images - fallback_path: curConfig.imgPath, - fallback:{ - 'new_image':'clear.png', - 'save':'save.png', - 'open':'open.png', - 'source':'source.png', - 'docprops':'document-properties.png', - 'wireframe':'wireframe.png', - - 'undo':'undo.png', - 'redo':'redo.png', - - 'select':'select.png', - 'select_node':'select_node.png', - 'pencil':'fhpath.png', - 'pen':'line.png', - 'square':'square.png', - 'rect':'rect.png', - 'fh_rect':'freehand-square.png', - 'circle':'circle.png', - 'ellipse':'ellipse.png', - 'fh_ellipse':'freehand-circle.png', - 'path':'path.png', - 'text':'text.png', - 'image':'image.png', - 'zoom':'zoom.png', - - 'clone':'clone.png', - 'node_clone':'node_clone.png', - 'delete':'delete.png', - 'node_delete':'node_delete.png', - //'group':'shape_group.png', - //'ungroup':'shape_ungroup.png', - 'move_top':'move_top.png', - 'move_bottom':'move_bottom.png', - 'to_path':'to_path.png', - 'link_controls':'link_controls.png', - 'reorient':'reorient.png', - - 'align_left':'align-left.png', - 'align_center':'align-center', - 'align_right':'align-right', - 'align_top':'align-top', - 'align_middle':'align-middle', - 'align_bottom':'align-bottom', - - 'go_up':'go-up.png', - 'go_down':'go-down.png', - - 'ok':'save.png', - 'cancel':'cancel.png', - - 'arrow_right':'flyouth.png', - 'arrow_down':'dropdown.gif' - }, - placement: { - '#tool_docprops > div':'docprops', - - '#tool_select':'select', - '#tool_fhpath':'pencil', - '#tool_line':'pen', - '#tool_rect,#tools_rect_show':'rect', - '#tool_square':'square', - '#tool_fhrect':'fh_rect', - '#tool_ellipse,#tools_ellipse_show':'ellipse', - '#tool_circle':'circle', - '#tool_fhellipse':'fh_ellipse', - '#tool_path':'path', - '#tool_text,#layer_rename':'text', - '#tool_image':'image', - '#tool_zoom':'zoom', - - '#tool_node_clone':'node_clone', - '#tool_node_delete':'node_delete', - '#tool_add_subpath':'add_subpath', - '#tool_openclose_path':'open_path', - //'#tool_node_link':'link_controls', - //'#tool_group':'group', - //'#tool_ungroup':'ungroup', - //'#tool_unlink_use':'unlink_use', - - '#tool_alignleft, #tool_posleft':'align_left', - '#tool_aligncenter, #tool_poscenter':'align_center', - '#tool_alignright, #tool_posright':'align_right', - '#tool_aligntop, #tool_postop':'align_top', - '#tool_alignmiddle, #tool_posmiddle':'align_middle', - '#tool_alignbottom, #tool_posbottom':'align_bottom', - '#cur_position':'align', - - '#linecap_butt,#cur_linecap':'linecap_butt', - '#linecap_round':'linecap_round', - '#linecap_square':'linecap_square', - - '#linejoin_miter,#cur_linejoin':'linejoin_miter', - '#linejoin_round':'linejoin_round', - '#linejoin_bevel':'linejoin_bevel', - - '#url_notice':'warning', - - '#layer_up':'go_up', - '#layer_down':'go_down', - '#layer_moreopts':'context_menu', - '#layerlist td.layervis':'eye', - - '#tool_source_save,#tool_docprops_save,#tool_prefs_save':'ok', - '#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel':'cancel', - - '#rwidthLabel, #iwidthLabel':'width', - '#rheightLabel, #iheightLabel':'height', - //'#cornerRadiusLabel span':'c_radius', - '#angleLabel':'angle', - '#linkLabel,#tool_make_link,#tool_make_link_multi':'globe_link', - '#zoomLabel':'zoom', - //'#tool_fill label': 'fill', - //'#tool_stroke .icon_label': 'stroke', - //'#group_opacityLabel': 'opacity', - '#blurLabel': 'blur', - //'#font_sizeLabel': 'fontsize', - - '.flyout_arrow_horiz':'arrow_right', - //'.dropdown button, #main_button .dropdown':'arrow_down', - '#palette .palette_item:first, #fill_bg, #stroke_bg':'no_color' - }, - resize: { - '#logo .svg_icon': 32, - '.flyout_arrow_horiz .svg_icon': 5, - '.layer_button .svg_icon, #layerlist td.layervis .svg_icon': 14, - //'.dropdown button .svg_icon': 7, - '#main_button .dropdown .svg_icon': 9, - '#fill_bg .svg_icon, #stroke_bg .svg_icon': 24, - '.palette_item:first .svg_icon': 16, - '.toolbar_button button .svg_icon':16, - '.stroke_tool div div .svg_icon': 20, - '#tools_bottom label .svg_icon': 18, - '#zoom_dropdown .svg_icon': 7 - }, - callback: function(icons) { - $('.toolbar_button button > svg, .toolbar_button button > img').each(function() { - $(this).parent().prepend(this); - }); - - var tleft = $('#tools_left'); - if (tleft.length != 0) { - var min_height = tleft.offset().top + tleft.outerHeight(); - } - - // Look for any missing flyout icons from plugins - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var sel = shower.attr('data-curopt'); - // Check if there's an icon here - if(!shower.children('svg, img').length) { - var clone = $(sel).children().clone(); - if(clone.length) { - clone[0].removeAttribute('style'); //Needed for Opera - shower.append(clone); - } - } - }); - - svgEditor.runCallbacks(); - - setTimeout(function() { - $('.flyout_arrow_horiz:empty').each(function() { - $(this).append($.getSvgIcon('arrow_right').width(5).height(5)); - }); - }, 1); - } - }); - - Editor.canvas = svgCanvas = new $.SvgCanvas(document.getElementById("svgcanvas"), curConfig); - Editor.show_save_warning = false; - var palette = ["#000000", "#3f3f3f", "#7f7f7f", "#bfbfbf", "#ffffff", - "#ff0000", "#ff7f00", "#ffff00", "#7fff00", - "#00ff00", "#00ff7f", "#00ffff", "#007fff", - "#0000ff", "#7f00ff", "#ff00ff", "#ff007f", - "#7f0000", "#7f3f00", "#7f7f00", "#3f7f00", - "#007f00", "#007f3f", "#007f7f", "#003f7f", - "#00007f", "#3f007f", "#7f007f", "#7f003f", - "#ffaaaa", "#ffd4aa", "#ffffaa", "#d4ffaa", - "#aaffaa", "#aaffd4", "#aaffff", "#aad4ff" - ], - isMac = (navigator.platform.indexOf("Mac") >= 0), - isWebkit = (navigator.userAgent.indexOf("AppleWebKit") >= 0), - modKey = (isMac ? "meta+" : "ctrl+"), // ⌘ - path = svgCanvas.pathActions, - undoMgr = svgCanvas.undoMgr, - Utils = svgedit.utilities, - default_img_url = curConfig.imgPath + "placeholder.svg", - workarea = $("#workarea"), - canv_menu = $("#cmenu_canvas"), - layer_menu = $("#cmenu_layers"), - exportWindow = null, - tool_scale = 1, - zoomInIcon = 'crosshair', - zoomOutIcon = 'crosshair', - ui_context = 'toolbars', - orig_source = '', - paintBox = {fill: null, stroke:null}; - - // This sets up alternative dialog boxes. They mostly work the same way as - // their UI counterparts, expect instead of returning the result, a callback - // needs to be included that returns the result as its first parameter. - // In the future we may want to add additional types of dialog boxes, since - // they should be easy to handle this way. - (function() { - $('#dialog_container').draggable({cancel:'#dialog_content, #dialog_buttons *', containment: 'window'}); - var box = $('#dialog_box'), btn_holder = $('#dialog_buttons'); - - var dbox = function(type, msg, callback, defText) { - $('#dialog_content').html('

          '+msg.replace(/\n/g,'

          ')+'

          ') - .toggleClass('prompt',(type=='prompt')); - btn_holder.empty(); - - var ok = $('').appendTo(btn_holder); - - if(type != 'alert') { - $('') - .appendTo(btn_holder) - .click(function() { box.hide();callback(false)}); - } - - if(type == 'prompt') { - var input = $('').prependTo(btn_holder); - input.val(defText || ''); - input.bind('keydown', 'return', function() {ok.click();}); - } - - if(type == 'process') { - ok.hide(); - } - - box.show(); - - ok.click(function() { - box.hide(); - var resp = (type == 'prompt')?input.val():true; - if(callback) callback(resp); - }).focus(); - - if(type == 'prompt') input.focus(); - } - - $.alert = function(msg, cb) { dbox('alert', msg, cb);}; - $.confirm = function(msg, cb) { dbox('confirm', msg, cb);}; - $.process_cancel = function(msg, cb) { dbox('process', msg, cb);}; - $.prompt = function(msg, txt, cb) { dbox('prompt', msg, cb, txt);}; - }()); - - var setSelectMode = function() { - var curr = $('.tool_button_current'); - if(curr.length && curr[0].id !== 'tool_select') { - curr.removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}'); - } - svgCanvas.setMode('select'); - }; - - var togglePathEditMode = function(editmode, elems) { - $('#path_node_panel').toggle(editmode); - $('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); - if(editmode) { - // Change select icon - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - setIcon('#tool_select', 'select_node'); - multiselected = false; - if(elems.length) { - selectedElement = elems[0]; - } - } else { - setIcon('#tool_select', 'select'); - } - } - - // used to make the flyouts stay on the screen longer the very first time - var flyoutspeed = 1250; - var textBeingEntered = false; - var selectedElement = null; - var multiselected = false; - var editingsource = false; - var docprops = false; - var preferences = false; - var cur_context = ''; - var orig_title = $('title:first').text(); - - var saveHandler = function(window,svg) { - Editor.show_save_warning = false; - - // 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; - - // Opens the SVG in new window, with warning about Mozilla bug #308590 when applicable - - var ua = navigator.userAgent; - - // Chrome 5 (and 6?) don't allow saving, show source instead ( http://code.google.com/p/chromium/issues/detail?id=46735 ) - // IE9 doesn't allow standalone Data URLs ( https://connect.microsoft.com/IE/feedback/details/542600/data-uri-images-fail-when-loaded-by-themselves ) - if((~ua.indexOf('Chrome') && $.browser.version >= 533) || ~ua.indexOf('MSIE')) { - showSourceEditor(0,true); - return; - } - var win = window.open("data:image/svg+xml;base64," + Utils.encode64(svg)); - - // Alert will only appear the first time saved OR the first time the bug is encountered - var done = $.pref('save_notice_done'); - if(done !== "all") { - - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'SVG'); - - // Check if FF and has - if(ua.indexOf('Gecko/') !== -1) { - if(svg.indexOf('', {id: 'export_canvas'}).hide().appendTo('body'); - } - var c = $('#export_canvas')[0]; - - c.width = svgCanvas.contentW; - c.height = svgCanvas.contentH; - canvg(c, data.svg, {renderCallback: function() { - var datauri = c.toDataURL('image/png'); - exportWindow.location.href = datauri; - var done = $.pref('export_notice_done'); - if(done !== "all") { - var note = uiStrings.notification.saveFromBrowser.replace('%s', 'PNG'); - - // Check if there's issues - if(issues.length) { - var pre = "\n \u2022 "; - note += ("\n\n" + uiStrings.notification.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 - var selectedChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") setSelectMode(); - var is_node = (mode == "pathedit"); - // if elems[1] is present, then we have more than one element - selectedElement = (elems.length == 1 || elems[1] == null ? elems[0] : null); - multiselected = (elems.length >= 2 && elems[1] != null); - if (selectedElement != null) { - // unless we're already in always set the mode of the editor to select because - // upon creation of a text element the editor is switched into - // select mode and this event fires - we need our UI to be in sync - - if (!is_node) { - updateToolbar(); - } - - } // if (elem != null) - // Deal with pathedit mode - togglePathEditMode(is_node, elems); - updateContextPanel(); - svgCanvas.runExtensions("selectedChanged", { - elems: elems, - selectedElement: selectedElement, - multiselected: multiselected - }); - }; - - // Call when part of element is in process of changing, generally - // on mousemove actions like rotate, move, etc. - var elementTransition = function(window,elems) { - var mode = svgCanvas.getMode(); - var elem = elems[0]; - - if(!elem) return; - - multiselected = (elems.length >= 2 && elems[1] != null); - // Only updating fields for single elements for now - if(!multiselected) { - switch ( mode ) { - case "rotate": - var ang = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(ang)); - $('#tool_reorient').toggleClass('disabled', ang == 0); - break; - - // TODO: Update values that change on move/resize, etc -// case "select": -// case "resize": -// break; - } - } - svgCanvas.runExtensions("elementTransition", { - elems: elems - }); - }; - - // called when any element has changed - var elementChanged = function(window,elems) { - var mode = svgCanvas.getMode(); - if(mode === "select") { - setSelectMode(); - } - - for (var i = 0; i < elems.length; ++i) { - var elem = elems[i]; - - // if the element changed was the svg, then it could be a resolution change - if (elem && elem.tagName === "svg") { - populateLayers(); - updateCanvas(); - } - // 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) { // This was added in r1430, but not sure why - selectedElement = elem; - } - } - - Editor.show_save_warning = true; - - // we update the contextual panel with potentially new - // positional/sizing information (we DON'T want to update the - // toolbar here as that creates an infinite loop) - // also this updates the history buttons - - // we tell it to skip focusing the text control if the - // text element was previously in focus - updateContextPanel(); - - // In the event a gradient was flipped: - if(selectedElement && mode === "select") { - paintBox.fill.update(); - paintBox.stroke.update(); - } - - svgCanvas.runExtensions("elementChanged", { - elems: elems - }); - }; - - var zoomChanged = function(window, bbox, autoCenter) { - var scrbar = 15, - res = svgCanvas.getResolution(), - w_area = workarea, - canvas_pos = $('#svgcanvas').position(); - var z_info = svgCanvas.setBBoxZoom(bbox, w_area.width()-scrbar, w_area.height()-scrbar); - if(!z_info) return; - var zoomlevel = z_info.zoom, - bb = z_info.bbox; - - if(zoomlevel < .001) { - changeZoom({value: .1}); - return; - } - -// $('#zoom').val(Math.round(zoomlevel*100)); - $('#zoom').val(zoomlevel*100); - - if(autoCenter) { - updateCanvas(); - } else { - updateCanvas(false, {x: bb.x * zoomlevel + (bb.width * zoomlevel)/2, y: bb.y * zoomlevel + (bb.height * zoomlevel)/2}); - } - - if(svgCanvas.getMode() == 'zoom' && bb.width) { - // Go to select if a zoom box was drawn - setSelectMode(); - } - - zoomDone(); - } - - $('#cur_context_panel').delegate('a', 'click', function() { - var link = $(this); - if(link.attr('data-root')) { - svgCanvas.leaveContext(); - } else { - svgCanvas.setContext(link.text()); - } - return false; - }); - - var contextChanged = function(win, context) { - - var link_str = ''; - if(context) { - var str = ''; - link_str = '' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + ''; - - $(context).parentsUntil('#svgcontent > g').andSelf().each(function() { - if(this.id) { - str += ' > ' + this.id; - if(this !== context) { - link_str += ' > ' + this.id + ''; - } else { - link_str += ' > ' + this.id; - } - } - }); - - cur_context = str; - } else { - cur_context = null; - } - $('#cur_context_panel').toggle(!!context).html(link_str); - - - updateTitle(); - } - - // Makes sure the current selected paint is available to work with - var prepPaints = function() { - paintBox.fill.prep(); - paintBox.stroke.prep(); - } - - var flyout_funcs = {}; - - var setupFlyouts = function(holders) { - $.each(holders, function(hold_sel, btn_opts) { - var buttons = $(hold_sel).children(); - var show_sel = hold_sel + '_show'; - var shower = $(show_sel); - var def = false; - buttons.addClass('tool_button') - .unbind('click mousedown mouseup') // may not be necessary - .each(function(i) { - // Get this buttons options - var opts = btn_opts[i]; - - // Remember the function that goes with this ID - flyout_funcs[opts.sel] = opts.fn; - - if(opts.isDefault) def = i; - - // Clicking the icon in flyout should set this set's icon - var func = function(event) { - var options = opts; - //find the currently selected tool if comes from keystroke - if (event.type === "keydown") { - var flyoutIsSelected = $(options.parent + "_show").hasClass('tool_button_current'); - var currentOperation = $(options.parent + "_show").attr("data-curopt"); - $.each(holders[opts.parent], function(i, tool){ - if (tool.sel == currentOperation) { - if(!event.shiftKey || !flyoutIsSelected) { - options = tool; - } - else { - options = holders[opts.parent][i+1] || holders[opts.parent][0]; - } - } - }); - } - if($(this).hasClass('disabled')) return false; - if (toolButtonClick(show_sel)) { - options.fn(); - } - if(options.icon) { - var icon = $.getSvgIcon(options.icon, true); - } else { - var icon = $(options.sel).children().eq(0).clone(); - } - - icon[0].setAttribute('width',shower.width()); - icon[0].setAttribute('height',shower.height()); - shower.children(':not(.flyout_arrow_horiz)').remove(); - shower.append(icon).attr('data-curopt', options.sel); // This sets the current mode - } - - $(this).mouseup(func); - - if(opts.key) { - $(document).bind('keydown', opts.key[0] + " shift+" + opts.key[0], func); - } - }); - - if(def) { - shower.attr('data-curopt', btn_opts[def].sel); - } else if(!shower.attr('data-curopt')) { - // Set first as default - shower.attr('data-curopt', btn_opts[0].sel); - } - - var timer; - - var pos = $(show_sel).position(); - $(hold_sel).css({'left': pos.left+34, 'top': pos.top+77}); - - // Clicking the "show" icon should set the current mode - shower.mousedown(function(evt) { - if ($('#tools_shapelib').is(":visible")) toolButtonClick(show_sel, false); - if(shower.hasClass('disabled')) return false; - var holder = $(hold_sel); - var l = pos.left+34; - var w = holder.width()*-1; - var time = holder.data('shown_popop')?200:0; - timer = setTimeout(function() { - // Show corresponding menu - if(!shower.data('isLibrary')) { - holder.css('left', w).show().animate({ - left: l - },150); - } else { - holder.css('left', l).show(); - } - holder.data('shown_popop',true); - },time); - evt.preventDefault(); - }).mouseup(function(evt) { - clearTimeout(timer); - var opt = $(this).attr('data-curopt'); - // Is library and popped up, so do nothing - if(shower.data('isLibrary') && $(show_sel.replace('_show','')).is(':visible')) { - toolButtonClick(show_sel, true); - return; - } - if (toolButtonClick(show_sel) && (opt in flyout_funcs)) { - flyout_funcs[opt](); - } - }); - - // $('#tools_rect').mouseleave(function(){$('#tools_rect').fadeOut();}); - }); - - setFlyoutTitles(); - } - - var makeFlyoutHolder = function(id, child) { - var div = $('
          ',{ - 'class': 'tools_flyout', - id: id - }).appendTo('#svg_editor').append(child); - - return div; - } - - var setFlyoutPositions = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var pos = shower.offset(); - var w = shower.outerWidth(); - $(this).css({left: (pos.left + w)*tool_scale, top: pos.top}); - }); - } - - var setFlyoutTitles = function() { - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - if(shower.data('isLibrary')) return; - - var tooltips = []; - $(this).children().each(function() { - tooltips.push(this.title); - }); - 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 && cb_ready) { - cb_called = true; - ext.callback(); - } - } - - var btn_selects = []; - - if(ext.context_tools) { - $.each(ext.context_tools, function(i, tool) { - // Add select tool - var cont_id = tool.container_id?(' id="' + tool.container_id + '"'):""; - - var panel = $('#' + tool.panel); - - // create the panel if it doesn't exist - if(!panel.length) - panel = $('
          ', {id: tool.panel}).appendTo("#tools_top"); - - // TODO: Allow support for other types, or adding to existing tool - switch (tool.type) { - case 'tool_button': - var html = '
          ' + tool.id + '
          '; - var div = $(html).appendTo(panel); - if (tool.events) { - $.each(tool.events, function(evt, func) { - $(div).bind(evt, func); - }); - } - break; - case 'select': - var html = '' - + '"; - // Creates the tool, hides & adds it, returns the select element - var sel = $(html).appendTo(panel).find('select'); - - $.each(tool.events, function(evt, func) { - $(sel).bind(evt, func); - }); - break; - case 'button-select': - var html = ''; - - var list = $('
            ').appendTo('#option_lists'); - - if(tool.colnum) { - list.addClass('optcols' + tool.colnum); - } - - // Creates the tool, hides & adds it, returns the select element - var dropdown = $(html).appendTo(panel).children(); - - btn_selects.push({ - elem: ('#' + tool.id), - list: ('#' + tool.id + '_opts'), - title: tool.title, - callback: tool.events.change, - cur: ('#cur_' + tool.id) - }); - - break; - case 'input': - var html = '' - + '' - + tool.label + ':' - + '' - - // Creates the tool, hides & adds it, returns the select element - - // Add to given tool.panel - var inp = $(html).appendTo(panel).find('input'); - - if(tool.spindata) { - inp.SpinButton(tool.spindata); - } - - if(tool.events) { - $.each(tool.events, function(evt, func) { - inp.bind(evt, func); - }); - } - break; - - default: - break; - } - }); - } - - if(ext.buttons) { - var fallback_obj = {}, - placement_obj = {}, - svgicons = ext.svgicons; - var holders = {}; - - - // Add buttons given by extension - $.each(ext.buttons, function(i, btn) { - var icon; - var id = btn.id; - var num = i; - - // Give button a unique ID - while($('#'+id).length) { - id = btn.id + '_' + (++num); - } - - if(!svgicons) { - icon = (btn.type == "menu") ? "" : $(''); - } else { - fallback_obj[id] = btn.icon; - var svgicon = btn.svgicon?btn.svgicon:btn.id; - if(btn.type == 'app_menu') { - placement_obj['#' + id + ' > div'] = svgicon; - } else { - placement_obj['#' + id] = svgicon; - } - } - - var cls, parent; - - - - // Set button up according to its type - switch ( btn.type ) { - case 'mode_flyout': - case 'mode': - cls = 'tool_button'; - if(btn.cls) { - cls += " " + btn.cls; - } - parent = "#tools_left"; - break; - case 'context': - cls = 'tool_button'; - parent = "#" + btn.panel; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
            ', {id: btn.panel}).appendTo("#tools_top"); - break; - case 'menu': - cls = 'menu_item tool_button'; - parent = "#" + (btn.after || btn.panel); - break; - case 'app_menu': - cls = ''; - parent = btn.parent || '#main_menu ul'; - // create the panel if it doesn't exist - if(!$(parent).length) - $('
            ', {id: btn.panel}).appendTo("#tools_top"); - break; - } - - var button = $((btn.list || btn.type == 'app_menu')?'
          • ':'
            ') - .attr("id", id) - .attr("title", btn.title) - .addClass(cls); - if(!btn.includeWith && !btn.list) { - if("position" in btn) { - $(parent).children().eq(btn.position).before(button); - } else { - if (btn.type != "menu" || !btn.after) button.appendTo(parent); - else $(parent).after(button); - } - - if(btn.type =='mode_flyout') { - // Add to flyout menu / make flyout menu - // var opts = btn.includeWith; - // // opts.button, default, position - var ref_btn = $(button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
            ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - flyout_holder.data('isLibrary', true); - show_btn.data('isLibrary', true); - } - - - - // var ref_data = Actions.getButtonData(opts.button); - - placement_obj['#' + tls_id + '_show'] = btn.id; - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, -// key: btn.key, - isDefault: true - }, ref_data]; - - } else if(btn.type == 'app_menu' || btn.type == 'menu') { - button.append(btn.title); - } - - } else if(btn.list) { - // Add button to list - button.addClass('push_button'); - $('#' + btn.list + '_opts').append(button); - if(btn.isDefault) { - $('#cur_' + btn.list).append(button.children().clone()); - var svgicon = btn.svgicon?btn.svgicon:btn.id; - placement_obj['#cur_' + btn.list] = svgicon; - } - } else if(btn.includeWith) { - // Add to flyout menu / make flyout menu - var opts = btn.includeWith; - // opts.button, default, position - var ref_btn = $(opts.button); - - var flyout_holder = ref_btn.parent(); - // Create a flyout menu if there isn't one already - if(!ref_btn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - var tls_id = ref_btn[0].id.replace('tool_','tools_') - var show_btn = ref_btn.clone() - .attr('id',tls_id + '_show') - .append($('
            ',{'class':'flyout_arrow_horiz'})); - - ref_btn.before(show_btn); - - // Create a flyout div - flyout_holder = makeFlyoutHolder(tls_id, ref_btn); - } - - var ref_data = Actions.getButtonData(opts.button); - - if(opts.isDefault) { - placement_obj['#' + tls_id + '_show'] = btn.id; - } - // TODO: Find way to set the current icon using the iconloader if this is not default - - // Include data for extension button as well as ref button - var cur_h = holders['#'+flyout_holder[0].id] = [{ - sel: '#'+id, - fn: btn.events.click, - icon: btn.id, - key: btn.key, - isDefault: btn.includeWith?btn.includeWith.isDefault:0 - }, ref_data]; - - // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} - - var pos = ("position" in opts)?opts.position:'last'; - var len = flyout_holder.children().length; - - // Add at given position or end - if(!isNaN(pos) && pos >= 0 && pos < len) { - flyout_holder.children().eq(pos).before(button); - } else { - flyout_holder.append(button); - cur_h.reverse(); - } - } - - if(!svgicons) { - button.append(icon); - } - - if(!btn.list) { - // Add given events to button - $.each(btn.events, function(name, func) { - if(name == "click") { - if(btn.type == 'mode') { - if(btn.includeWith) { - button.bind(name, func); - } else { - button.bind(name, function() { - if(toolButtonClick(button)) { - func(); - } - }); - } - if(btn.key) { - $(document).bind('keydown', btn.key, func); - if(btn.title) button.attr("title", btn.title + ' ['+btn.key+']'); - } - } else { - button.bind(name, func); - } - } else { - button.bind(name, func); - } - }); - } - setupFlyouts(holders); - }); - - $.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, - id_match: false, - no_img: (!isWebkit), - fallback: fallback_obj, - placement: placement_obj, - callback: function(icons) { - // Non-ideal hack to make the icon match the current size - if(curPrefs.iconsize && curPrefs.iconsize != 'm') { - prepResize(); - } - cb_ready = true; // Ready for callback - runCallback(); - } - - }); - } - - runCallback(); - }; - - var getPaint = function(color, opac, type) { - // update the editor's fill paint - var opts = null; - if (color.indexOf("url(#") === 0) { - var refElem = svgCanvas.getRefElem(color); - if(refElem) { - refElem = refElem.cloneNode(true); - } else { - refElem = $("#" + type + "_color defs *")[0]; - } - - opts = { alpha: opac }; - opts[refElem.tagName] = refElem; - } - else if (color.indexOf("#") === 0) { - opts = { - alpha: opac, - solidColor: color.substr(1) - }; - } - else { - opts = { - alpha: opac, - solidColor: 'none' - }; - } - return new $.jGraduate.Paint(opts); - }; - - // set the canvas properties at init - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#docprops_button').on("click", function(){showDocProperties()}); - - // 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) { - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - break; - case 'g': - case 'a': - // Look for common styles - - var gWidth = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var swidth = childs[i].getAttribute("stroke-width"); - - if(i === 0) { - gWidth = swidth; - } else if(gWidth !== swidth) { - gWidth = null; - } - } - - $('#stroke_width').val(gWidth === null ? "" : gWidth); - - paintBox.fill.update(true); - paintBox.stroke.update(true); - - - break; - default: - paintBox.fill.update(true); - paintBox.stroke.update(true); - - $('#stroke_width').val(selectedElement.getAttribute("stroke-width") || 1); - $('#stroke_style').val(selectedElement.getAttribute("stroke-dasharray")||"none"); - - var attr = selectedElement.getAttribute("stroke-linejoin") || 'miter'; - - if ($('#linejoin_' + attr).length != 0) - setStrokeOpt($('#linejoin_' + attr)[0]); - - attr = selectedElement.getAttribute("stroke-linecap") || 'butt'; - - if ($('#linecap_' + attr).length != 0) - setStrokeOpt($('#linecap_' + attr)[0]); - } - - } - - // All elements including image and group have opacity - if(selectedElement != null) { - var opac_perc = ((selectedElement.getAttribute("opacity")||1.0)*100); - $('#group_opacity').val(opac_perc); - $('#opac_slider').slider('option', 'value', opac_perc); - $('#elem_id').val(selectedElement.id); - } - - updateToolButtonState(); - }; - - var setImageURL = Editor.setImageURL = function(url) { - if(!url) url = default_img_url; - - svgCanvas.setImageURL(url); - $('#image_url').val(url); - - if(url.indexOf('data:') === 0) { - // data URI found - $('#image_url').hide(); - $('#change_image_url').show(); - } else { - // regular URL - - svgCanvas.embedImage(url, function(datauri) { - if(!datauri) { - // Couldn't embed, so show warning - $('#url_notice').show(); - } else { - $('#url_notice').hide(); - } - default_img_url = url; - }); - $('#image_url').show(); - $('#change_image_url').hide(); - } - } - - 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; - // If element has just been deleted, consider it null - if(elem != null && !elem.parentNode) elem = null; - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var currentMode = svgCanvas.getMode(); - var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; - - var is_node = currentMode == 'pathedit'; //elem ? (elem.id && elem.id.indexOf('pathpointgrip') == 0) : false; - var menu_items = $('#cmenu_canvas li'); - $('#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\ - #ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel').hide(); - $('.menu_item', '#edit_menu').addClass('disabled'); - $('.menu_item', '#object_menu').addClass('disabled'); - if (!elem && !multiselected) $("#canvas_panel").show(); - if (elem != null) { - var elname = elem.nodeName; - var angle = svgCanvas.getRotationAngle(elem); - $('#angle').val(Math.round(angle)); - - var blurval = svgCanvas.getBlur(elem); - $('#blur').val(blurval); - $('#blur_slider').slider('option', 'value', blurval); - - if(svgCanvas.addedNew) { - if(elname === 'image') { - // Prompt for URL if not a data URL - if(svgCanvas.getHref(elem).indexOf('data:') !== 0) { - promptImgURL(); - } - } /*else if(elname == 'text') { - // TODO: Do something here for new text - }*/ - } - - if(!is_node && currentMode != 'pathedit') { - $('#selected_panel').show(); - $('.action_selected').removeClass('disabled'); - // Elements in this array already have coord fields - if(['line', 'circle', 'ellipse'].indexOf(elname) >= 0) { - $('#xy_panel').hide(); - } else { - var x,y; - - // Get BBox vals for g, polyline and path - if(['g', 'polyline', 'path'].indexOf(elname) >= 0) { - var bb = svgCanvas.getStrokedBBox([elem]); - if(bb) { - x = bb.x; - y = bb.y; - } - } else { - x = elem.getAttribute('x'); - y = elem.getAttribute('y'); - } - - if(unit) { - x = svgedit.units.convertUnit(x); - y = svgedit.units.convertUnit(y); - } - - $('#selected_x').val(x || 0); - $('#selected_y').val(y || 0); - $('#xy_panel').show(); - } - - // Elements in this array cannot be converted to a path - var no_path = ['image', 'text', 'path', 'g', 'use'].indexOf(elname) == -1; - if (no_path) $('.action_path_convert_selected').removeClass('disabled'); - if (elname === "path") $('.action_path_selected').removeClass('disabled'); - } else { - var point = path.getNodePoint(); - $('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); - $('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); - - // Show open/close button based on selected point - setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); - - if(point) { - var seg_type = $('#seg_type'); - if(unit) { - point.x = svgedit.units.convertUnit(point.x); - point.y = svgedit.units.convertUnit(point.y); - } - $('#path_node_x').val(point.x); - $('#path_node_y').val(point.y); - if(point.type) { - seg_type.val(point.type).removeAttr('disabled'); - } else { - seg_type.val(4).attr('disabled','disabled'); - } - } - return; - } - - // update contextual tools here - var panels = { - g: [], - a: [], - rect: ['rx','width','height'], - image: ['width','height'], - circle: ['cx','cy','r'], - ellipse: ['cx','cy','rx','ry'], - line: ['x1','y1','x2','y2'], - text: [], - 'use': [] - }; - - var el_name = elem.tagName; - - if($(elem).data('gsvg')) { - $('#g_panel').show(); - } - - if (el_name == "path") { - $('#path_panel').show(); - } - -// var link_href = null; -// if (el_name === 'a') { -// link_href = svgCanvas.getHref(elem); -// $('#g_panel').show(); -// } -// -// if(elem.parentNode.tagName === 'a') { -// if(!$(elem).siblings().length) { -// $('#a_panel').show(); -// link_href = svgCanvas.getHref(elem.parentNode); -// } -// } -// -// // Hide/show the make_link buttons -// $('#tool_make_link, #tool_make_link').toggle(!link_href); -// -// if(link_href) { -// $('#link_url').val(link_href); -// } - - if(panels[el_name]) { - var cur_panel = panels[el_name]; - $('#' + el_name + '_panel').show(); - - $.each(cur_panel, function(i, item) { - var attrVal = elem.getAttribute(item); - if(curConfig.baseUnit !== 'px' && elem[item]) { - var bv = elem[item].baseVal.value; - attrVal = svgedit.units.convertUnit(bv); - } - - $('#' + el_name + '_' + item).val(attrVal || 0); - }); - if(el_name == 'text') { - $('#text_panel').css("display", "inline"); - if (svgCanvas.getItalic()) { - $('#tool_italic').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_italic').removeClass('push_button_pressed').addClass('tool_button'); - } - if (svgCanvas.getBold()) { - $('#tool_bold').addClass('push_button_pressed').removeClass('tool_button'); - } - else { - $('#tool_bold').removeClass('push_button_pressed').addClass('tool_button'); - } - $('#font_family').val(elem.getAttribute("font-family")); - $('#font_size').val(elem.getAttribute("font-size")); - $('#text').val(elem.textContent); - if (svgCanvas.addedNew) { - // Timeout needed for IE9 - setTimeout(function() { - $('#text').focus().select(); - },100); - } - } // text - else if(el_name == 'image') { - setImageURL(svgCanvas.getHref(elem)); - } // image - else if(el_name === 'g' || el_name === 'use') { - $('#container_panel').show(); - $('.action_group_selected').removeClass('disabled'); - 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); - } - } - } - menu_items[(el_name === 'g' ? 'en':'dis') + 'ableContextMenuItems']('#ungroup'); - menu_items[((el_name === 'g' || !multiselected) ? 'dis':'en') + 'ableContextMenuItems']('#group'); - } // if (elem != null) - else if (multiselected) { - $('#multiselected_panel').show(); - $('.action_multi_selected').removeClass('disabled'); - menu_items - .enableContextMenuItems('#group') - .disableContextMenuItems('#ungroup'); - } else { - menu_items.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); - } - - // update history buttons - if (undoMgr.getUndoStackSize() > 0) { - $('#tool_undo').removeClass( 'disabled'); - } - else { - $('#tool_undo').addClass( 'disabled'); - } - if (undoMgr.getRedoStackSize() > 0) { - $('#tool_redo').removeClass( 'disabled'); - } - else { - $('#tool_redo').addClass( 'disabled'); - } - - svgCanvas.addedNew = false; - - if ( (elem && !is_node) || multiselected) { - // update the selected elements' layer - $('#selLayerNames').removeAttr('disabled').val(currentLayerName); - - // Enable regular menu options - canv_menu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); - } - else { - $('#selLayerNames').attr('disabled', 'disabled'); - } - }; - - $('#text').focus( function(){ textBeingEntered = true; } ); - $('#text').blur( function(){ textBeingEntered = false; } ); - - // bind the selected event to our function that handles updates to the UI - svgCanvas.bind("selected", selectedChanged); - svgCanvas.bind("transition", elementTransition); - svgCanvas.bind("changed", elementChanged); - svgCanvas.bind("saved", saveHandler); - svgCanvas.bind("exported", exportHandler); - svgCanvas.bind("zoomed", zoomChanged); - svgCanvas.bind("contextset", contextChanged); - svgCanvas.bind("extension_added", extAdded); - svgCanvas.textActions.setInputElem($("#text")[0]); - - var str = '
            ' - $.each(palette, function(i,item){ - str += '
            '; - }); - $('#palette').append(str); - - // Set up editor background functionality - // TODO add checkerboard as "pattern" - var color_blocks = ['#FFF','#888','#000']; // ,'url(data:image/gif;base64,R0lGODlhEAAQAIAAAP%2F%2F%2F9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG%2Bgq4jM3IFLJgpswNly%2FXkcBpIiVaInlLJr9FZWAQA7)']; - var str = ''; - $.each(color_blocks, function() { - str += '
            '; - }); - $('#bg_blocks').append(str); - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - blocks.each(function() { - var blk = $(this); - blk.click(function() { - blocks.removeClass(cur_bg); - $(this).addClass(cur_bg); - }); - }); - - if($.pref('bkgd_color')) { - setBackground($.pref('bkgd_color'), $.pref('bkgd_url')); - } else if($.pref('bkgd_url')) { - // No color set, only URL - setBackground(defaultPrefs.bkgd_color, $.pref('bkgd_url')); - } - - if($.pref('img_save')) { - curPrefs.img_save = $.pref('img_save'); - $('#image_save_opts input').val([curPrefs.img_save]); - } - - var changeRectRadius = function(ctl) { - svgCanvas.setRectRadius(ctl.value); - } - - var changeFontSize = function(ctl) { - svgCanvas.setFontSize(ctl.value); - } - - var changeStrokeWidth = function(ctl) { - var val = ctl.value; - if(val == 0 && selectedElement && ['line', 'polyline'].indexOf(selectedElement.nodeName) >= 0) { - val = ctl.value = 1; - } - svgCanvas.setStrokeWidth(val); - } - - var changeRotationAngle = function(ctl) { - svgCanvas.setRotationAngle(ctl.value); - $('#tool_reorient').toggleClass('disabled', ctl.value == 0); - } - var changeZoom = function(ctl) { - var zoomlevel = ctl.value / 100; - if(zoomlevel < .001) { - ctl.value = .1; - return; - } - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - - zoomChanged(window, { - width: 0, - height: 0, - // center pt of scroll position - x: (w_area[0].scrollLeft + w_area.width()/2)/zoom, - y: (w_area[0].scrollTop + w_area.height()/2)/zoom, - zoom: zoomlevel - }, true); - } - - var changeOpacity = function(ctl, val) { - if(val == null) val = ctl.value; - $('#group_opacity').val(val); - if(!ctl || !ctl.handle) { - $('#opac_slider').slider('option', 'value', val); - } - svgCanvas.setOpacity(val/100); - } - - var changeBlur = function(ctl, val, noUndo) { - if(val == null) val = ctl.value; - $('#blur').val(val); - var complete = false; - if(!ctl || !ctl.handle) { - $('#blur_slider').slider('option', 'value', val); - complete = true; - } - if(noUndo) { - svgCanvas.setBlurNoUndo(val); - } else { - svgCanvas.setBlur(val, complete); - } - } - - var operaRepaint = function() { - // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change - if(!window.opera) return; - $('

            ').hide().appendTo('body').remove(); - } - - $('#stroke_style').change(function(){ - svgCanvas.setStrokeAttr('stroke-dasharray', $(this).val()); - operaRepaint(); - }); - - $('#stroke_linejoin').change(function(){ - svgCanvas.setStrokeAttr('stroke-linejoin', $(this).val()); - operaRepaint(); - }); - - - // Lose focus for select elements when changed (Allows keyboard shortcuts to work better) - $('select').change(function(){$(this).blur();}); - - // fired when user wants to move elements to another layer - var promptMoveLayerOnce = false; - $('#selLayerNames').change(function(){ - var destLayer = this.options[this.selectedIndex].value; - var confirm_str = uiStrings.notification.QmoveElemsToLayer.replace('%s',destLayer); - var moveToLayer = function(ok) { - if(!ok) return; - promptMoveLayerOnce = true; - svgCanvas.moveSelectedToLayer(destLayer); - svgCanvas.clearSelection(); - populateLayers(); - } - if (destLayer) { - if(promptMoveLayerOnce) { - moveToLayer(true); - } else { - $.confirm(confirm_str, moveToLayer); - } - } - }); - - $('#font_family').change(function() { - svgCanvas.setFontFamily(this.value); - }); - - $('#seg_type').change(function() { - svgCanvas.setSegType($(this).val()); - }); - - $('#text').keyup(function(){ - svgCanvas.setTextContent(this.value); - }); - - $('#image_url').change(function(){ - setImageURL(this.value); - }); - - $('#link_url').change(function() { - if(this.value.length) { - svgCanvas.setLinkURL(this.value); - } else { - svgCanvas.removeHyperlink(); - } - }); - - $('#g_title').change(function() { - svgCanvas.setGroupTitle(this.value); - }); - - $('.attr_changer').change(function() { - var attr = this.getAttribute("data-attr"); - var val = this.value; - var valid = svgedit.units.isValidUnit(attr, val, selectedElement); - if(!valid) { - $.alert(uiStrings.notification.invalidAttrValGiven); - this.value = selectedElement.getAttribute(attr); - return false; - } - else{ - this.blur() - } - - if (attr !== "id") { - if (isNaN(val)) { - val = svgCanvas.convertToNum(attr, val); - } else if(curConfig.baseUnit !== 'px') { - // Convert unitless value to one with given unit - - var unitData = svgedit.units.getTypeMap(); - - if(selectedElement[attr] || svgCanvas.getMode() === "pathedit" || attr === "x" || attr === "y") { - val *= unitData[curConfig.baseUnit]; - } - } - } - - // if the user is changing the id, then de-select the element first - // change the ID, then re-select it with the new ID - if (attr === "id") { - var elem = selectedElement; - svgCanvas.clearSelection(); - elem.id = val; - svgCanvas.addToSelection([elem],true); - } - else { - svgCanvas.changeSelectedAttribute(attr, val); - } - this.blur(); - }); - - // Prevent selection of elements when shift-clicking - $('#palette').mouseover(function() { - var inp = $(''); - $(this).append(inp); - inp.focus().remove(); - }); - - $('.palette_item').mousedown(function(evt){ - var isStroke = $('#tool_stroke').hasClass('active'); - var picker = isStroke ? "stroke" : "fill"; - var color = $(this).attr('data-rgb'); - var paint = null; - - // Webkit-based browsers returned 'initial' here for no stroke - console.log(color); - if (color === 'transparent' || color === 'initial' || color === '#none') { - color = 'none'; - paint = new $.jGraduate.Paint(); - } - else { - paint = new $.jGraduate.Paint({alpha: 100, solidColor: color.substr(1)}); - } - - paintBox[picker].setPaint(paint); - - if (isStroke) { - svgCanvas.setColor('stroke', color); - if (color != 'none' && svgCanvas.getStrokeOpacity() != 1) { - svgCanvas.setPaintOpacity('stroke', 1.0); - } - } else { - svgCanvas.setColor('fill', color); - if (color != 'none' && svgCanvas.getFillOpacity() != 1) { - svgCanvas.setPaintOpacity('fill', 1.0); - } - } - updateToolButtonState(); - }).bind('contextmenu', function(e) {e.preventDefault()}); - - $("#toggle_stroke_tools").toggle(function() { - $(".stroke_tool").css('display','table-cell'); - $(this).addClass('expanded'); - resetScrollPos(); - }, function() { - $(".stroke_tool").css('display','none'); - $(this).removeClass('expanded'); - resetScrollPos(); - }); - - // This is a common function used when a tool has been clicked (chosen) - // It does several common things: - // - removes the tool_button_current class from whatever tool currently has it - // - hides any flyouts - // - adds the tool_button_current class to the button passed in - var toolButtonClick = function(button, noHiding) { - if ($(button).hasClass('disabled')) return false; - if($(button).parent().hasClass('tools_flyout')) return true; - var fadeFlyouts = fadeFlyouts || 'normal'; - if(!noHiding) { - $('.tools_flyout').fadeOut(fadeFlyouts); - } - $('#styleoverrides').text(''); - $('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $(button).addClass('tool_button_current').removeClass('tool_button'); - return true; - }; - - (function() { - var last_x = null, last_y = null, w_area = workarea[0], - panning = false, keypan = false; - - $('#svgcanvas').bind('mousemove mouseup', function(evt) { - if(panning === false) return; - - w_area.scrollLeft -= (evt.clientX - last_x); - w_area.scrollTop -= (evt.clientY - last_y); - - last_x = evt.clientX; - last_y = evt.clientY; - - if(evt.type === 'mouseup') panning = false; - return false; - }).mousedown(function(evt) { - if(evt.button === 1 || keypan === true) { - panning = true; - last_x = evt.clientX; - last_y = evt.clientY; - return false; - } - }); - - $(window).mouseup(function() { - panning = false; - }); - - $(document).bind('keydown', 'space', function(evt) { - svgCanvas.spaceKey = keypan = true; - evt.preventDefault(); - }).bind('keyup', 'space', function(evt) { - evt.preventDefault(); - svgCanvas.spaceKey = keypan = false; - }).bind('keydown', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.addClass('out'); - } - }).bind('keyup', 'alt', function(evt) { - if(svgCanvas.getMode() === 'zoom') { - workarea.removeClass('out'); - } - }) - }()); - - - function setStrokeOpt(opt, changeElem) { - var id = opt.id; - var bits = id.split('_'); - var pre = bits[0]; - var val = bits[1]; - - if(changeElem) { - svgCanvas.setStrokeAttr('stroke-' + pre, val); - } - operaRepaint(); - setIcon('#cur_' + pre , id, 20); - $(opt).addClass('current').siblings().removeClass('current'); - } - - //menu handling - var menus = $('.menu'); - var blinker = function(e) { - e.target.style.background = "#fff"; - setTimeout(function(){e.target.style.background = "#ddd";}, 50); - setTimeout(function(){e.target.style.background = "#fff";}, 150); - setTimeout(function(){e.target.style.background = "#ddd";}, 200); - setTimeout(function(){e.target.style.background = "";}, 200); - setTimeout(function(){$('#menu_bar').removeClass('active')}, 220); - return false; - } - var closer = function(e){ - if (!$(e.target).hasClass("menu_title") && $('#menu_bar').hasClass("active")) { - if(!$(e.target).hasClass("disabled") && $(e.target).hasClass("menu_item")) { - blinker(e); - return; - } - $('#menu_bar').removeClass('active') - $('.tools_flyout').hide(); - $('input').blur(); - } - } - $('.menu_item').live('click', function(e){blinker(e)}); - $("svg, body").on('click', function(e){closer(e)}); - $('.menu_title').on('click', function() {$("#menu_bar").toggleClass('active');}); - $('.menu_title').on('mouseover', function() { - menus.removeClass('open'); - $(this).parent().addClass('open'); - }); - - // Made public for UI customization. - // TODO: Group UI functions into a public svgEditor.ui interface. - Editor.addDropDown = function(elem, callback, dropUp) { - if ($(elem).length == 0) return; // Quit if called on non-existant element - var button = $(elem).find('button'); - - var list = $(elem).find('ul').attr('id', $(elem)[0].id + '-list'); - - if(!dropUp) { - // Move list to place where it can overflow container - $('#option_lists').append(list); - } - - var on_button = false; - if(dropUp) { - $(elem).addClass('dropup'); - } - - list.find('li').bind('mouseup', callback); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - } - on_button = false; - }); - - button.bind('mousedown',function() { - if (!button.hasClass('down')) { - button.addClass('down'); - - if(!dropUp) { - var pos = $(elem).offset(); - // position slider - list.css({ - top: pos.top, - left: pos.left - 110 - }); - } - list.show(); - - on_button = true; - } else { - button.removeClass('down'); - list.hide(); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - } - - // TODO: Combine this with addDropDown or find other way to optimize - var addAltDropDown = function(elem, list, callback, opts) { - var button = $(elem); - var list = $(list); - var on_button = false; - var dropUp = opts.dropUp; - if(dropUp) { - $(elem).addClass('dropup'); - } - list.find('li').bind('mouseup', function() { - if(opts.seticon) { - setIcon('#cur_' + button[0].id , $(this).children()); - $(this).addClass('current').siblings().removeClass('current'); - } - callback.apply(this, arguments); - - }); - - $(window).mouseup(function(evt) { - if(!on_button) { - button.removeClass('down'); - list.hide(); - list.css({top:0, left:0}); - } - on_button = false; - }); - - var height = list.height(); - $(elem).bind('mousedown',function() { - var off = $(elem).offset(); - if(dropUp) { - off.top -= list.height(); - off.left += 8; - } else { - off.top += $(elem).height(); - } - $(list).offset(off); - - if (!button.hasClass('down')) { - button.addClass('down'); - list.show(); - on_button = true; - return false; - } else { - button.removeClass('down'); - // CSS position must be reset for Webkit - list.hide(); - list.css({top:0, left:0}); - } - }).hover(function() { - on_button = true; - }).mouseout(function() { - on_button = false; - }); - - if(opts.multiclick) { - list.mousedown(function() { - on_button = true; - }); - } - } - - Editor.addDropDown('#font_family_dropdown', function() { - var fam = $(this).text(); - $('#font_family').val($(this).text()).change(); - }); - - Editor.addDropDown('#opacity_dropdown', function() { - if($(this).find('div').length) return; - var perc = parseInt($(this).text().split('%')[0]); - changeOpacity(false, perc); - }, false); - - // For slider usage, see: http://jqueryui.com/demos/slider/ - $("#opac_slider").slider({ - start: function() { - $('#opacity_dropdown li:not(.special)').hide(); - }, - stop: function() { - $('#opacity_dropdown li').show(); - $(window).mouseup(); - }, - slide: function(evt, ui){ - changeOpacity(ui); - } - }); - - Editor.addDropDown('#blur_dropdown', $.noop); - - var slideStart = false; - - $("#blur_slider").slider({ - max: 10, - step: .1, - stop: function(evt, ui) { - slideStart = false; - changeBlur(ui); - $('#blur_dropdown li').show(); - $(window).mouseup(); - }, - start: function() { - slideStart = true; - }, - slide: function(evt, ui){ - changeBlur(ui, null, slideStart); - } - }); - - - Editor.addDropDown('#zoom_dropdown', function() { - var item = $(this); - var val = item.attr('data-val'); - if(val) { - zoomChanged(window, val); - } else { - changeZoom({value:parseInt(item.text())}); - } - }, true); - - addAltDropDown('#stroke_linecap', '#linecap_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - addAltDropDown('#stroke_linejoin', '#linejoin_opts', function() { - setStrokeOpt(this, true); - }, {dropUp: true}); - - $('div', '#position_opts').each(function(){ - this.addEventListener("mouseup", function(){ - var letter = this.id.replace('tool_pos','').charAt(0); - svgCanvas.alignSelectedElements(letter, 'page'); - }) - }); - - /* - - When a flyout icon is selected - (if flyout) { - - Change the icon - - Make pressing the button run its stuff - } - - Run its stuff - - When its shortcut key is pressed - - If not current in list, do as above - , else: - - Just run its stuff - - */ - - // Unfocus text input when workarea is mousedowned. - (function() { - var inp; - var unfocus = function() { - $(inp).blur(); - } - - $('#svg_editor').find('button, select, input:not(#text)').focus(function() { - inp = this; - ui_context = 'toolbars'; - workarea.mousedown(unfocus); - }).blur(function() { - ui_context = 'canvas'; - workarea.unbind('mousedown', unfocus); - // Go back to selecting text if in textedit mode - if(svgCanvas.getMode() == 'textedit') { - $('#text').focus(); - } - }); - - }()); - - var clickSelect = function() { - if (toolButtonClick('#tool_select')) { - svgCanvas.setMode('select'); - $('#styleoverrides').text('#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}'); - } - }; - - var clickFHPath = function() { - if (toolButtonClick('#tool_fhpath')) { - svgCanvas.setMode('fhpath'); - } - }; - - var clickLine = function() { - if (toolButtonClick('#tool_line')) { - svgCanvas.setMode('line'); - } - }; - - var clickSquare = function(){ - if (toolButtonClick('#tool_square')) { - svgCanvas.setMode('square'); - } - }; - - var clickRect = function(){ - if (toolButtonClick('#tool_rect')) { - svgCanvas.setMode('rect'); - } - }; - - var clickFHRect = function(){ - if (toolButtonClick('#tool_fhrect')) { - svgCanvas.setMode('fhrect'); - } - }; - - var clickCircle = function(){ - if (toolButtonClick('#tool_circle')) { - svgCanvas.setMode('circle'); - } - }; - - var clickEllipse = function(){ - if (toolButtonClick('#tool_ellipse')) { - svgCanvas.setMode('ellipse'); - } - }; - - var clickFHEllipse = function(){ - if (toolButtonClick('#tool_fhellipse')) { - svgCanvas.setMode('fhellipse'); - } - }; - - var clickImage = function(){ - if (toolButtonClick('#tool_image')) { - svgCanvas.setMode('image'); - } - }; - - var clickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - svgCanvas.setMode('zoom'); - } - }; - - var dblclickZoom = function(){ - if (toolButtonClick('#tool_zoom')) { - zoomImage(); - setSelectMode(); - } - }; - - var clickText = function(){ - if (toolButtonClick('#tool_text')) { - svgCanvas.setMode('text'); - } - }; - - var clickPath = function(){ - if (toolButtonClick('#tool_path')) { - svgCanvas.setMode('path'); - } - }; - - // Delete is a contextual tool that only appears in the ribbon if - // an element has been selected - var deleteSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.deleteSelectedElements(); - } - }; - - var cutSelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.cutSelectedElements(); - } - }; - - var copySelected = function() { - if (selectedElement != null || multiselected) { - svgCanvas.copySelectedElements(); - } - }; - - var pasteInCenter = function() { - var zoom = svgCanvas.getZoom(); - - var x = (workarea[0].scrollLeft + workarea.width()/2)/zoom - svgCanvas.contentW; - var y = (workarea[0].scrollTop + workarea.height()/2)/zoom - svgCanvas.contentH; - svgCanvas.pasteElements('point', x, y); - } - - var moveToTopSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToTopSelectedElement(); - } - }; - - var moveToBottomSelected = function() { - if (selectedElement != null) { - svgCanvas.moveToBottomSelectedElement(); - } - }; - - var moveUpSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Up"); - } - }; - - var moveDownSelected = function() { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected("Down"); - } - }; - - var moveUpDownSelected = function(dir) { - if (selectedElement != null) { - svgCanvas.moveUpDownSelected(dir); - } - }; - - var convertToPath = function() { - if (selectedElement != null) { - svgCanvas.convertToPath(); - } - } - - var reorientPath = function() { - if (selectedElement != null) { - path.reorient(); - } - } - - var makeHyperlink = function() { - if (selectedElement != null || multiselected) { - $.prompt(uiStrings.notification.enterNewLinkURL, "http://", function(url) { - if(url) svgCanvas.makeHyperlink(url); - }); - } - } - - var moveSelected = function(dx,dy) { - if (selectedElement != null || multiselected) { - if(curConfig.gridSnapping) { - // Use grid snap value regardless of zoom level - var multi = svgCanvas.getZoom() * curConfig.snappingStep; - dx *= multi; - dy *= multi; - } - svgCanvas.moveSelectedElements(dx,dy); - } - }; - - var linkControlPoints = function() { - var linked = !$('#tool_node_link').hasClass('push_button_pressed'); - if (linked) - $('#tool_node_link').addClass('push_button_pressed').removeClass('tool_button').find("input").attr("checked", true); - else - $('#tool_node_link').removeClass('push_button_pressed').addClass('tool_button').find("input").attr("checked", false); - - path.linkControlPoints(linked); - } - - var clonePathNode = function() { - if (path.getNodePoint()) { - path.clonePathNode(); - } - }; - - var deletePathNode = function() { - if (path.getNodePoint()) { - path.deletePathNode(); - } - }; - - var addSubPath = function() { - var button = $('#tool_add_subpath'); - var sp = !button.hasClass('push_button_pressed'); - if (sp) { - button.addClass('push_button_pressed').removeClass('tool_button'); - } else { - button.removeClass('push_button_pressed').addClass('tool_button'); - } - - path.addSubPath(sp); - - }; - - var opencloseSubPath = function() { - path.opencloseSubPath(); - } - - var selectNext = function() { - svgCanvas.cycleElement(1); - }; - - var selectPrev = function() { - svgCanvas.cycleElement(0); - }; - - var rotateSelected = function(cw,step) { - if (selectedElement == null || multiselected) return; - if(!cw) step *= -1; - var new_angle = $('#angle').val()*1 + step; - svgCanvas.setRotationAngle(new_angle); - updateContextPanel(); - }; - - var clickClear = function(){ - var dims = curConfig.dimensions; - $.confirm(uiStrings.notification.QwantToClear, function(ok) { - if(!ok) return; - setSelectMode(); - svgCanvas.clear(); - svgCanvas.setResolution(dims[0], dims[1]); - updateCanvas(true); - zoomImage(); - populateLayers(); - updateContextPanel(); - prepPaints(); - svgCanvas.runExtensions('onNewDocument'); - }); - }; - - var clickBold = function(){ - svgCanvas.setBold( !svgCanvas.getBold() ); - updateContextPanel(); - return false; - }; - - var clickItalic = function(){ - svgCanvas.setItalic( !svgCanvas.getItalic() ); - updateContextPanel(); - return false; - }; - - var clickSave = function(){ - // In the future, more options can be provided here - var saveOpts = { - 'images': curPrefs.img_save, - 'round_digits': 6 - } - svgCanvas.save(saveOpts); - }; - - var clickExport = function() { - // Open placeholder window (prevents popup) - if(!customHandlers.pngsave) { - var str = uiStrings.notification.loadingImage; - exportWindow = window.open("data:text/html;charset=utf-8," + str + "<\/title><h1>" + str + "<\/h1>"); - } - - if(window.canvg) { - svgCanvas.rasterExport(); - } else { - $.getScript('canvg/rgbcolor.js', function() { - $.getScript('canvg/canvg.js', function() { - svgCanvas.rasterExport(); - }); - }); - } - } - - // by default, svgCanvas.open() is a no-op. - // it is up to an extension mechanism (opera widget, etc) - // to call setCustomHandlers() which will make it do something - var clickOpen = function(){ - svgCanvas.open(); - }; - var clickImport = function(){ - }; - - var flash = function($menu){ - var menu_title = $menu.prev(); - menu_title.css("background", "#09f"); - setTimeout(function(){menu_title.css("background", "")}, 200); - } - - var clickUndo = function(){ - if (undoMgr.getUndoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.undo(); - populateLayers(); - } - }; - - var clickRedo = function(){ - if (undoMgr.getRedoStackSize() > 0) { - if (window.event.type === "keydown") flash($('#edit_menu')); - undoMgr.redo(); - populateLayers(); - } - }; - - var clickGroup = function(){ - // group - if (multiselected) { - svgCanvas.groupSelectedElements(); - } - // ungroup - else if(selectedElement){ - svgCanvas.ungroupSelectedElement(); - } - }; - - var clickClone = function(){ - if (window.event.type === "keydown") flash($('#edit_menu')); - svgCanvas.cloneSelectedElements(20,20); - }; - - var clickAlign = function() { - var letter = this.id.replace('tool_align','').charAt(0); - svgCanvas.alignSelectedElements(letter, $('#align_relative_to').val()); - }; - - var clickSwitch = function() { - var stroke_rect = document.querySelector('#tool_stroke rect'); - var fill_rect = document.querySelector('#tool_fill rect'); - var fill_color = fill_rect.getAttribute("fill"); - var stroke_color = stroke_rect.getAttribute("fill"); - var stroke_opacity = parseFloat(stroke_rect.getAttribute("stroke-opacity")); - if (isNaN(stroke_opacity)) {stroke_opacity = 100;} - var fill_opacity = parseFloat(fill_rect.getAttribute("fill-opacity")); - if (isNaN(fill_opacity)) {fill_opacity = 100;} - var stroke = getPaint(stroke_color, stroke_opacity, "stroke"); - var fill = getPaint(fill_color, fill_opacity, "fill"); - paintBox.fill.setPaint(stroke, true); - paintBox.stroke.setPaint(fill, true); - - }; - - var zoomImage = function(multiplier) { - var res = svgCanvas.getResolution(); - multiplier = multiplier?res.zoom * multiplier:1; - // setResolution(res.w * multiplier, res.h * multiplier, true); - $('#zoom').val(multiplier * 100); - svgCanvas.setZoom(multiplier); - zoomDone(); - updateCanvas(true); - }; - - var zoomDone = function() { - // updateBgImage(); - updateWireFrame(); - //updateCanvas(); // necessary? - } - - var clickWireframe = function() { - var wf = !$('#tool_wireframe').hasClass('push_button_pressed'); - if (wf) - $('#tool_wireframe').addClass('push_button_pressed'); - else - $('#tool_wireframe').removeClass('push_button_pressed'); - workarea.toggleClass('wireframe'); - - if(supportsNonSS) return; - var wf_rules = $('#wireframe_rules'); - if(!wf_rules.length) { - wf_rules = $('<style id="wireframe_rules"><\/style>').appendTo('head'); - } else { - wf_rules.empty(); - } - - updateWireFrame(); - } - - var clickRulers = function() { - var rulers = !$('#tool_rulers').hasClass('push_button_pressed'); - if (rulers) { - $('#tool_rulers').addClass('push_button_pressed'); - $('#show_rulers').attr("checked", true); - curConfig.showRulers = true; - } - else { - $('#tool_rulers').removeClass('push_button_pressed'); - $('#show_rulers').attr("checked", false); - curConfig.showRulers = false; - } - $('#rulers').toggle(!!curConfig.showRulers) - } - - var updateWireFrame = function() { - // Test support - if(supportsNonSS) return; - - var rule = "#workarea.wireframe #svgcontent * { stroke-width: " + 1/svgCanvas.getZoom() + "px; }"; - $('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ""); - } - - var showSourceEditor = function(e, forSaving){ - if (editingsource) return; - editingsource = true; - - $('#save_output_btns').toggle(!!forSaving); - $('#tool_source_back').toggle(!forSaving); - - var str = orig_source = svgCanvas.getSvgString(); - $('#svg_source_textarea').val(str); - $('#svg_source_editor').fadeIn(); - properlySourceSizeTextArea(); - $('#svg_source_textarea').focus(); - }; - - var showDocProperties = function(){ - if (docprops) return; - docprops = true; - - // This selects the correct radio button by using the array notation - $('#image_save_opts input').val([curPrefs.img_save]); - - // update resolution option with actual resolution - var res = svgCanvas.getResolution(); - if(curConfig.baseUnit !== "px") { - res.w = svgedit.units.convertUnit(res.w) + curConfig.baseUnit; - res.h = svgedit.units.convertUnit(res.h) + curConfig.baseUnit; - } - $('.canvas_width').val(res.w); - $('.canvas_height').val(res.h); - $('#canvas_title').val(svgCanvas.getDocumentTitle()); - - $('#svg_docprops').show(); - }; - - var showPreferences = function(){ - if (preferences) return; - preferences = true; - - // Update background color with current one - var blocks = $('#bg_blocks div'); - var cur_bg = 'cur_background'; - var canvas_bg = $.pref('bkgd_color'); - var url = $.pref('bkgd_url'); - // if(url) url = url[1]; - blocks.each(function() { - var blk = $(this); - var is_bg = blk.css('background-color') == canvas_bg; - blk.toggleClass(cur_bg, is_bg); - if(is_bg) $('#canvas_bg_url').removeClass(cur_bg); - }); - if(!canvas_bg) blocks.eq(0).addClass(cur_bg); - if(url) { - $('#canvas_bg_url').val(url); - } - $('grid_snapping_step').attr('value', curConfig.snappingStep); - if (curConfig.gridSnapping == true) { - $('#grid_snapping_on').attr('checked', 'checked'); - } else { - $('#grid_snapping_on').removeAttr('checked'); - } - - $('#svg_prefs').show(); - }; - - var properlySourceSizeTextArea = function(){ - // TODO: remove magic numbers here and get values from CSS - var height = $('#svg_source_container').height() - 50; - $('#svg_source_textarea').css('height', height); - }; - - var saveSourceEditor = function(){ - if (!editingsource) return; - - var saveChanges = function() { - svgCanvas.clearSelection(); - hideSourceEditor(); - zoomImage(); - populateLayers(); - updateTitle(); - prepPaints(); - } - - if (!svgCanvas.setSvgString($('#svg_source_textarea').val())) { - $.confirm(uiStrings.notification.QerrorsRevertToSource, function(ok) { - if(!ok) return false; - saveChanges(); - }); - } else { - saveChanges(); - } - setSelectMode(); - }; - - var updateTitle = function(title) { - title = title || svgCanvas.getDocumentTitle(); - var new_title = orig_title + (title?': ' + title:''); - - // Remove title update with current context info, isn't really necessary -// if(cur_context) { -// new_title = new_title + cur_context; -// } - $('title:first').text(new_title); - } - - var saveDocProperties = function(){ - - // update resolution - var width = $('#canvas_width'), w = width.val(); - var height = $('#canvas_height'), h = height.val(); - - if(w != "fit" && !svgedit.units.isValidUnit('width', w)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - width.parent().addClass('error'); - return false; - } - - width.parent().removeClass('error'); - - if(h != "fit" && !svgedit.units.isValidUnit('height', h)) { - $.alert(uiStrings.notification.invalidAttrValGiven); - height.parent().addClass('error'); - return false; - } - - height.parent().removeClass('error'); - - if(!svgCanvas.setResolution(w, h)) { - $.alert(uiStrings.notification.noContentToFitTo); - return false; - } - - // set image save option - curPrefs.img_save = $('#image_save_opts :checked').val(); - $.pref('img_save',curPrefs.img_save); - updateCanvas(); - hideDocProperties(); - }; - - var savePreferences = function() { - // set background - var color = $('#bg_blocks div.cur_background').css('background-color') || '#FFF'; - setBackground(color, $('#canvas_bg_url').val()); - - // set language - var lang = $('#lang_select').val(); - if(lang != curPrefs.lang) { - Editor.putLocale(lang); - } - - // set icon size - setIconSize($('#iconsize').val()); - - // set grid setting - curConfig.gridSnapping = $('#grid_snapping_on')[0].checked; - curConfig.snappingStep = $('#grid_snapping_step').val(); - curConfig.showRulers = $('#show_rulers')[0].checked; - - $('#rulers').toggle(curConfig.showRulers); - if(curConfig.showRulers) updateRulers(); - curConfig.baseUnit = $('#base_unit').val(); - - svgCanvas.setConfig(curConfig); - - updateCanvas(); - hidePreferences(); - } - - function setBackground(color, url) { -// if(color == curPrefs.bkgd_color && url == curPrefs.bkgd_url) return; - $.pref('bkgd_color', color); - $.pref('bkgd_url', url); - - // This should be done in svgcanvas.js for the borderRect fill - svgCanvas.setBackground(color, url); - } - - var setIcon = Editor.setIcon = function(elem, icon_id, forcedSize) { - var icon = (typeof icon_id === 'string') ? $.getSvgIcon(icon_id, true) : icon_id.clone(); - if(!icon) { - console.log('NOTE: Icon image missing: ' + icon_id); - return; - } - - $(elem).append(icon); - } - - 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); - - - // 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}); -// } - - // 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'} -// }, - "#tools_top": { - 'left': 50, - 'height': 72 - }, - "#tools_left": { - 'width': 31, - 'top': 74 - }, - "div#workarea": { - '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'} -// } - }; - - var rule_elem = $('#tool_size_rules'); - if(!rule_elem.length) { - rule_elem = $('<style id="tool_size_rules"><\/style>').appendTo('head'); - } else { - rule_elem.empty(); - } - - if(size != 'm') { - var style_str = ''; - $.each(cssResizeRules, function(selector, rules) { - selector = '#svg_editor ' + selector.replace(/,/g,', #svg_editor'); - style_str += selector + '{'; - $.each(rules, function(prop, values) { - 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); - } - - setFlyoutPositions(); - } - - var cancelOverlays = function() { - $('#dialog_box').hide(); - if (!editingsource && !docprops && !preferences) { - if(cur_context) { - svgCanvas.leaveContext(); - } - return; - }; - - if (editingsource) { - if (orig_source !== $('#svg_source_textarea').val()) { - $.confirm(uiStrings.notification.QignoreSourceChanges, function(ok) { - if(ok) hideSourceEditor(); - }); - } else { - hideSourceEditor(); - } - } - else if (docprops) { - hideDocProperties(); - } else if (preferences) { - hidePreferences(); - } - resetScrollPos(); - }; - - var hideSourceEditor = function(){ - $('#svg_source_editor').hide(); - editingsource = false; - $('#svg_source_textarea').blur(); - }; - - var hideDocProperties = function(){ - $('#svg_docprops').hide(); - $('#canvas_width,#canvas_height').removeAttr('disabled'); - $('#resolution')[0].selectedIndex = 0; - $('#image_save_opts input').val([curPrefs.img_save]); - docprops = false; - }; - - var hidePreferences = function(){ - $('#svg_prefs').hide(); - preferences = false; - }; - - var win_wh = {width:$(window).width(), height:$(window).height()}; - - var resetScrollPos = $.noop, curScrollPos; - - // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9) - if(svgedit.browser.isIE()) { - (function() { - resetScrollPos = function() { - if(workarea[0].scrollLeft === 0 - && workarea[0].scrollTop === 0) { - workarea[0].scrollLeft = curScrollPos.left; - workarea[0].scrollTop = curScrollPos.top; - } - } - - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - - $(window).resize(resetScrollPos); - svgEditor.ready(function() { - // TODO: Find better way to detect when to do this to minimize - // flickering effect - setTimeout(function() { - resetScrollPos(); - }, 500); - }); - - workarea.scroll(function() { - curScrollPos = { - left: workarea[0].scrollLeft, - top: workarea[0].scrollTop - }; - }); - }()); - } - - $(window).resize(function(evt) { - if (editingsource) { - properlySourceSizeTextArea(); - } - - $.each(win_wh, function(type, val) { - var curval = $(window)[type](); - workarea[0]['scroll' + (type==='width'?'Left':'Top')] -= (curval - val)/2; - win_wh[type] = curval; - }); - }); - - (function() { - workarea.scroll(function() { - // TODO: jQuery's scrollLeft/Top() wouldn't require a null check - if ($('#ruler_x').length != 0) { - $('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; - } - if ($('#ruler_y').length != 0) { - $('#ruler_y')[0].scrollTop = workarea[0].scrollTop; - } - }); - - }()); - - $('#url_notice').click(function() { - $.alert(this.title); - }); - - $('#change_image_url').click(promptImgURL); - - function promptImgURL() { - var curhref = svgCanvas.getHref(selectedElement); - curhref = curhref.indexOf("data:") === 0?"":curhref; - $.prompt(uiStrings.notification.enterNewImgURL, curhref, function(url) { - if(url) setImageURL(url); - }); - } - - // added these event handlers for all the push buttons so they - // behave more like buttons being pressed-in and not images - (function() { - var toolnames = ['clear','open','save','source','delete','delete_multi','paste','clone','clone_multi','move_top','move_bottom']; - var all_tools = ''; - var cur_class = 'tool_button_current'; - - $.each(toolnames, function(i,item) { - all_tools += '#tool_' + item + (i==toolnames.length-1?',':''); - }); - - $(all_tools).mousedown(function() { - $(this).addClass(cur_class); - }).bind('mousedown mouseout', function() { - $(this).removeClass(cur_class); - }); - - $('#tool_undo, #tool_redo').mousedown(function(){ - if (!$(this).hasClass('disabled')) $(this).addClass(cur_class); - }).bind('mousedown mouseout',function(){ - $(this).removeClass(cur_class);} - ); - }()); - - // switch modifier key in tooltips if mac - // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta - // in Opera and Chrome - if (isMac && !window.opera) { - var shortcutButtons = ["tool_clear", "tool_save", "tool_source", "tool_undo", "tool_redo", "tool_clone"]; - var i = shortcutButtons.length; - while (i--) { - var button = document.getElementById(shortcutButtons[i]); - if (button != null) { - var title = button.title; - var index = title.indexOf("Ctrl+"); - button.title = [title.substr(0, index), "Cmd+", title.substr(index + 5)].join(''); - } - } - } - - // TODO: go back to the color boxes having white background-color and then setting - // background-image to none.png (otherwise partially transparent gradients look weird) - var colorPicker = function(elem) { - var picker = elem.attr('id') == 'stroke_color' ? 'stroke' : 'fill'; -// var opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); - var paint = paintBox[picker].paint; - var title = (picker == 'stroke' ? 'Pick a Stroke Paint and Opacity' : 'Pick a Fill Paint and Opacity'); - var was_none = false; - var pos = elem.position(); - $("#color_picker") - .draggable({cancel:'.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window'}) - .css(curConfig.colorPickerCSS || {'left': pos.left, 'bottom': 50 - pos.top}) - .jGraduate( - { - paint: paint, - window: { pickerTitle: title }, - images: { clientPath: curConfig.jGraduatePath }, - newstop: 'inverse' - }, - function(p) { - paint = new $.jGraduate.Paint(p); - - paintBox[picker].setPaint(paint); - svgCanvas.setPaint(picker, paint); - - $('#color_picker').hide(); - }, - function(p) { - $('#color_picker').hide(); - }); - }; - - var updateToolButtonState = function() { - var bNoFill = (svgCanvas.getColor('fill') == 'none'); - var bNoStroke = (svgCanvas.getColor('stroke') == 'none'); - var buttonsNeedingStroke = [ '#tool_fhpath', '#tool_line' ]; - var buttonsNeedingFillAndStroke = [ '#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; - if (bNoStroke) { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingStroke) { - var button = buttonsNeedingStroke[index]; - $(button).removeClass('disabled'); - } - } - - if (bNoStroke && bNoFill) { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - if ($(button).hasClass('tool_button_current')) { - clickSelect(); - } - $(button).addClass('disabled'); - } - } - else { - for (var index in buttonsNeedingFillAndStroke) { - var button = buttonsNeedingFillAndStroke[index]; - $(button).removeClass('disabled'); - } - } - - svgCanvas.runExtensions("toolButtonStateUpdate", { - nofill: bNoFill, - nostroke: bNoStroke - }); - - // Disable flyouts if all inside are disabled - $('.tools_flyout').each(function() { - var shower = $('#' + this.id + '_show'); - var has_enabled = false; - $(this).children().each(function() { - if(!$(this).hasClass('disabled')) { - has_enabled = true; - } - }); - shower.toggleClass('disabled', !has_enabled); - }); - - operaRepaint(); - }; - - - - var PaintBox = function(container, type) { - var cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke']; - - // set up gradients to be used for the buttons - var svgdocbox = new DOMParser().parseFromString( - '<svg xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%"\ - fill="#' + cur.color + '" opacity="' + cur.opacity + '"/>\ - <defs><linearGradient id="gradbox_"/></defs></svg>', 'text/xml'); - var docElem = svgdocbox.documentElement; - - docElem = $(container)[0].appendChild(document.importNode(docElem, true)); - - docElem.setAttribute('width',24.5); - - this.rect = docElem.firstChild; - this.defs = docElem.getElementsByTagName('defs')[0]; - this.grad = this.defs.firstChild; - this.paint = new $.jGraduate.Paint({solidColor: cur.color}); - this.type = type; - - this.setPaint = function(paint, apply) { - this.paint = paint; - - var fillAttr = "none"; - var ptype = paint.type; - var opac = paint.alpha / 100; - - switch ( ptype ) { - case 'solidColor': - fillAttr = "#" + paint[ptype]; - break; - case 'linearGradient': - case 'radialGradient': - this.defs.removeChild(this.grad); - this.grad = this.defs.appendChild(paint[ptype]); - var id = this.grad.id = 'gradbox_' + this.type; - fillAttr = "url(#" + id + ')'; - } - - this.rect.setAttribute('fill', fillAttr); - this.rect.setAttribute('opacity', opac); - - if(apply) { - svgCanvas.setColor(this.type, fillAttr, true); - svgCanvas.setPaintOpacity(this.type, opac, true); - } - } - - this.update = function(apply) { - if(!selectedElement) return; - var type = this.type; - - switch ( selectedElement.tagName ) { - case 'use': - case 'image': - case 'foreignObject': - // These elements don't have fill or stroke, so don't change - // the current value - return; - case 'g': - case 'a': - var gPaint = null; - - var childs = selectedElement.getElementsByTagName('*'); - for(var i = 0, len = childs.length; i < len; i++) { - var elem = childs[i]; - var p = elem.getAttribute(type); - if(i === 0) { - gPaint = p; - } else if(gPaint !== p) { - gPaint = null; - break; - } - } - if(gPaint === null) { - // No common color, don't update anything - var paintColor = null; - return; - } - var paintColor = gPaint; - - var paintOpacity = 1; - break; - default: - var paintOpacity = parseFloat(selectedElement.getAttribute(type + "-opacity")); - if (isNaN(paintOpacity)) { - paintOpacity = 1.0; - } - - var defColor = type === "fill" ? "black" : "none"; - var paintColor = selectedElement.getAttribute(type) || defColor; - } - - if(apply) { - svgCanvas.setColor(type, paintColor, true); - svgCanvas.setPaintOpacity(type, paintOpacity, true); - } - - paintOpacity *= 100; - - var paint = getPaint(paintColor, paintOpacity, type); - // update the rect inside #fill_color/#stroke_color - this.setPaint(paint); - } - - this.prep = function() { - var ptype = this.paint.type; - - switch ( ptype ) { - case 'linearGradient': - case 'radialGradient': - var paint = new $.jGraduate.Paint({copy: this.paint}); - svgCanvas.setPaint(type, paint); - } - } - }; - - paintBox.fill = new PaintBox('#fill_color', 'fill'); - paintBox.stroke = new PaintBox('#stroke_color', 'stroke'); - - $('#stroke_width').val(curConfig.initStroke.width); - $('#group_opacity').val(curConfig.initOpacity * 100); - - // Use this SVG elem to test vectorEffect support - var test_el = paintBox.fill.rect.cloneNode(false); - test_el.setAttribute('style','vector-effect:non-scaling-stroke'); - var supportsNonSS = (test_el.style.vectorEffect === 'non-scaling-stroke'); - test_el.removeAttribute('style'); - var svgdocbox = paintBox.fill.rect.ownerDocument; - // Use this to test support for blur element. Seems to work to test support in Webkit - var blur_test = svgdocbox.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur'); - if(typeof blur_test.stdDeviationX === "undefined") { - $('#tool_blur').hide(); - } - $(blur_test).remove(); - - - - // Test for embedImage support (use timeout to not interfere with page load) - setTimeout(function() { - svgCanvas.embedImage('images/placeholder.svg', function(datauri) { - if(!datauri) { - // Disable option - $('#image_save_opts [value=embed]').attr('disabled','disabled'); - $('#image_save_opts input').val(['ref']); - curPrefs.img_save = 'ref'; - $('#image_opt_embed').css('color','#666').attr('title',uiStrings.notification.featNotSupported); - } - }); - },1000); - - $('#tool_fill').click(function(){ - if ($('#tool_fill').hasClass('active')) { - colorPicker($('#fill_color')); - updateToolButtonState(); - } - else { - $('#tool_fill').addClass('active'); - $("#tool_stroke").removeClass('active'); - } - }); - - $('#tool_stroke').click(function(){ - - if ($('#tool_stroke').hasClass('active')) { - colorPicker($('#stroke_color')); - updateToolButtonState(); - } - else { - $('#tool_stroke').addClass('active'); - console.log($('#tool_stroke')); - $("#tool_fill").removeClass('active'); - } - }); - - $('#group_opacityLabel').click(function() { - $('#opacity_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#zoomLabel').click(function() { - $('#zoom_dropdown button').mousedown(); - $(window).mouseup(); - }); - - $('#tool_move_top').mousedown(function(evt){ - $('#tools_stacking').show(); - evt.preventDefault(); - }); - - $('.layer_button').mousedown(function() { - $(this).addClass('layer_buttonpressed'); - }).mouseout(function() { - $(this).removeClass('layer_buttonpressed'); - }).mouseup(function() { - $(this).removeClass('layer_buttonpressed'); - }); - - $('.push_button').mousedown(function() { - if (!$(this).hasClass('disabled')) { - $(this).addClass('push_button_pressed').removeClass('push_button'); - } - }).mouseout(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }).mouseup(function() { - $(this).removeClass('push_button_pressed').addClass('push_button'); - }); - - $('#layer_new').click(function() { - var i = svgCanvas.getCurrentDrawing().getNumLayers(); - do { - var uniqName = uiStrings.layers.layer + " " + ++i; - } while(svgCanvas.getCurrentDrawing().hasLayer(uniqName)); - - $.prompt(uiStrings.notification.enterUniqueLayerName,uniqName, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.createLayer(newName); - updateContextPanel(); - populateLayers(); - }); - }); - - function deleteLayer() { - if (svgCanvas.deleteCurrentLayer()) { - updateContextPanel(); - populateLayers(); - // This matches what SvgCanvas does - // TODO: make this behavior less brittle (svg-editor should get which - // layer is selected from the canvas and then select that one in the UI) - $('#layerlist tr.layer').removeClass("layersel"); - $('#layerlist tr.layer:first').addClass("layersel"); - } - } - - function cloneLayer() { - var name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy'; - - $.prompt(uiStrings.notification.enterUniqueLayerName, name, function(newName) { - if (!newName) return; - if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.dupeLayerName); - return; - } - svgCanvas.cloneLayer(newName); - updateContextPanel(); - populateLayers(); - }); - } - - function mergeLayer() { - if($('#layerlist tr.layersel').index() == svgCanvas.getCurrentDrawing().getNumLayers()-1) return; - svgCanvas.mergeLayer(); - updateContextPanel(); - populateLayers(); - } - - function moveLayer(pos) { - var curIndex = $('#layerlist tr.layersel').index(); - var total = svgCanvas.getCurrentDrawing().getNumLayers(); - if(curIndex > 0 || curIndex < total-1) { - curIndex += pos; - svgCanvas.setCurrentLayerPosition(total-curIndex-1); - populateLayers(); - } - } - - $('#layer_delete').click(deleteLayer); - - $('#layer_up').click(function() { - moveLayer(-1); - }); - - $('#layer_down').click(function() { - moveLayer(1); - }); - - $('#layer_rename').click(function() { - var curIndex = $('#layerlist tr.layersel').prevAll().length; - var oldName = $('#layerlist tr.layersel td.layername').text(); - $.prompt(uiStrings.notification.enterNewLayerName,"", function(newName) { - if (!newName) return; - if (oldName == newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) { - $.alert(uiStrings.notification.layerHasThatName); - return; - } - - svgCanvas.renameCurrentLayer(newName); - populateLayers(); - }); - }); - - var SIDEPANEL_MAXWIDTH = 300; - var SIDEPANEL_OPENWIDTH = 150; - var sidedrag = -1, sidedragging = false, allowmove = false; - - var resizePanel = function(evt) { - if (!allowmove) return; - if (sidedrag == -1) return; - sidedragging = true; - var deltax = sidedrag - evt.pageX; - - var sidepanels = $('#sidepanels'); - var sidewidth = parseInt(sidepanels.css('width')); - if (sidewidth+deltax > SIDEPANEL_MAXWIDTH) { - deltax = SIDEPANEL_MAXWIDTH - sidewidth; - sidewidth = SIDEPANEL_MAXWIDTH; - } - else if (sidewidth+deltax < 2) { - deltax = 2 - sidewidth; - sidewidth = 2; - } - - if (deltax == 0) return; - sidedrag -= deltax; - - var layerpanel = $('#layerpanel'); - workarea.css('right', parseInt(workarea.css('right'))+deltax); - sidepanels.css('width', parseInt(sidepanels.css('width'))+deltax); - layerpanel.css('width', parseInt(layerpanel.css('width'))+deltax); - var ruler_x = $('#ruler_x'); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - } - - $('#sidepanel_handle') - .mousedown(function(evt) { - sidedrag = evt.pageX; - $(window).mousemove(resizePanel); - allowmove = false; - // Silly hack for Chrome, which always runs mousemove right after mousedown - setTimeout(function() { - allowmove = true; - }, 20); - }) - .mouseup(function(evt) { - if (!sidedragging) toggleSidePanel(); - sidedrag = -1; - sidedragging = false; - }); - - $(window).mouseup(function() { - sidedrag = -1; - sidedragging = false; - $('#svg_editor').unbind('mousemove', resizePanel); - }); - - // if width is non-zero, then fully close it, otherwise fully open it - // the optional close argument forces the side panel closed - var toggleSidePanel = function(close){ - var w = parseInt($('#sidepanels').css('width')); - var deltax = (w > 2 || close ? 2 : SIDEPANEL_OPENWIDTH) - w; - var sidepanels = $('#sidepanels'); - var layerpanel = $('#layerpanel'); - var ruler_x = $('#ruler_x'); - workarea.css('right', parseInt(workarea.css('right')) + deltax); - sidepanels.css('width', parseInt(sidepanels.css('width')) + deltax); - layerpanel.css('width', parseInt(layerpanel.css('width')) + deltax); - ruler_x.css('right', parseInt(ruler_x.css('right')) + deltax); - }; - - // this function highlights the layer passed in (by fading out the other layers) - // if no layer is passed in, this function restores the other layers - var toggleHighlightLayer = function(layerNameToHighlight) { - var curNames = new Array(svgCanvas.getCurrentDrawing().getNumLayers()); - for (var i = 0; i < curNames.length; ++i) { curNames[i] = svgCanvas.getCurrentDrawing().getLayerName(i); } - - if (layerNameToHighlight) { - for (var i = 0; i < curNames.length; ++i) { - if (curNames[i] != layerNameToHighlight) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 0.5); - } - } - } - else { - for (var i = 0; i < curNames.length; ++i) { - svgCanvas.getCurrentDrawing().setLayerOpacity(curNames[i], 1.0); - } - } - }; - - var populateLayers = function(){ - var layerlist = $('#layerlist tbody'); - var selLayerNames = $('#selLayerNames'); - layerlist.empty(); - selLayerNames.empty(); - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var layer = svgCanvas.getCurrentDrawing().getNumLayers(); - var icon = $.getSvgIcon('eye'); - // we get the layers in the reverse z-order (the layer rendered on top is listed first) - while (layer--) { - var name = svgCanvas.getCurrentDrawing().getLayerName(layer); - // contenteditable=\"true\" - var appendstr = "<tr class=\"layer"; - if (name == currentLayerName) { - appendstr += " layersel" - } - appendstr += "\">"; - - if (svgCanvas.getCurrentDrawing().getLayerVisibility(name)) { - appendstr += "<td class=\"layervis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - else { - appendstr += "<td class=\"layervis layerinvis\"/><td class=\"layername\" >" + name + "</td></tr>"; - } - layerlist.append(appendstr); - selLayerNames.append("<option value=\"" + name + "\">" + name + "</option>"); - } - if(icon !== undefined) { - var copy = icon.clone(); - $('td.layervis',layerlist).append(icon.clone()); - $.resizeSvgIcons({'td.layervis .svg_icon':14}); - } - // handle selection of layer - $('#layerlist td.layername') - .mouseup(function(evt){ - $('#layerlist tr.layer').removeClass("layersel"); - var row = $(this.parentNode); - row.addClass("layersel"); - svgCanvas.setCurrentLayer(this.textContent); - evt.preventDefault(); - }) - .mouseover(function(evt){ - $(this).css({"font-style": "italic", "color":"blue"}); - toggleHighlightLayer(this.textContent); - }) - .mouseout(function(evt){ - $(this).css({"font-style": "normal", "color":"black"}); - toggleHighlightLayer(); - }); - $('#layerlist td.layervis').click(function(evt){ - var row = $(this.parentNode).prevAll().length; - var name = $('#layerlist tr.layer:eq(' + row + ') td.layername').text(); - var vis = $(this).hasClass('layerinvis'); - svgCanvas.setLayerVisibility(name, vis); - if (vis) { - $(this).removeClass('layerinvis'); - } - else { - $(this).addClass('layerinvis'); - } - }); - - // if there were too few rows, let's add a few to make it not so lonely - var num = 5 - $('#layerlist tr.layer').size(); - while (num-- > 0) { - // FIXME: there must a better way to do this - layerlist.append("<tr><td style=\"color:white\">_</td><td/></tr>"); - } - }; - populateLayers(); - - // function changeResolution(x,y) { - // var zoom = svgCanvas.getResolution().zoom; - // setResolution(x * zoom, y * zoom); - // } - - var centerCanvas = function() { - // this centers the canvas vertically in the workarea (horizontal handled in CSS) - workarea.css('line-height', workarea.height() + 'px'); - }; - - $(window).bind('load resize', centerCanvas); - - function stepFontSize(elem, step) { - var orig_val = elem.value-0; - var sug_val = orig_val + step; - var increasing = sug_val >= orig_val; - if(step === 0) return orig_val; - - if(orig_val >= 24) { - if(increasing) { - return Math.round(orig_val * 1.1); - } else { - return Math.round(orig_val / 1.1); - } - } else if(orig_val <= 1) { - if(increasing) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } else { - return sug_val; - } - } - - function stepZoom(elem, step) { - var orig_val = elem.value-0; - if(orig_val === 0) return 100; - var sug_val = orig_val + step; - if(step === 0) return orig_val; - - if(orig_val >= 100) { - return sug_val; - } else { - if(sug_val >= orig_val) { - return orig_val * 2; - } else { - return orig_val / 2; - } - } - } - - // function setResolution(w, h, center) { - // updateCanvas(); - // // w-=0; h-=0; - // // $('#svgcanvas').css( { 'width': w, 'height': h } ); - // // $('#canvas_width').val(w); - // // $('#canvas_height').val(h); - // // - // // if(center) { - // // var w_area = workarea; - // // var scroll_y = h/2 - w_area.height()/2; - // // var scroll_x = w/2 - w_area.width()/2; - // // w_area[0].scrollTop = scroll_y; - // // w_area[0].scrollLeft = scroll_x; - // // } - // } - - $('#resolution').change(function(){ - var wh = $('#canvas_width,#canvas_height'); - if(!this.selectedIndex) { - if($('#canvas_width').val() == 'fit') { - wh.removeAttr("disabled").val(100); - } - } else if(this.value == 'content') { - wh.val('fit').attr("disabled","disabled"); - } else { - var dims = this.value.split('x'); - $('#canvas_width').val(dims[0]); - $('#canvas_height').val(dims[1]); - wh.removeAttr("disabled"); - } - }); - - //Prevent browser from erroneously repopulating fields - $('input,select').attr("autocomplete","off"); - - // Associate all button actions as well as non-button keyboard shortcuts - var Actions = function() { - // sel:'selector', fn:function, evt:'event', key:[key, preventDefault, NoDisableInInput] - var tool_buttons = [ - {sel:'#tool_select', fn: clickSelect, evt: 'click', key: ['V', true]}, - {sel:'#tool_fhpath', fn: clickFHPath, evt: 'click', key: ['Q', true]}, - {sel:'#tool_line', fn: clickLine, evt: 'click', key: ['L', true]}, - {sel:'#tool_rect', fn: clickRect, evt: 'click', key: ['R', true], icon: 'rect'}, - {sel:'#tool_ellipse', fn: clickEllipse, evt: 'mouseup', key: ['C', true], icon: 'ellipse'}, - //{sel:'#tool_circle', fn: clickCircle, evt: 'mouseup', icon: 'circle'}, - //{sel:'#tool_fhellipse', fn: clickFHEllipse, evt: 'mouseup', parent: '#tools_ellipse', icon: 'fh_ellipse'}, - {sel:'#tool_path', fn: clickPath, evt: 'click', key: ['P', true]}, - {sel:'#tool_text', fn: clickText, evt: 'click', key: ['T', true]}, - {sel:'#tool_image', fn: clickImage, evt: 'mouseup'}, - {sel:'#tool_zoom', fn: clickZoom, evt: 'mouseup', key: ['Z', true]}, - {sel:'#tool_clear', fn: clickClear, evt: 'mouseup', key: [modKey + 'N', true]}, - {sel:'#tool_save', fn: function() { editingsource?saveSourceEditor():clickSave()}, evt: 'mouseup', key: [modKey + 'S', true]}, - {sel:'#tool_export', fn: clickExport, evt: 'mouseup'}, - {sel:'#tool_open', fn: clickOpen, evt: 'mouseup'}, - {sel:'#tool_import', fn: clickImport, evt: 'mouseup'}, - {sel:'#tool_source', fn: showSourceEditor, evt: 'click', key: [modKey + 'U', true]}, - {sel:'#tool_wireframe', fn: clickWireframe, evt: 'click'}, - {sel:'#tool_rulers', fn: clickRulers, evt: 'click'}, - {sel:'#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel', fn: cancelOverlays, evt: 'click', key: ['esc', false, false], hidekey: true}, - {sel:'#tool_source_save', fn: saveSourceEditor, evt: 'click'}, - {sel:'#tool_docprops_save', fn: saveDocProperties, evt: 'click'}, - {sel:'#tool_docprops', fn: showDocProperties, evt: 'mouseup'}, - {sel:'#tool_prefs_save', fn: savePreferences, evt: 'click'}, - {sel:'#tool_prefs_option', fn: function() {showPreferences();return false}, evt: 'mouseup'}, - {sel:'#tool_delete,#tool_delete_multi', fn: deleteSelected, evt: 'click', key: ['del/backspace', true]}, - {sel:'#tool_reorient', fn: reorientPath, evt: 'click'}, - {sel:'#tool_node_link', fn: linkControlPoints, evt: 'click'}, - {sel:'#tool_node_clone', fn: clonePathNode, evt: 'click'}, - {sel:'#tool_node_delete', fn: deletePathNode, evt: 'click'}, - {sel:'#tool_openclose_path', fn: opencloseSubPath, evt: 'click'}, - {sel:'#tool_add_subpath', fn: addSubPath, evt: 'click'}, - {sel:'#tool_move_top', fn: moveToTopSelected, evt: 'click', key: modKey + 'shift+up'}, - {sel:'#tool_move_bottom', fn: moveToBottomSelected, evt: 'click', key: modKey + 'shift+down'}, - {sel:'#tool_move_up', fn: moveUpSelected, evt:'click', key: [modKey+'up', true]}, - {sel:'#tool_move_down', fn: moveDownSelected, evt:'click', key: [modKey+'down', true]}, - {sel:'#tool_topath', fn: convertToPath, evt: 'click'}, - {sel:'#tool_make_link,#tool_make_link_multi', fn: makeHyperlink, evt: 'click'}, - {sel:'#tool_undo', fn: clickUndo, evt: 'click', key: [modKey + 'Z', true]}, - {sel:'#tool_redo', fn: clickRedo, evt: 'click', key: ['Y', true]}, - {sel:'#tool_clone,#tool_clone_multi', fn: clickClone, evt: 'click', key: [modKey + 'D', true]}, - {sel:'#tool_group', fn: clickGroup, evt: 'click', key: [modKey + 'G', true]}, - {sel:'#tool_ungroup', fn: clickGroup, evt: 'click', key: modKey + 'shift+G'}, - {sel:'#tool_unlink_use', fn: clickGroup, evt: 'click'}, - {sel:'[id^=tool_align]', fn: clickAlign, evt: 'click'}, - {sel:'#tool_switch', fn: clickSwitch, evt: 'click', key: ['X', true]}, - // these two lines are required to make Opera work properly with the flyout mechanism - // {sel:'#tools_rect_show', fn: clickRect, evt: 'click'}, - // {sel:'#tools_ellipse_show', fn: clickEllipse, evt: 'click'}, - {sel:'#tool_bold', fn: clickBold, evt: 'mousedown', key: [modKey + 'B', true]}, - {sel:'#tool_italic', fn: clickItalic, evt: 'mousedown', key: [modKey + 'I', true]}, - //{sel:'#sidepanel_handle', fn: toggleSidePanel, key: ['X']}, - {sel:'#copy_save_done', fn: cancelOverlays, evt: 'click'}, - - // Shortcuts not associated with buttons - - {key: 'ctrl+left', fn: function(){rotateSelected(0,1)}}, - {key: 'ctrl+right', fn: function(){rotateSelected(1,1)}}, - {key: 'ctrl+shift+left', fn: function(){rotateSelected(0,5)}}, - {key: 'ctrl+shift+right', fn: function(){rotateSelected(1,5)}}, - {key: 'shift+O', fn: selectPrev}, - {key: 'shift+P', fn: selectNext}, - {key: [modKey+'+', true], fn: function(){zoomImage(2);}}, - {key: [modKey+'-', true], fn: function(){zoomImage(.5);}}, - {key: ['up', true], fn: function(){moveSelected(0,-1);}}, - {key: ['down', true], fn: function(){moveSelected(0,1);}}, - {key: ['left', true], fn: function(){moveSelected(-1,0);}}, - {key: ['right', true], fn: function(){moveSelected(1,0);}}, - {key: 'shift+up', fn: function(){moveSelected(0,-10)}}, - {key: 'shift+down', fn: function(){moveSelected(0,10)}}, - {key: 'shift+left', fn: function(){moveSelected(-10,0)}}, - {key: 'shift+right', fn: function(){moveSelected(10,0)}}, - {key: ['alt+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-1)}}, - {key: ['alt+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,1)}}, - {key: ['alt+left', true], fn: function(){svgCanvas.cloneSelectedElements(-1,0)}}, - {key: ['alt+right', true], fn: function(){svgCanvas.cloneSelectedElements(1,0)}}, - {key: ['alt+shift+up', true], fn: function(){svgCanvas.cloneSelectedElements(0,-10)}}, - {key: ['alt+shift+down', true], fn: function(){svgCanvas.cloneSelectedElements(0,10)}}, - {key: ['alt+shift+left', true], fn: function(){svgCanvas.cloneSelectedElements(-10,0)}}, - {key: ['alt+shift+right', true], fn: function(){svgCanvas.cloneSelectedElements(10,0)}}, - {key: modKey + 'A', fn: function(){svgCanvas.selectAllInCurrentLayer();}}, - - // Standard shortcuts - {key: modKey + 'z', fn: clickUndo}, - {key: modKey + 'shift+z', fn: clickRedo}, - {key: modKey + 'y', fn: clickRedo}, - - {key: modKey+'x', fn: cutSelected}, - {key: modKey+'c', fn: copySelected}, - {key: modKey+'v', fn: pasteInCenter} - - - ]; - - // Tooltips not directly associated with a single function - var key_assocs = { - '4/Shift+4': '#tools_rect_show', - '5/Shift+5': '#tools_ellipse_show' - }; - - return { - setAll: function() { - var flyouts = {}; - - $.each(tool_buttons, function(i, opts) { - // Bind function to button - if(opts.sel) { - var btn = $(opts.sel); - if (btn.length == 0) return true; // Skip if markup does not exist - if(opts.evt) { - if (svgedit.browser.isTouch() && opts.evt === "click") opts.evt = "mousedown" - btn[opts.evt](opts.fn); - } - - // Add to parent flyout menu, if able to be displayed - if(opts.parent && $(opts.parent + '_show').length != 0) { - var f_h = $(opts.parent); - if(!f_h.length) { - f_h = makeFlyoutHolder(opts.parent.substr(1)); - } - - f_h.append(btn); - - if(!$.isArray(flyouts[opts.parent])) { - flyouts[opts.parent] = []; - } - flyouts[opts.parent].push(opts); - } - } - - - // Bind function to shortcut key - if(opts.key) { - // Set shortcut based on options - var keyval, shortcut = '', disInInp = true, fn = opts.fn, pd = false; - if($.isArray(opts.key)) { - keyval = opts.key[0]; - if(opts.key.length > 1) pd = opts.key[1]; - if(opts.key.length > 2) disInInp = opts.key[2]; - } else { - keyval = opts.key; - } - keyval += ''; - if (svgedit.browser.isMac && keyval.indexOf("+") != -1) { - var modifier_key = keyval.split("+")[0]; - if (modifier_key == "ctrl") keyval.replace("ctrl", "cmd") - } - - $.each(keyval.split('/'), function(i, key) { - $(document).bind('keydown', key, function(e) { - fn(); - if(pd) { - e.preventDefault(); - } - // Prevent default on ALL keys? - return false; - }); - }); - - // Put shortcut in title - if(opts.sel && !opts.hidekey && btn.attr('title')) { - var new_title = btn.attr('title').split('[')[0] + ' (' + keyval + ')'; - key_assocs[keyval] = opts.sel; - // Disregard for menu items - if(!btn.parents('#main_menu').length) { - btn.attr('title', new_title); - } - } - } - }); - - // Setup flyouts - setupFlyouts(flyouts); - - - // Misc additional actions - - // Make "return" keypress trigger the change event - $('.attr_changer, #image_url').bind('keydown', 'return', - function(evt) {$(this).change();evt.preventDefault();} - ); - - $(window).bind('keydown', 'tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectNext(); - } - }).bind('keydown', 'shift+tab', function(e) { - if(ui_context === 'canvas') { - e.preventDefault(); - selectPrev(); - } - }); - - $('#tool_zoom').dblclick(dblclickZoom); - }, - setTitles: function() { - $.each(key_assocs, function(keyval, sel) { - var menu = ($(sel).parents('#main_menu').length); - - $(sel).each(function() { - if(menu) { - var t = $(this).text().split(' [')[0]; - } else { - var t = this.title.split(' [')[0]; - } - var key_str = ''; - // Shift+Up - $.each(keyval.split('/'), function(i, key) { - var mod_bits = key.split('+'), mod = ''; - if(mod_bits.length > 1) { - mod = mod_bits[0] + '+'; - key = mod_bits[1]; - } - key_str += (i?'/':'') + mod + (uiStrings['key_'+key] || key); - }); - if(menu) { - this.lastChild.textContent = t +' ['+key_str+']'; - } else { - this.title = t +' ['+key_str+']'; - } - }); - }); - }, - getButtonData: function(sel) { - var b; - $.each(tool_buttons, function(i, btn) { - if(btn.sel === sel) b = btn; - }); - return b; - } - }; - }(); - - Actions.setAll(); - - // Select given tool - Editor.ready(function() { - var tool, - itool = curConfig.initTool, - container = $("#tools_left, #svg_editor .tools_flyout"), - pre_tool = container.find("#tool_" + itool), - reg_tool = container.find("#" + itool); - if(pre_tool.length) { - tool = pre_tool; - } else if(reg_tool.length){ - tool = reg_tool; - } else { - tool = $("#tool_select"); - } - tool.click().mouseup(); - - if(curConfig.wireframe) { - $('#tool_wireframe').click(); - } - - if(curConfig.showlayers) { - toggleSidePanel(); - } - - $('#rulers').toggle(!!curConfig.showRulers); - - if (curConfig.showRulers) { - $('#show_rulers')[0].checked = true; - } - - if(curConfig.gridSnapping) { - $('#grid_snapping_on')[0].checked = true; - } - - if(curConfig.baseUnit) { - $('#base_unit').val(curConfig.baseUnit); - } - - if(curConfig.snappingStep) { - $('#grid_snapping_step').val(curConfig.snappingStep); - } - }); - - $('#rect_rx').SpinButton({ min: 0, max: 1000, step: 1, callback: changeRectRadius }); - $('#stroke_width').SpinButton({ min: 0, max: 99, step: 1, smallStep: 0.1, callback: changeStrokeWidth }); - $('#angle').SpinButton({ min: -180, max: 180, step: 5, callback: changeRotationAngle }); - $('#font_size').SpinButton({ step: 1, min: 0.001, stepfunc: stepFontSize, callback: changeFontSize }); - $('#group_opacity').SpinButton({ step: 5, min: 0, max: 100, callback: changeOpacity }); - $('#blur').SpinButton({ step: .1, min: 0, max: 10, callback: changeBlur }); - $('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, callback: changeZoom }) - // Set default zoom - .val(svgCanvas.getZoom() * 100); - - $("#workarea").contextMenu({ - menu: 'cmenu_canvas', - inSpeed: 0 - }, - function(action, el, pos) { - switch ( action ) { - case 'delete': - deleteSelected(); - break; - case 'cut': - cutSelected(); - break; - case 'copy': - copySelected(); - break; - case 'paste': - svgCanvas.pasteElements(); - break; - case 'paste_in_place': - svgCanvas.pasteElements('in_place'); - break; - case 'group': - svgCanvas.groupSelectedElements(); - break; - case 'ungroup': - svgCanvas.ungroupSelectedElement(); - break; - case 'move_front': - moveToTopSelected(); - break; - case 'move_up': - moveUpDownSelected('Up'); - break; - case 'move_down': - moveUpDownSelected('Down'); - break; - case 'move_back': - moveToBottomSelected(); - break; - default: - if(svgedit.contextmenu && svgedit.contextmenu.hasCustomHandler(action)){ - svgedit.contextmenu.getCustomHandler(action).call(); - } - break; - } - - if(svgCanvas.clipBoard.length) { - canv_menu.enableContextMenuItems('#paste,#paste_in_place'); - } - }); - - var lmenu_func = function(action, el, pos) { - switch ( action ) { - case 'dupe': - cloneLayer(); - break; - case 'delete': - deleteLayer(); - break; - case 'merge_down': - mergeLayer(); - break; - case 'merge_all': - svgCanvas.mergeAllLayers(); - updateContextPanel(); - populateLayers(); - break; - } - } - - $("#layerlist").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0 - }, - lmenu_func - ); - - $("#layer_moreopts").contextMenu({ - menu: 'cmenu_layers', - inSpeed: 0, - allowLeft: true - }, - lmenu_func - ); - - $('.contextMenu li').mousedown(function(ev) { - ev.preventDefault(); - }) - - $('#cmenu_canvas li').disableContextMenu(); - canv_menu.enableContextMenuItems('#delete,#cut,#copy'); - - window.onbeforeunload = function() { - // Suppress warning if page is empty - if(undoMgr.getUndoStackSize() === 0) { - Editor.show_save_warning = false; - } - - // show_save_warning is set to "false" when the page is saved. - if(!curConfig.no_save_warning && Editor.show_save_warning) { - // Browser already asks question about closing the page - return uiStrings.notification.unsavedChanges; - } - }; - - Editor.openPrep = function(func) { - $('#main_menu').hide(); - if(undoMgr.getUndoStackSize() === 0) { - func(true); - } else { - $.confirm(uiStrings.notification.QwantToOpen, func); - } - } - - // use HTML5 File API: http://www.w3.org/TR/FileAPI/ - // if browser has HTML5 File API support, then we will show the open menu item - // and provide a file input to click. When that change event fires, it will - // get the text contents of the file and send it to the canvas - if (window.FileReader) { - var inp = $('<input type="file">').change(function() { - var f = this; - Editor.openPrep(function(ok) { - if(!ok) return; - svgCanvas.clear(); - if(f.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - loadSvgString(e.target.result); - updateCanvas(); - }; - reader.readAsText(f.files[0]); - } - }); - }); - $("#tool_open").show().prepend(inp); - var inp2 = $('<input type="file">').change(function() { - $('#main_menu').hide(); - if(this.files.length==1) { - var reader = new FileReader(); - reader.onloadend = function(e) { - svgCanvas.importSvgString(e.target.result, true); - updateCanvas(); - }; - reader.readAsText(this.files[0]); - } - }); - $("#tool_import").show().prepend(inp2); - } - - var updateCanvas = Editor.updateCanvas = function(center, new_ctr) { - - var w = workarea.width(), h = workarea.height(); - var w_orig = w, h_orig = h; - var zoom = svgCanvas.getZoom(); - var w_area = workarea; - var cnvs = $("#svgcanvas"); - - var old_ctr = { - x: w_area[0].scrollLeft + w_orig/2, - y: w_area[0].scrollTop + h_orig/2 - }; - - var multi = curConfig.canvas_expansion; - w = Math.max(w_orig, svgCanvas.contentW * zoom * multi); - h = Math.max(h_orig, svgCanvas.contentH * zoom * multi); - - if(w == w_orig && h == h_orig) { - workarea.css('overflow','hidden'); - } else { - workarea.css('overflow','scroll'); - } - - var old_can_y = cnvs.height()/2; - var old_can_x = cnvs.width()/2; - cnvs.width(w).height(h); - var new_can_y = h/2; - var new_can_x = w/2; - var offset = svgCanvas.updateCanvas(w, h); - - var ratio = new_can_x / old_can_x; - - var scroll_x = w/2 - w_orig/2; - var scroll_y = h/2 - h_orig/2; - - if(!new_ctr) { - - var old_dist_x = old_ctr.x - old_can_x; - var new_x = new_can_x + old_dist_x * ratio; - - var old_dist_y = old_ctr.y - old_can_y; - var new_y = new_can_y + old_dist_y * ratio; - - new_ctr = { - x: new_x, - y: new_y - }; - - } else { - new_ctr.x += offset.x, - new_ctr.y += offset.y; - } - - if(center) { - // Go to top-left for larger documents - if(svgCanvas.contentW > w_area.width()) { - // Top-left - workarea[0].scrollLeft = offset.x - 10; - workarea[0].scrollTop = offset.y - 10; - } else { - // Center - w_area[0].scrollLeft = scroll_x; - w_area[0].scrollTop = scroll_y; - } - } else { - w_area[0].scrollLeft = new_ctr.x - w_orig/2; - w_area[0].scrollTop = new_ctr.y - h_orig/2; - } - if(curConfig.showRulers) { - updateRulers(cnvs, zoom); - workarea.scroll(); - } - } - - // Make [1,2,5] array - var r_intervals = []; - for(var i = .1; i < 1E5; i *= 10) { - r_intervals.push(1 * i); - r_intervals.push(2 * i); - r_intervals.push(5 * i); - } - - function updateRulers(scanvas, zoom) { - var ruler_x_cursor = document.getElementById("ruler_x_cursor"); - var ruler_y_cursor = document.getElementById("ruler_y_cursor"); - var workarea = document.getElementById("workarea"); - var title_show = document.getElementById("title_show"); - var offset_x = 66; - var offset_y = 48; - $("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers", function(e){ - e.stopPropagation(); - ruler_x_cursor.style.left = (e.pageX-offset_x+workarea.scrollLeft) + "px"; - ruler_y_cursor.style.top = (e.pageY-offset_y+workarea.scrollTop) + "px"; - var title = e.target.getAttribute("title"); - if (typeof title != 'undefined' && title) title_show.innerHTML(title); - }) - if(!zoom) zoom = svgCanvas.getZoom(); - if(!scanvas) scanvas = $("#svgcanvas"); - - var limit = 30000; - - var c_elem = svgCanvas.getContentElem(); - - var units = svgedit.units.getTypeMap(); - var unit = units[curConfig.baseUnit]; // 1 = 1px - - for(var d = 0; d < 2; d++) { - var is_x = (d === 0); - var dim = is_x ? 'x' : 'y'; - var lentype = is_x?'width':'height'; - var content_d = c_elem.getAttribute(dim)-0; - - var $hcanv_orig = $('#ruler_' + dim + ' canvas:first'); - - // Bit of a hack to fully clear the canvas in Safari & IE9 - $hcanv = $hcanv_orig.clone(); - $hcanv_orig.replaceWith($hcanv); - - var hcanv = $hcanv[0]; - - // Set the canvas size to the width of the container - var ruler_len = scanvas[lentype]()*2; - var total_len = ruler_len; - hcanv.parentNode.style[lentype] = total_len + 'px'; - - var canv_count = 1; - var ctx_num = 0; - var ctx_arr; - var ctx = hcanv.getContext("2d"); - - ctx.fillStyle = "rgb(200,0,0)"; - ctx.fillRect(0,0,hcanv.width,hcanv.height); - - // Remove any existing canvasses - $hcanv.siblings().remove(); - - // Create multiple canvases when necessary (due to browser limits) - if(ruler_len >= limit) { - var num = parseInt(ruler_len / limit) + 1; - ctx_arr = Array(num); - ctx_arr[0] = ctx; - for(var i = 1; i < num; i++) { - hcanv[lentype] = limit; - var copy = hcanv.cloneNode(true); - hcanv.parentNode.appendChild(copy); - ctx_arr[i] = copy.getContext('2d'); - } - - copy[lentype] = ruler_len % limit; - - // set copy width to last - ruler_len = limit; - } - - hcanv[lentype] = ruler_len; - - var u_multi = unit * zoom; - - // Calculate the main number interval - var raw_m = 50 / u_multi; - var multi = 1; - for(var i = 0; i < r_intervals.length; i++) { - var num = r_intervals[i]; - multi = num; - if(raw_m <= num) { - break; - } - } - - var big_int = multi * u_multi; - ctx.font = "normal 9px 'Lucida Grande', sans-serif"; - ctx.fillStyle = "#777"; - - var ruler_d = ((content_d / u_multi) % multi) * u_multi; - var label_pos = ruler_d - big_int; - for (; ruler_d < total_len; ruler_d += big_int) { - label_pos += big_int; - var real_d = ruler_d - content_d; - - var cur_d = Math.round(ruler_d) + .5; - if(is_x) { - ctx.moveTo(cur_d, 15); - ctx.lineTo(cur_d, 0); - } else { - ctx.moveTo(15, cur_d); - ctx.lineTo(0, cur_d); - } - - var num = (label_pos - content_d) / u_multi; - var label; - if(multi >= 1) { - label = Math.round(num); - } else { - var decs = (multi+'').split('.')[1].length; - label = num.toFixed(decs)-0; - } - - // Do anything special for negative numbers? -// var is_neg = label < 0; -// real_d2 = Math.abs(real_d2); - - // Change 1000s to Ks - if(label !== 0 && label !== 1000 && label % 1000 === 0) { - label = (label / 1000) + 'K'; - } - - if(is_x) { - ctx.fillText(label, ruler_d+2, 8); - ctx.fillStyle = "#777"; - } else { - var str = (label+'').split(''); - for(var i = 0; i < str.length; i++) { - ctx.fillText(str[i], 1, (ruler_d+9) + i*9); - ctx.fillStyle = "#777"; - } - } - - var part = big_int / 10; - for(var i = 1; i < 10; i++) { - var sub_d = Math.round(ruler_d + part * i) + .5; - if(ctx_arr && sub_d > ruler_len) { - ctx_num++; - ctx.stroke(); - if(ctx_num >= ctx_arr.length) { - i = 10; - ruler_d = total_len; - continue; - } - ctx = ctx_arr[ctx_num]; - ruler_d -= limit; - sub_d = Math.round(ruler_d + part * i) + .5; - } - - var line_num = (i % 2)?12:10; - if(is_x) { - ctx.moveTo(sub_d, 15); - ctx.lineTo(sub_d, line_num); - } else { - ctx.moveTo(15, sub_d); - ctx.lineTo(line_num ,sub_d); - } - } - } - - // console.log('ctx', ctx); - ctx.strokeStyle = "#666"; - ctx.stroke(); - } - } - -// $(function() { - updateCanvas(true); -// }); - - // var revnums = "svg-editor.js ($Rev: 2083 $) "; - // revnums += svgCanvas.getVersion(); - // $('#copyright')[0].setAttribute("title", revnums); - - // Callback handler for embedapi.js - try{ - var json_encode = function(obj){ - //simple partial JSON encoder implementation - if(window.JSON && JSON.stringify) return JSON.stringify(obj); - var enc = arguments.callee; //for purposes of recursion - if(typeof obj == "boolean" || typeof obj == "number"){ - return obj+'' //should work... - }else if(typeof obj == "string"){ - //a large portion of this is stolen from Douglas Crockford's json2.js - return '"'+ - obj.replace( - /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g - , function (a) { - return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); - }) - +'"'; //note that this isn't quite as purtyful as the usualness - }else if(obj.length){ //simple hackish test for arrayish-ness - for(var i = 0; i < obj.length; i++){ - obj[i] = enc(obj[i]); //encode every sub-thingy on top - } - return "["+obj.join(",")+"]"; - }else{ - var pairs = []; //pairs will be stored here - for(var k in obj){ //loop through thingys - pairs.push(enc(k)+":"+enc(obj[k])); //key: value - } - return "{"+pairs.join(",")+"}" //wrap in the braces - } - } - window.addEventListener("message", function(e){ - var cbid = parseInt(e.data.substr(0, e.data.indexOf(";"))); - try{ - e.source.postMessage("SVGe"+cbid+";"+json_encode(eval(e.data)), "*"); - }catch(err){ - e.source.postMessage("SVGe"+cbid+";error:"+err.message, "*"); - } - }, false) - }catch(err){ - window.embed_error = err; - } - - - - // For Compatibility with older extensions - $(function() { - window.svgCanvas = svgCanvas; - svgCanvas.ready = svgEditor.ready; - }); - - - Editor.setLang = function(lang, allStrings) { - $.pref('lang', lang); - $('#lang_select').val(lang); - if(allStrings) { - - var notif = allStrings.notification; - - - - // $.extend will only replace the given strings - var oldLayerName = $('#layerlist tr.layersel td.layername').text(); - var rename_layer = (oldLayerName == uiStrings.common.layer + ' 1'); - - $.extend(uiStrings, allStrings); - svgCanvas.setUiStrings(allStrings); - Actions.setTitles(); - - if(rename_layer) { - svgCanvas.renameCurrentLayer(uiStrings.common.layer + ' 1'); - populateLayers(); - } - - svgCanvas.runExtensions("langChanged", lang); - - // Update flyout tooltips - setFlyoutTitles(); - - // Copy title for certain tool elements - var elems = { - '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', - '#fill_color': '#tool_fill label, #tool_fill .color_block', - '#linejoin_miter': '#cur_linejoin', - '#linecap_butt': '#cur_linecap' - } - - $.each(elems, function(source, dest) { - $(dest).attr('title', $(source)[0].title); - }); - - // Copy alignment titles - $('#multiselected_panel div[id^=tool_align]').each(function() { - $('#tool_pos' + this.id.substr(10))[0].title = this.title; - }); - - } - }; - }; - - var callbacks = []; - - function loadSvgString(str, callback) { - var success = svgCanvas.setSvgString(str) !== false; - callback = callback || $.noop; - if(success) { - callback(true); - } else { - $.alert(uiStrings.notification.errorLoadingSVG, function() { - callback(false); - }); - } - } - - Editor.ready = function(cb) { - if(!is_ready) { - callbacks.push(cb); - } else { - cb(); - } - }; - - Editor.runCallbacks = function() { - $.each(callbacks, function() { - this(); - }); - is_ready = true; - }; - - Editor.loadFromString = function(str) { - Editor.ready(function() { - loadSvgString(str); - }); - }; - - Editor.disableUI = function(featList) { -// $(function() { -// $('#tool_wireframe, #tool_image, #main_button, #tool_source, #sidepanels').remove(); -// $('#tools_top').css('left', 5); -// }); - }; - - Editor.loadFromURL = function(url, opts) { - if(!opts) opts = {}; - - var cache = opts.cache; - var cb = opts.callback; - - Editor.ready(function() { - $.ajax({ - 'url': url, - 'dataType': 'text', - cache: !!cache, - success: function(str) { - loadSvgString(str, cb); - }, - error: function(xhr, stat, err) { - if(xhr.status != 404 && xhr.responseText) { - loadSvgString(xhr.responseText, cb); - } else { - $.alert(uiStrings.notification.URLloadFail + ": \n"+err+'', cb); - } - } - }); - }); - }; - - Editor.loadFromDataURI = function(str) { - Editor.ready(function() { - var pre = 'data:image/svg+xml;base64,'; - var src = str.substring(pre.length); - loadSvgString(svgedit.utilities.decode64(src)); - }); - }; - - Editor.addExtension = function() { - var args = arguments; - - // Note that we don't want this on Editor.ready since some extensions - // may want to run before then (like server_opensave). - $(function() { - if(svgCanvas) svgCanvas.addExtension.apply(this, args); - }); - }; - - return Editor; - }(jQuery); - - // Run init once DOM is loaded - $(svgEditor.init); - -})(); - -// ?iconsize=s&bkgd_color=555 - -// svgEditor.setConfig({ -// // imgPath: 'foo', -// dimensions: [800, 600], -// canvas_expansion: 5, -// initStroke: { -// color: '0000FF', -// width: 3.5, -// opacity: .5 -// }, -// initFill: { -// color: '550000', -// opacity: .75 -// }, -// extensions: ['ext-helloworld.js'] -// }) diff --git a/build/svg-edit-2.6/svg-editor.manifest b/build/svg-edit-2.6/svg-editor.manifest deleted file mode 100644 index b156374..0000000 --- a/build/svg-edit-2.6/svg-editor.manifest +++ /dev/null @@ -1,121 +0,0 @@ -CACHE MANIFEST -svg-editor.html -images/logo.png -jgraduate/css/jPicker-1.0.9.css -jgraduate/css/jGraduate-0.2.0.css -svg-editor.css -spinbtn/JQuerySpinBtn.css -jquery.js -js-hotkeys/jquery.hotkeys.min.js -jquery-ui/jquery-ui-1.7.2.custom.min.js -jgraduate/jpicker-1.0.9.min.js -jgraduate/jquery.jgraduate.js -spinbtn/JQuerySpinBtn.js -svgcanvas.js -svg-editor.js -images/align-bottom.png -images/align-center.png -images/align-left.png -images/align-middle.png -images/align-right.png -images/align-top.png -images/bold.png -images/cancel.png -images/circle.png -images/clear.png -images/clone.png -images/copy.png -images/cut.png -images/delete.png -images/document-properties.png -images/dropdown.gif -images/ellipse.png -images/eye.png -images/flyouth.png -images/flyup.gif -images/freehand-circle.png -images/freehand-square.png -images/go-down.png -images/go-up.png -images/image.png -images/italic.png -images/line.png -images/logo.png -images/logo.svg -images/move_bottom.png -images/move_top.png -images/none.png -images/open.png -images/paste.png -images/path.png -images/polygon.png -images/rect.png -images/redo.png -images/save.png -images/select.png -images/sep.png -images/shape_group.png -images/shape_ungroup.png -images/source.png -images/square.png -images/text.png -images/undo.png -images/view-refresh.png -images/wave.png -images/zoom.png -locale/locale.js -locale/lang.af.js -locale/lang.ar.js -locale/lang.az.js -locale/lang.be.js -locale/lang.bg.js -locale/lang.ca.js -locale/lang.cs.js -locale/lang.cy.js -locale/lang.da.js -locale/lang.de.js -locale/lang.el.js -locale/lang.en.js -locale/lang.es.js -locale/lang.et.js -locale/lang.fa.js -locale/lang.fi.js -locale/lang.fr.js -locale/lang.ga.js -locale/lang.gl.js -locale/lang.hi.js -locale/lang.hr.js -locale/lang.hu.js -locale/lang.hy.js -locale/lang.id.js -locale/lang.is.js -locale/lang.it.js -locale/lang.iw.js -locale/lang.ja.js -locale/lang.ko.js -locale/lang.lt.js -locale/lang.lv.js -locale/lang.mk.js -locale/lang.ms.js -locale/lang.mt.js -locale/lang.nl.js -locale/lang.no.js -locale/lang.pl.js -locale/lang.pt-PT.js -locale/lang.ro.js -locale/lang.ru.js -locale/lang.sk.js -locale/lang.sl.js -locale/lang.sq.js -locale/lang.sr.js -locale/lang.sv.js -locale/lang.sw.js -locale/lang.th.js -locale/lang.tl.js -locale/lang.tr.js -locale/lang.uk.js -locale/lang.vi.js -locale/lang.yi.js -locale/lang.zh-CN.js -locale/lang.zh-TW.js -locale/lang.zh.js diff --git a/build/svg-edit-2.6/svgcanvas.js b/build/svg-edit-2.6/svgcanvas.js deleted file mode 100644 index abf427b..0000000 --- a/build/svg-edit-2.6/svgcanvas.js +++ /dev/null @@ -1,8819 +0,0 @@ -/* - * svgcanvas.js - * - * Licensed under the Apache License, Version 2 - * - * Copyright(c) 2010 Alexis Deveria - * Copyright(c) 2010 Pavol Rusnak - * Copyright(c) 2010 Jeff Schiller - * - */ - -// Dependencies: -// 1) jQuery -// 2) browser.js -// 3) svgtransformlist.js -// 4) math.js -// 5) units.js -// 6) svgutils.js -// 7) sanitize.js -// 8) history.js -// 9) select.js -// 10) draw.js -// 11) path.js - -/*jslint browser: true*/ - -if(!window.console) { - window.console = {}; - window.console.log = function(str) {}; - window.console.dir = function(str) {}; -} - -if(window.opera) { - window.console.log = function(str) { opera.postError(str); }; - window.console.dir = function(str) {}; -} - -(function() { - - // This fixes $(...).attr() to work as expected with SVG elements. - // Does not currently use *AttributeNS() since we rarely need that. - - // See http://api.jquery.com/attr/ for basic documentation of .attr() - - // Additional functionality: - // - When getting attributes, a string that's a number is return as type number. - // - If an array is supplied as first parameter, multiple values are returned - // as an object with values for each given attributes - - var proxied = jQuery.fn.attr, svgns = "http://www.w3.org/2000/svg"; - jQuery.fn.attr = function(key, value) { - var len = this.length; - if(!len) return proxied.apply(this, arguments); - for(var i=0; i<len; i++) { - var elem = this[i]; - // set/get SVG attribute - if(elem.namespaceURI === svgns) { - // Setting attribute - if(value !== undefined) { - elem.setAttribute(key, value); - } else if($.isArray(key)) { - // Getting attributes from array - var j = key.length, obj = {}; - - while(j--) { - var aname = key[j]; - var attr = elem.getAttribute(aname); - // This returns a number when appropriate - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - obj[aname] = attr; - } - return obj; - - } else if(typeof key === "object") { - // Setting attributes form object - for(var v in key) { - elem.setAttribute(v, key[v]); - } - // Getting attribute - } else { - var attr = elem.getAttribute(key); - if(attr || attr === "0") { - attr = isNaN(attr)?attr:attr-0; - } - - return attr; - } - } else { - return proxied.apply(this, arguments); - } - } - return this; - }; - -}()); - -// Class: SvgCanvas -// The main SvgCanvas class that manages all SVG-related functions -// -// Parameters: -// container - The container HTML element that should hold the SVG root element -// config - An object that contains configuration data -$.SvgCanvas = function(container, config) -{ -// Namespace constants -var svgns = "http://www.w3.org/2000/svg", - xlinkns = "http://www.w3.org/1999/xlink", - xmlns = "http://www.w3.org/XML/1998/namespace", - xmlnsns = "http://www.w3.org/2000/xmlns/", // see http://www.w3.org/TR/REC-xml-names/#xmlReserved - se_ns = "http://svg-edit.googlecode.com", - htmlns = "http://www.w3.org/1999/xhtml", - mathns = "http://www.w3.org/1998/Math/MathML"; - -// Default configuration options -var curConfig = { - show_outside_canvas: true, - selectNew: true, - dimensions: [640, 480] -}; - -// Update config with new one if given -if(config) { - $.extend(curConfig, config); -} - -// Array with width/height of canvas -var dimensions = curConfig.dimensions; - -var canvas = this; - -// "document" element associated with the container (same as window.document using default svg-editor.js) -// NOTE: This is not actually a SVG document, but a HTML document. -var svgdoc = container.ownerDocument; - -// This is a container for the document being edited, not the document itself. -var svgroot = svgdoc.importNode(svgedit.utilities.text2xml( - '<svg id="svgroot" xmlns="' + svgns + '" xlinkns="' + xlinkns + '" ' + - 'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' + - '<defs>' + - '<filter id="canvashadow" filterUnits="objectBoundingBox">' + - '<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>'+ - '<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>'+ - '<feMerge>'+ - '<feMergeNode in="offsetBlur"/>'+ - '<feMergeNode in="SourceGraphic"/>'+ - '</feMerge>'+ - '</filter>'+ - '</defs>'+ - '</svg>').documentElement, true); -container.appendChild(svgroot); - -// The actual element that represents the final output SVG element -var svgcontent = svgdoc.createElementNS(svgns, "svg"); - -// This function resets the svgcontent element while keeping it in the DOM. -var clearSvgContentElement = canvas.clearSvgContentElement = function() { - while (svgcontent.firstChild) { svgcontent.removeChild(svgcontent.firstChild); } - - // TODO: Clear out all other attributes first? - $(svgcontent).attr({ - id: 'svgcontent', - width: dimensions[0], - height: dimensions[1], - x: dimensions[0], - y: dimensions[1], - overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden', - xmlns: svgns, - "xmlns:se": se_ns, - "xmlns:xlink": xlinkns - }).appendTo(svgroot); - - // TODO: make this string optional and set by the client - var comment = svgdoc.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ "); - svgcontent.appendChild(comment); -}; -clearSvgContentElement(); - -// Prefix string for element IDs -var idprefix = "svg_"; - -// Function: setIdPrefix -// Changes the ID prefix to the given value -// -// Parameters: -// p - String with the new prefix -canvas.setIdPrefix = function(p) { - idprefix = p; -}; - -// Current svgedit.draw.Drawing object -// @type {svgedit.draw.Drawing} -canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - -// Function: getCurrentDrawing -// Returns the current Drawing. -// @return {svgedit.draw.Drawing} -var getCurrentDrawing = canvas.getCurrentDrawing = function() { - return canvas.current_drawing_; -}; - -// Float displaying the current zoom level (1 = 100%, .5 = 50%, etc) -var current_zoom = 1; - -// pointer to current group (for in-group editing) -var current_group = null; - -// Object containing data for the currently selected styles -var all_properties = { - shape: { - fill: (curConfig.initFill.color == 'none' ? '' : '#') + curConfig.initFill.color, - fill_paint: null, - fill_opacity: curConfig.initFill.opacity, - stroke: "#" + curConfig.initStroke.color, - stroke_paint: null, - stroke_opacity: curConfig.initStroke.opacity, - stroke_width: curConfig.initStroke.width, - stroke_dasharray: 'none', - stroke_linejoin: 'miter', - stroke_linecap: 'butt', - opacity: curConfig.initOpacity - } -}; - -all_properties.text = $.extend(true, {}, all_properties.shape); -$.extend(all_properties.text, { - fill: "#000000", - stroke_width: 0, - font_size: 24, - font_family: 'Junction' -}); - -// Current shape style properties -var cur_shape = all_properties.shape; - -// Array with all the currently selected elements -// default size of 1 until it needs to grow bigger -var selectedElements = new Array(1); - -// Function: addSvgElementFromJson -// Create a new SVG element based on the given object keys/values and add it to the current layer -// The element will be ran through cleanupElement before being returned -// -// Parameters: -// data - Object with the following keys/values: -// * element - tag name of the SVG element to create -// * attr - Object with attributes key-values to assign to the new element -// * curStyles - Boolean indicating that current style attributes should be applied first -// -// Returns: The new element -var addSvgElementFromJson = this.addSvgElementFromJson = function(data) { - var shape = svgedit.utilities.getElem(data.attr.id); - // if shape is a path but we need to create a rect/ellipse, then remove the path - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (shape && data.element != shape.tagName) { - current_layer.removeChild(shape); - shape = null; - } - if (!shape) { - shape = svgdoc.createElementNS(svgns, data.element); - if (current_layer) { - (current_group || current_layer).appendChild(shape); - } - } - if(data.curStyles) { - svgedit.utilities.assignAttributes(shape, { - "fill": cur_shape.fill, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill-opacity": cur_shape.fill_opacity, - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - }, 100); - } - svgedit.utilities.assignAttributes(shape, data.attr, 100); - svgedit.utilities.cleanupElement(shape); - return shape; -}; - - -// import svgtransformlist.js -var getTransformList = canvas.getTransformList = svgedit.transformlist.getTransformList; - -// import from math.js. -var transformPoint = svgedit.math.transformPoint; -var matrixMultiply = canvas.matrixMultiply = svgedit.math.matrixMultiply; -var hasMatrixTransform = canvas.hasMatrixTransform = svgedit.math.hasMatrixTransform; -var transformListToTransform = canvas.transformListToTransform = svgedit.math.transformListToTransform; -var snapToAngle = svgedit.math.snapToAngle; -var getMatrix = svgedit.math.getMatrix; - -// initialize from units.js -// send in an object implementing the ElementContainer interface (see units.js) -svgedit.units.init({ - getBaseUnit: function() { return curConfig.baseUnit; }, - getElement: svgedit.utilities.getElem, - getHeight: function() { return svgcontent.getAttribute("height")/current_zoom; }, - getWidth: function() { return svgcontent.getAttribute("width")/current_zoom; }, - getRoundDigits: function() { return save_options.round_digits; } -}); -// import from units.js -var convertToNum = canvas.convertToNum = svgedit.units.convertToNum; - -// import from svgutils.js -svgedit.utilities.init({ - getDOMDocument: function() { return svgdoc; }, - getDOMContainer: function() { return container; }, - getSVGRoot: function() { return svgroot; }, - // TODO: replace this mostly with a way to get the current drawing. - getSelectedElements: function() { return selectedElements; }, - getSVGContent: function() { return svgcontent; } -}); -var getUrlFromAttr = canvas.getUrlFromAttr = svgedit.utilities.getUrlFromAttr; -var getHref = canvas.getHref = svgedit.utilities.getHref; -var setHref = canvas.setHref = svgedit.utilities.setHref; -var getPathBBox = svgedit.utilities.getPathBBox; -var getBBox = canvas.getBBox = svgedit.utilities.getBBox; -var getRotationAngle = canvas.getRotationAngle = svgedit.utilities.getRotationAngle; -var getElem = canvas.getElem = svgedit.utilities.getElem; -var assignAttributes = canvas.assignAttributes = svgedit.utilities.assignAttributes; -var cleanupElement = this.cleanupElement = svgedit.utilities.cleanupElement; - -// import from sanitize.js -var nsMap = svgedit.sanitize.getNSMap(); -var sanitizeSvg = canvas.sanitizeSvg = svgedit.sanitize.sanitizeSvg; - -// import from history.js -var MoveElementCommand = svgedit.history.MoveElementCommand; -var InsertElementCommand = svgedit.history.InsertElementCommand; -var RemoveElementCommand = svgedit.history.RemoveElementCommand; -var ChangeElementCommand = svgedit.history.ChangeElementCommand; -var BatchCommand = svgedit.history.BatchCommand; -// Implement the svgedit.history.HistoryEventHandler interface. -canvas.undoMgr = new svgedit.history.UndoManager({ - handleHistoryEvent: function(eventType, cmd) { - var EventTypes = svgedit.history.HistoryEventTypes; - // TODO: handle setBlurOffsets. - if (eventType == EventTypes.BEFORE_UNAPPLY || eventType == EventTypes.BEFORE_APPLY) { - canvas.clearSelection(); - } else if (eventType == EventTypes.AFTER_APPLY || eventType == EventTypes.AFTER_UNAPPLY) { - var elems = cmd.elements(); - canvas.pathActions.clear(); - call("changed", elems); - - var cmdType = cmd.type(); - var isApply = (eventType == EventTypes.AFTER_APPLY); - if (cmdType == MoveElementCommand.type()) { - var parent = isApply ? cmd.newParent : cmd.oldParent; - if (parent == svgcontent) { - canvas.identifyLayers(); - } - } else if (cmdType == InsertElementCommand.type() || - cmdType == RemoveElementCommand.type()) { - if (cmd.parent == svgcontent) { - canvas.identifyLayers(); - } - if (cmdType == InsertElementCommand.type()) { - if (isApply) restoreRefElems(cmd.elem); - } else { - if (!isApply) restoreRefElems(cmd.elem); - } - - if(cmd.elem.tagName === 'use') { - setUseData(cmd.elem); - } - } else if (cmdType == ChangeElementCommand.type()) { - // if we are changing layer names, re-identify all layers - if (cmd.elem.tagName == "title" && cmd.elem.parentNode.parentNode == svgcontent) { - canvas.identifyLayers(); - } - var values = isApply ? cmd.newValues : cmd.oldValues; - // If stdDeviation was changed, update the blur. - if (values["stdDeviation"]) { - canvas.setBlurOffsets(cmd.elem.parentNode, values["stdDeviation"]); - } - - // Remove & Re-add hack for Webkit (issue 775) - if(cmd.elem.tagName === 'use' && svgedit.browser.isWebkit()) { - var elem = cmd.elem; - if(!elem.getAttribute('x') && !elem.getAttribute('y')) { - var parent = elem.parentNode; - var sib = elem.nextSibling; - parent.removeChild(elem); - parent.insertBefore(elem, sib); - } - } - } - } - } -}); -var addCommandToHistory = function(cmd) { - canvas.undoMgr.addCommandToHistory(cmd); -}; - -// import from select.js -svgedit.select.init(curConfig, { - createSVGElement: function(jsonMap) { return canvas.addSvgElementFromJson(jsonMap); }, - svgRoot: function() { return svgroot; }, - svgContent: function() { return svgcontent; }, - currentZoom: function() { return current_zoom; }, - // TODO(codedread): Remove when getStrokedBBox() has been put into svgutils.js. - getStrokedBBox: function(elems) { return canvas.getStrokedBBox([elems]); } -}); -// this object manages selectors for us -var selectorManager = this.selectorManager = svgedit.select.getSelectorManager(); - -// Import from path.js -svgedit.path.init({ - getCurrentZoom: function() { return current_zoom; }, - getSVGRoot: function() { return svgroot; } -}); - -// Function: snapToGrid -// round value to for snapping -// NOTE: This function did not move to svgutils.js since it depends on curConfig. -svgedit.utilities.snapToGrid = function(value){ - var stepSize = curConfig.snappingStep; - var unit = curConfig.baseUnit; - if(unit !== "px") { - stepSize *= svgedit.units.getTypeMap()[unit]; - } - value = Math.round(value/stepSize)*stepSize; - return value; -}; -var snapToGrid = svgedit.utilities.snapToGrid; - -// Interface strings, usually for title elements -var uiStrings = { - "exportNoBlur": "Blurred elements will appear as un-blurred", - "exportNoforeignObject": "foreignObject elements will not appear", - "exportNoDashArray": "Strokes will appear filled", - "exportNoText": "Text may not appear as expected" -}; - -var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; -var ref_attrs = ["clip-path", "fill", "filter", "marker-end", "marker-mid", "marker-start", "mask", "stroke"]; - -var elData = $.data; - -// Animation element to change the opacity of any newly created element -var opac_ani = false; //document.createElementNS(svgns, 'animate'); -//$(opac_ani).attr({ -// attributeName: 'opacity', -// begin: 'indefinite', -// dur: 0, -// fill: 'freeze' -//}).appendTo(svgroot); - -var restoreRefElems = function(elem) { - // Look for missing reference elements, restore any found - var attrs = $(elem).attr(ref_attrs); - for(var o in attrs) { - var val = attrs[o]; - if (val && val.indexOf('url(') === 0) { - var id = getUrlFromAttr(val).substr(1); - var ref = getElem(id); - if(!ref) { - findDefs().appendChild(removedElements[id]); - delete removedElements[id]; - } - } - } - - var childs = elem.getElementsByTagName('*'); - - if(childs.length) { - for(var i = 0, l = childs.length; i < l; i++) { - restoreRefElems(childs[i]); - } - } -}; - -(function() { - // TODO For Issue 208: this is a start on a thumbnail - // var svgthumb = svgdoc.createElementNS(svgns, "use"); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // svgedit.utilities.setHref(svgthumb, '#svgcontent'); - // svgroot.appendChild(svgthumb); - -})(); - -// Object to contain image data for raster images that were found encodable -var encodableImages = {}, - - // String with image URL of last loadable image - last_good_img_url = curConfig.imgPath + 'logo.png', - - // Array with current disabled elements (for in-group editing) - disabled_elems = [], - - // Object with save options - save_options = {round_digits: 5}, - - // Boolean indicating whether or not a draw action has been started - started = false, - - // String with an element's initial transform attribute value - start_transform = null, - - // String indicating the current editor mode - current_mode = "select", - - // String with the current direction in which an element is being resized - current_resize_mode = "none", - - // Object with IDs for imported files, to see if one was already added - import_ids = {}; - -// Current text style properties -var cur_text = all_properties.text, - - // Current general properties - cur_properties = cur_shape, - - // Array with selected elements' Bounding box object -// selectedBBoxes = new Array(1), - - // The DOM element that was just selected - justSelected = null, - - // DOM element for selection rectangle drawn by the user - rubberBox = null, - - // Array of current BBoxes (still needed?) - curBBoxes = [], - - // Object to contain all included extensions - extensions = {}, - - // Canvas point for the most recent right click - lastClickPoint = null, - - // Map of deleted reference elements - removedElements = {} - -// Clipboard for cut, copy&pasted elements -canvas.clipBoard = []; - -// Should this return an array by default, so extension results aren't overwritten? -var runExtensions = this.runExtensions = function(action, vars, returnArray) { - var result = false; - if(returnArray) result = []; - $.each(extensions, function(name, opts) { - if(action in opts) { - if(returnArray) { - result.push(opts[action](vars)) - } else { - result = opts[action](vars); - } - } - }); - return result; -} - -// Function: addExtension -// Add an extension to the editor -// -// Parameters: -// name - String with the ID of the extension -// ext_func - Function supplied by the extension with its data -this.addExtension = function(name, ext_func) { - if(!(name in extensions)) { - // Provide private vars/funcs here. Is there a better way to do this? - - if($.isFunction(ext_func)) { - var ext = ext_func($.extend(canvas.getPrivateMethods(), { - svgroot: svgroot, - svgcontent: svgcontent, - nonce: getCurrentDrawing().getNonce(), - selectorManager: selectorManager - })); - } else { - var ext = ext_func; - } - extensions[name] = ext; - call("extension_added", ext); - } else { - console.log('Cannot add extension "' + name + '", an extension by that name already exists"'); - } -}; - -// This method rounds the incoming value to the nearest value based on the current_zoom -var round = this.round = function(val) { - return parseInt(val*current_zoom)/current_zoom; -}; - -// This method sends back an array or a NodeList full of elements that -// intersect the multi-select rubber-band-box on the current_layer only. -// -// Since the only browser that supports the SVG DOM getIntersectionList is Opera, -// we need to provide an implementation here. We brute-force it for now. -// -// Reference: -// Firefox does not implement getIntersectionList(), see https://bugzilla.mozilla.org/show_bug.cgi?id=501421 -// Webkit does not implement getIntersectionList(), see https://bugs.webkit.org/show_bug.cgi?id=11274 -var getIntersectionList = this.getIntersectionList = function(rect) { - if (rubberBox == null) { return null; } - - var parent = current_group || getCurrentDrawing().getCurrentLayer(); - - if(!curBBoxes.length) { - // Cache all bboxes - curBBoxes = getVisibleElementsAndBBoxes(parent); - } - - var resultList = null; - try { - resultList = parent.getIntersectionList(rect, null); - } catch(e) { } - - if (resultList == null || typeof(resultList.item) != "function") { - resultList = []; - - if(!rect) { - var rubberBBox = rubberBox.getBBox(); - var bb = {}; - - for(var o in rubberBBox) { - bb[o] = rubberBBox[o] / current_zoom; - } - rubberBBox = bb; - - } else { - var rubberBBox = rect; - } - var i = curBBoxes.length; - while (i--) { - if(!rubberBBox.width || !rubberBBox.width) continue; - if (svgedit.math.rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); - } - } - } - // addToSelection expects an array, but it's ok to pass a NodeList - // because using square-bracket notation is allowed: - // http://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html - return resultList; -}; - -// TODO(codedread): Migrate this into svgutils.js -// Function: getStrokedBBox -// Get the bounding box for one or more stroked and/or transformed elements -// -// Parameters: -// elems - Array with DOM elements to check -// -// Returns: -// A single bounding box object -getStrokedBBox = this.getStrokedBBox = function(elems) { - if(!elems) elems = getVisibleElements(); - if(!elems.length) return false; - // Make sure the expected BBox is returned if the element is a group - 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 - // in Issue 339 comment #2). - - var bb = svgedit.utilities.getBBox(elem); - - var angle = svgedit.utilities.getRotationAngle(elem); - if ((angle && angle % 90) || - svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(elem))) { - // Accurate way to get BBox of rotated element in Firefox: - // Put element in group and get its BBox - - var good_bb = false; - - // Get the BBox from the raw path for these elements - var elemNames = ['ellipse','path','line','polyline','polygon']; - if(elemNames.indexOf(elem.tagName) >= 0) { - bb = good_bb = canvas.convertToPath(elem, true); - } else if(elem.tagName == 'rect') { - // Look for radius - var rx = elem.getAttribute('rx'); - var ry = elem.getAttribute('ry'); - if(rx || ry) { - bb = good_bb = canvas.convertToPath(elem, true); - } - } - - if(!good_bb) { - // Must use clone else FF freaks out - var clone = elem.cloneNode(true); - var g = document.createElementNS(svgns, "g"); - var parent = elem.parentNode; - parent.appendChild(g); - g.appendChild(clone); - bb = svgedit.utilities.bboxToObj(g.getBBox()); - parent.removeChild(g); - } - - - // Old method: Works by giving the rotated BBox, - // this is (unfortunately) what Opera and Safari do - // natively when getting the BBox of the parent group -// var angle = angle * Math.PI / 180.0; -// var rminx = Number.MAX_VALUE, rminy = Number.MAX_VALUE, -// rmaxx = Number.MIN_VALUE, rmaxy = Number.MIN_VALUE; -// var cx = round(bb.x + bb.width/2), -// cy = round(bb.y + bb.height/2); -// var pts = [ [bb.x - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y - cy], -// [bb.x + bb.width - cx, bb.y + bb.height - cy], -// [bb.x - cx, bb.y + bb.height - cy] ]; -// var j = 4; -// while (j--) { -// var x = pts[j][0], -// y = pts[j][1], -// r = Math.sqrt( x*x + y*y ); -// var theta = Math.atan2(y,x) + angle; -// x = round(r * Math.cos(theta) + cx); -// y = round(r * Math.sin(theta) + cy); -// -// // now set the bbox for the shape after it's been rotated -// if (x < rminx) rminx = x; -// if (y < rminy) rminy = y; -// if (x > rmaxx) rmaxx = x; -// if (y > rmaxy) rmaxy = y; -// } -// -// bb.x = rminx; -// bb.y = rminy; -// bb.width = rmaxx - rminx; -// bb.height = rmaxy - rminy; - } - return bb; - } catch(e) { - console.log(elem, e); - return null; - } - }; - - var full_bb; - $.each(elems, function() { - if(full_bb) return; - if(!this.parentNode) return; - full_bb = getCheckedBBox(this); - }); - - // This shouldn't ever happen... - if(full_bb == null) return null; - - // full_bb doesn't include the stoke, so this does no good! -// if(elems.length == 1) return full_bb; - - var max_x = full_bb.x + full_bb.width; - var max_y = full_bb.y + full_bb.height; - var min_x = full_bb.x; - var min_y = full_bb.y; - - // FIXME: same re-creation problem with this function as getCheckedBBox() above - var getOffset = function(elem) { - var sw = elem.getAttribute("stroke-width"); - var offset = 0; - if (elem.getAttribute("stroke") != "none" && !isNaN(sw)) { - offset += sw/2; - } - return offset; - } - var bboxes = []; - $.each(elems, function(i, elem) { - var cur_bb = getCheckedBBox(elem); - if(cur_bb) { - var offset = getOffset(elem); - min_x = Math.min(min_x, cur_bb.x - offset); - min_y = Math.min(min_y, cur_bb.y - offset); - bboxes.push(cur_bb); - } - }); - - full_bb.x = min_x; - full_bb.y = min_y; - - $.each(elems, function(i, elem) { - var cur_bb = bboxes[i]; - // ensure that elem is really an element node - if (cur_bb && elem.nodeType == 1) { - var offset = getOffset(elem); - max_x = Math.max(max_x, cur_bb.x + cur_bb.width + offset); - max_y = Math.max(max_y, cur_bb.y + cur_bb.height + offset); - } - }); - - full_bb.width = max_x - min_x; - full_bb.height = max_y - min_y; - return full_bb; -} - -// Function: getVisibleElements -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with all "visible" elements. -var getVisibleElements = this.getVisibleElements = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push(elem); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: getVisibleElementsAndBBoxes -// Get all elements that have a BBox (excludes <defs>, <title>, etc). -// Note that 0-opacity, off-screen etc elements are still considered "visible" -// for this function -// -// Parameters: -// parent - The parent DOM element to search within -// -// Returns: -// An array with objects that include: -// * elem - The element -// * bbox - The element's BBox as retrieved from getStrokedBBox -var getVisibleElementsAndBBoxes = this.getVisibleElementsAndBBoxes = function(parent) { - if(!parent) parent = $(svgcontent).children(); // Prevent layers from being included - - var contentElems = []; - $(parent).children().each(function(i, elem) { - try { - if (elem.getBBox()) { - contentElems.push({'elem':elem, 'bbox':getStrokedBBox([elem])}); - } - } catch(e) {} - }); - return contentElems.reverse(); -}; - -// Function: groupSvgElem -// Wrap an SVG element into a group element, mark the group as 'gsvg' -// -// Parameters: -// elem - SVG element to wrap -var groupSvgElem = this.groupSvgElem = function(elem) { - var g = document.createElementNS(svgns, "g"); - elem.parentNode.replaceChild(g, elem); - $(g).append(elem).data('gsvg', elem)[0].id = getNextId(); -} - -// Function: copyElem -// Create a clone of an element, updating its ID and its children's IDs when needed -// -// Parameters: -// el - DOM element to clone -// -// Returns: The cloned element -var copyElem = function(el) { - var new_el = document.createElementNS(el.namespaceURI, el.nodeName); - // set the copied element's new id - new_el.removeAttribute("id"); - // manually create a copy of the element - $.each(el.attributes, function(i, attr) { - if (attr.localName != '-moz-math-font-style') { - new_el.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.nodeValue); - } - }); - - // Opera's "d" value needs to be reset for Opera/Win/non-EN - // Also needed for webkit (else does not keep curved segments on clone) - if(svgedit.browser.isWebkit() && el.nodeName == 'path') { - var fixed_d = pathActions.convertPath(el); - new_el.setAttribute('d', fixed_d); - } - - // now create copies of all children - $.each(el.childNodes, function(i, child) { - switch(child.nodeType) { - case 1: // element node - new_el.appendChild(copyElem(child)); - break; - case 3: // text node - new_el.textContent = child.nodeValue; - break; - default: - break; - } - }); - - if($(el).data('gsvg')) { - $(new_el).data('gsvg', new_el.firstChild); - } 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); - } - new_el.id = getNextId(); - console.log(new_el); - return new_el; -}; - -// Set scope for these functions -var getId, getNextId, call; - -(function(c) { - - // Object to contain editor event names and callback functions - var events = {}; - - getId = c.getId = function() { return getCurrentDrawing().getId(); }; - getNextId = c.getNextId = function() { return getCurrentDrawing().getNextId(); }; - - // Function: call - // Run the callback function associated with the given event - // - // Parameters: - // event - String with the event name - // arg - Argument to pass through to the callback function - call = c.call = function(event, arg) { - if (events[event]) { - return events[event](this, arg); - } - }; - - // Function: bind - // Attaches a callback function to an event - // - // Parameters: - // event - String indicating the name of the event - // f - The callback function to bind to the event - // - // Return: - // The previous event - c.bind = function(event, f) { - var old = events[event]; - events[event] = f; - return old; - }; - -}(canvas)); - -// Function: canvas.prepareSvg -// Runs the SVG Document through the sanitizer and then updates its paths. -// -// Parameters: -// newDoc - The SVG DOM document -this.prepareSvg = function(newDoc) { - this.sanitizeSvg(newDoc.documentElement); - - // convert paths into absolute commands - var paths = newDoc.getElementsByTagNameNS(svgns, "path"); - for (var i = 0, len = paths.length; i < len; ++i) { - var path = paths[i]; - path.setAttribute('d', pathActions.convertPath(path)); - pathActions.fixEnd(path); - } -}; - -// Function getRefElem -// Get the reference element associated with the given attribute value -// -// Parameters: -// attrVal - The attribute value as a string -var getRefElem = this.getRefElem = function(attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); -} - -// Function: ffClone -// Hack for Firefox bugs where text element features aren't updated or get -// messed up. See issue 136 and issue 137. -// This function clones the element and re-selects it -// TODO: Test for this bug on load and add it to "support" object instead of -// browser sniffing -// -// Parameters: -// elem - The (text) DOM element to clone -var ffClone = function(elem) { - if(!svgedit.browser.isGecko()) return elem; - var clone = elem.cloneNode(true) - elem.parentNode.insertBefore(clone, elem); - elem.parentNode.removeChild(elem); - selectorManager.releaseSelector(elem); - selectedElements[0] = clone; - selectorManager.requestSelector(clone).showGrips(true); - return clone; -} - - -// this.each is deprecated, if any extension used this it can be recreated by doing this: -// $(canvas.getRootElem()).children().each(...) - -// this.each = function(cb) { -// $(svgroot).children().each(cb); -// }; - - -// Function: setRotationAngle -// Removes any old rotations if present, prepends a new rotation at the -// transformed center -// -// Parameters: -// val - The new rotation angle in degrees -// preventUndo - Boolean indicating whether the action should be undoable or not -this.setRotationAngle = function(val, preventUndo) { - // ensure val is the proper type - val = parseFloat(val); - var elem = selectedElements[0]; - var oldTransform = elem.getAttribute("transform"); - var bbox = svgedit.utilities.getBBox(elem); - var cx = bbox.x+bbox.width/2, cy = bbox.y+bbox.height/2; - var tlist = getTransformList(elem); - - // only remove the real rotational transform if present (i.e. at index=0) - if (tlist.numberOfItems > 0) { - var xform = tlist.getItem(0); - if (xform.type == 4) { - tlist.removeItem(0); - } - } - // find R_nc and insert it - if (val != 0) { - var center = transformPoint(cx,cy,transformListToTransform(tlist).matrix); - var R_nc = svgroot.createSVGTransform(); - R_nc.setRotate(val, center.x, center.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(R_nc, 0); - } else { - tlist.appendItem(R_nc); - } - } - else if (tlist.numberOfItems == 0) { - elem.removeAttribute("transform"); - } - - if (!preventUndo) { - // we need to undo it, then redo it so it can be undo-able! :) - // TODO: figure out how to make changes to transform list undo-able cross-browser? - var newTransform = elem.getAttribute("transform"); - elem.setAttribute("transform", oldTransform); - changeSelectedAttribute("transform",newTransform,selectedElements); - call("changed", selectedElements); - } - var pointGripContainer = getElem("pathpointgrip_container"); -// if(elem.nodeName == "path" && pointGripContainer) { -// pathActions.setPointContainerTransform(elem.getAttribute("transform")); -// } - var selector = selectorManager.requestSelector(selectedElements[0]); - selector.resize(); - selector.updateGripCursors(val); -}; - -// Function: recalculateAllSelectedDimensions -// Runs recalculateDimensions on the selected elements, -// adding the changes to a single batch command -var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function() { - var text = (current_resize_mode == "none" ? "position" : "size"); - var batchCmd = new BatchCommand(text); - - var i = selectedElements.length; - while(i--) { - var elem = selectedElements[i]; -// if(getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) continue; - var cmd = recalculateDimensions(elem); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - } - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - call("changed", selectedElements); - } -}; - -// this is how we map paths to our preferred relative segment types -var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', - 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; - -// Debug tool to easily see the current matrix in the browser's console -var logMatrix = function(m) { - console.log([m.a,m.b,m.c,m.d,m.e,m.f]); -}; - -// Function: remapElement -// Applies coordinate changes to an element based on the given matrix -// -// Parameters: -// selected - DOM element to be changed -// changes - Object with changes to be remapped -// m - Matrix object to use for remapping coordinates -var remapElement = this.remapElement = function(selected,changes,m) { - - var remap = function(x,y) { return transformPoint(x,y,m); }, - scalew = function(w) { return m.a*w; }, - scaleh = function(h) { return m.d*h; }, - doSnapping = curConfig.gridSnapping && selected.parentNode.parentNode.localName === "svg", - finishUp = function() { - if(doSnapping) for(var o in changes) changes[o] = snapToGrid(changes[o]); - assignAttributes(selected, changes, 1000, true); - } - box = svgedit.utilities.getBBox(selected); - - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = selected.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - if(m.a < 0 || m.d < 0) { - var grad = getRefElem(attrVal); - var newgrad = grad.cloneNode(true); - - if(m.a < 0) { - //flip x - var x1 = newgrad.getAttribute('x1'); - var x2 = newgrad.getAttribute('x2'); - newgrad.setAttribute('x1', -(x1 - 1)); - newgrad.setAttribute('x2', -(x2 - 1)); - } - - if(m.d < 0) { - //flip y - var y1 = newgrad.getAttribute('y1'); - var y2 = newgrad.getAttribute('y2'); - newgrad.setAttribute('y1', -(y1 - 1)); - newgrad.setAttribute('y2', -(y2 - 1)); - } - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - selected.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - - // Not really working :( -// if(selected.tagName === 'path') { -// reorientGrads(selected, m); -// } - } - } - - - var elName = selected.tagName; - if(elName === "g" || elName === "text" || elName === "use") { - // if it was a translate, then just update x,y - if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && - (m.e != 0 || m.f != 0) ) - { - // [T][M] = [M][T'] - // therefore [T'] = [M_inv][T][M] - var existing = transformListToTransform(selected).matrix, - t_new = matrixMultiply(existing.inverse(), m, existing); - changes.x = parseFloat(changes.x) + t_new.e; - changes.y = parseFloat(changes.y) + t_new.f; - } - else { - // we just absorb all matrices into the element and don't do any remapping - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } - } - - // now we have a set of changes and an applied reduced transform list - // we apply the changes directly to the DOM - switch (elName) - { - case "foreignObject": - case "rect": - case "image": - - // Allow images to be inverted (give them matrix when flipped) - if(elName === 'image' && (m.a < 0 || m.d < 0)) { - // Convert to matrix - var chlist = getTransformList(selected); - var mt = svgroot.createSVGTransform(); - mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix,m)); - chlist.clear(); - chlist.appendItem(mt); - } else { - var pt1 = remap(changes.x,changes.y); - - changes.width = scalew(changes.width); - changes.height = scaleh(changes.height); - - changes.x = pt1.x + Math.min(0,changes.width); - changes.y = pt1.y + Math.min(0,changes.height); - changes.width = Math.abs(changes.width); - changes.height = Math.abs(changes.height); - } - finishUp(); - break; - case "ellipse": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - changes.rx = scalew(changes.rx); - changes.ry = scaleh(changes.ry); - - changes.rx = Math.abs(changes.rx); - changes.ry = Math.abs(changes.ry); - finishUp(); - break; - case "circle": - var c = remap(changes.cx,changes.cy); - changes.cx = c.x; - changes.cy = c.y; - // take the minimum of the new selected box's dimensions for the new circle radius - var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m); - var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y; - changes.r = Math.min(w/2, h/2); - - if(changes.r) changes.r = Math.abs(changes.r); - finishUp(); - break; - case "line": - var pt1 = remap(changes.x1,changes.y1), - pt2 = remap(changes.x2,changes.y2); - changes.x1 = pt1.x; - changes.y1 = pt1.y; - changes.x2 = pt2.x; - changes.y2 = pt2.y; - - case "text": - var tspan = selected.querySelectorAll('tspan'); - var i = tspan.length - while(i--) { - var selX = convertToNum("x", selected.getAttribute('x')); - var tx = convertToNum("x", tspan[i].getAttribute('x')); - var selY = convertToNum("y", selected.getAttribute('y')); - var ty = convertToNum("y", tspan[i].getAttribute('y')); - var offset = new Object(); - if (!isNaN(selX) && !isNaN(tx) && selX!=0 && tx!=0 && changes.x) - offset.x = changes.x - (selX - tx); - if (!isNaN(selY) && !isNaN(ty) && selY!=0 && ty!=0 && changes.y) - offset.y = changes.y - (selY - ty); - if (offset.x || offset.y) - assignAttributes(tspan[i], offset, 1000, true); - } - finishUp(); - break; - case "use": - finishUp(); - break; - case "g": - var gsvg = $(selected).data('gsvg'); - if(gsvg) { - assignAttributes(gsvg, changes, 1000, true); - } - break; - case "polyline": - case "polygon": - var len = changes.points.length; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pt = remap(pt.x,pt.y); - changes.points[i].x = pt.x; - changes.points[i].y = pt.y; - } - - var len = changes.points.length; - var pstr = ""; - for (var i = 0; i < len; ++i) { - var pt = changes.points[i]; - pstr += pt.x + "," + pt.y + " "; - } - selected.setAttribute("points", pstr); - break; - case "path": - - var segList = selected.pathSegList; - var len = segList.numberOfItems; - changes.d = new Array(len); - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - changes.d[i] = { - type: seg.pathSegType, - x: seg.x, - y: seg.y, - x1: seg.x1, - y1: seg.y1, - x2: seg.x2, - y2: seg.y2, - r1: seg.r1, - r2: seg.r2, - angle: seg.angle, - largeArcFlag: seg.largeArcFlag, - sweepFlag: seg.sweepFlag - }; - } - - var len = changes.d.length, - firstseg = changes.d[0], - currentpt = remap(firstseg.x,firstseg.y); - changes.d[0].x = currentpt.x; - changes.d[0].y = currentpt.y; - for (var i = 1; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 - // if relative, we want to scalew, scaleh - if (type % 2 == 0) { // absolute - var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands - thisy = (seg.y != undefined) ? seg.y : currentpt.y, // for H commands - pt = remap(thisx,thisy), - pt1 = remap(seg.x1,seg.y1), - pt2 = remap(seg.x2,seg.y2); - seg.x = pt.x; - seg.y = pt.y; - seg.x1 = pt1.x; - seg.y1 = pt1.y; - seg.x2 = pt2.x; - seg.y2 = pt2.y; - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - else { // relative - seg.x = scalew(seg.x); - seg.y = scaleh(seg.y); - seg.x1 = scalew(seg.x1); - seg.y1 = scaleh(seg.y1); - seg.x2 = scalew(seg.x2); - seg.y2 = scaleh(seg.y2); - seg.r1 = scalew(seg.r1), - seg.r2 = scaleh(seg.r2); - } - } // for each segment - - var dstr = ""; - var len = changes.d.length; - for (var i = 0; i < len; ++i) { - var seg = changes.d[i]; - var type = seg.type; - dstr += pathMap[type]; - switch(type) { - case 13: // relative horizontal line (h) - case 12: // absolute horizontal line (H) - dstr += seg.x + " "; - break; - case 15: // relative vertical line (v) - case 14: // absolute vertical line (V) - dstr += seg.y + " "; - break; - case 3: // relative move (m) - case 5: // relative line (l) - case 19: // relative smooth quad (t) - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - dstr += seg.x + "," + seg.y + " "; - break; - case 7: // relative cubic (c) - case 6: // absolute cubic (C) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x2 + "," + seg.y2 + " " + - seg.x + "," + seg.y + " "; - break; - case 9: // relative quad (q) - case 8: // absolute quad (Q) - dstr += seg.x1 + "," + seg.y1 + " " + seg.x + "," + seg.y + " "; - break; - case 11: // relative elliptical arc (a) - case 10: // absolute elliptical arc (A) - dstr += seg.r1 + "," + seg.r2 + " " + seg.angle + " " + (+seg.largeArcFlag) + - " " + (+seg.sweepFlag) + " " + seg.x + "," + seg.y + " "; - break; - case 17: // relative smooth cubic (s) - case 16: // absolute smooth cubic (S) - dstr += seg.x2 + "," + seg.y2 + " " + seg.x + "," + seg.y + " "; - break; - } - } - - selected.setAttribute("d", dstr); - break; - } -}; - -// Function: updateClipPath -// Updates a <clipPath>s values based on the given translation of an element -// -// Parameters: -// attr - The clip-path attribute value with the clipPath's ID -// tx - The translation's x value -// ty - The translation's y value -var updateClipPath = function(attr, tx, ty) { - var path = getRefElem(attr).firstChild; - - var cp_xform = getTransformList(path); - - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx, ty); - - cp_xform.appendItem(newxlate); - - // Update clipPath's dimensions - recalculateDimensions(path); -} - -// Function: recalculateDimensions -// Decides the course of action based on the element's transform list -// -// Parameters: -// selected - The DOM element to recalculate -// -// Returns: -// Undo command object with the resulting change -var recalculateDimensions = this.recalculateDimensions = function(selected) { - if (selected == null) return null; - - var tlist = getTransformList(selected); - - // remove any unnecessary transforms - if (tlist && tlist.numberOfItems > 0) { - var k = tlist.numberOfItems; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 0) { - tlist.removeItem(k); - } - // remove identity matrices - else if (xform.type === 1) { - if (svgedit.math.isIdentity(xform.matrix)) { - tlist.removeItem(k); - } - } - // remove zero-degree rotations - else if (xform.type === 4) { - if (xform.angle === 0) { - tlist.removeItem(k); - } - } - } - // End here if all it has is a rotation - if(tlist.numberOfItems === 1 && getRotationAngle(selected)) return null; - } - - // if this element had no transforms, we are done - if (!tlist || tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - return null; - } - - // TODO: Make this work for more than 2 - if (tlist) { - var k = tlist.numberOfItems; - var mxs = []; - while (k--) { - var xform = tlist.getItem(k); - if (xform.type === 1) { - mxs.push([xform.matrix, k]); - } else if(mxs.length) { - mxs = []; - } - } - if(mxs.length === 2) { - var m_new = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])); - tlist.removeItem(mxs[0][1]); - tlist.removeItem(mxs[1][1]); - tlist.insertItemBefore(m_new, mxs[1][1]); - } - - // combine matrix + translate - k = tlist.numberOfItems; - if(k >= 2 && tlist.getItem(k-2).type === 1 && tlist.getItem(k-1).type === 2) { - var mt = svgroot.createSVGTransform(); - - var m = matrixMultiply( - tlist.getItem(k-2).matrix, - tlist.getItem(k-1).matrix - ); - mt.setMatrix(m); - tlist.removeItem(k-2); - tlist.removeItem(k-2); - tlist.appendItem(mt); - } - } - - // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). - switch ( selected.tagName ) { - // Ignore these elements, as they can absorb the [M] - case 'line': - case 'polyline': - case 'polygon': - case 'path': - break; - default: - if( - (tlist.numberOfItems === 1 && tlist.getItem(0).type === 1) - || (tlist.numberOfItems === 2 && tlist.getItem(0).type === 1 && tlist.getItem(0).type === 4) - ) { - return null; - } - } - - // Grouped SVG element - var gsvg = $(selected).data('gsvg'); - - // we know we have some transforms, so set up return variable - var batchCmd = new BatchCommand("Transform"); - - // store initial values that will be affected by reducing the transform list - var changes = {}, initial = null, attrs = []; - switch (selected.tagName) - { - case "line": - attrs = ["x1", "y1", "x2", "y2"]; - break; - case "circle": - attrs = ["cx", "cy", "r"]; - break; - case "ellipse": - attrs = ["cx", "cy", "rx", "ry"]; - break; - case "foreignObject": - case "rect": - case "image": - attrs = ["width", "height", "x", "y"]; - break; - case "use": - case "text": - case "tspan": - attrs = ["x", "y"]; - break; - case "polygon": - case "polyline": - initial = {}; - initial["points"] = selected.getAttribute("points"); - var list = selected.points; - var len = list.numberOfItems; - changes["points"] = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes["points"][i] = {x:pt.x,y:pt.y}; - } - break; - case "path": - initial = {}; - initial["d"] = selected.getAttribute("d"); - changes["d"] = selected.getAttribute("d"); - break; - } // switch on element type to get initial values - - if(attrs.length) { - changes = $(selected).attr(attrs); - $.each(changes, function(attr, val) { - changes[attr] = convertToNum(attr, val); - }); - } else if(gsvg) { - // GSVG exception - changes = { - x: $(gsvg).attr('x') || 0, - y: $(gsvg).attr('y') || 0 - }; - } - - // if we haven't created an initial array in polygon/polyline/path, then - // make a copy of initial values and include the transform - if (initial == null) { - initial = $.extend(true, {}, changes); - $.each(initial, function(attr, val) { - initial[attr] = convertToNum(attr, val); - }); - } - // save the start transform value too - initial["transform"] = start_transform ? start_transform : ""; - - // if it's a regular group, we have special processing to flatten transforms - if ((selected.tagName == "g" && !gsvg) || selected.tagName == "a") { - var box = svgedit.utilities.getBBox(selected), - oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix), - m = svgroot.createSVGMatrix(); - - - // temporarily strip off the rotate and save the old center - var gangle = getRotationAngle(selected); - if (gangle) { - var a = gangle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - var tx = 0, ty = 0, - operation = 0, - N = tlist.numberOfItems; - - if(N) { - var first_m = tlist.getItem(0).matrix; - } - - // first, if it was a scale then the second-last transform will be it - if (N >= 3 && tlist.getItem(N-2).type == 3 && - tlist.getItem(N-3).type == 2 && tlist.getItem(N-1).type == 2) - { - operation = 3; // scale - - // if the children are unrotated, pass the scale down directly - // otherwise pass the equivalent matrix() down directly - var tm = tlist.getItem(N-3).matrix, - sm = tlist.getItem(N-2).matrix, - tmn = tlist.getItem(N-1).matrix; - - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - tx = 0; - ty = 0; - if (child.nodeType == 1) { - var childTlist = getTransformList(child); - - // some children might not have a transform (<metadata>, <defs>, etc) - 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; - var childxforms = []; - start_transform = child.getAttribute("transform"); - if(angle || hasMatrixTransform(childTlist)) { - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(matrixMultiply(tm, sm, tmn, m)); - childTlist.clear(); - childTlist.appendItem(e2t); - childxforms.push(e2t); - } - // if not rotated or skewed, push the [T][S][-T] down to the child - else { - // update the transform list with translate,scale,translate - - // slide the [T][S][-T] from the front to the back - // [T][S][-T][M] = [M][T2][S2][-T2] - - // (only bringing [-T] to the right of [M]) - // [T][S][-T][M] = [T][S][M][-T2] - // [-T2] = [M_inv][-T][M] - var t2n = matrixMultiply(m.inverse(), tmn, m); - // [T2] is always negative translation of [-T2] - var t2 = svgroot.createSVGMatrix(); - t2.e = -t2n.e; - t2.f = -t2n.f; - - // [T][S][-T][M] = [M][T2][S2][-T2] - // [S2] = [T2_inv][M_inv][T][S][-T][M][-T2_inv] - var s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()); - - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - translateOrigin.setTranslate(t2n.e, t2n.f); - scale.setScale(s2.a, s2.d); - translateBack.setTranslate(t2.e, t2.f); - childTlist.appendItem(translateBack); - childTlist.appendItem(scale); - childTlist.appendItem(translateOrigin); - childxforms.push(translateBack); - childxforms.push(scale); - childxforms.push(translateOrigin); -// logMatrix(translateBack.matrix); -// logMatrix(scale.matrix); - } // not rotated - batchCmd.addSubCommand( recalculateDimensions(child) ); - // TODO: If any <use> have this group as a parent and are - // referencing this child, then we need to impose a reverse - // scale on it so that when it won't get double-translated -// var uses = selected.getElementsByTagNameNS(svgns, "use"); -// var href = "#"+child.id; -// var u = uses.length; -// while (u--) { -// var useElem = uses.item(u); -// if(href == getHref(useElem)) { -// var usexlate = svgroot.createSVGTransform(); -// usexlate.setTranslate(-tx,-ty); -// getTransformList(useElem).insertItemBefore(usexlate,0); -// batchCmd.addSubCommand( recalculateDimensions(useElem) ); -// } -// } - start_transform = old_start_transform; - } // element - } // for each child - // Remove these transforms from group - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } - else if (N >= 3 && tlist.getItem(N-1).type == 1) - { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - } - // next, check if the first transform was a translate - // if we had [ T1 ] [ M ] we want to transform this into [ M ] [ T2 ] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var T_M = transformListToTransform(tlist).matrix; - tlist.removeItem(0); - var M_inv = transformListToTransform(tlist).matrix.inverse(); - var M2 = matrixMultiply( M_inv, T_M ); - - tx = M2.e; - ty = M2.f; - - if (tx != 0 || ty != 0) { - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - - var clipPaths_done = []; - - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - - // Check if child has clip-path - if(child.getAttribute('clip-path')) { - // tx, ty - var attr = child.getAttribute('clip-path'); - if(clipPaths_done.indexOf(attr) === -1) { - updateClipPath(attr, tx, ty); - clipPaths_done.push(attr); - } - } - - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - - var childTlist = getTransformList(child); - // some children might not have a transform (<metadata>, <defs>, etc) - if (childTlist) { - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - batchCmd.addSubCommand( recalculateDimensions(child) ); - // If any <use> have this group as a parent and are - // referencing this child, then impose a reverse translate on it - // so that when it won't get double-translated - var uses = selected.getElementsByTagNameNS(svgns, "use"); - var href = "#"+child.id; - var u = uses.length; - while (u--) { - var useElem = uses.item(u); - if(href == getHref(useElem)) { - var usexlate = svgroot.createSVGTransform(); - usexlate.setTranslate(-tx,-ty); - getTransformList(useElem).insertItemBefore(usexlate,0); - batchCmd.addSubCommand( recalculateDimensions(useElem) ); - } - } - start_transform = old_start_transform; - } - } - } - - clipPaths_done = []; - - start_transform = old_start_transform; - } - } - // else, a matrix imposition from a parent group - // keep pushing it down to the children - else if (N == 1 && tlist.getItem(0).type == 1 && !gangle) { - operation = 1; - var m = tlist.getItem(0).matrix, - children = selected.childNodes, - c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - 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); - childTlist.clear(); - childTlist.appendItem(e2m,0); - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - - // Convert stroke - // TODO: Find out if this should actually happen somewhere else - var sw = child.getAttribute("stroke-width"); - if (child.getAttribute("stroke") !== "none" && !isNaN(sw)) { - var avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; - child.setAttribute('stroke-width', sw * avg); - } - - } - } - tlist.clear(); - } - // else it was just a rotate - else { - if (gangle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (gangle) { - newcenter = { - x: oldcenter.x + first_m.e, - y: oldcenter.y + first_m.f - }; - - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(gangle,newcenter.x,newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // if it was a resize - else if (operation == 3) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(gangle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(gangle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(), - m_inv = m.inverse(), - extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - tx = extrat.e; - ty = extrat.f; - - if (tx != 0 || ty != 0) { - // now push this transform down to the children - // we pass the translates down to the individual children - var children = selected.childNodes; - var c = children.length; - while (c--) { - var child = children.item(c); - if (child.nodeType == 1) { - var old_start_transform = start_transform; - start_transform = child.getAttribute("transform"); - var childTlist = getTransformList(child); - var newxlate = svgroot.createSVGTransform(); - newxlate.setTranslate(tx,ty); - if(childTlist.numberOfItems) { - childTlist.insertItemBefore(newxlate, 0); - } else { - childTlist.appendItem(newxlate); - } - - batchCmd.addSubCommand( recalculateDimensions(child) ); - start_transform = old_start_transform; - } - } - } - - if (gangle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } - // else, it's a non-group - else { - - // FIXME: box might be null for some elements (<metadata> etc), need to handle this - var box = svgedit.utilities.getBBox(selected); - - // Paths (and possbly other shapes) will have no BBox while still in <defs>, - // but we still may need to recalculate them (see issue 595). - // TODO: Figure out how to get BBox from these elements in case they - // have a rotation transform - - if(!box && selected.tagName != 'path') return null; - - - var m = svgroot.createSVGMatrix(), - // temporarily strip off the rotate and save the old center - angle = getRotationAngle(selected); - if (angle) { - var oldcenter = {x: box.x+box.width/2, y: box.y+box.height/2}, - newcenter = transformPoint(box.x+box.width/2, box.y+box.height/2, - transformListToTransform(tlist).matrix); - - var a = angle * Math.PI / 180; - if ( Math.abs(a) > (1.0e-10) ) { - var s = Math.sin(a)/(1 - Math.cos(a)); - } else { - // FIXME: This blows up if the angle is exactly 0! - var s = 2/a; - } - for (var i = 0; i < tlist.numberOfItems; ++i) { - var xform = tlist.getItem(i); - if (xform.type == 4) { - // extract old center through mystical arts - var rm = xform.matrix; - oldcenter.y = (s*rm.e + rm.f)/2; - oldcenter.x = (rm.e - s*rm.f)/2; - tlist.removeItem(i); - break; - } - } - } - - // 2 = translate, 3 = scale, 4 = rotate, 1 = matrix imposition - var operation = 0; - var N = tlist.numberOfItems; - - // Check if it has a gradient with userSpaceOnUse, in which case - // adjust it by recalculating the matrix transform. - // TODO: Make this work in Webkit using svgedit.transformlist.SVGTransformList - if(!svgedit.browser.isWebkit()) { - var fill = selected.getAttribute('fill'); - if(fill && fill.indexOf('url(') === 0) { - var paint = getRefElem(fill); - var type = 'pattern'; - if(paint.tagName !== type) type = 'gradient'; - var attrVal = paint.getAttribute(type + 'Units'); - if(attrVal === 'userSpaceOnUse') { - //Update the userSpaceOnUse element - m = transformListToTransform(tlist).matrix; - var gtlist = getTransformList(paint); - var gmatrix = transformListToTransform(gtlist).matrix; - m = matrixMultiply(m, gmatrix); - var m_str = "matrix(" + [m.a,m.b,m.c,m.d,m.e,m.f].join(",") + ")"; - paint.setAttribute(type + 'Transform', m_str); - } - } - } - - // first, if it was a scale of a non-skewed element, then the second-last - // transform will be the [S] - // 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) - - // Removed this so a <use> 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; - tlist.removeItem(N-1); - tlist.removeItem(N-2); - tlist.removeItem(N-3); - } // if we had [T][S][-T][M], then this was a skewed element being resized - // Thus, we simply combine it all into one matrix - else if(N == 4 && tlist.getItem(N-1).type == 1) { - operation = 3; // scale - m = transformListToTransform(tlist).matrix; - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(m); - tlist.clear(); - tlist.appendItem(e2t); - // reset the matrix so that the element is not re-mapped - m = svgroot.createSVGMatrix(); - } // if we had [R][T][S][-T][M], then this was a rotated matrix-element - // if we had [T1][M] we want to transform this into [M][T2] - // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] and we can push [T2] - // down to the element - else if ( (N == 1 || (N > 1 && tlist.getItem(1).type != 3)) && - tlist.getItem(0).type == 2) - { - operation = 2; // translate - var oldxlate = tlist.getItem(0).matrix, - meq = transformListToTransform(tlist,1).matrix, - meq_inv = meq.inverse(); - m = matrixMultiply( meq_inv, oldxlate, meq ); - tlist.removeItem(0); - } - // else if this child now has a matrix imposition (from a parent group) - // we might be able to simplify - else if (N == 1 && tlist.getItem(0).type == 1 && !angle) { - // Remap all point-based elements - m = transformListToTransform(tlist).matrix; - switch (selected.tagName) { - case 'line': - changes = $(selected).attr(["x1","y1","x2","y2"]); - case 'polyline': - case 'polygon': - changes.points = selected.getAttribute("points"); - if(changes.points) { - var list = selected.points; - var len = list.numberOfItems; - changes.points = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); - changes.points[i] = {x:pt.x,y:pt.y}; - } - } - case 'path': - changes.d = selected.getAttribute("d"); - operation = 1; - tlist.clear(); - break; - default: - break; - } - } - // if it was a rotation, put the rotate back and return without a command - // (this function has zero work to do for a rotate()) - else { - operation = 4; // rotation - if (angle) { - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle,newcenter.x,newcenter.y); - - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - return null; - } - - // if it was a translate or resize, we need to remap the element and absorb the xform - if (operation == 1 || operation == 2 || operation == 3) { - remapElement(selected,changes,m); - } // if we are remapping - - // if it was a translate, put back the rotate at the new center - if (operation == 2) { - if (angle) { - if(!hasMatrixTransform(tlist)) { - newcenter = { - x: oldcenter.x + m.e, - y: oldcenter.y + m.f - }; - } - var newRot = svgroot.createSVGTransform(); - newRot.setRotate(angle, newcenter.x, newcenter.y); - if(tlist.numberOfItems) { - tlist.insertItemBefore(newRot, 0); - } else { - tlist.appendItem(newRot); - } - } - } - // [Rold][M][T][S][-T] became [Rold][M] - // we want it to be [Rnew][M][Tr] where Tr is the - // translation required to re-center it - // Therefore, [Tr] = [M_inv][Rnew_inv][Rold][M] - else if (operation == 3 && angle) { - var m = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); - roldt.setRotate(angle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); - rnew.setRotate(angle, newcenter.x, newcenter.y); - var rnew_inv = rnew.matrix.inverse(); - var m_inv = m.inverse(); - var extrat = matrixMultiply(m_inv, rnew_inv, rold, m); - - remapElement(selected,changes,extrat); - if (angle) { - if(tlist.numberOfItems) { - tlist.insertItemBefore(rnew, 0); - } else { - tlist.appendItem(rnew); - } - } - } - } // a non-group - - // if the transform list has been emptied, remove it - if (tlist.numberOfItems == 0) { - selected.removeAttribute("transform"); - } - - batchCmd.addSubCommand(new ChangeElementCommand(selected, initial)); - - return batchCmd; -}; - -// Root Current Transformation Matrix in user units -var root_sctm = null; - -// Group: Selection - -// Function: clearSelection -// Clears the selection. The 'selected' handler is then called. -// Parameters: -// noCall - Optional boolean that when true does not call the "selected" handler -var clearSelection = this.clearSelection = function(noCall) { - if (selectedElements[0] != null) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - selectorManager.releaseSelector(elem); - selectedElements[i] = null; - } -// selectedBBoxes[0] = null; - } - if(!noCall) call("selected", selectedElements); -}; - -// TODO: do we need to worry about selectedBBoxes here? - - -// Function: addToSelection -// Adds a list of elements to the selection. The 'selected' handler is then called. -// -// Parameters: -// elemsToAdd - an array of DOM elements to add to the selection -// showGrips - a boolean flag indicating whether the resize grips should be shown -var addToSelection = this.addToSelection = function(elemsToAdd, showGrips) { - if (elemsToAdd.length == 0) { return; } - // find the first null in our selectedElements array - var j = 0; - - while (j < selectedElements.length) { - if (selectedElements[j] == null) { - break; - } - ++j; - } - - // now add each element consecutively - var i = elemsToAdd.length; - while (i--) { - var elem = elemsToAdd[i]; - if (!elem || !svgedit.utilities.getBBox(elem)) continue; - - if(elem.tagName === 'a' && elem.childNodes.length === 1) { - // Make "a" element's child be the selected element - elem = elem.firstChild; - } - - // if it's not already there, add it - if (selectedElements.indexOf(elem) == -1) { - - selectedElements[j] = elem; - - // only the first selectedBBoxes element is ever used in the codebase these days -// if (j == 0) selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - j++; - var sel = selectorManager.requestSelector(elem); - - if (selectedElements.length > 1) { - sel.showGrips(false); - } - } - } - call("selected", selectedElements); - - if (showGrips || selectedElements.length == 1) { - selectorManager.requestSelector(selectedElements[0]).showGrips(true); - } - else { - selectorManager.requestSelector(selectedElements[0]).showGrips(false); - } - - // make sure the elements are in the correct order - // See: http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - - selectedElements.sort(function(a,b) { - if(a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); - } else if(a == null) { - return 1; - } - }); - - // Make sure first elements are not null - while(selectedElements[0] == null) selectedElements.shift(0); -}; - -// Function: selectOnly() -// Selects only the given elements, shortcut for clearSelection(); addToSelection() -// -// Parameters: -// elems - an array of DOM elements to be selected -var selectOnly = this.selectOnly = function(elems, showGrips) { - clearSelection(true); - addToSelection(elems, showGrips); -} - -// TODO: could use slice here to make this faster? -// TODO: should the 'selected' handler - -// Function: removeFromSelection -// Removes elements from the selection. -// -// Parameters: -// elemsToRemove - an array of elements to remove from selection -var removeFromSelection = this.removeFromSelection = function(elemsToRemove) { - if (selectedElements[0] == null) { return; } - if (elemsToRemove.length == 0) { return; } - - // find every element and remove it from our array copy - var newSelectedItems = new Array(selectedElements.length); - j = 0, - len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem) { - // keep the item - if (elemsToRemove.indexOf(elem) == -1) { - newSelectedItems[j] = elem; - j++; - } - else { // remove the item and its selector - selectorManager.releaseSelector(elem); - } - } - } - // the copy becomes the master now - selectedElements = newSelectedItems; -}; - -// Function: selectAllInCurrentLayer -// Clears the selection, then adds all elements in the current layer to the selection. -this.selectAllInCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - if (current_layer) { - current_mode = "select"; - selectOnly($(current_group || current_layer).children()); - } -}; - -// Function: getMouseTarget -// Gets the desired element from a mouse event -// -// Parameters: -// evt - Event object from the mouse event -// -// Returns: -// DOM element we want -var getMouseTarget = this.getMouseTarget = function(evt) { - if (evt == null) { - return null; - } - var mouse_target = evt.target; - - // if it was a <use>, Opera and WebKit return the SVGElementInstance - if (mouse_target.correspondingUseElement) mouse_target = mouse_target.correspondingUseElement; - - // for foreign content, go up until we find the foreignObject - // WebKit browsers set the mouse target to the svgcanvas div - if ([mathns, htmlns].indexOf(mouse_target.namespaceURI) >= 0 && - mouse_target.id != "svgcanvas") - { - while (mouse_target.nodeName != "foreignObject") { - mouse_target = mouse_target.parentNode; - if(!mouse_target) return svgroot; - } - } - - // Get the desired mouse_target with jQuery selector-fu - // If it's root-like, select the root - var current_layer = getCurrentDrawing().getCurrentLayer(); - if([svgroot, container, svgcontent, current_layer].indexOf(mouse_target) >= 0) { - return svgroot; - } - - var $target = $(mouse_target); - - // If it's a selection grip, return the grip parent - if($target.closest('#selectorParentGroup').length) { - // While we could instead have just returned mouse_target, - // this makes it easier to indentify as being a selector grip - return selectorManager.selectorParentGroup; - } - - while (mouse_target.parentNode !== (current_group || current_layer)) { - mouse_target = mouse_target.parentNode; - } - -// -// // go up until we hit a child of a layer -// while (mouse_target.parentNode.parentNode.tagName == 'g') { -// mouse_target = mouse_target.parentNode; -// } - // Webkit bubbles the mouse event all the way up to the div, so we - // set the mouse_target to the svgroot like the other browsers -// if (mouse_target.nodeName.toLowerCase() == "div") { -// mouse_target = svgroot; -// } - - return mouse_target; -}; - -// Mouse events -(function() { - var d_attr = null, - start_x = null, - start_y = null, - r_start_x = null, - r_start_y = null, - init_bbox = {}, - freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - - // - when we are in a create mode, the element is added to the canvas - // but the action is not recorded until mousing up - // - when we are in select mode, select the element, remember the position - // and do nothing else - var mouseDown = function(evt) - { - if(canvas.spaceKey || evt.button === 1) return; - - var right_click = evt.button === 2; - - if(evt.altKey) { // duplicate when dragging - svgCanvas.cloneSelectedElements(0,0); - } - - root_sctm = svgcontent.getScreenCTM().inverse(); - - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom; - - evt.preventDefault(); - - if(right_click) { - current_mode = "select"; - lastClickPoint = pt; - } - - // This would seem to be unnecessary... -// if(['select', 'resize'].indexOf(current_mode) == -1) { -// setGradient(); -// } - - var x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - mouse_target = getMouseTarget(evt); - - if(mouse_target.tagName === 'a' && mouse_target.childNodes.length === 1) { - mouse_target = mouse_target.firstChild; - } - - // real_x/y ignores grid-snap value - var real_x = r_start_x = start_x = x; - var real_y = r_start_y = start_y = y; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - - // if it is a selector grip, then it must be a single element selected, - // set the mouse_target to that and update the mode to rotate/resize - - if (mouse_target == selectorManager.selectorParentGroup && selectedElements[0] != null) { - var grip = evt.target; - var griptype = elData(grip, "type"); - // rotating - if (griptype == "rotate") { - current_mode = "rotate"; - current_rotate_mode = elData(grip, "dir"); - } - // resizing - else if(griptype == "resize") { - current_mode = "resize"; - current_resize_mode = elData(grip, "dir"); - } - mouse_target = selectedElements[0]; - } - - start_transform = mouse_target.getAttribute("transform"); - var tlist = getTransformList(mouse_target); - switch (current_mode) { - case "select": - started = true; - current_resize_mode = "none"; - if(right_click) started = false; - - if (mouse_target != svgroot) { - // if this element is not yet selected, clear selection and select it - if (selectedElements.indexOf(mouse_target) == -1) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) - if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection - clearSelection(true); - } - addToSelection([mouse_target]); - justSelected = mouse_target; - pathActions.clear(); - } - // else if it's a path, go into pathedit mode in mouseup - - if(!right_click) { - // insert a dummy transform so if the element(s) are moved it will have - // a transform to use for its translate - for (var i = 0; i < selectedElements.length; ++i) { - if(selectedElements[i] == null) continue; - var slist = getTransformList(selectedElements[i]); - if(slist.numberOfItems) { - slist.insertItemBefore(svgroot.createSVGTransform(), 0); - } else { - slist.appendItem(svgroot.createSVGTransform()); - } - } - } - } - else if(!right_click){ - clearSelection(); - current_mode = "multiselect"; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - r_start_x *= current_zoom; - r_start_y *= current_zoom; -// console.log('p',[evt.pageX, evt.pageY]); -// console.log('c',[evt.clientX, evt.clientY]); -// console.log('o',[evt.offsetX, evt.offsetY]); -// console.log('s',[start_x, start_y]); - - assignAttributes(rubberBox, { - 'x': r_start_x, - 'y': r_start_y, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - break; - case "zoom": - started = true; - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': real_x * current_zoom, - 'y': real_x * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - break; - case "resize": - started = true; - start_x = x; - start_y = y; - - // Getting the BBox from the selection box, since we know we - // want to orient around it - init_bbox = svgedit.utilities.getBBox($('#selectedBox0')[0]); - var bb = {}; - $.each(init_bbox, function(key, val) { - bb[key] = val/current_zoom; - }); - init_bbox = bb; - // append three dummy transforms to the tlist so that - // we can translate,scale,translate in mousemove - var pos = getRotationAngle(mouse_target)?1:0; - - if(hasMatrixTransform(tlist)) { - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - } else { - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - - if(svgedit.browser.supportsNonScalingStroke()) { - //Handle crash for newer Chrome: https://code.google.com/p/svg-edit/issues/detail?id=904 - //Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 - // TODO: Remove this workaround (all isChrome blocks) once vendor fixes the issue - var isChrome = svgedit.browser.isChrome(); - if(isChrome) { - var delayedStroke = function(ele) { - var _stroke = ele.getAttributeNS(null, 'stroke'); - ele.removeAttributeNS(null, 'stroke'); - //Re-apply stroke after delay. Anything higher than 1 seems to cause flicker - setTimeout(function() { ele.setAttributeNS(null, 'stroke', _stroke) }, 1); - } - } - mouse_target.style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(mouse_target); - - var all = mouse_target.getElementsByTagName('*'), - len = all.length; - for(var i = 0; i < len; i++) { - all[i].style.vectorEffect = 'non-scaling-stroke'; - if(isChrome) delayedStroke(all[i]); - } - } - } - break; - case "fhellipse": - case "fhrect": - case "fhpath": - started = true; - d_attr = real_x + "," + real_y + " "; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "polyline", - "curStyles": true, - "attr": { - "points": d_attr, - "id": getNextId(), - "fill": "none", - "opacity": cur_shape.opacity / 2, - "stroke-linecap": "round", - "style": "pointer-events:none" - } - }); - freehand.minx = real_x; - freehand.maxx = real_x; - freehand.miny = real_y; - freehand.maxy = real_y; - break; - case "image": - started = true; - var newImage = addSvgElementFromJson({ - "element": "image", - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:inherit" - } - }); - setHref(newImage, last_good_img_url); - preventClickDefault(newImage); - break; - case "square": - // FIXME: once we create the rect, we lose information that this was a square - // (for resizing purposes this could be important) - case "rect": - started = true; - start_x = x; - start_y = y; - addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "width": 0, - "height": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "line": - started = true; - var stroke_w = cur_shape.stroke_width == 0?1:cur_shape.stroke_width; - addSvgElementFromJson({ - "element": "line", - "curStyles": true, - "attr": { - "x1": x, - "y1": y, - "x2": x, - "y2": y, - "id": getNextId(), - "stroke": cur_shape.stroke, - "stroke-width": stroke_w, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "fill": "none", - "opacity": cur_shape.opacity / 2, - "style": "pointer-events:none" - } - }); - break; - case "circle": - started = true; - addSvgElementFromJson({ - "element": "circle", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "r": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "ellipse": - started = true; - addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": x, - "cy": y, - "rx": 0, - "ry": 0, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - break; - case "text": - started = true; - var newText = addSvgElementFromJson({ - "element": "text", - "curStyles": true, - "attr": { - "x": x, - "y": y, - "id": getNextId(), - "fill": cur_text.fill, - "stroke-width": cur_text.stroke_width, - "font-size": cur_text.font_size, - "font-family": cur_text.font_family, - "text-anchor": "left", - "xml:space": "preserve", - "opacity": cur_shape.opacity - } - }); -// newText.textContent = "text"; - break; - case "path": - // Fall through - case "pathedit": - start_x *= current_zoom; - start_y *= current_zoom; - pathActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "textedit": - start_x *= current_zoom; - start_y *= current_zoom; - textActions.mouseDown(evt, mouse_target, start_x, start_y); - started = true; - break; - case "rotate": - started = true; - // we are starting an undoable change (a drag-rotation) - canvas.undoMgr.beginUndoableChange("transform", selectedElements); - document.getElementById("workarea").className = "rotate"; - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseDown", { - event: evt, - start_x: start_x, - start_y: start_y, - selectedElements: selectedElements - }, true); - - $.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 - // any elements that are still being created, moved or resized on the canvas) - var mouseMove = function(evt) - { - if (!started) return; - if(evt.button === 1 || canvas.spaceKey) return; - - var selected = selectedElements[0], - pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - shape = getElem(getId()); - - var real_x = x = mouse_x / current_zoom; - var real_y = y = mouse_y / current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - evt.preventDefault(); - - switch (current_mode) - { - case "select": - // we temporarily use a translate on the element(s) being dragged - // this transform is removed upon mousing up and the element is - // relocated to the new location - if (selectedElements[0] !== null) { - var dx = x - start_x; - var dy = y - start_y; - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - } - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x,y); x=xya.x; y=xya.y; } - - if (dx != 0 || dy != 0) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; -// if (i==0) { -// var box = svgedit.utilities.getBBox(selected); -// selectedBBoxes[i].x = box.x + dx; -// selectedBBoxes[i].y = box.y + dy; -// } - - // update the dummy transform in our transform list - // 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); - } else { - tlist.appendItem(xform); - } - - // update our internal bbox that we're tracking while dragging - selectorManager.requestSelector(selected).resize(); - } - - call("transition", selectedElements); - } - } - break; - case "multiselect": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y) - },100); - - // for each selected: - // - if newList contains selected, do nothing - // - if newList doesn't contain selected, remove it from selected - // - for any newList that was not in selectedElements, add it to selected - var elemsToRemove = [], elemsToAdd = [], - newList = getIntersectionList(), - len = selectedElements.length; - - for (var i = 0; i < len; ++i) { - var ind = newList.indexOf(selectedElements[i]); - if (ind == -1) { - elemsToRemove.push(selectedElements[i]); - } - else { - newList[ind] = null; - } - } - - len = newList.length; - for (i = 0; i < len; ++i) { if (newList[i]) elemsToAdd.push(newList[i]); } - - if (elemsToRemove.length > 0) - canvas.removeFromSelection(elemsToRemove); - - if (elemsToAdd.length > 0) - addToSelection(elemsToAdd); - - break; - case "resize": - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates - var tlist = getTransformList(selected), - hasMatrix = hasMatrixTransform(tlist), - box = hasMatrix ? init_bbox : svgedit.utilities.getBBox(selected), - left=box.x, top=box.y, width=box.width, - height=box.height, dx=(x-start_x), dy=(y-start_y); - - if(curConfig.gridSnapping){ - dx = snapToGrid(dx); - dy = snapToGrid(dy); - height = snapToGrid(height); - width = snapToGrid(width); - } - - // if rotated, adjust the dx,dy values - var angle = getRotationAngle(selected); - if (angle) { - var r = Math.sqrt( dx*dx + dy*dy ), - theta = Math.atan2(dy,dx) - angle * Math.PI / 180.0; - dx = r * Math.cos(theta); - dy = r * Math.sin(theta); - } - - // if not stretching in y direction, set dy to 0 - // if not stretching in x direction, set dx to 0 - if(current_resize_mode.indexOf("n")==-1 && current_resize_mode.indexOf("s")==-1) { - dy = 0; - } - if(current_resize_mode.indexOf("e")==-1 && current_resize_mode.indexOf("w")==-1) { - dx = 0; - } - - var ts = null, - tx = 0, ty = 0, - sy = height ? (height+dy)/height : 1, - sx = width ? (width+dx)/width : 1; - // if we are dragging on the north side, then adjust the scale factor and ty - if(current_resize_mode.indexOf("n") >= 0) { - sy = height ? (height-dy)/height : 1; - ty = height; - } - - // if we dragging on the east side, then adjust the scale factor and tx - if(current_resize_mode.indexOf("w") >= 0) { - sx = width ? (width-dx)/width : 1; - tx = width; - } - - // update the transform list with translate,scale,translate - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - - if(curConfig.gridSnapping){ - left = snapToGrid(left); - tx = snapToGrid(tx); - top = snapToGrid(top); - ty = snapToGrid(ty); - } - - translateOrigin.setTranslate(-(left+tx),-(top+ty)); - if(evt.shiftKey) { - if(sx == 1) sx = sy - else sy = sx; - } - scale.setScale(sx,sy); - - translateBack.setTranslate(left+tx,top+ty); - if(hasMatrix) { - var diff = angle?1:0; - tlist.replaceItem(translateOrigin, 2+diff); - tlist.replaceItem(scale, 1+diff); - tlist.replaceItem(translateBack, 0+diff); - } else { - var N = tlist.numberOfItems; - tlist.replaceItem(translateBack, N-3); - tlist.replaceItem(scale, N-2); - tlist.replaceItem(translateOrigin, N-1); - } - - selectorManager.requestSelector(selected).resize(); - - call("transition", selectedElements); - - break; - case "zoom": - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - break; - case "text": - assignAttributes(shape,{ - 'x': x, - 'y': y - },1000); - break; - case "line": - // Opera has a problem with suspendRedraw() apparently - var handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - } - - var x2 = x; - var y2 = y; - - if(evt.shiftKey) { var xya = snapToAngle(start_x,start_y,x2,y2); x2=xya.x; y2=xya.y; } - - shape.setAttributeNS(null, "x2", x2); - shape.setAttributeNS(null, "y2", y2); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "foreignObject": - // fall through - case "square": - // fall through - case "rect": - // fall through - case "image": - var square = (current_mode == 'square') || evt.shiftKey, - w = Math.abs(x - start_x), - h = Math.abs(y - start_y), - new_x, new_y; - if(square) { - w = h = Math.max(w, h); - new_x = start_x < x ? start_x : start_x - w; - new_y = start_y < y ? start_y : start_y - h; - } else { - new_x = Math.min(start_x,x); - new_y = Math.min(start_y,y); - } - - if(curConfig.gridSnapping){ - w = snapToGrid(w); - h = snapToGrid(h); - new_x = snapToGrid(new_x); - new_y = snapToGrid(new_y); - } - - assignAttributes(shape,{ - 'width': w, - 'height': h, - 'x': new_x, - 'y': new_y - },1000); - - break; - case "circle": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy, - rad = Math.sqrt( (x-cx)*(x-cx) + (y-cy)*(y-cy) ); - if(curConfig.gridSnapping){ - rad = snapToGrid(rad); - } - shape.setAttributeNS(null, "r", rad); - break; - case "ellipse": - var c = $(shape).attr(["cx", "cy"]); - var cx = c.cx, cy = c.cy; - // Opera has a problem with suspendRedraw() apparently - handle = null; - if (!window.opera) svgroot.suspendRedraw(1000); - if(curConfig.gridSnapping){ - x = snapToGrid(x); - cx = snapToGrid(cx); - y = snapToGrid(y); - cy = snapToGrid(cy); - } - shape.setAttributeNS(null, "rx", Math.abs(x - cx) ); - var ry = Math.abs(evt.shiftKey?(x - cx):(y - cy)); - shape.setAttributeNS(null, "ry", ry ); - if (!window.opera) svgroot.unsuspendRedraw(handle); - break; - case "fhellipse": - case "fhrect": - freehand.minx = Math.min(real_x, freehand.minx); - freehand.maxx = Math.max(real_x, freehand.maxx); - freehand.miny = Math.min(real_y, freehand.miny); - freehand.maxy = Math.max(real_y, freehand.maxy); - // break; missing on purpose - case "fhpath": - d_attr += + real_x + "," + real_y + " "; - shape.setAttributeNS(null, "points", d_attr); - break; - // update path stretch line coordinates - case "path": - // fall through - case "pathedit": - x *= current_zoom; - y *= current_zoom; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - start_x = snapToGrid(start_x); - start_y = snapToGrid(start_y); - } - if(evt.shiftKey) { - var path = svgedit.path.path; - if(path) { - var x1 = path.dragging?path.dragging[0]:start_x; - var y1 = path.dragging?path.dragging[1]:start_y; - } else { - var x1 = start_x; - var y1 = start_y; - } - var xya = snapToAngle(x1,y1,x,y); - x=xya.x; y=xya.y; - } - - if(rubberBox && rubberBox.getAttribute('display') !== 'none') { - real_x *= current_zoom; - real_y *= current_zoom; - assignAttributes(rubberBox, { - 'x': Math.min(r_start_x*current_zoom, real_x), - 'y': Math.min(r_start_y*current_zoom, real_y), - 'width': Math.abs(real_x - r_start_x*current_zoom), - 'height': Math.abs(real_y - r_start_y*current_zoom) - },100); - } - pathActions.mouseMove(evt, x, y); - - break; - case "textedit": - x *= current_zoom; - y *= current_zoom; -// if(rubberBox && rubberBox.getAttribute('display') != 'none') { -// assignAttributes(rubberBox, { -// 'x': Math.min(start_x,x), -// 'y': Math.min(start_y,y), -// 'width': Math.abs(x-start_x), -// 'height': Math.abs(y-start_y) -// },100); -// } - - textActions.mouseMove(mouse_x, mouse_y); - - break; - case "rotate": - var box = svgedit.utilities.getBBox(selected), - cx = box.x + box.width/2, - cy = box.y + box.height/2, - m = getMatrix(selected), - center = transformPoint(cx,cy,m); - cx = center.x; - cy = center.y; - var ccx = box.x // ne - var ccy = box.y // ne - if (current_rotate_mode == "nw") ccx = box.x + box.width; - if (current_rotate_mode == "se") ccy = box.y + box.height; - if (current_rotate_mode == "sw"){ ccx = box.x + box.width; ccy = box.y + box.height; } - compensation_angle = ((Math.atan2(cy-ccy,cx-ccx) * (180/Math.PI))-90) % 360; - var angle = ((Math.atan2(cy-y,cx-x) * (180/Math.PI))-90) % 360; - angle += compensation_angle; - if(curConfig.gridSnapping){ - angle = snapToGrid(angle); - } - if(evt.shiftKey) { // restrict rotations to nice angles (WRS) - var snap = 45; - angle= Math.round(angle/snap)*snap; - } - - canvas.setRotationAngle(angle<-180?(360+angle):angle, true); - call("transition", selectedElements); - break; - default: - break; - } - - runExtensions("mouseMove", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y, - selected: selected - }); - - }; // mouseMove() - - // - in create mode, the element's opacity is set properly, we create an InsertElementCommand - // and store it on the Undo stack - // - in move/resize mode, the element's attributes which were affected by the move/resize are - // identified, a ChangeElementCommand is created and stored on the stack for those attrs - // this is done in when we recalculate the selected dimensions() - var mouseUp = function(evt) - { - if(evt.button === 2) return; - var tempJustSelected = justSelected; - justSelected = null; - if (!started) return; - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = pt.x * current_zoom, - mouse_y = pt.y * current_zoom, - x = mouse_x / current_zoom, - y = mouse_y / current_zoom, - element = getElem(getId()), - keep = false; - - var real_x = x; - var real_y = y; - - // TODO: Make true when in multi-unit mode - var useUnit = false; // (curConfig.baseUnit !== 'px'); - started = false; - switch (current_mode) - { - // intentionally fall-through to select here - case "resize": - case "multiselect": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - curBBoxes = []; - } - current_mode = "select"; - case "select": - if (selectedElements[0] != null) { - // if we only have one selected element - if (selectedElements[1] == null) { - // set our current stroke/fill properties to the element's - var selected = selectedElements[0]; - switch ( selected.tagName ) { - case "g": - case "use": - case "image": - case "foreignObject": - break; - default: - cur_properties.fill = selected.getAttribute("fill"); - cur_properties.fill_opacity = selected.getAttribute("fill-opacity"); - cur_properties.stroke = selected.getAttribute("stroke"); - cur_properties.stroke_opacity = selected.getAttribute("stroke-opacity"); - cur_properties.stroke_width = selected.getAttribute("stroke-width"); - cur_properties.stroke_dasharray = selected.getAttribute("stroke-dasharray"); - cur_properties.stroke_linejoin = selected.getAttribute("stroke-linejoin"); - cur_properties.stroke_linecap = selected.getAttribute("stroke-linecap"); - } - - if (selected.tagName == "text") { - cur_text.font_size = selected.getAttribute("font-size"); - cur_text.font_family = selected.getAttribute("font-family"); - } - selectorManager.requestSelector(selected).showGrips(true); - - // This shouldn't be necessary as it was done on mouseDown... -// call("selected", [selected]); - } - // always recalculate dimensions to strip off stray identity transforms - recalculateAllSelectedDimensions(); - // if it was being dragged/resized - if (real_x != r_start_x || real_y != r_start_y) { - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - if(!selectedElements[i].firstChild) { - // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - selectorManager.requestSelector(selectedElements[i]).resize(); - } - } - } - // no change in position/size, so maybe we should move to pathedit - else { - var t = evt.target; - if (selectedElements[0].nodeName === "path" && selectedElements[1] == null) { - pathActions.select(selectedElements[0]); - } // if it was a path - // else, if it was selected and this is a shift-click, remove it from selection - else if (evt.shiftKey) { - if(tempJustSelected != t) { - canvas.removeFromSelection([t]); - } - } - } // no change in mouse position - - // Remove non-scaling stroke - if(svgedit.browser.supportsNonScalingStroke()) { - var elem = selectedElements[0]; - if (elem) { - elem.removeAttribute('style'); - svgedit.utilities.walkTree(elem, function(elem) { - elem.removeAttribute('style'); - }); - } - } - - } - return; - break; - case "zoom": - if (rubberBox != null) { - rubberBox.setAttribute("display", "none"); - } - var factor = evt.altKey?.5:2; - call("zoomed", { - 'x': Math.min(r_start_x, real_x), - 'y': Math.min(r_start_y, real_y), - 'width': Math.abs(real_x - r_start_x), - 'height': Math.abs(real_y - r_start_y), - 'factor': factor - }); - return; - case "fhpath": - // Check that the path contains at least 2 points; a degenerate one-point path - // causes problems. - // Webkit ignores how we set the points attribute with commas and uses space - // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 - var coords = element.getAttribute('points'); - var commaIndex = coords.indexOf(','); - if (commaIndex >= 0) { - keep = coords.indexOf(',', commaIndex+1) >= 0; - } else { - keep = coords.indexOf(' ', coords.indexOf(' ')+1) >= 0; - } - if (keep) { - element = pathActions.smoothPolylineIntoPath(element); - } - break; - case "line": - var attrs = $(element).attr(["x1", "x2", "y1", "y2"]); - keep = (attrs.x1 != attrs.x2 || attrs.y1 != attrs.y2); - break; - case "foreignObject": - case "square": - case "rect": - case "image": - var attrs = $(element).attr(["width", "height"]); - // Image should be kept regardless of size (use inherit dimensions later) - keep = (attrs.width != 0 || attrs.height != 0) || current_mode === "image"; - break; - case "circle": - keep = (element.getAttribute('r') != 0); - break; - case "ellipse": - var attrs = $(element).attr(["rx", "ry"]); - keep = (attrs.rx != null || attrs.ry != null); - break; - case "fhellipse": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "ellipse", - "curStyles": true, - "attr": { - "cx": (freehand.minx + freehand.maxx) / 2, - "cy": (freehand.miny + freehand.maxy) / 2, - "rx": (freehand.maxx - freehand.minx) / 2, - "ry": (freehand.maxy - freehand.miny) / 2, - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "fhrect": - if ((freehand.maxx - freehand.minx) > 0 && - (freehand.maxy - freehand.miny) > 0) { - element = addSvgElementFromJson({ - "element": "rect", - "curStyles": true, - "attr": { - "x": freehand.minx, - "y": freehand.miny, - "width": (freehand.maxx - freehand.minx), - "height": (freehand.maxy - freehand.miny), - "id": getId() - } - }); - call("changed",[element]); - keep = true; - } - break; - case "text": - keep = true; - selectOnly([element]); - textActions.start(element); - break; - case "path": - // set element to null here so that it is not removed nor finalized - element = null; - // continue to be set to true so that mouseMove happens - started = true; - - var res = pathActions.mouseUp(evt, element, mouse_x, mouse_y); - element = res.element - keep = res.keep; - break; - case "pathedit": - keep = true; - element = null; - pathActions.mouseUp(evt); - break; - case "textedit": - keep = false; - element = null; - textActions.mouseUp(evt, mouse_x, mouse_y); - break; - case "rotate": - keep = true; - element = null; - current_mode = "select"; - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } - // perform recalculation to weed out any stray identity transforms that might get stuck - recalculateAllSelectedDimensions(); - call("changed", selectedElements); - break; - default: - // This could occur in an extension - break; - } - - var ext_result = runExtensions("mouseUp", { - event: evt, - mouse_x: mouse_x, - mouse_y: mouse_y - }, true); - - $.each(ext_result, function(i, r) { - if(r) { - keep = r.keep || keep; - element = r.element; - started = r.started || started; - } - }); - - if (!keep && element != null) { - getCurrentDrawing().releaseId(getId()); - element.parentNode.removeChild(element); - element = null; - - var t = evt.target; - - // if this element is in a group, go up until we reach the top-level group - // just below the layer groups - // TODO: once we implement links, we also would have to check for <a> elements - while (t.parentNode.parentNode.tagName == "g") { - t = t.parentNode; - } - // if we are not in the middle of creating a path, and we've clicked on some shape, - // then go to Select mode. - // WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> - if ( (current_mode != "path" || !drawn_path) && - t.parentNode.id != "selectorParentGroup" && - t.id != "svgcanvas" && t.id != "svgroot") - { - // switch into "select" mode if we've clicked on an element - canvas.setMode("select"); - selectOnly([t], true); - } - - } else if (element != null) { - canvas.addedNew = true; - - if(useUnit) svgedit.units.convertAttrs(element); - - var ani_dur = .2, c_ani; - if(opac_ani.beginElement && element.getAttribute('opacity') != cur_shape.opacity) { - c_ani = $(opac_ani).clone().attr({ - to: cur_shape.opacity, - dur: ani_dur - }).appendTo(element); - try { - // Fails in FF4 on foreignObject - c_ani[0].beginElement(); - } catch(e){} - } else { - ani_dur = 0; - } - - // Ideally this would be done on the endEvent of the animation, - // but that doesn't seem to be supported in Webkit - setTimeout(function() { - if(c_ani) c_ani.remove(); - element.setAttribute("opacity", cur_shape.opacity); - element.setAttribute("style", "pointer-events:inherit"); - cleanupElement(element); - if(current_mode === "path") { - pathActions.toEditMode(element); - } else { - if(curConfig.selectNew) { - selectOnly([element], true); - } - } - // we create the insert command that is stored on the stack - // undo means to call cmd.unapply(), redo means to call cmd.apply() - addCommandToHistory(new InsertElementCommand(element)); - - call("changed",[element]); - }, ani_dur * 1000); - } - - start_transform = null; - }; - - var dblClick = function(evt) { - var evt_target = evt.target; - var parent = evt_target.parentNode; - - // Do nothing if already in current group - if(parent === current_group) return; - - var mouse_target = getMouseTarget(evt); - var tagName = mouse_target.tagName; - - if(tagName === 'text' && current_mode !== 'textedit') { - var pt = transformPoint( evt.pageX, evt.pageY, root_sctm ); - textActions.select(mouse_target, pt.x, pt.y); - } - - if((tagName === "g" || tagName === "a") && getRotationAngle(mouse_target)) { - // TODO: Allow method of in-group editing without having to do - // this (similar to editing rotated paths) - - // Ungroup and regroup - pushGroupProperties(mouse_target); - mouse_target = selectedElements[0]; - clearSelection(true); - } - // Reset context - if(current_group) { - leaveContext(); - } - - if((parent.tagName !== 'g' && parent.tagName !== 'a') || - parent === getCurrentDrawing().getCurrentLayer() || - mouse_target === selectorManager.selectorParentGroup) - { - // Escape from in-group edit - return; - } - setContext(mouse_target); - } - - // prevent links from being followed in the canvas - var handleLinkInCanvas = function(e) { - e.preventDefault(); - return false; - }; - - // Added mouseup to the container here. - // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. - $(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp); -// $(window).mouseup(mouseUp); - - $(container).bind("mousewheel DOMMouseScroll", function(e){ - if(!e.shiftKey) return; - e.preventDefault(); - - root_sctm = svgcontent.getScreenCTM().inverse(); - var pt = transformPoint( e.pageX, e.pageY, root_sctm ); - var bbox = { - 'x': pt.x, - 'y': pt.y, - 'width': 0, - 'height': 0 - }; - - // Respond to mouse wheel in IE/Webkit/Opera. - // (It returns up/dn motion in multiples of 120) - if(e.wheelDelta) { - if (e.wheelDelta >= 120) { - bbox.factor = 2; - } else if (e.wheelDelta <= -120) { - bbox.factor = .5; - } - } else if(e.detail) { - if (e.detail > 0) { - bbox.factor = .5; - } else if (e.detail < 0) { - bbox.factor = 2; - } - } - - if(!bbox.factor) return; - call("zoomed", bbox); - }); - -}()); - -// Function: preventClickDefault -// Prevents default browser click behaviour on the given element -// -// Parameters: -// img - The DOM element to prevent the cilck on -var preventClickDefault = function(img) { - $(img).click(function(e){e.preventDefault()}); -} - -// Group: Text edit functions -// Functions relating to editing text elements -var textActions = canvas.textActions = function() { - var curtext; - var textinput; - var cursor; - var selblock; - var blinker; - var chardata = []; - var textbb, transbb; - var matrix; - var last_x, last_y; - var allow_dbl; - - function setCursor(index) { - var empty = (textinput.value === ""); - $(textinput).focus(); - - if(!arguments.length) { - if(empty) { - index = 0; - } else { - if(textinput.selectionEnd !== textinput.selectionStart) return; - index = textinput.selectionEnd; - } - } - - var charbb; - charbb = chardata[index]; - if(!empty) { - textinput.setSelectionRange(index, index); - } - cursor = getElem("text_cursor"); - if (!cursor) { - cursor = document.createElementNS(svgns, "line"); - assignAttributes(cursor, { - 'id': "text_cursor", - 'stroke': "#333", - 'stroke-width': 1 - }); - cursor = getElem("selectorParentGroup").appendChild(cursor); - } - - if(!blinker) { - blinker = setInterval(function() { - var show = (cursor.getAttribute('display') === 'none'); - cursor.setAttribute('display', show?'inline':'none'); - }, 600); - - } - - - var start_pt = ptToScreen(charbb.x, textbb.y); - var end_pt = ptToScreen(charbb.x, (textbb.y + textbb.height)); - - assignAttributes(cursor, { - x1: start_pt.x, - y1: start_pt.y, - x2: end_pt.x, - y2: end_pt.y, - visibility: 'visible', - display: 'inline' - }); - - if(selblock) selblock.setAttribute('d', ''); - } - - function setSelection(start, end, skipInput) { - if(start === end) { - setCursor(end); - return; - } - - if(!skipInput) { - textinput.setSelectionRange(start, end); - } - - selblock = getElem("text_selectblock"); - if (!selblock) { - - selblock = document.createElementNS(svgns, "path"); - assignAttributes(selblock, { - 'id': "text_selectblock", - 'fill': "green", - 'opacity': .5, - 'style': "pointer-events:none" - }); - getElem("selectorParentGroup").appendChild(selblock); - } - - - var startbb = chardata[start]; - - var endbb = chardata[end]; - - cursor.setAttribute('visibility', 'hidden'); - - var tl = ptToScreen(startbb.x, textbb.y), - tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y), - bl = ptToScreen(startbb.x, textbb.y + textbb.height), - br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); - - - var dstr = "M" + tl.x + "," + tl.y - + " L" + tr.x + "," + tr.y - + " " + br.x + "," + br.y - + " " + bl.x + "," + bl.y + "z"; - - assignAttributes(selblock, { - d: dstr, - 'display': 'inline' - }); - } - - function getIndexFromPoint(mouse_x, mouse_y) { - // Position cursor here - var pt = svgroot.createSVGPoint(); - pt.x = mouse_x; - pt.y = mouse_y; - - // No content, so return 0 - if(chardata.length == 1) return 0; - // Determine if cursor should be on left or right of character - var charpos = curtext.getCharNumAtPosition(pt); - if(charpos < 0) { - // Out of text range, look at mouse coords - charpos = chardata.length - 2; - if(mouse_x <= chardata[0].x) { - charpos = 0; - } - } else if(charpos >= chardata.length - 2) { - charpos = chardata.length - 2; - } - var charbb = chardata[charpos]; - var mid = charbb.x + (charbb.width/2); - if(mouse_x > mid) { - charpos++; - } - return charpos; - } - - function setCursorFromPoint(mouse_x, mouse_y) { - setCursor(getIndexFromPoint(mouse_x, mouse_y)); - } - - function setEndSelectionFromPoint(x, y, apply) { - var i1 = textinput.selectionStart; - var i2 = getIndexFromPoint(x, y); - - var start = Math.min(i1, i2); - var end = Math.max(i1, i2); - setSelection(start, end, !apply); - } - - function screenToPt(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - out.x /= current_zoom; - out.y /= current_zoom; - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix.inverse()); - out.x = pt.x; - out.y = pt.y; - } - - return out; - } - - function ptToScreen(x_in, y_in) { - var out = { - x: x_in, - y: y_in - } - - if(matrix) { - var pt = transformPoint(out.x, out.y, matrix); - out.x = pt.x; - out.y = pt.y; - } - - out.x *= current_zoom; - out.y *= current_zoom; - - return out; - } - - function hideCursor() { - if(cursor) { - cursor.setAttribute('visibility', 'hidden'); - } - } - - function selectAll(evt) { - setSelection(0, curtext.textContent.length); - $(this).unbind(evt); - } - - function selectWord(evt) { - if(!allow_dbl || !curtext) return; - - var ept = transformPoint( evt.pageX, evt.pageY, root_sctm ), - mouse_x = ept.x * current_zoom, - mouse_y = ept.y * current_zoom; - var pt = screenToPt(mouse_x, mouse_y); - - var index = getIndexFromPoint(pt.x, pt.y); - var str = curtext.textContent; - var first = str.substr(0, index).replace(/[a-z0-9]+$/i, '').length; - var m = str.substr(index).match(/^[a-z0-9]+/i); - var last = (m?m[0].length:0) + index; - setSelection(first, last); - - // Set tripleclick - $(evt.target).click(selectAll); - setTimeout(function() { - $(evt.target).unbind('click', selectAll); - }, 300); - - } - - return { - select: function(target, x, y) { - curtext = target; - textActions.toEditMode(x, y); - }, - start: function(elem) { - curtext = elem; - textActions.toEditMode(); - }, - mouseDown: function(evt, mouse_target, start_x, start_y) { - var pt = screenToPt(start_x, start_y); - - textinput.focus(); - setCursorFromPoint(pt.x, pt.y); - last_x = start_x; - last_y = start_y; - - // TODO: Find way to block native selection - }, - mouseMove: function(mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - setEndSelectionFromPoint(pt.x, pt.y); - }, - mouseUp: function(evt, mouse_x, mouse_y) { - var pt = screenToPt(mouse_x, mouse_y); - - setEndSelectionFromPoint(pt.x, pt.y, true); - - // TODO: Find a way to make this work: Use transformed BBox instead of evt.target -// if(last_x === mouse_x && last_y === mouse_y -// && !svgedit.math.rectsIntersect(transbb, {x: pt.x, y: pt.y, width:0, height:0})) { -// textActions.toSelectMode(true); -// } - - if( - evt.target !== curtext - && mouse_x < last_x + 2 - && mouse_x > last_x - 2 - && mouse_y < last_y + 2 - && mouse_y > last_y - 2) { - - textActions.toSelectMode(true); - } - - }, - setCursor: setCursor, - toEditMode: function(x, y) { - 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'); - -// if(svgedit.browser.supportsEditableText()) { -// curtext.setAttribute('editable', 'simple'); -// return; -// } - - if(!arguments.length) { - setCursor(); - } else { - var pt = screenToPt(x, y); - setCursorFromPoint(pt.x, pt.y); - } - - setTimeout(function() { - allow_dbl = true; - }, 300); - }, - toSelectMode: function(selectElem) { - current_mode = "select"; - clearInterval(blinker); - blinker = null; - if(selblock) $(selblock).attr('display','none'); - if(cursor) $(cursor).attr('visibility','hidden'); - $(curtext).css('cursor', 'move'); - - if(selectElem) { - clearSelection(); - $(curtext).css('cursor', 'move'); - - call("selected", [curtext]); - addToSelection([curtext], true); - } - if(curtext && !curtext.textContent.length) { - // No content, so delete - canvas.deleteSelectedElements(); - } - - $(textinput).blur(); - - curtext = false; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.removeAttribute('editable'); -// } - }, - setInputElem: function(elem) { - textinput = elem; -// $(textinput).blur(hideCursor); - }, - clear: function() { - if(current_mode == "textedit") { - textActions.toSelectMode(); - } - }, - init: function(inputElem) { - if(!curtext) return; - -// if(svgedit.browser.supportsEditableText()) { -// curtext.select(); -// return; -// } - - if(!curtext.parentNode) { - // Result of the ffClone, need to get correct element - curtext = selectedElements[0]; - selectorManager.requestSelector(curtext).showGrips(false); - } - - var str = curtext.textContent; - var len = str.length; - - var xform = curtext.getAttribute('transform'); - - textbb = svgedit.utilities.getBBox(curtext); - - matrix = xform?getMatrix(curtext):null; - - chardata = Array(len); - textinput.focus(); - - $(curtext).unbind('dblclick', selectWord).dblclick(selectWord); - - if(!len) { - var end = {x: textbb.x + (textbb.width/2), width: 0}; - } - - for(var i=0; i<len; i++) { - var start = curtext.getStartPositionOfChar(i); - var end = curtext.getEndPositionOfChar(i); - - if(!svgedit.browser.supportsGoodTextCharPos()) { - var offset = canvas.contentW * current_zoom; - start.x -= offset; - end.x -= offset; - - start.x /= current_zoom; - end.x /= current_zoom; - } - - // Get a "bbox" equivalent for each character. Uses the - // bbox data of the actual text for y, height purposes - - // TODO: Decide if y, width and height are actually necessary - chardata[i] = { - x: start.x, - y: textbb.y, // start.y? - width: end.x - start.x, - height: textbb.height - }; - } - - // Add a last bbox for cursor at end of text - chardata.push({ - x: end.x, - width: 0 - }); - setSelection(textinput.selectionStart, textinput.selectionEnd, true); - } - } -}(); - -// TODO: Migrate all of this code into path.js -// Group: Path edit functions -// Functions relating to editing path elements -var pathActions = canvas.pathActions = function() { - - var subpath = false; - var current_path; - var newPoint, firstCtrl; - - function resetD(p) { - p.setAttribute("d", pathActions.convertPath(p)); - } - - // TODO: Move into path.js - svgedit.path.Path.prototype.endChanges = function(text) { - if(svgedit.browser.isWebkit()) resetD(this.elem); - var cmd = new ChangeElementCommand(this.elem, {d: this.last_d}, text); - addCommandToHistory(cmd); - call("changed", [this.elem]); - } - - svgedit.path.Path.prototype.addPtsToSelection = function(indexes) { - if(!$.isArray(indexes)) indexes = [indexes]; - for(var i=0; i< indexes.length; i++) { - var index = indexes[i]; - var seg = this.segs[index]; - if(seg.ptgrip) { - if(this.selected_pts.indexOf(index) == -1 && index >= 0) { - this.selected_pts.push(index); - } - } - }; - this.selected_pts.sort(); - var i = this.selected_pts.length, - grips = new Array(i); - // Loop through points to be selected and highlight each - while(i--) { - var pt = this.selected_pts[i]; - var seg = this.segs[pt]; - seg.select(true); - grips[i] = seg.ptgrip; - } - // TODO: Correct this: - pathActions.canDeleteNodes = true; - - pathActions.closed_subpath = this.subpathIsClosed(this.selected_pts[0]); - - call("selected", grips); - } - - var current_path = null, - drawn_path = null, - hasMoved = false; - - // This function converts a polyline (created by the fh_path tool) into - // a path element and coverts every three line segments into a single bezier - // curve in an attempt to smooth out the free-hand - var smoothPolylineIntoPath = function(element) { - var points = element.points; - var N = points.numberOfItems; - if (N >= 4) { - // loop through every 3 points and convert to a cubic bezier curve segment - // - // NOTE: this is cheating, it means that every 3 points has the potential to - // be a corner instead of treating each point in an equal manner. In general, - // this technique does not look that good. - // - // I am open to better ideas! - // - // Reading: - // - http://www.efg2.com/Lab/Graphics/Jean-YvesQueinecBezierCurves.htm - // - http://www.codeproject.com/KB/graphics/BezierSpline.aspx?msg=2956963 - // - http://www.ian-ko.com/ET_GeoWizards/UserGuide/smooth.htm - // - http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html - var curpos = points.getItem(0), prevCtlPt = null; - var d = []; - d.push(["M",curpos.x,",",curpos.y," C"].join("")); - for (var i = 1; i <= (N-4); i += 3) { - var ct1 = points.getItem(i); - var ct2 = points.getItem(i+1); - var end = points.getItem(i+2); - - // if the previous segment had a control point, we want to smooth out - // the control points on both sides - if (prevCtlPt) { - var newpts = svgedit.path.smoothControlPoints( prevCtlPt, ct1, curpos ); - if (newpts && newpts.length == 2) { - var prevArr = d[d.length-1].split(','); - prevArr[2] = newpts[0].x; - prevArr[3] = newpts[0].y; - d[d.length-1] = prevArr.join(','); - ct1 = newpts[1]; - } - } - - d.push([ct1.x,ct1.y,ct2.x,ct2.y,end.x,end.y].join(',')); - - curpos = end; - prevCtlPt = ct2; - } - // handle remaining line segments - d.push("L"); - for(;i < N;++i) { - var pt = points.getItem(i); - d.push([pt.x,pt.y].join(",")); - } - d = d.join(" "); - - // create new path element - element = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "id": getId(), - "d": d, - "fill": "none" - } - }); - // No need to call "changed", as this is already done under mouseUp - } - return element; - }; - - return { - mouseDown: function(evt, mouse_target, start_x, start_y) { - if(current_mode === "path") { - mouse_x = start_x; - mouse_y = start_y; - - var x = mouse_x/current_zoom, - y = mouse_y/current_zoom, - stretchy = getElem("path_stretch_line"); - newPoint = [x, y]; - - if(curConfig.gridSnapping){ - x = snapToGrid(x); - y = snapToGrid(y); - mouse_x = snapToGrid(mouse_x); - mouse_y = snapToGrid(mouse_y); - } - - if (!stretchy) { - stretchy = document.createElementNS(svgns, "path"); - assignAttributes(stretchy, { - 'id': "path_stretch_line", - 'stroke': "#22C", - 'stroke-width': "0.5", - 'fill': 'none' - }); - stretchy = getElem("selectorParentGroup").appendChild(stretchy); - } - stretchy.setAttribute("display", "inline"); - - var keep = null; - - // if pts array is empty, create path element with M at current point - if (!drawn_path) { - d_attr = "M" + x + "," + y + " "; - drawn_path = addSvgElementFromJson({ - "element": "path", - "curStyles": true, - "attr": { - "d": d_attr, - "id": getNextId(), - "opacity": cur_shape.opacity / 2 - } - }); - // set stretchy line to first point - stretchy.setAttribute('d', ['M', mouse_x, mouse_y, mouse_x, mouse_y].join(' ')); - var index = subpath ? svgedit.path.path.segs.length : 0; - svgedit.path.addPointGrip(index, mouse_x, mouse_y); - } - else { - // determine if we clicked on an existing point - var seglist = drawn_path.pathSegList; - var i = seglist.numberOfItems; - var FUZZ = 6/current_zoom; - var clickOnPoint = false; - while(i) { - i --; - var item = seglist.getItem(i); - var px = item.x, py = item.y; - // found a matching point - if ( x >= (px-FUZZ) && x <= (px+FUZZ) && y >= (py-FUZZ) && y <= (py+FUZZ) ) { - clickOnPoint = true; - break; - } - } - - // get path element that we are in the process of creating - var id = getId(); - - // Remove previous path object if previously created - svgedit.path.removePath_(id); - - var newpath = getElem(id); - - var len = seglist.numberOfItems; - // if we clicked on an existing point, then we are done this path, commit it - // (i,i+1) are the x,y that were clicked on - if (clickOnPoint) { - // if clicked on any other point but the first OR - // the first point was clicked on and there are less than 3 points - // then leave the path open - // otherwise, close the path - if (i <= 1 && len >= 2) { - // Create end segment - var abs_x = seglist.getItem(0).x; - var abs_y = seglist.getItem(0).y; - - - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(abs_x, abs_y); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - abs_x, - abs_y, - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - abs_x, - abs_y - ); - } - - var endseg = drawn_path.createSVGPathSegClosePath(); - seglist.appendItem(newseg); - seglist.appendItem(endseg); - } else if(len < 3) { - keep = false; - return keep; - } - $(stretchy).remove(); - - // this will signal to commit the path - element = newpath; - drawn_path = null; - started = false; - - if(subpath) { - if(svgedit.path.path.matrix) { - remapElement(newpath, {}, svgedit.path.path.matrix.inverse()); - } - - var new_d = newpath.getAttribute("d"); - var orig_d = $(svgedit.path.path.elem).attr("d"); - $(svgedit.path.path.elem).attr("d", orig_d + new_d); - $(newpath).remove(); - if(svgedit.path.path.matrix) { - svgedit.path.recalcRotatedPath(); - } - svgedit.path.path.init(); - pathActions.toEditMode(svgedit.path.path.elem); - svgedit.path.path.selectPt(); - return false; - } - } - // else, create a new point, update path element - else { - // Checks if current target or parents are #svgcontent - if(!$.contains(container, getMouseTarget(evt))) { - // Clicked outside canvas, so don't make point - console.log("Clicked outside canvas"); - return false; - } - - var num = drawn_path.pathSegList.numberOfItems; - var last = drawn_path.pathSegList.getItem(num -1); - var lastx = last.x, lasty = last.y; - - if(evt.shiftKey) { var xya = snapToAngle(lastx,lasty,x,y); x=xya.x; y=xya.y; } - - // Use the segment defined by stretchy - var s_seg = stretchy.pathSegList.getItem(1); - if(s_seg.pathSegType === 4) { - var newseg = drawn_path.createSVGPathSegLinetoAbs(round(x), round(y)); - } else { - var newseg = drawn_path.createSVGPathSegCurvetoCubicAbs( - round(x), - round(y), - s_seg.x1 / current_zoom, - s_seg.y1 / current_zoom, - s_seg.x2 / current_zoom, - s_seg.y2 / current_zoom - ); - } - - drawn_path.pathSegList.appendItem(newseg); - - x *= current_zoom; - y *= current_zoom; - - // set stretchy line to latest point - stretchy.setAttribute('d', ['M', x, y, x, y].join(' ')); - var index = num; - if(subpath) index += svgedit.path.path.segs.length; - svgedit.path.addPointGrip(index, x, y); - } -// keep = true; - } - - return; - } - - // TODO: Make sure current_path isn't null at this point - if(!svgedit.path.path) return; - - svgedit.path.path.storeD(); - - var id = evt.target.id; - if (id.substr(0,14) == "pathpointgrip_") { - // Select this point - var cur_pt = svgedit.path.path.cur_pt = parseInt(id.substr(14)); - svgedit.path.path.dragging = [start_x, start_y]; - var seg = svgedit.path.path.segs[cur_pt]; - - // only clear selection if shift is not pressed (otherwise, add - // node to selection) - if (!evt.shiftKey) { - if(svgedit.path.path.selected_pts.length <= 1 || !seg.selected) { - svgedit.path.path.clearSelection(); - } - svgedit.path.path.addPtsToSelection(cur_pt); - } else if(seg.selected) { - svgedit.path.path.removePtFromSelection(cur_pt); - } else { - svgedit.path.path.addPtsToSelection(cur_pt); - } - } else if(id.indexOf("ctrlpointgrip_") == 0) { - svgedit.path.path.dragging = [start_x, start_y]; - - var parts = id.split('_')[1].split('c'); - var cur_pt = parts[0]-0; - var ctrl_num = parts[1]-0; - svgedit.path.path.selectPt(cur_pt, ctrl_num); - } - - // Start selection box - if(!svgedit.path.path.dragging) { - if (rubberBox == null) { - rubberBox = selectorManager.getRubberBandBox(); - } - assignAttributes(rubberBox, { - 'x': start_x * current_zoom, - 'y': start_y * current_zoom, - 'width': 0, - 'height': 0, - 'display': 'inline' - }, 100); - } - }, - mouseMove: function(evt, mouse_x, mouse_y) { - hasMoved = true; - if(current_mode === "path") { - if(!drawn_path) return; - var seglist = drawn_path.pathSegList; - var index = seglist.numberOfItems - 1; - - if(newPoint) { - // First point -// if(!index) return; - - // Set control points - var pointGrip1 = svgedit.path.addCtrlGrip('1c1'); - var pointGrip2 = svgedit.path.addCtrlGrip('0c2'); - var current_pointGrip2_x = pointGrip2.getAttribute('cx') || 0; - var current_pointGrip2_y = pointGrip2.getAttribute('cy') || 0; - // dragging pointGrip1 - pointGrip1.setAttribute('cx', mouse_x); - pointGrip1.setAttribute('cy', mouse_y); - pointGrip1.setAttribute('display', 'inline'); - - var pt_x = newPoint[0]; - var pt_y = newPoint[1]; - - // set curve - var seg = seglist.getItem(index); - var cur_x = mouse_x / current_zoom; - var cur_y = mouse_y / current_zoom; - var alt_x = (pt_x + (pt_x - cur_x)); - var alt_y = (pt_y + (pt_y - cur_y)); - - - pointGrip2.setAttribute('cx', alt_x * current_zoom); - pointGrip2.setAttribute('cy', alt_y * current_zoom); - pointGrip2.setAttribute('display', 'inline'); - - - var ctrlLine = svgedit.path.getCtrlLine(1); - var ctrlLine2 = svgedit.path.getCtrlLine(2); - assignAttributes(ctrlLine, { - x1: mouse_x, - y1: mouse_y, - x2: pt_x * current_zoom, - y2: pt_y * current_zoom, - display: 'inline' - }); - - - assignAttributes(ctrlLine2, { - x1: alt_x * current_zoom, - y1: alt_y * current_zoom, - x2: pt_x * current_zoom, - y2: pt_y * current_zoom, - display: 'inline' - }); - - - if(index === 0) { - firstCtrl = [mouse_x, mouse_y]; - } else { - var last_x, last_y; - - var last = seglist.getItem(index - 1); - var last_x = last.x; - var last_y = last.y - - if(last.pathSegType === 6) { - last_x += (last_x - last.x2); - last_y += (last_y - last.y2); - } else if(firstCtrl) { - last_x = firstCtrl[0]/current_zoom; - last_y = firstCtrl[1]/current_zoom; - } - svgedit.path.replacePathSeg(6, index, [pt_x, pt_y, last_x, last_y, alt_x, alt_y], drawn_path); - } - } else { - var stretchy = getElem("path_stretch_line"); - if (stretchy) { - var prev = seglist.getItem(index); - if(prev.pathSegType === 6) { - var prev_x = prev.x + (prev.x - prev.x2); - var prev_y = prev.y + (prev.y - prev.y2); - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, prev_x * current_zoom, prev_y * current_zoom, mouse_x, mouse_y], stretchy); - } else if(firstCtrl) { - svgedit.path.replacePathSeg(6, 1, [mouse_x, mouse_y, firstCtrl[0], firstCtrl[1], mouse_x, mouse_y], stretchy); - } else { - svgedit.path.replacePathSeg(4, 1, [mouse_x, mouse_y], stretchy); - } - } - } - return; - } - // if we are dragging a point, let's move it - if (svgedit.path.path.dragging) { - var pt = svgedit.path.getPointFromGrip({ - x: svgedit.path.path.dragging[0], - y: svgedit.path.path.dragging[1] - }, svgedit.path.path); - var mpt = svgedit.path.getPointFromGrip({ - x: mouse_x, - y: mouse_y - }, svgedit.path.path); - var diff_x = mpt.x - pt.x; - var diff_y = mpt.y - pt.y; - svgedit.path.path.dragging = [mouse_x, mouse_y]; - - if(svgedit.path.path.dragctrl) { - svgedit.path.path.moveCtrl(diff_x, diff_y); - } else { - svgedit.path.path.movePts(diff_x, diff_y); - } - } else { - svgedit.path.path.selected_pts = []; - svgedit.path.path.eachSeg(function(i) { - var seg = this; - if(!seg.next && !seg.prev) return; - - var item = seg.item; - var rbb = rubberBox.getBBox(); - - var pt = svgedit.path.getGripPt(seg); - var pt_bb = { - x: pt.x, - y: pt.y, - width: 0, - height: 0 - }; - - var sel = svgedit.math.rectsIntersect(rbb, pt_bb); - - this.select(sel); - //Note that addPtsToSelection is not being run - if(sel) svgedit.path.path.selected_pts.push(seg.index); - }); - - } - }, - mouseUp: function(evt, element, mouse_x, mouse_y) { - - // Create mode - if(current_mode === "path") { - newPoint = null; - if(!drawn_path) { - element = getElem(getId()); - started = false; - firstCtrl = null; - } - - return { - keep: true, - element: element - } - } - - // Edit mode - - if (svgedit.path.path.dragging) { - var last_pt = svgedit.path.path.cur_pt; - - svgedit.path.path.dragging = false; - svgedit.path.path.dragctrl = false; - svgedit.path.path.update(); - - - if(hasMoved) { - svgedit.path.path.endChanges("Move path point(s)"); - } - - if(!evt.shiftKey && !hasMoved) { - svgedit.path.path.selectPt(last_pt); - } - } - else if(rubberBox && rubberBox.getAttribute('display') != 'none') { - // Done with multi-node-select - rubberBox.setAttribute("display", "none"); - - if(rubberBox.getAttribute('width') <= 2 && rubberBox.getAttribute('height') <= 2) { - pathActions.toSelectMode(evt.target); - } - - // else, move back to select mode - } else { - pathActions.toSelectMode(evt.target); - } - hasMoved = false; - }, - toEditMode: function(element) { - svgedit.path.path = svgedit.path.getPath_(element); - current_mode = "pathedit"; - clearSelection(); - svgedit.path.path.show(true).update(); - svgedit.path.path.oldbbox = svgedit.utilities.getBBox(svgedit.path.path.elem); - subpath = false; - }, - toSelectMode: function(elem) { - var selPath = (elem == svgedit.path.path.elem); - current_mode = "select"; - svgedit.path.path.show(false); - current_path = false; - clearSelection(); - - if(svgedit.path.path.matrix) { - // Rotated, so may need to re-calculate the center - svgedit.path.recalcRotatedPath(); - } - - if(selPath) { - call("selected", [elem]); - addToSelection([elem], true); - } - }, - addSubPath: function(on) { - if(on) { - // Internally we go into "path" mode, but in the UI it will - // still appear as if in "pathedit" mode. - current_mode = "path"; - subpath = true; - } else { - pathActions.clear(true); - pathActions.toEditMode(svgedit.path.path.elem); - } - }, - select: function(target) { - if (current_path === target) { - pathActions.toEditMode(target); - current_mode = "pathedit"; - } // going into pathedit mode - else { - current_path = target; - } - }, - reorient: function() { - var elem = selectedElements[0]; - if(!elem) return; - var angle = getRotationAngle(elem); - if(angle == 0) return; - - var batchCmd = new BatchCommand("Reorient path"); - var changes = { - d: elem.getAttribute('d'), - transform: elem.getAttribute('transform') - }; - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - clearSelection(); - this.resetOrientation(elem); - - addCommandToHistory(batchCmd); - - // Set matrix to null - svgedit.path.getPath_(elem).show(false).matrix = null; - - this.clear(); - - addToSelection([elem], true); - call("changed", selectedElements); - }, - - clear: function(remove) { - current_path = null; - if (drawn_path) { - var elem = getElem(getId()); - $(getElem("path_stretch_line")).remove(); - $(elem).remove(); - $(getElem("pathpointgrip_container")).find('*').attr('display', 'none'); - drawn_path = firstCtrl = null; - started = false; - } else if (current_mode == "pathedit") { - this.toSelectMode(); - } - if(svgedit.path.path) svgedit.path.path.init().show(false); - }, - resetOrientation: function(path) { - if(path == null || path.nodeName != 'path') return false; - var tlist = getTransformList(path); - var m = transformListToTransform(tlist).matrix; - tlist.clear(); - path.removeAttribute("transform"); - var segList = path.pathSegList; - - // Opera/win/non-EN throws an error here. - // TODO: Find out why! - // Presumed fixed in Opera 10.5, so commented out for now - -// try { - var len = segList.numberOfItems; -// } catch(err) { -// var fixed_d = pathActions.convertPath(path); -// path.setAttribute('d', fixed_d); -// segList = path.pathSegList; -// var len = segList.numberOfItems; -// } - var last_x, last_y; - - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - var type = seg.pathSegType; - if(type == 1) continue; - var pts = []; - $.each(['',1,2], function(j, n) { - var x = seg['x'+n], y = seg['y'+n]; - if(x !== undefined && y !== undefined) { - var pt = transformPoint(x, y, m); - pts.splice(pts.length, 0, pt.x, pt.y); - } - }); - svgedit.path.replacePathSeg(type, i, pts, path); - } - - reorientGrads(path, m); - - - }, - zoomChange: function() { - if(current_mode == "pathedit") { - svgedit.path.path.update(); - } - }, - getNodePoint: function() { - var sel_pt = svgedit.path.path.selected_pts.length ? svgedit.path.path.selected_pts[0] : 1; - - var seg = svgedit.path.path.segs[sel_pt]; - return { - x: seg.item.x, - y: seg.item.y, - type: seg.type - }; - }, - linkControlPoints: function(linkPoints) { - svgedit.path.setLinkControlPoints(linkPoints); - }, - clonePathNode: function() { - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var segs = svgedit.path.path.segs; - - var i = sel_pts.length; - var nums = []; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.addSeg(pt); - nums.push(pt + i); - nums.push(pt + i + 1); - } - svgedit.path.path.init().addPtsToSelection(nums); - - svgedit.path.path.endChanges("Clone path node(s)"); - }, - opencloseSubPath: function() { - var sel_pts = svgedit.path.path.selected_pts; - // Only allow one selected node for now - if(sel_pts.length !== 1) return; - - var elem = svgedit.path.path.elem; - var list = elem.pathSegList; - - var len = list.numberOfItems; - - var index = sel_pts[0]; - - var open_pt = null; - var start_item = null; - - // Check if subpath is already open - svgedit.path.path.eachSeg(function(i) { - if(this.type === 2 && i <= index) { - start_item = this.item; - } - if(i <= index) return true; - if(this.type === 2) { - // Found M first, so open - open_pt = i; - return false; - } else if(this.type === 1) { - // Found Z first, so closed - open_pt = false; - return false; - } - }); - - if(open_pt == null) { - // Single path, so close last seg - open_pt = svgedit.path.path.segs.length - 1; - } - - if(open_pt !== false) { - // Close this path - - // Create a line going to the previous "M" - var newseg = elem.createSVGPathSegLinetoAbs(start_item.x, start_item.y); - - var closer = elem.createSVGPathSegClosePath(); - if(open_pt == svgedit.path.path.segs.length - 1) { - list.appendItem(newseg); - list.appendItem(closer); - } else { - svgedit.path.insertItemBefore(elem, closer, open_pt); - svgedit.path.insertItemBefore(elem, newseg, open_pt); - } - - svgedit.path.path.init().selectPt(open_pt+1); - return; - } - - - - // M 1,1 L 2,2 L 3,3 L 1,1 z // open at 2,2 - // M 2,2 L 3,3 L 1,1 - - // M 1,1 L 2,2 L 1,1 z M 4,4 L 5,5 L6,6 L 5,5 z - // M 1,1 L 2,2 L 1,1 z [M 4,4] L 5,5 L(M)6,6 L 5,5 z - - var seg = svgedit.path.path.segs[index]; - - if(seg.mate) { - list.removeItem(index); // Removes last "L" - list.removeItem(index); // Removes the "Z" - svgedit.path.path.init().selectPt(index - 1); - return; - } - - var last_m, z_seg; - - // Find this sub-path's closing point and remove - for(var i=0; i<list.numberOfItems; i++) { - var item = list.getItem(i); - - if(item.pathSegType === 2) { - // Find the preceding M - last_m = i; - } else if(i === index) { - // Remove it - list.removeItem(last_m); -// index--; - } else if(item.pathSegType === 1 && index < i) { - // Remove the closing seg of this subpath - z_seg = i-1; - list.removeItem(i); - break; - } - } - - var num = (index - last_m) - 1; - - while(num--) { - svgedit.path.insertItemBefore(elem, list.getItem(last_m), z_seg); - } - - var pt = list.getItem(last_m); - - // Make this point the new "M" - svgedit.path.replacePathSeg(2, last_m, [pt.x, pt.y]); - - var i = index - - svgedit.path.path.init().selectPt(0); - }, - deletePathNode: function() { - if(!pathActions.canDeleteNodes) return; - svgedit.path.path.storeD(); - - var sel_pts = svgedit.path.path.selected_pts; - var i = sel_pts.length; - - while(i--) { - var pt = sel_pts[i]; - svgedit.path.path.deleteSeg(pt); - } - - // Cleanup - var cleanup = function() { - var segList = svgedit.path.path.elem.pathSegList; - var len = segList.numberOfItems; - - var remItems = function(pos, count) { - while(count--) { - segList.removeItem(pos); - } - } - - if(len <= 1) return true; - - while(len--) { - var item = segList.getItem(len); - if(item.pathSegType === 1) { - var prev = segList.getItem(len-1); - var nprev = segList.getItem(len-2); - if(prev.pathSegType === 2) { - remItems(len-1, 2); - cleanup(); - break; - } else if(nprev.pathSegType === 2) { - remItems(len-2, 3); - cleanup(); - break; - } - - } else if(item.pathSegType === 2) { - if(len > 0) { - var prev_type = segList.getItem(len-1).pathSegType; - // Path has M M - if(prev_type === 2) { - remItems(len-1, 1); - cleanup(); - break; - // Entire path ends with Z M - } else if(prev_type === 1 && segList.numberOfItems-1 === len) { - remItems(len, 1); - cleanup(); - break; - } - } - } - } - return false; - } - - cleanup(); - - // Completely delete a path with 1 or 0 segments - if(svgedit.path.path.elem.pathSegList.numberOfItems <= 1) { - pathActions.toSelectMode(svgedit.path.path.elem); - canvas.deleteSelectedElements(); - return; - } - - svgedit.path.path.init(); - - svgedit.path.path.clearSelection(); - - // TODO: Find right way to select point now - // path.selectPt(sel_pt); - if(window.opera) { // Opera repaints incorrectly - var cp = $(svgedit.path.path.elem); cp.attr('d',cp.attr('d')); - } - svgedit.path.path.endChanges("Delete path node(s)"); - }, - smoothPolylineIntoPath: smoothPolylineIntoPath, - setSegType: function(v) { - svgedit.path.path.setSegType(v); - }, - moveNode: function(attr, newValue) { - var sel_pts = svgedit.path.path.selected_pts; - if(!sel_pts.length) return; - - svgedit.path.path.storeD(); - - // Get first selected point - var seg = svgedit.path.path.segs[sel_pts[0]]; - var diff = {x:0, y:0}; - diff[attr] = newValue - seg.item[attr]; - - seg.move(diff.x, diff.y); - svgedit.path.path.endChanges("Move path point"); - }, - fixEnd: function(elem) { - // Adds an extra segment if the last seg before a Z doesn't end - // at its M point - // M0,0 L0,100 L100,100 z - var segList = elem.pathSegList; - var len = segList.numberOfItems; - var last_m; - for (var i = 0; i < len; ++i) { - var item = segList.getItem(i); - if(item.pathSegType === 2) { - last_m = item; - } - - if(item.pathSegType === 1) { - var prev = segList.getItem(i-1); - if(prev.x != last_m.x || prev.y != last_m.y) { - // Add an L segment here - var newseg = elem.createSVGPathSegLinetoAbs(last_m.x, last_m.y); - svgedit.path.insertItemBefore(elem, newseg, i); - // Can this be done better? - pathActions.fixEnd(elem); - break; - } - - } - } - if(svgedit.browser.isWebkit()) resetD(elem); - }, - // Convert a path to one with only absolute or relative values - convertPath: function(path, toRel) { - var segList = path.pathSegList; - var len = segList.numberOfItems; - var curx = 0, cury = 0; - var d = ""; - var last_m = null; - - for (var i = 0; i < len; ++i) { - var seg = segList.getItem(i); - // if these properties are not in the segment, set them to zero - var x = seg.x || 0, - y = seg.y || 0, - x1 = seg.x1 || 0, - y1 = seg.y1 || 0, - x2 = seg.x2 || 0, - y2 = seg.y2 || 0; - - var type = seg.pathSegType; - var letter = pathMap[type]['to'+(toRel?'Lower':'Upper')+'Case'](); - - var addToD = function(pnts, more, last) { - var str = ''; - var more = more?' '+more.join(' '):''; - var last = last?' '+svgedit.units.shortFloat(last):''; - $.each(pnts, function(i, pnt) { - pnts[i] = svgedit.units.shortFloat(pnt); - }); - d += letter + pnts.join(' ') + more + last; - } - - switch (type) { - case 1: // z,Z closepath (Z/z) - d += "z"; - break; - case 12: // absolute horizontal line (H) - x -= curx; - case 13: // relative horizontal line (h) - if(toRel) { - curx += x; - letter = 'l'; - } else { - x += curx; - curx = x; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[x, cury]]); - break; - case 14: // absolute vertical line (V) - y -= cury; - case 15: // relative vertical line (v) - if(toRel) { - cury += y; - letter = 'l'; - } else { - y += cury; - cury = y; - letter = 'L'; - } - // Convert to "line" for easier editing - addToD([[curx, y]]); - break; - case 2: // absolute move (M) - case 4: // absolute line (L) - case 18: // absolute smooth quad (T) - x -= curx; - y -= cury; - case 5: // relative line (l) - case 3: // relative move (m) - // If the last segment was a "z", this must be relative to - if(last_m && segList.getItem(i-1).pathSegType === 1 && !toRel) { - curx = last_m[0]; - cury = last_m[1]; - } - - case 19: // relative smooth quad (t) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - if(type === 3) last_m = [curx, cury]; - - addToD([[x,y]]); - break; - case 6: // absolute cubic (C) - x -= curx; x1 -= curx; x2 -= curx; - y -= cury; y1 -= cury; y2 -= cury; - case 7: // relative cubic (c) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; x2 += curx; - y += cury; y1 += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x2,y2],[x,y]]); - break; - case 8: // absolute quad (Q) - x -= curx; x1 -= curx; - y -= cury; y1 -= cury; - case 9: // relative quad (q) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x1 += curx; - y += cury; y1 += cury; - curx = x; - cury = y; - } - addToD([[x1,y1],[x,y]]); - break; - case 10: // absolute elliptical arc (A) - x -= curx; - y -= cury; - case 11: // relative elliptical arc (a) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; - y += cury; - curx = x; - cury = y; - } - addToD([[seg.r1,seg.r2]], [ - seg.angle, - (seg.largeArcFlag ? 1 : 0), - (seg.sweepFlag ? 1 : 0) - ],[x,y] - ); - break; - case 16: // absolute smooth cubic (S) - x -= curx; x2 -= curx; - y -= cury; y2 -= cury; - case 17: // relative smooth cubic (s) - if(toRel) { - curx += x; - cury += y; - } else { - x += curx; x2 += curx; - y += cury; y2 += cury; - curx = x; - cury = y; - } - addToD([[x2,y2],[x,y]]); - break; - } // switch on path segment type - } // for each segment - return d; - } - } -}(); -// end pathActions - -// Group: Serialization - -// Function: removeUnusedDefElems -// Looks at DOM elements inside the <defs> to see if they are referred to, -// removes them from the DOM if they are not. -// -// Returns: -// The amount of elements that were removed -var removeUnusedDefElems = this.removeUnusedDefElems = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if(!defs || !defs.length) return 0; - -// if(!defs.firstChild) return; - - var defelem_uses = [], - numRemoved = 0; - var attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']; - var alen = attrs.length; - - var all_els = svgcontent.getElementsByTagNameNS(svgns, '*'); - var all_len = all_els.length; - - for(var i=0; i<all_len; i++) { - var el = all_els[i]; - for(var j = 0; j < alen; j++) { - var ref = getUrlFromAttr(el.getAttribute(attrs[j])); - if(ref) { - defelem_uses.push(ref.substr(1)); - } - } - - // gradients can refer to other gradients - var href = getHref(el); - if (href && href.indexOf('#') === 0) { - defelem_uses.push(href.substr(1)); - } - }; - - var defelems = $(defs).find("linearGradient, radialGradient, filter, marker, svg, symbol"); - defelem_ids = [], - i = defelems.length; - while (i--) { - var defelem = defelems[i]; - var id = defelem.id; - if(defelem_uses.indexOf(id) < 0) { - // Not found, so remove (but remember) - removedElements[id] = defelem; - defelem.parentNode.removeChild(defelem); - numRemoved++; - } - } - - return numRemoved; -} - -// Function: svgCanvasToString -// Main function to set up the SVG content for output -// -// Returns: -// String containing the SVG image for output -this.svgCanvasToString = function() { - // keep calling it until there are none to remove - while (removeUnusedDefElems() > 0) {}; - - pathActions.clear(true); - - // Keep SVG-Edit comment on top - $.each(svgcontent.childNodes, function(i, node) { - if(i && node.nodeType === 8 && node.data.indexOf('Created with') >= 0) { - svgcontent.insertBefore(node, svgcontent.firstChild); - } - }); - - // Move out of in-group editing mode - if(current_group) { - leaveContext(); - selectOnly([current_group]); - } - - var naked_svgs = []; - - // Unwrap gsvg if it has no special attributes (only id and style) - $(svgcontent).find('g:data(gsvg)').each(function() { - var attrs = this.attributes; - var len = attrs.length; - for(var i=0; i<len; i++) { - if(attrs[i].nodeName == 'id' || attrs[i].nodeName == 'style') { - len--; - } - } - // No significant attributes, so ungroup - if(len <= 0) { - var svg = this.firstChild; - naked_svgs.push(svg); - $(this).replaceWith(svg); - } - }); - var output = this.svgToString(svgcontent, 0); - - // Rewrap gsvg - if(naked_svgs.length) { - $(naked_svgs).each(function() { - groupSvgElem(this); - }); - } - - return output; -}; - -// Function: svgToString -// Sub function ran on each SVG element to convert it to a string as desired -// -// Parameters: -// elem - The SVG element to convert -// indent - Integer with the amount of spaces to indent this tag -// -// Returns: -// String with the given element as an SVG tag -this.svgToString = function(elem, indent) { - var out = new Array(), toXml = svgedit.utilities.toXml; - var unit = curConfig.baseUnit; - var unit_re = new RegExp('^-?[\\d\\.]+' + unit + '$'); - - if (elem) { - cleanupElement(elem); - var attrs = elem.attributes, - attr, - i, - childs = elem.childNodes; - - for (var i=0; i<indent; i++) out.push(" "); - out.push("<"); out.push(elem.nodeName); - if(elem.id === 'svgcontent') { - // Process root element separately - var res = getResolution(); - - var vb = ""; - // TODO: Allow this by dividing all values by current baseVal - // Note that this also means we should properly deal with this on import -// if(curConfig.baseUnit !== "px") { -// var unit = curConfig.baseUnit; -// var unit_m = svgedit.units.getTypeMap()[unit]; -// res.w = svgedit.units.shortFloat(res.w / unit_m) -// res.h = svgedit.units.shortFloat(res.h / unit_m) -// vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"'; -// res.w += unit; -// res.h += unit; -// } - - if(unit !== "px") { - res.w = svgedit.units.convertUnit(res.w, unit) + unit; - res.h = svgedit.units.convertUnit(res.h, unit) + unit; - } - - out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="'+svgns+'"'); - - var nsuris = {}; - - // Check elements for namespaces, add if found - $(elem).find('*').andSelf().each(function() { - var el = this; - $.each(this.attributes, function(i, attr) { - var uri = attr.namespaceURI; - if(uri && !nsuris[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml' ) { - nsuris[uri] = true; - out.push(" xmlns:" + nsMap[uri] + '="' + uri +'"'); - } - }); - }); - - var i = attrs.length; - var attr_names = ['width','height','xmlns','x','y','viewBox','id','overflow']; - while (i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - - // Namespaces have already been dealt with, so skip - if(attr.nodeName.indexOf('xmlns:') === 0) continue; - - // only serialize attributes we don't use internally - if (attrVal != "" && attr_names.indexOf(attr.localName) == -1) - { - - if(!attr.namespaceURI || nsMap[attr.namespaceURI]) { - out.push(' '); - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } else { - // Skip empty defs - if(elem.nodeName === 'defs' && !elem.firstChild) return; - - var moz_attrs = ['-moz-math-font-style', '_moz-math-font-style']; - for (var i=attrs.length-1; i>=0; i--) { - attr = attrs.item(i); - var attrVal = toXml(attr.nodeValue); - //remove bogus attributes added by Gecko - if (moz_attrs.indexOf(attr.localName) >= 0) continue; - if (attrVal != "") { - if(attrVal.indexOf('pointer-events') === 0) continue; - if(attr.localName === "class" && attrVal.indexOf('se_') === 0) continue; - out.push(" "); - if(attr.localName === 'd') attrVal = pathActions.convertPath(elem, true); - if(!isNaN(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal); - } else if(unit_re.test(attrVal)) { - attrVal = svgedit.units.shortFloat(attrVal) + unit; - } - - // Embed images when saving - if(save_options.apply - && elem.nodeName === 'image' - && attr.localName === 'href' - && save_options.images - && save_options.images === 'embed') - { - var img = encodableImages[attrVal]; - if(img) attrVal = img; - } - - // map various namespaces to our fixed namespace prefixes - // (the default xmlns attribute itself does not get a prefix) - if(!attr.namespaceURI || attr.namespaceURI == svgns || nsMap[attr.namespaceURI]) { - out.push(attr.nodeName); out.push("=\""); - out.push(attrVal); out.push("\""); - } - } - } - } - - if (elem.hasChildNodes()) { - out.push(">"); - indent++; - var bOneLine = false; - - for (var i=0; i<childs.length; i++) - { - var child = childs.item(i); - switch(child.nodeType) { - case 1: // element node - out.push("\n"); - out.push(this.svgToString(childs.item(i), indent)); - break; - case 3: // text node - var str = child.nodeValue.replace(/^\s+|\s+$/g, ""); - if (str != "") { - bOneLine = true; - out.push(toXml(str) + ""); - } - break; - case 4: // cdata node - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<![CDATA["); - out.push(child.nodeValue); - out.push("]]>"); - break; - case 8: // comment - out.push("\n"); - out.push(new Array(indent+1).join(" ")); - out.push("<!--"); - out.push(child.data); - out.push("-->"); - break; - } // switch on node type - } - indent--; - if (!bOneLine) { - out.push("\n"); - for (var i=0; i<indent; i++) out.push(" "); - } - out.push("</"); out.push(elem.nodeName); out.push(">"); - } else { - out.push("/>"); - } - } - return out.join(''); -}; // end svgToString() - -// Function: embedImage -// Converts a given image file to a data URL when possible, then runs a given callback -// -// Parameters: -// val - String with the path/URL of the image -// callback - Optional function to run when image data is found, supplies the -// result (data URL or false) as first parameter. -this.embedImage = function(val, callback) { - - // load in the image and once it's loaded, get the dimensions - $(new Image()).load(function() { - // create a canvas the same size as the raster image - var canvas = document.createElement("canvas"); - canvas.width = this.width; - canvas.height = this.height; - // load the raster image into the canvas - canvas.getContext("2d").drawImage(this,0,0); - // retrieve the data: URL - try { - var urldata = ';svgedit_url=' + encodeURIComponent(val); - urldata = canvas.toDataURL().replace(';base64',urldata+';base64'); - encodableImages[val] = urldata; - } catch(e) { - encodableImages[val] = false; - } - last_good_img_url = val; - if(callback) callback(encodableImages[val]); - }).attr('src',val); -} - -// Function: setGoodImage -// Sets a given URL to be a "last good image" URL -this.setGoodImage = function(val) { - last_good_img_url = val; -} - -this.open = function() { - // Nothing by default, handled by optional widget/extension -}; - -// Function: save -// Serializes the current drawing into SVG XML text and returns it to the 'saved' handler. -// This function also includes the XML prolog. Clients of the SvgCanvas bind their save -// function to the 'saved' event. -// -// Returns: -// Nothing -this.save = function(opts) { - // remove the selected outline before serializing - clearSelection(); - // Update save options if provided - if(opts) $.extend(save_options, opts); - save_options.apply = true; - - // no need for doctype, see http://jwatt.org/svg/authoring/#doctype-declaration - var str = this.svgCanvasToString(); - call("saved", str); -}; - -// Function: rasterExport -// Generates a PNG Data URL based on the current image, then calls "exported" -// with an object including the string and any issues found -this.rasterExport = function() { - // remove the selected outline before serializing - clearSelection(); - - // Check for known CanVG issues - var issues = []; - - // Selector and notice - var issue_list = { - 'feGaussianBlur': uiStrings.exportNoBlur, - 'foreignObject': uiStrings.exportNoforeignObject, - '[stroke-dasharray]': uiStrings.exportNoDashArray - }; - var content = $(svgcontent); - - // Add font/text check if Canvas Text API is not implemented - if(!("font" in $('<canvas>')[0].getContext('2d'))) { - issue_list['text'] = uiStrings.exportNoText; - } - - $.each(issue_list, function(sel, descr) { - if(content.find(sel).length) { - issues.push(descr); - } - }); - - var str = this.svgCanvasToString(); - call("exported", {svg: str, issues: issues}); -}; - -// Function: getSvgString -// Returns the current drawing as raw SVG XML text. -// -// Returns: -// The current drawing as raw SVG XML text. -this.getSvgString = function() { - save_options.apply = false; - return this.svgCanvasToString(); -}; - -// Function: randomizeIds -// This function determines whether to use a nonce in the prefix, when -// generating IDs for future documents in SVG-Edit. -// -// Parameters: -// an opional boolean, which, if true, adds a nonce to the prefix. Thus -// svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true) -// -// if you're controlling SVG-Edit externally, and want randomized IDs, call -// this BEFORE calling svgCanvas.setSvgString -// -this.randomizeIds = function() { - if (arguments.length > 0 && arguments[0] == false) { - svgedit.draw.randomizeIds(false, getCurrentDrawing()); - } else { - svgedit.draw.randomizeIds(true, getCurrentDrawing()); - } -}; - -// Function: uniquifyElems -// Ensure each element has a unique ID -// -// Parameters: -// g - The parent element of the tree to give unique IDs -var uniquifyElems = this.uniquifyElems = function(g) { - var ids = {}; - // TODO: Handle markers and connectors. These are not yet re-identified properly - // as their referring elements do not get remapped. - // - // <marker id='se_marker_end_svg_7'/> - // <polyline id='svg_7' se:connector='svg_1 svg_6' marker-end='url(#se_marker_end_svg_7)'/> - // - // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute - // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute - var ref_elems = ["filter", "linearGradient", "pattern", "radialGradient", "symbol", "textPath", "use"]; - - svgedit.utilities.walkTree(g, function(n) { - // if it's an element node - if (n.nodeType == 1) { - // and the element has an ID - if (n.id) { - // and we haven't tracked this ID yet - if (!(n.id in ids)) { - // add this id to our map - ids[n.id] = {elem:null, attrs:[], hrefs:[]}; - } - ids[n.id]["elem"] = n; - } - - // now search for all attributes on this element that might refer - // to other elements - $.each(ref_attrs,function(i,attr) { - var attrnode = n.getAttributeNode(attr); - if (attrnode) { - // the incoming file has been sanitized, so we should be able to safely just strip off the leading # - var url = svgedit.utilities.getUrlFromAttr(attrnode.value), - refid = url ? url.substr(1) : null; - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["attrs"].push(attrnode); - } - } - }); - - // check xlink:href now - var href = svgedit.utilities.getHref(n); - // TODO: what if an <image> or <a> element refers to an element internally? - if(href && ref_elems.indexOf(n.nodeName) >= 0) - { - var refid = href.substr(1); - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = {elem:null, attrs:[], hrefs:[]}; - } - ids[refid]["hrefs"].push(n); - } - } - } - }); - - // in ids, we now have a map of ids, elements and attributes, let's re-identify - for (var oldid in ids) { - if (!oldid) continue; - var elem = ids[oldid]["elem"]; - if (elem) { - var newid = getNextId(); - - // assign element its new id - elem.id = newid; - - // remap all url() attributes - var attrs = ids[oldid]["attrs"]; - var j = attrs.length; - while (j--) { - var attr = attrs[j]; - attr.ownerElement.setAttribute(attr.name, "url(#" + newid + ")"); - } - - // remap all href attributes - var hreffers = ids[oldid]["hrefs"]; - var k = hreffers.length; - while (k--) { - var hreffer = hreffers[k]; - svgedit.utilities.setHref(hreffer, "#"+newid); - } - } - } -} - -// Function setUseData -// Assigns reference data for each use element -var setUseData = this.setUseData = function(parent) { - var elems = $(parent); - - if(parent.tagName !== 'use') { - elems = elems.find('use'); - } - - elems.each(function() { - var id = getHref(this).substr(1); - var ref_elem = getElem(id); - if(!ref_elem) return; - $(this).data('ref', ref_elem); - if(ref_elem.tagName == 'symbol' || ref_elem.tagName == 'svg') { - $(this).data('symbol', ref_elem).data('ref', ref_elem); - } - }); -} - -// Function convertGradients -// Converts gradients from userSpaceOnUse to objectBoundingBox -var convertGradients = this.convertGradients = function(elem) { - var elems = $(elem).find('linearGradient, radialGradient'); - if(!elems.length && svgedit.browser.isWebkit()) { - // Bug in webkit prevents regular *Gradient selector search - elems = $(elem).find('*').filter(function() { - return (this.tagName.indexOf('Gradient') >= 0); - }); - } - - elems.each(function() { - var grad = this; - if($(grad).attr('gradientUnits') === 'userSpaceOnUse') { - // TODO: Support more than one element with this ref by duplicating parent grad - var elems = $(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - if(!elems.length) return; - - // get object's bounding box - var bb = svgedit.utilities.getBBox(elems[0]); - - // This will occur if the element is inside a <defs> or a <symbol>, - // in which we shouldn't need to convert anyway. - if(!bb) return; - - if(grad.tagName === 'linearGradient') { - var g_coords = $(grad).attr(['x1', 'y1', 'x2', 'y2']); - - // If has transform, convert - var tlist = grad.gradientTransform.baseVal; - if(tlist && tlist.numberOfItems > 0) { - var m = transformListToTransform(tlist).matrix; - var pt1 = transformPoint(g_coords.x1, g_coords.y1, m); - var pt2 = transformPoint(g_coords.x2, g_coords.y2, m); - - g_coords.x1 = pt1.x; - g_coords.y1 = pt1.y; - g_coords.x2 = pt2.x; - g_coords.y2 = pt2.y; - grad.removeAttribute('gradientTransform'); - } - - $(grad).attr({ - x1: (g_coords.x1 - bb.x) / bb.width, - y1: (g_coords.y1 - bb.y) / bb.height, - x2: (g_coords.x2 - bb.x) / bb.width, - y2: (g_coords.y2 - bb.y) / bb.height - }); - grad.removeAttribute('gradientUnits'); - } else { - // Note: radialGradient elements cannot be easily converted - // because userSpaceOnUse will keep circular gradients, while - // objectBoundingBox will x/y scale the gradient according to - // its bbox. - - // For now we'll do nothing, though we should probably have - // the gradient be updated as the element is moved, as - // inkscape/illustrator do. - -// var g_coords = $(grad).attr(['cx', 'cy', 'r']); -// -// $(grad).attr({ -// cx: (g_coords.cx - bb.x) / bb.width, -// cy: (g_coords.cy - bb.y) / bb.height, -// r: g_coords.r -// }); -// -// grad.removeAttribute('gradientUnits'); - } - - - } - }); -} - -// Function: convertToGroup -// Converts selected/given <use> 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']); - - var vb = elem.getAttribute('viewBox'); - - if(vb) { - var nums = vb.split(' '); - pos.x -= +nums[0]; - pos.y -= +nums[1]; - } - - // Not ideal, but works - ts += " translate(" + (pos.x || 0) + "," + (pos.y || 0) + ")"; - - var prev = $elem.prev(); - - // Remove <use> element - batchCmd.addSubCommand(new RemoveElementCommand($elem[0], $elem[0].nextSibling, $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)); - } - - // Duplicate the gradients for Gecko, since they weren't included in the <symbol> - if(svgedit.browser.isGecko()) { - var dupeGrads = $(findDefs()).children('linearGradient,radialGradient,pattern').clone(); - $(g).append(dupeGrads); - } - - if (ts) { - g.setAttribute("transform", ts); - } - - var parent = elem.parentNode; - - uniquifyElems(g); - - // Put the dupe gradients back into <defs> (after uniquifying them) - if(svgedit.browser.isGecko()) { - $(findDefs()).append( $(g).find('linearGradient,radialGradient,pattern') ); - } - - // now give the g itself a new id - g.id = getNextId(); - - prev.after(g); - - if(parent) { - if(!has_more) { - // remove symbol/svg element - var nextSibling = elem.nextSibling; - parent.removeChild(elem); - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - } - - setUseData(g); - - if(svgedit.browser.isGecko()) { - convertGradients(findDefs()); - } else { - convertGradients(g); - } - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(g, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - // Give ID for any visible element missing one - $(g).find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - selectOnly([g]); - - var cm = pushGroupProperties(g, true); - if(cm) { - batchCmd.addSubCommand(cm); - } - - addCommandToHistory(batchCmd); - - } else { - console.log('Unexpected element to ungroup:', elem); - } -} - -// -// Function: setSvgString -// This function sets the current drawing as the input SVG XML. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the set was unsuccessful, true otherwise. -this.setSvgString = function(xmlString) { - try { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - var batchCmd = new BatchCommand("Change Source"); - - // remove old svg document - var nextSibling = svgcontent.nextSibling; - var oldzoom = svgroot.removeChild(svgcontent); - batchCmd.addSubCommand(new RemoveElementCommand(oldzoom, nextSibling, svgroot)); - - // set new svg document - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svgcontent = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svgcontent = svgdoc.importNode(newDoc.documentElement, true); - } - - svgroot.appendChild(svgcontent); - var content = $(svgcontent); - - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent, idprefix); - - // retrieve or set the nonce - var nonce = getCurrentDrawing().getNonce(); - if (nonce) { - call("setnonce", nonce); - } else { - call("unsetnonce"); - } - - // change image href vals if possible - content.find('image').each(function() { - var image = this; - preventClickDefault(image); - var val = getHref(this); - 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); - }); - - // Wrap child SVGs in group elements - content.find('svg').each(function() { - // Skip if it's in a <defs> - if($(this).closest('defs').length) return; - - uniquifyElems(this); - - // Check if it already has a gsvg group - var pa = this.parentNode; - if(pa.childNodes.length === 1 && pa.nodeName === 'g') { - $(pa).data('gsvg', this); - pa.id = pa.id || getNextId(); - } else { - groupSvgElem(this); - } - }); - - // For Firefox: Put all paint elems in defs - if(svgedit.browser.isGecko()) { - content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); - } - - - // Set ref element for <use> elements - - // TODO: This should also be done if the object is re-added through "redo" - setUseData(content); - - convertGradients(content[0]); - - // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - svgedit.utilities.walkTreePost(svgcontent, function(n){try{recalculateDimensions(n)}catch(e){console.log(e)}}); - - var attrs = { - id: 'svgcontent', - overflow: curConfig.show_outside_canvas?'visible':'hidden' - }; - - var percs = false; - - // determine proper size - if (content.attr("viewBox")) { - var vb = content.attr("viewBox").split(' '); - attrs.width = vb[2]; - attrs.height = vb[3]; - } - // handle content that doesn't have a viewBox - else { - $.each(['width', 'height'], function(i, dim) { - // Set to 100 if not given - var val = content.attr(dim); - - if(!val) val = '100%'; - - if((val+'').substr(-1) === "%") { - // Use user units if percentage given - percs = true; - } else { - attrs[dim] = convertToNum(dim, val); - } - }); - } - - // identify layers - identifyLayers(); - - // Give ID for any visible layer children missing one - content.children().find(visElems).each(function() { - if(!this.id) this.id = getNextId(); - }); - - // Percentage width/height, so let's base it on visible elements - if(percs) { - var bb = getStrokedBBox(); - attrs.width = bb.width + bb.x; - attrs.height = bb.height + bb.y; - } - - // Just in case negative numbers are given or - // result from the percs calculation - if(attrs.width <= 0) attrs.width = 100; - if(attrs.height <= 0) attrs.height = 100; - - content.attr(attrs); - this.contentW = attrs['width']; - this.contentH = attrs['height']; - - batchCmd.addSubCommand(new InsertElementCommand(svgcontent)); - // update root to the correct size - var changes = content.attr(["width", "height"]); - batchCmd.addSubCommand(new ChangeElementCommand(svgroot, changes)); - - // reset zoom - current_zoom = 1; - - // reset transform lists - svgedit.transformlist.resetListMap(); - clearSelection(); - svgedit.path.clearData(); - svgroot.appendChild(selectorManager.selectorParentGroup); - - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// Function: importSvgString -// This function imports the input SVG XML as a <symbol> in the <defs>, then adds a -// <use> to the current layer. -// -// Parameters: -// xmlString - The SVG as XML text. -// -// Returns: -// This function returns false if the import was unsuccessful, true otherwise. -// TODO: -// * properly handle if namespace is introduced by imported content (must add to svgcontent -// and update all prefixes in the imported node) -// * properly handle recalculating dimensions, recalculateDimensions() doesn't handle -// arbitrary transform lists, but makes some assumptions about how the transform list -// was obtained -// * import should happen in top-left of current zoomed viewport -this.importSvgString = function(xmlString) { - - try { - // Get unique ID - var uid = svgedit.utilities.encode64(xmlString.length + xmlString).substr(0,32); - - var useExisting = false; - - // Look for symbol and make sure symbol exists in image - if(import_ids[uid]) { - if( $(import_ids[uid].symbol).parents('#svgroot').length ) { - useExisting = true; - } - } - - var batchCmd = new BatchCommand("Import SVG"); - - if(useExisting) { - var symbol = import_ids[uid].symbol; - var ts = import_ids[uid].xform; - } else { - // convert string into XML document - var newDoc = svgedit.utilities.text2xml(xmlString); - - this.prepareSvg(newDoc); - - // import new svg document into our document - var svg; - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - if(svgdoc.adoptNode) { - svg = svgdoc.adoptNode(newDoc.documentElement); - } - else { - svg = svgdoc.importNode(newDoc.documentElement, true); - } - - uniquifyElems(svg); - - 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) - vb[j] = +(vb[j]); - - // TODO: properly handle preserveAspectRatio - var canvasw = +svgcontent.getAttribute("width"), - canvash = +svgcontent.getAttribute("height"); - // imported content should be 1/3 of the canvas on its largest dimension - - if (innerh > innerw) { - var ts = "scale(" + (canvash/3)/vb[3] + ")"; - } - else { - var ts = "scale(" + (canvash/3)/vb[2] + ")"; - } - - // Hack to make recalculateDimensions understand how to scale - ts = "translate(0) " + ts + " translate(0)"; - - var symbol = svgdoc.createElementNS(svgns, "symbol"); - var defs = findDefs(); - - if(svgedit.browser.isGecko()) { - // Move all gradients into root for Firefox, workaround for this bug: - // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 - // TODO: Make this properly undo-able. - $(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); - } - - while (svg.firstChild) { - var first = svg.firstChild; - symbol.appendChild(first); - } - var attrs = svg.attributes; - for(var i=0; i < attrs.length; i++) { - var attr = attrs[i]; - symbol.setAttribute(attr.nodeName, attr.nodeValue); - } - symbol.id = getNextId(); - - // Store data - import_ids[uid] = { - symbol: symbol, - xform: ts - } - - findDefs().appendChild(symbol); - batchCmd.addSubCommand(new InsertElementCommand(symbol)); - } - - - var use_el = svgdoc.createElementNS(svgns, "use"); - use_el.id = getNextId(); - setHref(use_el, "#" + symbol.id); - - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(use_el); - batchCmd.addSubCommand(new InsertElementCommand(use_el)); - clearSelection(); - - use_el.setAttribute("transform", ts); - recalculateDimensions(use_el); - $(use_el).data('symbol', symbol).data('ref', symbol); - addToSelection([use_el]); - - // 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; - addCommandToHistory(batchCmd); - call("changed", [svgcontent]); - - } catch(e) { - console.log(e); - return false; - } - - return true; -}; - -// TODO(codedread): Move all layer/context functions in draw.js -// Layer API Functions - -// Group: Layers - -// Function: identifyLayers -// Updates layer system -var identifyLayers = canvas.identifyLayers = function() { - leaveContext(); - getCurrentDrawing().identifyLayers(); -}; - -// Function: createLayer -// Creates a new top-level layer in the drawing with the given name, sets the current layer -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.createLayer = function(name) { - var batchCmd = new BatchCommand("Create Layer"); - var new_layer = getCurrentDrawing().createLayer(name); - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [new_layer]); -}; - -// Function: cloneLayer -// Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents -// to it, and then clears the selection This function then calls the 'changed' handler. -// This is an undoable action. -// -// Parameters: -// name - The given name -this.cloneLayer = function(name) { - var batchCmd = new BatchCommand("Duplicate Layer"); - var new_layer = svgdoc.createElementNS(svgns, "g"); - var layer_title = svgdoc.createElementNS(svgns, "title"); - layer_title.textContent = name; - new_layer.appendChild(layer_title); - var current_layer = getCurrentDrawing().getCurrentLayer(); - $(current_layer).after(new_layer); - var childs = current_layer.childNodes; - for(var i = 0; i < childs.length; i++) { - var ch = childs[i]; - if(ch.localName == 'title') continue; - new_layer.appendChild(copyElem(ch)); - } - - clearSelection(); - identifyLayers(); - - batchCmd.addSubCommand(new InsertElementCommand(new_layer)); - addCommandToHistory(batchCmd); - canvas.setCurrentLayer(name); - call("changed", [new_layer]); -}; - -// Function: deleteCurrentLayer -// Deletes the current layer from the drawing and then clears the selection. This function -// then calls the 'changed' handler. This is an undoable action. -this.deleteCurrentLayer = function() { - var current_layer = getCurrentDrawing().getCurrentLayer(); - var nextSibling = current_layer.nextSibling; - var parent = current_layer.parentNode; - current_layer = getCurrentDrawing().deleteCurrentLayer(); - if (current_layer) { - var batchCmd = new BatchCommand("Delete Layer"); - // store in our Undo History - batchCmd.addSubCommand(new RemoveElementCommand(current_layer, nextSibling, parent)); - addCommandToHistory(batchCmd); - clearSelection(); - call("changed", [parent]); - return true; - } - return false; -}; - -// Function: setCurrentLayer -// 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 undo-able action. -// -// Parameters: -// name - the name of the layer you want to switch to. -// -// Returns: -// true if the current layer was switched, otherwise false -this.setCurrentLayer = function(name) { - var result = getCurrentDrawing().setCurrentLayer(svgedit.utilities.toXml(name)); - if (result) { - clearSelection(); - } - return result; -}; - -// Function: renameCurrentLayer -// Renames the current layer. If the layer name is not valid (i.e. unique), then this function -// does nothing and returns false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// newname - the new name you want to give the current layer. This name must be unique -// among all layer names. -// -// Returns: -// true if the rename succeeded, false otherwise. -this.renameCurrentLayer = function(newname) { - 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 batchCmd = new BatchCommand("Rename Layer"); - // find the index of the layer - for (var 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 (var 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 ChangeElementCommand(child, {"#text":oldname})); - addCommandToHistory(batchCmd); - call("changed", [oldLayer]); - return true; - } - } - } - drawing.current_layer = oldLayer; - } - return false; -}; - -// Function: setCurrentLayerPosition -// Changes the position of the current layer to the new value. If the new index is not valid, -// this function does nothing and returns false, otherwise it returns true. This is an -// undo-able action. -// -// Parameters: -// newpos - The zero-based index of the new position of the layer. This should be between -// 0 and (number of layers - 1) -// -// Returns: -// true if the current layer position was changed, false otherwise. -this.setCurrentLayerPosition = function(newpos) { - var drawing = getCurrentDrawing(); - if (drawing.current_layer && newpos >= 0 && newpos < drawing.getNumLayers()) { - for (var 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 MoveElementCommand(drawing.current_layer, oldNextSibling, svgcontent)); - - identifyLayers(); - canvas.setCurrentLayer(drawing.getLayerName(newpos)); - - return true; - } - } - - return false; -}; - -// Function: setLayerVisibility -// Sets the visibility of the layer. If the layer name is not valid, this function return -// false, otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer to change the visibility -// bVisible - true/false, whether the layer should be visible -// -// Returns: -// true if the layer's visibility was set, false otherwise -this.setLayerVisibility = function(layername, bVisible) { - var drawing = getCurrentDrawing(); - var prevVisibility = drawing.getLayerVisibility(layername); - var layer = drawing.setLayerVisibility(layername, bVisible); - if (layer) { - var oldDisplay = prevVisibility ? 'inline' : 'none'; - addCommandToHistory(new ChangeElementCommand(layer, {'display':oldDisplay}, 'Layer Visibility')); - } else { - return false; - } - - if (layer == drawing.getCurrentLayer()) { - clearSelection(); - pathActions.clear(); - } -// call("changed", [selected]); - return true; -}; - -// Function: moveSelectedToLayer -// Moves the selected elements to layername. If the name is not a valid layer name, then false -// is returned. Otherwise it returns true. This is an undo-able action. -// -// Parameters: -// layername - the name of the layer you want to which you want to move the selected elements -// -// Returns: -// true if the selected elements were moved to the layer, false otherwise. -this.moveSelectedToLayer = function(layername) { - // find the layer - var layer = null; - var drawing = getCurrentDrawing(); - for (var i = 0; i < drawing.getNumLayers(); ++i) { - if (drawing.getLayerName(i) == layername) { - layer = drawing.all_layers[i][1]; - break; - } - } - if (!layer) return false; - - var batchCmd = new BatchCommand("Move Elements to Layer"); - - // loop for each selected element and move it - var selElems = selectedElements; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (!elem) continue; - var oldNextSibling = elem.nextSibling; - // TODO: this is pretty brittle! - var oldLayer = elem.parentNode; - layer.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); - } - - addCommandToHistory(batchCmd); - - return true; -}; - -this.mergeLayer = function(skipHistory) { - var batchCmd = new 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 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 RemoveElementCommand(ch, chNextSibling, drawing.current_layer)); - drawing.current_layer.removeChild(ch); - continue; - } - var oldNextSibling = ch.nextSibling; - prev.appendChild(ch); - batchCmd.addSubCommand(new MoveElementCommand(ch, oldNextSibling, drawing.current_layer)); - } - - // Remove current layer - svgcontent.removeChild(drawing.current_layer); - - if(!skipHistory) { - clearSelection(); - identifyLayers(); - - call("changed", [svgcontent]); - - addCommandToHistory(batchCmd); - } - - drawing.current_layer = prev; - return batchCmd; -} - -this.mergeAllLayers = function() { - var batchCmd = new 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)); - } - - clearSelection(); - identifyLayers(); - call("changed", [svgcontent]); - addCommandToHistory(batchCmd); -} - -// Function: leaveContext -// Return from a group context to the regular kind, make any previously -// disabled elements enabled again -var leaveContext = this.leaveContext = function() { - var len = disabled_elems.length; - if(len) { - for(var i = 0; i < len; i++) { - var elem = disabled_elems[i]; - - var orig = elData(elem, 'orig_opac'); - if(orig !== 1) { - elem.setAttribute('opacity', orig); - } else { - elem.removeAttribute('opacity'); - } - elem.setAttribute('style', 'pointer-events: inherit'); - } - disabled_elems = []; - clearSelection(true); - call("contextset", null); - } - current_group = null; -} - -// Function: setContext -// Set the current context (for in-group editing) -var setContext = this.setContext = function(elem) { - leaveContext(); - if(typeof elem === 'string') { - elem = getElem(elem); - } - - // Edit inside this group - current_group = elem; - - // Disable other elements - $(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function() { - var opac = this.getAttribute('opacity') || 1; - // Store the original's opacity - elData(this, 'orig_opac', opac); - this.setAttribute('opacity', opac * .33); - this.setAttribute('style', 'pointer-events: none'); - disabled_elems.push(this); - }); - - clearSelection(); - call("contextset", current_group); -} - -// Group: Document functions - -// Function: clear -// Clears the current document. This is not an undoable action. -this.clear = function() { - pathActions.clear(); - - clearSelection(); - - // clear the svgcontent node - canvas.clearSvgContentElement(); - - // create new document - canvas.current_drawing_ = new svgedit.draw.Drawing(svgcontent); - - // create empty first layer - canvas.createLayer("Layer 1"); - - // clear the undo stack - canvas.undoMgr.resetUndoStack(); - - // reset the selector manager - selectorManager.initGroup(); - - // reset the rubber band box - rubberBox = selectorManager.getRubberBandBox(); - - call("cleared"); -}; - -// Function: linkControlPoints -// Alias function -this.linkControlPoints = pathActions.linkControlPoints; - -// Function: getContentElem -// Returns the content DOM element -this.getContentElem = function() { return svgcontent; }; - -// Function: getRootElem -// Returns the root DOM element -this.getRootElem = function() { return svgroot; }; - -// Function: getSelectedElems -// Returns the array with selected DOM elements -this.getSelectedElems = function() { return selectedElements; }; - -// Function: getResolution -// Returns the current dimensions and zoom level in an object -var getResolution = this.getResolution = function() { -// var vb = svgcontent.getAttribute("viewBox").split(' '); -// return {'w':vb[2], 'h':vb[3], 'zoom': current_zoom}; - - var width = svgcontent.getAttribute("width")/current_zoom; - var height = svgcontent.getAttribute("height")/current_zoom; - - return { - 'w': width, - 'h': height, - 'zoom': current_zoom - }; -}; - -// Function: getZoom -// Returns the current zoom level -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: 2082 $)"; -}; - -// Function: setUiStrings -// Update interface strings with given values -// -// Parameters: -// strs - Object with strings (see uiStrings for examples) -this.setUiStrings = function(strs) { - $.extend(uiStrings, strs.notification); -} - -// Function: setConfig -// Update configuration options with given values -// -// Parameters: -// opts - Object with options (see curConfig for examples) -this.setConfig = function(opts) { - $.extend(curConfig, opts); -} - -// Function: getTitle -// 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<childs.length; i++) { - if(childs[i].nodeName == 'title') { - return childs[i].textContent; - } - } - return ''; -} - -// Function: setGroupTitle -// Sets the group/SVG's title content -// TODO: Combine this with setDocumentTitle -this.setGroupTitle = function(val) { - var elem = selectedElements[0]; - elem = $(elem).data('gsvg') || elem; - - var ts = $(elem).children('title'); - - var batchCmd = new BatchCommand("Set Label"); - - if(!val.length) { - // Remove title element - var tsNextSibling = ts.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(ts[0], tsNextSibling, elem)); - ts.remove(); - } else if(ts.length) { - // Change title contents - var title = ts[0]; - batchCmd.addSubCommand(new ChangeElementCommand(title, {'#text': title.textContent})); - title.textContent = val; - } else { - // Add title element - title = svgdoc.createElementNS(svgns, "title"); - title.textContent = val; - $(elem).prepend(title); - batchCmd.addSubCommand(new InsertElementCommand(title)); - } - - addCommandToHistory(batchCmd); -} - -// Function: getDocumentTitle -// Returns the current document title or an empty string if not found -this.getDocumentTitle = function() { - return canvas.getTitle(svgcontent); -} - -// Function: setDocumentTitle -// Adds/updates a title element for the document with the given name. -// This is an undoable action -// -// Parameters: -// newtitle - String with the new title -this.setDocumentTitle = function(newtitle) { - var childs = svgcontent.childNodes, doc_title = false, old_title = ''; - - var batchCmd = new BatchCommand("Change Image Title"); - - for (var i=0; i<childs.length; i++) { - if(childs[i].nodeName == 'title') { - doc_title = childs[i]; - old_title = doc_title.textContent; - break; - } - } - if(!doc_title) { - doc_title = svgdoc.createElementNS(svgns, "title"); - svgcontent.insertBefore(doc_title, svgcontent.firstChild); - } - - if(newtitle.length) { - doc_title.textContent = newtitle; - } else { - // No title given, so element is not necessary - doc_title.parentNode.removeChild(doc_title); - } - batchCmd.addSubCommand(new ChangeElementCommand(doc_title, {'#text': old_title})); - addCommandToHistory(batchCmd); -} - -// Function: getEditorNS -// Returns the editor's namespace URL, optionally adds it to root element -// -// Parameters: -// add - Boolean to indicate whether or not to add the namespace value -this.getEditorNS = function(add) { - if(add) { - svgcontent.setAttribute('xmlns:se', se_ns); - } - return se_ns; -} - -// Function: setResolution -// Changes the document's dimensions to the given size -// -// Parameters: -// x - Number with the width of the new dimensions in user units. -// Can also be the string "fit" to indicate "fit to content" -// y - Number with the height of the new dimensions in user units. -// -// Returns: -// Boolean to indicate if resolution change was succesful. -// It will fail on "fit to content" option with no content to fit to. -this.setResolution = function(x, y) { - var res = getResolution(); - var w = res.w, h = res.h; - var batchCmd; - - if(x == 'fit') { - // Get bounding box - var bbox = getStrokedBBox(); - - if(bbox) { - batchCmd = new BatchCommand("Fit Canvas to Content"); - var visEls = getVisibleElements(); - addToSelection(visEls); - var dx = [], dy = []; - $.each(visEls, function(i, item) { - dx.push(bbox.x*-1); - dy.push(bbox.y*-1); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - clearSelection(); - - x = Math.round(bbox.width); - y = Math.round(bbox.height); - } else { - return false; - } - } - if (x != w || y != h) { - var handle = svgroot.suspendRedraw(1000); - if(!batchCmd) { - batchCmd = new BatchCommand("Change Image Dimensions"); - } - - x = convertToNum('width', x); - y = convertToNum('height', y); - - svgcontent.setAttribute('width', x); - svgcontent.setAttribute('height', y); - - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"width":w, "height":h})); - - svgcontent.setAttribute("viewBox", [0, 0, x/current_zoom, y/current_zoom].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand(svgcontent, {"viewBox": ["0 0", w, h].join(' ')})); - - addCommandToHistory(batchCmd); - svgroot.unsuspendRedraw(handle); - call("changed", [svgcontent]); - } - return true; -}; - -// Function: getOffset -// Returns an object with x, y values indicating the svgcontent element's -// position in the editor's canvas. -this.getOffset = function() { - return $(svgcontent).attr(['x', 'y']); -} - -// Function: setBBoxZoom -// Sets the zoom level on the canvas-side based on the given value -// -// Parameters: -// val - Bounding box object to zoom to or string indicating zoom option -// editor_w - Integer with the editor's workarea box's width -// editor_h - Integer with the editor's workarea box's height -this.setBBoxZoom = function(val, editor_w, editor_h) { - var spacer = .85; - var bb; - var calcZoom = function(bb) { - if(!bb) return false; - var w_zoom = Math.round((editor_w / bb.width)*100 * spacer)/100; - var h_zoom = Math.round((editor_h / bb.height)*100 * spacer)/100; - var zoomlevel = Math.min(w_zoom,h_zoom); - canvas.setZoom(zoomlevel); - return {'zoom': zoomlevel, 'bbox': bb}; - } - - if(typeof val == 'object') { - bb = val; - if(bb.width == 0 || bb.height == 0) { - var newzoom = bb.zoom?bb.zoom:current_zoom * bb.factor; - canvas.setZoom(newzoom); - return {'zoom': current_zoom, 'bbox': bb}; - } - return calcZoom(bb); - } - - switch (val) { - case 'selection': - if(!selectedElements[0]) return; - var sel_elems = $.map(selectedElements, function(n){ if(n) return n; }); - bb = getStrokedBBox(sel_elems); - break; - case 'canvas': - var res = getResolution(); - spacer = .95; - bb = {width:res.w, height:res.h ,x:0, y:0}; - break; - case 'content': - bb = getStrokedBBox(); - break; - case 'layer': - bb = getStrokedBBox(getVisibleElements(getCurrentDrawing().getCurrentLayer())); - break; - default: - return; - } - return calcZoom(bb); -} - -// Function: setZoom -// Sets the zoom to the given level -// -// Parameters: -// zoomlevel - Float indicating the zoom level to change to -this.setZoom = function(zoomlevel) { - var res = getResolution(); - svgcontent.setAttribute("viewBox", "0 0 " + res.w/zoomlevel + " " + res.h/zoomlevel); - current_zoom = zoomlevel; - $.each(selectedElements, function(i, elem) { - if(!elem) return; - selectorManager.requestSelector(elem).resize(); - }); - pathActions.zoomChange(); - runExtensions("zoomChanged", zoomlevel); -} - -// Function: getMode -// Returns the current editor mode string -this.getMode = function() { - return current_mode; -}; - -// Function: setMode -// Sets the editor's mode to the given string -// -// Parameters: -// name - String with the new mode to change to -this.setMode = function(name) { - pathActions.clear(true); - textActions.clear(); - $("#workarea").attr("class", name); - cur_properties = (selectedElements[0] && selectedElements[0].nodeName == 'text') ? cur_text : cur_shape; - current_mode = name; -}; - -// Group: Element Styling - -// Function: getColor -// Returns the current fill/stroke option -this.getColor = function(type) { - return cur_properties[type]; -}; - -// Function: setColor -// Change the current stroke/fill color/gradient value -// -// Parameters: -// type - String indicating fill or stroke -// val - The value to set the stroke attribute to -// preventUndo - Boolean indicating whether or not this should be and undoable option -this.setColor = function(type, val, preventUndo) { - cur_shape[type] = val; - cur_properties[type + '_paint'] = {type:"solidColor"}; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else { - if(type == 'fill') { - if(elem.tagName != "polyline" && elem.tagName != "line") { - elems.push(elem); - } - } else { - elems.push(elem); - } - } - } - } - if (elems.length > 0) { - if (!preventUndo) { - changeSelectedAttribute(type, val, elems); - call("changed", elems); - } else - changeSelectedAttributeNoUndo(type, val, elems); - } -} - - -// Function: findDefs -// Return the document's <defs> element, create it first if necessary -var findDefs = function() { - var defs = svgcontent.getElementsByTagNameNS(svgns, "defs"); - if (defs.length > 0) { - defs = defs[0]; - } - else { - defs = svgdoc.createElementNS(svgns, "defs" ); - if(svgcontent.firstChild) { - // first child is a comment, so call nextSibling - svgcontent.insertBefore( defs, svgcontent.firstChild.nextSibling); - } else { - svgcontent.appendChild(defs); - } - } - return defs; -}; - -// Function: setGradient -// Apply the current gradient to selected element's fill or stroke -// -// Parameters -// type - String indicating "fill" or "stroke" to apply to an element -var setGradient = this.setGradient = function(type) { - if(!cur_properties[type + '_paint'] || cur_properties[type + '_paint'].type == "solidColor") return; - var grad = canvas[type + 'Grad']; - // find out if there is a duplicate gradient already in the defs - var duplicate_grad = findDuplicateGradient(grad); - var defs = findDefs(); - // no duplicate found, so import gradient into defs - if (!duplicate_grad) { - var orig_grad = grad; - grad = defs.appendChild( svgdoc.importNode(grad, true) ); - // get next id and set it on the grad - grad.id = getNextId(); - } - else { // use existing gradient - grad = duplicate_grad; - } - canvas.setColor(type, "url(#" + grad.id + ")"); -} - -// Function: findDuplicateGradient -// Check if exact gradient already exists -// -// Parameters: -// grad - The gradient DOM element to compare to others -// -// Returns: -// The existing gradient if found, null if not -var findDuplicateGradient = function(grad) { - var defs = findDefs(); - var existing_grads = $(defs).find("linearGradient, radialGradient"); - var i = existing_grads.length; - var rad_attrs = ['r','cx','cy','fx','fy']; - while (i--) { - var og = existing_grads[i]; - if(grad.tagName == "linearGradient") { - if (grad.getAttribute('x1') != og.getAttribute('x1') || - grad.getAttribute('y1') != og.getAttribute('y1') || - grad.getAttribute('x2') != og.getAttribute('x2') || - grad.getAttribute('y2') != og.getAttribute('y2')) - { - continue; - } - } else { - var grad_attrs = $(grad).attr(rad_attrs); - var og_attrs = $(og).attr(rad_attrs); - - var diff = false; - $.each(rad_attrs, function(i, attr) { - if(grad_attrs[attr] != og_attrs[attr]) diff = true; - }); - - if(diff) continue; - } - - // else could be a duplicate, iterate through stops - var stops = grad.getElementsByTagNameNS(svgns, "stop"); - var ostops = og.getElementsByTagNameNS(svgns, "stop"); - - if (stops.length != ostops.length) { - continue; - } - - var j = stops.length; - while(j--) { - var stop = stops[j]; - var ostop = ostops[j]; - - if (stop.getAttribute('offset') != ostop.getAttribute('offset') || - stop.getAttribute('stop-opacity') != ostop.getAttribute('stop-opacity') || - stop.getAttribute('stop-color') != ostop.getAttribute('stop-color')) - { - break; - } - } - - if (j == -1) { - return og; - } - } // for each gradient in defs - - return null; -}; - -function reorientGrads(elem, m) { - var bb = svgedit.utilities.getBBox(elem); - for(var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = elem.getAttribute(type); - if(attrVal && attrVal.indexOf('url(') === 0) { - var grad = getRefElem(attrVal); - if(grad.tagName === 'linearGradient') { - var x1 = grad.getAttribute('x1') || 0; - var y1 = grad.getAttribute('y1') || 0; - var x2 = grad.getAttribute('x2') || 1; - var y2 = grad.getAttribute('y2') || 0; - - // Convert to USOU points - x1 = (bb.width * x1) + bb.x; - y1 = (bb.height * y1) + bb.y; - x2 = (bb.width * x2) + bb.x; - y2 = (bb.height * y2) + bb.y; - - // Transform those points - var pt1 = transformPoint(x1, y1, m); - var pt2 = transformPoint(x2, y2, m); - - // Convert back to BB points - var g_coords = {}; - - g_coords.x1 = (pt1.x - bb.x) / bb.width; - g_coords.y1 = (pt1.y - bb.y) / bb.height; - g_coords.x2 = (pt2.x - bb.x) / bb.width; - g_coords.y2 = (pt2.y - bb.y) / bb.height; - - var newgrad = grad.cloneNode(true); - $(newgrad).attr(g_coords); - - newgrad.id = getNextId(); - findDefs().appendChild(newgrad); - elem.setAttribute(type, 'url(#' + newgrad.id + ')'); - } - } - } -} - -// Function: setPaint -// Set a color/gradient to a fill/stroke -// -// Parameters: -// type - String with "fill" or "stroke" -// paint - The jGraduate paint object to apply -this.setPaint = function(type, paint) { - // make a copy - var p = new $.jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha/100, true); - - // now set the current paint object - cur_properties[type + '_paint'] = p; - switch ( p.type ) { - case "solidColor": - - if (p.solidColor != "none") { - this.setColor(type, "#"+p.solidColor) - } - else { - this.setColor(type, "none"); - var selector = (type == "fill") ? "#fill_color rect" : "#stroke_color rect" - document.querySelector(selector).setAttribute('fill', 'transparent'); - } - break; - case "linearGradient": - case "radialGradient": - canvas[type + 'Grad'] = p[p.type]; - setGradient(type); - break; - default: -// console.log("none!"); - } -}; - - -// this.setStrokePaint = function(p) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setStrokeOpacity(p.alpha/100); -// -// // now set the current paint object -// cur_properties.stroke_paint = p; -// switch ( p.type ) { -// case "solidColor": -// this.setColor('stroke', p.solidColor != "none" ? "#"+p.solidColor : "none");; -// break; -// case "linearGradient" -// case "radialGradient" -// canvas.strokeGrad = p[p.type]; -// setGradient(type); -// default: -// // console.log("none!"); -// } -// }; -// -// this.setFillPaint = function(p, addGrad) { -// // make a copy -// var p = new $.jGraduate.Paint(p); -// this.setFillOpacity(p.alpha/100, true); -// -// // now set the current paint object -// cur_properties.fill_paint = p; -// if (p.type == "solidColor") { -// this.setColor('fill', p.solidColor != "none" ? "#"+p.solidColor : "none"); -// } -// else if(p.type == "linearGradient") { -// canvas.fillGrad = p.linearGradient; -// if(addGrad) setGradient(); -// } -// else if(p.type == "radialGradient") { -// canvas.fillGrad = p.radialGradient; -// if(addGrad) setGradient(); -// } -// else { -// // console.log("none!"); -// } -// }; - -// Function: getStrokeWidth -// Returns the current stroke-width value -this.getStrokeWidth = function() { - return cur_properties.stroke_width; -}; - -// Function: setStrokeWidth -// Sets the stroke width for the current selected elements -// When attempting to set a line's width to 0, this changes it to 1 instead -// -// Parameters: -// val - A Float indicating the new stroke width value -this.setStrokeWidth = function(val) { - if(val == 0 && ['line', 'path'].indexOf(current_mode) >= 0) { - canvas.setStrokeWidth(1); - return; - } - cur_properties.stroke_width = val; - - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute("stroke-width", val, elems); - call("changed", selectedElements); - } -}; - -// Function: setStrokeAttr -// Set the given stroke-related attribute the given value for selected elements -// -// Parameters: -// attr - String with the attribute name -// val - String or number with the attribute value -this.setStrokeAttr = function(attr, val) { - cur_shape[attr.replace('-','_')] = val; - var elems = []; - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName == "g") - svgedit.utilities.walkTree(elem, function(e){if(e.nodeName!="g") elems.push(e);}); - else - elems.push(elem); - } - } - if (elems.length > 0) { - changeSelectedAttribute(attr, val, elems); - call("changed", selectedElements); - } -}; - -// Function: getStyle -// Returns current style options -this.getStyle = function() { - return cur_shape; -} - -// Function: getOpacity -// Returns the current opacity -this.getOpacity = function() { - return cur_shape.opacity; -}; - -// Function: setOpacity -// Sets the given opacity to the current selected elements -this.setOpacity = function(val) { - cur_shape.opacity = val; - changeSelectedAttribute("opacity", val); -}; - -// Function: getOpacity -// Returns the current fill opacity -this.getFillOpacity = function() { - return cur_shape.fill_opacity; -}; - -// Function: getStrokeOpacity -// Returns the current stroke opacity -this.getStrokeOpacity = function() { - return cur_shape.stroke_opacity; -}; - -// Function: setPaintOpacity -// Sets the current fill/stroke opacity -// -// Parameters: -// type - String with "fill" or "stroke" -// val - Float with the new opacity value -// preventUndo - Boolean indicating whether or not this should be an undoable action -this.setPaintOpacity = function(type, val, preventUndo) { - cur_shape[type + '_opacity'] = val; - if (!preventUndo) - changeSelectedAttribute(type + "-opacity", val); - else - changeSelectedAttributeNoUndo(type + "-opacity", val); -}; - -// Function: getBlur -// Gets the stdDeviation blur value of the given element -// -// Parameters: -// elem - The element to check the blur value for -this.getBlur = function(elem) { - var val = 0; -// var elem = selectedElements[0]; - - if(elem) { - var filter_url = elem.getAttribute('filter'); - if(filter_url) { - var blur = getElem(elem.id + '_blur'); - if(blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } - } - } - return val; -}; - -(function() { - var cur_command = null; - var filter = null; - var filterHidden = false; - - // Function: setBlurNoUndo - // Sets the stdDeviation blur value on the selected element without being undoable - // - // Parameters: - // val - The new stdDeviation value - canvas.setBlurNoUndo = function(val) { - if(!filter) { - canvas.setBlur(val); - return; - } - if(val === 0) { - // Don't change the StdDev, as that will hide the element. - // Instead, just remove the value for "filter" - changeSelectedAttributeNoUndo("filter", ""); - filterHidden = true; - } else { - var elem = selectedElements[0]; - if(filterHidden) { - changeSelectedAttributeNoUndo("filter", 'url(#' + elem.id + '_blur)'); - } - if(svgedit.browser.isWebkit()) { - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); - } - changeSelectedAttributeNoUndo("stdDeviation", val, [filter.firstChild]); - canvas.setBlurOffsets(filter, val); - } - } - - function finishChange() { - var bCmd = canvas.undoMgr.finishUndoableChange(); - cur_command.addSubCommand(bCmd); - addCommandToHistory(cur_command); - cur_command = null; - filter = null; - } - - // Function: setBlurOffsets - // Sets the x, y, with, height values of the filter element in order to - // make the blur not be clipped. Removes them if not neeeded - // - // Parameters: - // filter - The filter DOM element to update - // stdDev - The standard deviation value on which to base the offset size - canvas.setBlurOffsets = function(filter, stdDev) { - if(stdDev > 3) { - // TODO: Create algorithm here where size is based on expected blur - assignAttributes(filter, { - x: '-50%', - y: '-50%', - width: '200%', - height: '200%' - }, 100); - } else { - // Removing these attributes hides text in Chrome (see Issue 579) - if(!svgedit.browser.isWebkit()) { - filter.removeAttribute('x'); - filter.removeAttribute('y'); - filter.removeAttribute('width'); - filter.removeAttribute('height'); - } - } - } - - // Function: setBlur - // Adds/updates the blur filter to the selected element - // - // Parameters: - // val - Float with the new stdDeviation blur value - // complete - Boolean indicating whether or not the action should be completed (to add to the undo manager) - canvas.setBlur = function(val, complete) { - if(cur_command) { - finishChange(); - return; - } - - // Looks for associated blur, creates one if not found - var elem = selectedElements[0]; - var elem_id = elem.id; - filter = getElem(elem_id + '_blur'); - - val -= 0; - - var batchCmd = new BatchCommand(); - - // Blur found! - if(filter) { - if(val === 0) { - filter = null; - } - } else { - // Not found, so create - var newblur = addSvgElementFromJson({ "element": "feGaussianBlur", - "attr": { - "in": 'SourceGraphic', - "stdDeviation": val - } - }); - - filter = addSvgElementFromJson({ "element": "filter", - "attr": { - "id": elem_id + '_blur' - } - }); - - filter.appendChild(newblur); - findDefs().appendChild(filter); - - batchCmd.addSubCommand(new InsertElementCommand(filter)); - } - - var changes = {filter: elem.getAttribute('filter')}; - - if(val === 0) { - elem.removeAttribute("filter"); - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - return; - } else { - changeSelectedAttribute("filter", 'url(#' + elem_id + '_blur)'); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - - canvas.setBlurOffsets(filter, val); - } - - cur_command = batchCmd; - canvas.undoMgr.beginUndoableChange("stdDeviation", [filter?filter.firstChild:null]); - if(complete) { - canvas.setBlurNoUndo(val); - finishChange(); - } - }; -}()); - -// Function: getBold -// Check whether selected element is bold or not -// -// Returns: -// Boolean indicating whether or not element is bold -this.getBold = function() { - // should only have one element selected - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-weight") == "bold"); - } - return false; -}; - -// Function: setBold -// Make the selected element bold or normal -// -// Parameters: -// b - Boolean indicating bold (true) or normal (false) -this.setBold = function(b) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-weight", b ? "bold" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getItalic -// Check whether selected element is italic or not -// -// Returns: -// Boolean indicating whether or not element is italic -this.getItalic = function() { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - return (selected.getAttribute("font-style") == "italic"); - } - return false; -}; - -// Function: setItalic -// Make the selected element italic or normal -// -// Parameters: -// b - Boolean indicating italic (true) or normal (false) -this.setItalic = function(i) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "text" && - selectedElements[1] == null) - { - changeSelectedAttribute("font-style", i ? "italic" : "normal"); - } - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getFontFamily -// Returns the current font family -this.getFontFamily = function() { - return cur_text.font_family; -}; - -// Function: setFontFamily -// Set the new font family -// -// Parameters: -// val - String with the new font family -this.setFontFamily = function(val) { - cur_text.font_family = val; - changeSelectedAttribute("font-family", val); - if(selectedElements[0] && !selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - - -// Function: setFontColor -// Set the new font color -// -// Parameters: -// val - String with the new font color -this.setFontColor = function(val) { - cur_text.fill = val; - changeSelectedAttribute("fill", val); -}; - -// Function: getFontColor -// Returns the current font color -this.getFontSize = function() { - return cur_text.fill; -}; - -// Function: getFontSize -// Returns the current font size -this.getFontSize = function() { - return cur_text.font_size; -}; - -// Function: setFontSize -// Applies the given font size to the selected element -// -// Parameters: -// val - Float with the new font size -this.setFontSize = function(val) { - cur_text.font_size = val; - changeSelectedAttribute("font-size", val); - if(!selectedElements[0].textContent) { - textActions.setCursor(); - } -}; - -// Function: getText -// Returns the current text (textContent) of the selected element -this.getText = function() { - var selected = selectedElements[0]; - if (selected == null) { return ""; } - return selected.textContent; -}; - -// Function: setTextContent -// Updates the text element with the given string -// -// Parameters: -// val - String with the new text -this.setTextContent = function(val) { - changeSelectedAttribute("#text", val); - textActions.init(val); - textActions.setCursor(); -}; - -// Function: setImageURL -// Sets the new image URL for the selected image element. Updates its size if -// a new URL is given -// -// Parameters: -// val - String with the image URL/path -this.setImageURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - - var attrs = $(elem).attr(['width', 'height']); - var setsize = (!attrs.width || !attrs.height); - - var cur_href = getHref(elem); - - // Do nothing if no URL change or size change - if(cur_href !== val) { - setsize = true; - } else if(!setsize) return; - - var batchCmd = new BatchCommand("Change Image URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - if(setsize) { - $(new Image()).load(function() { - var changes = $(elem).attr(['width', 'height']); - - $(elem).attr({ - width: this.width, - height: this.height - }); - - selectorManager.requestSelector(elem).resize(); - - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - addCommandToHistory(batchCmd); - call("changed", [elem]); - }).attr('src',val); - } else { - addCommandToHistory(batchCmd); - } -}; - -// Function: setLinkURL -// Sets the new link URL for the selected anchor element. -// -// Parameters: -// val - String with the link URL/path -this.setLinkURL = function(val) { - var elem = selectedElements[0]; - if(!elem) return; - if(elem.tagName !== 'a') { - // See if parent is an anchor - var parents_a = $(elem).parents('a'); - if(parents_a.length) { - elem = parents_a[0]; - } else { - return; - } - } - - var cur_href = getHref(elem); - - if(cur_href === val) return; - - var batchCmd = new BatchCommand("Change Link URL"); - - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand(elem, { - "#href": cur_href - })); - - addCommandToHistory(batchCmd); -}; - - -// Function: setRectRadius -// Sets the rx & ry values to the selected rect element to change its corner radius -// -// Parameters: -// val - The new radius -this.setRectRadius = function(val) { - var selected = selectedElements[0]; - if (selected != null && selected.tagName == "rect") { - var r = selected.getAttribute("rx"); - if (r != val) { - selected.setAttribute("rx", val); - selected.setAttribute("ry", val); - addCommandToHistory(new ChangeElementCommand(selected, {"rx":r, "ry":r}, "Radius")); - call("changed", [selected]); - } - } -}; - -// Function: makeHyperlink -// Wraps the selected element(s) in an anchor element or converts group to one -this.makeHyperlink = function(url) { - canvas.groupSelectedElements('a', url); - - // TODO: If element is a single "g", convert to "a" - // if(selectedElements.length > 1 && selectedElements[1]) { - -} - -// Function: removeHyperlink -this.removeHyperlink = function() { - canvas.ungroupSelectedElement(); -} - -// Group: Element manipulation - -// Function: setSegType -// Sets the new segment type to the selected segment(s). -// -// Parameters: -// new_type - Integer with the new segment type -// See http://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg for list -this.setSegType = function(new_type) { - pathActions.setSegType(new_type); -} - -// TODO(codedread): Remove the getBBox argument and split this function into two. -// Function: convertToPath -// Convert selected element to a path, or get the BBox of an element-as-path -// -// Parameters: -// elem - The DOM element to be converted -// getBBox - Boolean on whether or not to only return the path's BBox -// -// Returns: -// If the getBBox flag is true, the resulting path's bounding box object. -// Otherwise the resulting path element is returned. -this.convertToPath = function(elem, getBBox) { - if(elem == null) { - var elems = selectedElements; - $.each(selectedElements, function(i, elem) { - if(elem) canvas.convertToPath(elem); - }); - return; - } - - if(!getBBox) { - var batchCmd = new BatchCommand("Convert element to Path"); - } - - var attrs = getBBox?{}:{ - "fill": cur_shape.fill, - "fill-opacity": cur_shape.fill_opacity, - "stroke": cur_shape.stroke, - "stroke-width": cur_shape.stroke_width, - "stroke-dasharray": cur_shape.stroke_dasharray, - "stroke-linejoin": cur_shape.stroke_linejoin, - "stroke-linecap": cur_shape.stroke_linecap, - "stroke-opacity": cur_shape.stroke_opacity, - "opacity": cur_shape.opacity, - "visibility":"hidden" - }; - - // any attribute on the element not covered by the above - // TODO: make this list global so that we can properly maintain it - // TODO: what about @transform, @clip-rule, @fill-rule, etc? - $.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function() { - if (elem.getAttribute(this)) { - attrs[this] = elem.getAttribute(this); - } - }); - - var path = addSvgElementFromJson({ - "element": "path", - "attr": attrs - }); - - var eltrans = elem.getAttribute("transform"); - if(eltrans) { - path.setAttribute("transform",eltrans); - } - - var id = elem.id; - var parent = elem.parentNode; - if(elem.nextSibling) { - parent.insertBefore(path, elem); - } else { - parent.appendChild(path); - } - - var d = ''; - - var joinSegs = function(segs) { - $.each(segs, function(j, seg) { - var l = seg[0], pts = seg[1]; - d += l; - for(var i=0; i < pts.length; i+=2) { - d += (pts[i] +','+pts[i+1]) + ' '; - } - }); - } - - // Possibly the cubed root of 6, but 1.81 works best - var num = 1.81; - - switch (elem.tagName) { - case 'ellipse': - case 'circle': - var a = $(elem).attr(['rx', 'ry', 'cx', 'cy']); - var cx = a.cx, cy = a.cy, rx = a.rx, ry = a.ry; - if(elem.tagName == 'circle') { - rx = ry = $(elem).attr('r'); - } - - joinSegs([ - ['M',[(cx-rx),(cy)]], - ['C',[(cx-rx),(cy-ry/num), (cx-rx/num),(cy-ry), (cx),(cy-ry)]], - ['C',[(cx+rx/num),(cy-ry), (cx+rx),(cy-ry/num), (cx+rx),(cy)]], - ['C',[(cx+rx),(cy+ry/num), (cx+rx/num),(cy+ry), (cx),(cy+ry)]], - ['C',[(cx-rx/num),(cy+ry), (cx-rx),(cy+ry/num), (cx-rx),(cy)]], - ['Z',[]] - ]); - break; - case 'path': - d = elem.getAttribute('d'); - break; - case 'line': - var a = $(elem).attr(["x1", "y1", "x2", "y2"]); - d = "M"+a.x1+","+a.y1+"L"+a.x2+","+a.y2; - break; - case 'polyline': - case 'polygon': - d = "M" + elem.getAttribute('points'); - break; - case 'rect': - var r = $(elem).attr(['rx', 'ry']); - var rx = r.rx, ry = r.ry; - var b = elem.getBBox(); - var x = b.x, y = b.y, w = b.width, h = b.height; - var num = 4-num; // Why? Because! - - if(!rx && !ry) { - // Regular rect - joinSegs([ - ['M',[x, y]], - ['L',[x+w, y]], - ['L',[x+w, y+h]], - ['L',[x, y+h]], - ['L',[x, y]], - ['Z',[]] - ]); - } else { - joinSegs([ - ['M',[x, y+ry]], - ['C',[x,y+ry/num, x+rx/num,y, x+rx,y]], - ['L',[x+w-rx, y]], - ['C',[x+w-rx/num,y, x+w,y+ry/num, x+w,y+ry]], - ['L',[x+w, y+h-ry]], - ['C',[x+w, y+h-ry/num, x+w-rx/num,y+h, x+w-rx,y+h]], - ['L',[x+rx, y+h]], - ['C',[x+rx/num, y+h, x,y+h-ry/num, x,y+h-ry]], - ['L',[x, y+ry]], - ['Z',[]] - ]); - } - break; - default: - path.parentNode.removeChild(path); - break; - } - - if(d) { - path.setAttribute('d',d); - } - - if(!getBBox) { - // Replace the current element with the converted one - - // Reorient if it has a matrix - if(eltrans) { - var tlist = getTransformList(path); - if(hasMatrixTransform(tlist)) { - pathActions.resetOrientation(path); - } - } - - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - batchCmd.addSubCommand(new InsertElementCommand(path)); - - clearSelection(); - elem.parentNode.removeChild(elem) - path.setAttribute('id', id); - path.removeAttribute("visibility"); - addToSelection([path], true); - - addCommandToHistory(batchCmd); - - } else { - // Get the correct BBox of the new path, then discard it - pathActions.resetOrientation(path); - var bb = false; - try { - bb = path.getBBox(); - } catch(e) { - // Firefox fails - } - path.parentNode.removeChild(path); - return bb; - } -}; - - -// Function: changeSelectedAttributeNoUndo -// This function makes the changes to the elements. It does not add the change -// to the history stack. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttributeNoUndo = function(attr, newValue, elems) { - var handle = svgroot.suspendRedraw(1000); - if(current_mode == 'pathedit') { - // Editing node - pathActions.moveNode(attr, newValue); - } - var elems = elems || selectedElements; - var i = elems.length; - var no_xy_elems = ['g', 'polyline', 'path']; - var good_g_attrs = ['transform', 'opacity', 'filter']; - - while (i--) { - var elem = elems[i]; - if (elem == null) continue; - - // Go into "select" mode for text changes - if(current_mode === "textedit" && attr !== "#text" && elem.textContent.length) { - textActions.toSelectMode(elem); - } - - // Set x,y vals on elements that don't have them - if((attr === 'x' || attr === 'y') && no_xy_elems.indexOf(elem.tagName) >= 0) { - var bbox = getStrokedBBox([elem]); - var diff_x = attr === 'x' ? newValue - bbox.x : 0; - var diff_y = attr === 'y' ? newValue - bbox.y : 0; - canvas.moveSelectedElements(diff_x*current_zoom, diff_y*current_zoom, true); - continue; - } - - // only allow the transform/opacity/filter attribute to change on <g> elements, slightly hacky - // if (elem.tagName === "g" && good_g_attrs.indexOf(attr) >= 0); - var oldval = attr === "#text" ? elem.textContent : elem.getAttribute(attr); - if (oldval == null) oldval = ""; - if (oldval !== String(newValue)) { - if (attr == "#text") { - var old_w = svgedit.utilities.getBBox(elem).width; - elem.textContent = newValue; - - // FF bug occurs on on rotated elements - if(/rotate/.test(elem.getAttribute('transform'))) { - elem = ffClone(elem); - } - - // Hoped to solve the issue of moving text with text-anchor="start", - // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd - -// var box=getBBox(elem), left=box.x, top=box.y, width=box.width, -// height=box.height, dx = width - old_w, dy=0; -// var angle = getRotationAngle(elem, true); -// if (angle) { -// var r = Math.sqrt( dx*dx + dy*dy ); -// var theta = Math.atan2(dy,dx) - angle; -// dx = r * Math.cos(theta); -// dy = r * Math.sin(theta); -// -// elem.setAttribute('x', elem.getAttribute('x')-dx); -// elem.setAttribute('y', elem.getAttribute('y')-dy); -// } - - } else if (attr == "#href") { - setHref(elem, newValue); - } - else elem.setAttribute(attr, newValue); -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(elem); - // Use the Firefox ffClone hack for text elements with gradients or - // where other text attributes are changed. - if(svgedit.browser.isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) { - if((newValue+'').indexOf('url') === 0 || ['font-size','font-family','x','y'].indexOf(attr) >= 0 && elem.textContent) { - elem = ffClone(elem); - } - } - // Timeout needed for Opera & Firefox - // codedread: it is now possible for this function to be called with elements - // that are not in the selectedElements array, we need to only request a - // selector if the element is in that array - if (selectedElements.indexOf(elem) >= 0) { - setTimeout(function() { - // Due to element replacement, this element may no longer - // be part of the DOM - if(!elem.parentNode) return; - selectorManager.requestSelector(elem).resize(); - },0); - } - // if this element was rotated, and we changed the position of this element - // we need to update the rotational transform attribute - var angle = getRotationAngle(elem); - if (angle != 0 && attr != "transform") { - var tlist = getTransformList(elem); - var n = tlist.numberOfItems; - while (n--) { - var xform = tlist.getItem(n); - if (xform.type == 4) { - // remove old rotate - tlist.removeItem(n); - - var box = svgedit.utilities.getBBox(elem); - var center = transformPoint(box.x+box.width/2, box.y+box.height/2, transformListToTransform(tlist).matrix); - var cx = center.x, - cy = center.y; - var newrot = svgroot.createSVGTransform(); - newrot.setRotate(angle, cx, cy); - tlist.insertItemBefore(newrot, n); - break; - } - } - } - } // if oldValue != newValue - } // for each elem - svgroot.unsuspendRedraw(handle); -}; - -// Function: changeSelectedAttribute -// Change the given/selected element and add the original value to the history stack -// If you want to change all selectedElements, ignore the elems argument. -// If you want to change only a subset of selectedElements, then send the -// subset to this function in the elems argument. -// -// Parameters: -// attr - String with the attribute name -// newValue - String or number with the new attribute value -// elems - The DOM elements to apply the change to -var changeSelectedAttribute = this.changeSelectedAttribute = function(attr, val, elems) { - var elems = elems || selectedElements; - canvas.undoMgr.beginUndoableChange(attr, elems); - var i = elems.length; - - changeSelectedAttributeNoUndo(attr, val, elems); - - var batchCmd = canvas.undoMgr.finishUndoableChange(); - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } -}; - -// Function: deleteSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack -this.deleteSelectedElements = function() { - var batchCmd = new BatchCommand("Delete Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - // Get the parent if it's a single-child anchor - if(parent.tagName === 'a' && parent.childNodes.length === 1) { - t = parent; - parent = parent.parentNode; - } - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); -}; - -// Function: cutSelectedElements -// Removes all selected elements from the DOM and adds the change to the -// history stack. Remembers removed elements on the clipboard - -// TODO: Combine similar code with deleteSelectedElements -this.cutSelectedElements = function() { - var batchCmd = new BatchCommand("Cut Elements"); - var len = selectedElements.length; - var selectedCopy = []; //selectedElements is being deleted - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - if (selected == null) break; - - var parent = selected.parentNode; - var t = selected; - - // this will unselect the element and remove the selectedOutline - selectorManager.releaseSelector(t); - - // Remove the path if present. - svgedit.path.removePath_(t.id); - - var nextSibling = t.nextSibling; - var elem = parent.removeChild(t); - selectedCopy.push(selected); //for the copy - selectedElements[i] = null; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, parent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - call("changed", selectedCopy); - clearSelection(); - - canvas.clipBoard = selectedCopy; -}; - -// Function: copySelectedElements -// Remembers the current selected elements on the clipboard -this.copySelectedElements = function() { - canvas.clipBoard = $.merge([], selectedElements); -}; - -this.pasteElements = function(type, x, y) { - var cb = canvas.clipBoard; - var len = cb.length; - if(!len) return; - - var pasted = []; - var batchCmd = new BatchCommand('Paste elements'); - - // Move elements to lastClickPoint - - while (len--) { - var elem = cb[len]; - if(!elem) continue; - var copy = copyElem(elem); - - // See if elem with elem ID is in the DOM already - if(!getElem(elem.id)) copy.id = elem.id; - pasted.push(copy); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(copy); - batchCmd.addSubCommand(new InsertElementCommand(copy)); - } - - selectOnly(pasted); - if(type != 'in_place') { - if(lastClickPoint == null) { - lastClickPoint.x = 0; - lastClickPoint.y = 0; - } - var ctr_x, ctr_y; - if(!type) { - ctr_x = lastClickPoint.x; - ctr_y = lastClickPoint.y; - } else if(type === 'point') { - ctr_x = x; - ctr_y = y; - } - - var bbox = getStrokedBBox(pasted); - var cx = ctr_x - (bbox.x + bbox.width/2), - cy = ctr_y - (bbox.y + bbox.height/2), - dx = [], - dy = []; - - $.each(pasted, function(i, item) { - dx.push(cx); - dy.push(cy); - }); - - var cmd = canvas.moveSelectedElements(dx, dy, false); - batchCmd.addSubCommand(cmd); - } - - - - addCommandToHistory(batchCmd); - call("changed", pasted); -} - -// Function: groupSelectedElements -// Wraps all the selected elements in a group (g) element - -// Parameters: -// type - type of element to group into, defaults to <g> -this.groupSelectedElements = function(type) { - if(!type) type = 'g'; - var cmd_str = ''; - - switch ( type ) { - case "a": - cmd_str = "Make hyperlink"; - var url = ''; - if(arguments.length > 1) { - url = arguments[1]; - } - break; - default: - type = 'g'; - cmd_str = "Group Elements"; - break; - } - - var batchCmd = new BatchCommand(cmd_str); - - // create and insert the group element - var g = addSvgElementFromJson({ - "element": type, - "attr": { - "id": getNextId() - } - }); - if(type === 'a') { - setHref(g, url); - } - batchCmd.addSubCommand(new InsertElementCommand(g)); - - // now move all children into the group - var i = selectedElements.length; - while (i--) { - var elem = selectedElements[i]; - if (elem == null) continue; - - if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { - elem = elem.parentNode; - } - - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - g.appendChild(elem); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - selectOnly([g], true); -}; - - -// Function: pushGroupProperties -// Pushes all appropriate parent group properties down to its children, then -// removes them from the group -var pushGroupProperties = this.pushGroupProperties = function(g, undoable) { - - var children = g.childNodes; - var len = children.length; - var xform = g.getAttribute("transform"); - - var glist = getTransformList(g); - var m = transformListToTransform(glist).matrix; - - var batchCmd = new BatchCommand("Push group properties"); - - // TODO: get all fill/stroke properties from the group that we are about to destroy - // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", - // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", - // "stroke-width" - // and then for each child, if they do not have the attribute (or the value is 'inherit') - // then set the child's attribute - - var i = 0; - var gangle = getRotationAngle(g); - - var gattrs = $(g).attr(['filter', 'opacity']); - var gfilter, gblur; - - for(var i = 0; i < len; i++) { - var elem = children[i]; - - if(elem.nodeType !== 1) continue; - - if(gattrs.opacity !== null && gattrs.opacity !== 1) { - var c_opac = elem.getAttribute('opacity') || 1; - var new_opac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100)/100; - changeSelectedAttribute('opacity', new_opac, [elem]); - } - - if(gattrs.filter) { - var cblur = this.getBlur(elem); - var orig_cblur = cblur; - if(!gblur) gblur = this.getBlur(g); - if(cblur) { - // Is this formula correct? - cblur = (gblur-0) + (cblur-0); - } else if(cblur === 0) { - cblur = gblur; - } - - // If child has no current filter, get group's filter or clone it. - if(!orig_cblur) { - // Set group's filter to use first child's ID - if(!gfilter) { - gfilter = getRefElem(gattrs.filter); - } else { - // Clone the group's filter - gfilter = copyElem(gfilter); - findDefs().appendChild(gfilter); - } - } else { - gfilter = getRefElem(elem.getAttribute('filter')); - } - - // Change this in future for different filters - var suffix = (gfilter.firstChild.tagName === 'feGaussianBlur')?'blur':'filter'; - gfilter.id = elem.id + '_' + suffix; - changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); - - // Update blur value - if(cblur) { - changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); - canvas.setBlurOffsets(gfilter, cblur); - } - } - - var chtlist = getTransformList(elem); - - // Don't process gradient transforms - if(~elem.tagName.indexOf('Gradient')) chtlist = null; - - // Hopefully not a problem to add this. Necessary for elements like <desc/> - if(!chtlist) continue; - - // Apparently <defs> can get get a transformlist, but we don't want it to have one! - if(elem.tagName === 'defs') 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 - // out any translates) - if (gangle && glist.numberOfItems == 1) { - // [Rg] [Rc] [Mc] - // we want [Tr] [Rc2] [Mc] where: - // - [Rc2] is at the child's current center but has the - // sum of the group and child's rotation angles - // - [Tr] is the equivalent translation that this child - // undergoes if the group wasn't there - - // [Tr] = [Rg] [Rc] [Rc2_inv] - - // get group's rotation matrix (Rg) - var rgm = glist.getItem(0).matrix; - - // get child's rotation matrix (Rc) - var rcm = svgroot.createSVGMatrix(); - var cangle = getRotationAngle(elem); - if (cangle) { - rcm = chtlist.getItem(0).matrix; - } - - // get child's old center of rotation - var cbox = svgedit.utilities.getBBox(elem); - var ceqm = transformListToTransform(chtlist).matrix; - var coldc = transformPoint(cbox.x+cbox.width/2, cbox.y+cbox.height/2,ceqm); - - // sum group and child's angles - var sangle = gangle + cangle; - - // get child's rotation at the old center (Rc2_inv) - var r2 = svgroot.createSVGTransform(); - r2.setRotate(sangle, coldc.x, coldc.y); - - // calculate equivalent translate - var trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); - - // set up tlist - if (cangle) { - chtlist.removeItem(0); - } - - if (sangle) { - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(r2, 0); - } else { - chtlist.appendItem(r2); - } - } - - if (trm.e || trm.f) { - var tr = svgroot.createSVGTransform(); - tr.setTranslate(trm.e, trm.f); - if(chtlist.numberOfItems) { - chtlist.insertItemBefore(tr, 0); - } else { - chtlist.appendItem(tr); - } - } - } - else { // more complicated than just a rotate - - // transfer the group's transform down to each child and then - // call recalculateDimensions() - var oldxform = elem.getAttribute("transform"); - var changes = {}; - changes["transform"] = oldxform ? oldxform : ""; - - var newxform = svgroot.createSVGTransform(); - - // [ gm ] [ chm ] = [ chm ] [ gm' ] - // [ gm' ] = [ chm_inv ] [ gm ] [ chm ] - var chm = transformListToTransform(chtlist).matrix, - chm_inv = chm.inverse(); - var gm = matrixMultiply( chm_inv, m, chm ); - newxform.setMatrix(gm); - chtlist.appendItem(newxform); - } - var cmd = recalculateDimensions(elem); - if(cmd) batchCmd.addSubCommand(cmd); - } - } - - - // remove transform and make it undo-able - if (xform) { - var changes = {}; - changes["transform"] = xform; - g.setAttribute("transform", ""); - g.removeAttribute("transform"); - batchCmd.addSubCommand(new ChangeElementCommand(g, changes)); - } - - if (undoable && !batchCmd.isEmpty()) { - return batchCmd; - } -} - - -// Function: ungroupSelectedElement -// Unwraps all the elements in a selected group (g) element. This requires -// significant recalculations to apply group's transforms, etc to its children -this.ungroupSelectedElement = function() { - var g = selectedElements[0]; - if($(g).data('gsvg') || $(g).data('symbol')) { - // Is svg, so actually convert to group - - convertToGroup(g); - return; - } else if(g.tagName === 'use') { - // Somehow doesn't have data set, so retrieve - var symbol = getElem(getHref(g).substr(1)); - $(g).data('symbol', symbol).data('ref', symbol); - convertToGroup(g); - return; - } - var parents_a = $(g).parents('a'); - if(parents_a.length) { - g = parents_a[0]; - } - - // Look for parent "a" - if (g.tagName === "g" || g.tagName === "a") { - - var batchCmd = new BatchCommand("Ungroup Elements"); - var cmd = pushGroupProperties(g, true); - if(cmd) batchCmd.addSubCommand(cmd); - - var parent = g.parentNode; - var anchor = g.nextSibling; - var children = new Array(g.childNodes.length); - - var i = 0; - - while (g.firstChild) { - var elem = g.firstChild; - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - - // Remove child title elements - if(elem.tagName === 'title') { - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand(elem, nextSibling, oldParent)); - oldParent.removeChild(elem); - continue; - } - - children[i++] = elem = parent.insertBefore(elem, anchor); - batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldParent)); - } - - // remove the group from the selection - clearSelection(); - - // delete the group element (but make undo-able) - var gNextSibling = g.nextSibling; - g = parent.removeChild(g); - batchCmd.addSubCommand(new RemoveElementCommand(g, gNextSibling, parent)); - - if (!batchCmd.isEmpty()) addCommandToHistory(batchCmd); - - // update selection - addToSelection(children); - } -}; - -// Function: moveToTopSelectedElement -// Repositions the selected element to the bottom in the DOM to appear on top of -// other elements -this.moveToTopSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - t = t.parentNode.appendChild(t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "top")); - call("changed", [t]); - } - } -}; - -// Function: moveToBottomSelectedElement -// Repositions the selected element to the top in the DOM to appear under -// other elements -this.moveToBottomSelectedElement = function() { - var selected = selectedElements[0]; - if (selected != null) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - var firstChild = t.parentNode.firstChild; - if (firstChild.tagName == 'title') { - firstChild = firstChild.nextSibling; - } - // This can probably be removed, as the defs should not ever apppear - // inside a layer group - if (firstChild.tagName == 'defs') { - firstChild = firstChild.nextSibling; - } - t = t.parentNode.insertBefore(t, firstChild); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "bottom")); - call("changed", [t]); - } - } -}; - -// Function: moveUpDownSelected -// Moves the select element up or down the stack, based on the visibly -// intersecting elements -// -// Parameters: -// dir - String that's either 'Up' or 'Down' -this.moveUpDownSelected = function(dir) { - var selected = selectedElements[0]; - if (!selected) return; - - curBBoxes = []; - var closest, found_cur; - // jQuery sorts this list - var list = $(getIntersectionList(getStrokedBBox([selected]))).toArray(); - if(dir == 'Down') list.reverse(); - - $.each(list, function() { - if(!found_cur) { - if(this == selected) { - found_cur = true; - } - return; - } - closest = this; - return false; - }); - if(!closest) return; - - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - $(closest)[dir == 'Down'?'before':'after'](t); - // If the element actually moved position, add the command and fire the changed - // event handler. - if (oldNextSibling != t.nextSibling) { - addCommandToHistory(new MoveElementCommand(t, oldNextSibling, oldParent, "Move " + dir)); - call("changed", [t]); - } -}; - -// Function: moveSelectedElements -// Moves selected elements on the X/Y axis -// -// Parameters: -// dx - Float with the distance to move on the x-axis -// dy - Float with the distance to move on the y-axis -// undoable - Boolean indicating whether or not the action should be undoable -// -// Returns: -// Batch command for the move -this.moveSelectedElements = function(dx, dy, undoable) { - // if undoable is not sent, default to true - // if single values, scale them to the zoom - if (dx.constructor != Array) { - dx /= current_zoom; - dy /= current_zoom; - } - var undoable = undoable || true; - var batchCmd = new BatchCommand("position"); - var i = selectedElements.length; - while (i--) { - var selected = selectedElements[i]; - if (selected != null) { -// if (i==0) -// selectedBBoxes[0] = svgedit.utilities.getBBox(selected); - -// var b = {}; -// for(var j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; -// selectedBBoxes[i] = b; - - var xform = svgroot.createSVGTransform(); - var tlist = getTransformList(selected); - - // dx and dy could be arrays - if (dx.constructor == Array) { -// if (i==0) { -// selectedBBoxes[0].x += dx[0]; -// selectedBBoxes[0].y += dy[0]; -// } - xform.setTranslate(dx[i],dy[i]); - } else { -// if (i==0) { -// selectedBBoxes[0].x += dx; -// selectedBBoxes[0].y += dy; -// } - xform.setTranslate(dx,dy); - } - - if(tlist.numberOfItems) { - tlist.insertItemBefore(xform, 0); - } else { - tlist.appendItem(xform); - } - - var cmd = recalculateDimensions(selected); - if (cmd) { - batchCmd.addSubCommand(cmd); - } - - selectorManager.requestSelector(selected).resize(); - } - } - if (!batchCmd.isEmpty()) { - if (undoable) - addCommandToHistory(batchCmd); - call("changed", selectedElements); - return batchCmd; - } -}; - -// Function: cloneSelectedElements -// Create deep DOM copies (clones) of all selected elements and move them slightly -// from their originals -this.cloneSelectedElements = function(x,y) { - var batchCmd = new BatchCommand("Clone Elements"); - // find all the elements selected (stop at first null) - var len = selectedElements.length; - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - if (elem == null) break; - } - // use slice to quickly get the subset of elements we need - var copiedElements = selectedElements.slice(0,i); - this.clearSelection(true); - // note that we loop in the reverse way because of the way elements are added - // to the selectedElements array (top-first) - var i = copiedElements.length; - while (i--) { - // clone each element and replace it within copiedElements - var elem = copiedElements[i] = copyElem(copiedElements[i]); - (current_group || getCurrentDrawing().getCurrentLayer()).appendChild(elem); - batchCmd.addSubCommand(new InsertElementCommand(elem)); - } - - if (!batchCmd.isEmpty()) { - addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - this.moveSelectedElements(x,y,false); - addCommandToHistory(batchCmd); - } -}; - -// Function: alignSelectedElements -// Aligns selected elements -// -// Parameters: -// type - String with single character indicating the alignment type -// relative_to - String that must be one of the following: -// "selected", "largest", "smallest", "page" -this.alignSelectedElements = function(type, relative_to) { - var bboxes = [], angles = []; - var minx = Number.MAX_VALUE, maxx = Number.MIN_VALUE, miny = Number.MAX_VALUE, maxy = Number.MIN_VALUE; - var curwidth = Number.MIN_VALUE, curheight = Number.MIN_VALUE; - var len = selectedElements.length; - if (!len) return; - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - bboxes[i] = getStrokedBBox([elem]); - - // now bbox is axis-aligned and handles rotation - switch (relative_to) { - case 'smallest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth > bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight > bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - case 'largest': - if ( (type == 'l' || type == 'c' || type == 'r') && (curwidth == Number.MIN_VALUE || curwidth < bboxes[i].width) || - (type == 't' || type == 'm' || type == 'b') && (curheight == Number.MIN_VALUE || curheight < bboxes[i].height) ) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - break; - default: // 'selected' - if (bboxes[i].x < minx) minx = bboxes[i].x; - if (bboxes[i].y < miny) miny = bboxes[i].y; - if (bboxes[i].x + bboxes[i].width > maxx) maxx = bboxes[i].x + bboxes[i].width; - if (bboxes[i].y + bboxes[i].height > maxy) maxy = bboxes[i].y + bboxes[i].height; - break; - } - } // loop for each element to find the bbox and adjust min/max - - if (relative_to == 'page') { - minx = 0; - miny = 0; - maxx = canvas.contentW; - maxy = canvas.contentH; - } - - var dx = new Array(len); - var dy = new Array(len); - for (var i = 0; i < len; ++i) { - if (selectedElements[i] == null) break; - var elem = selectedElements[i]; - var bbox = bboxes[i]; - dx[i] = 0; - dy[i] = 0; - switch (type) { - case 'l': // left (horizontal) - dx[i] = minx - bbox.x; - break; - case 'c': // center (horizontal) - dx[i] = (minx+maxx)/2 - (bbox.x + bbox.width/2); - break; - case 'r': // right (horizontal) - dx[i] = maxx - (bbox.x + bbox.width); - break; - case 't': // top (vertical) - dy[i] = miny - bbox.y; - break; - case 'm': // middle (vertical) - dy[i] = (miny+maxy)/2 - (bbox.y + bbox.height/2); - break; - case 'b': // bottom (vertical) - dy[i] = maxy - (bbox.y + bbox.height); - break; - } - } - this.moveSelectedElements(dx,dy); -}; - -// Group: Additional editor tools - -this.contentW = getResolution().w; -this.contentH = getResolution().h; - -// Function: updateCanvas -// Updates the editor canvas width/height/position after a zoom has occurred -// -// Parameters: -// w - Float with the new width -// h - Float with the new height -// -// Returns: -// Object with the following values: -// * x - The canvas' new x coordinate -// * y - The canvas' new y coordinate -// * old_x - The canvas' old x coordinate -// * old_y - The canvas' old y coordinate -// * d_x - The x position difference -// * d_y - The y position difference -this.updateCanvas = function(w, h) { - svgroot.setAttribute("width", w); - svgroot.setAttribute("height", h); - var bg = $('#canvasBackground')[0]; - var old_x = svgcontent.getAttribute('x'); - var old_y = svgcontent.getAttribute('y'); - var x = (w/2 - this.contentW*current_zoom/2); - var y = (h/2 - this.contentH*current_zoom/2); - - assignAttributes(svgcontent, { - width: this.contentW*current_zoom, - height: this.contentH*current_zoom, - 'x': x, - 'y': y, - "viewBox" : "0 0 " + this.contentW + " " + this.contentH - }); - - assignAttributes(bg, { - width: svgcontent.getAttribute('width'), - height: svgcontent.getAttribute('height'), - x: x, - y: y - }); - - var bg_img = getElem('background_image'); - if (bg_img) { - assignAttributes(bg_img, { - 'width': '100%', - 'height': '100%' - }); - } - - selectorManager.selectorParentGroup.setAttribute("transform","translate(" + x + "," + y + ")"); - - return {x:x, y:y, old_x:old_x, old_y:old_y, d_x:x - old_x, d_y:y - old_y}; -} - -// Function: setBackground -// Set the background of the editor (NOT the actual document) -// -// Parameters: -// color - String with fill color to apply -// url - URL or path to image to use -this.setBackground = function(color, url) { - var bg = getElem('canvasBackground'); - var border = $(bg).find('rect')[0]; - var bg_img = getElem('background_image'); - border.setAttribute('fill',color); - if(url) { - if(!bg_img) { - bg_img = svgdoc.createElementNS(svgns, "image"); - assignAttributes(bg_img, { - 'id': 'background_image', - 'width': '100%', - 'height': '100%', - 'preserveAspectRatio': 'xMinYMin', - 'style':'pointer-events:none' - }); - } - setHref(bg_img, url); - bg.appendChild(bg_img); - } else if(bg_img) { - bg_img.parentNode.removeChild(bg_img); - } -} - -// Function: cycleElement -// Select the next/previous element within the current layer -// -// Parameters: -// next - Boolean where true = next and false = previous element -this.cycleElement = function(next) { - var cur_elem = selectedElements[0]; - var elem = false; - var all_elems = getVisibleElements(current_group || getCurrentDrawing().getCurrentLayer()); - if(!all_elems.length) return; - if (cur_elem == null) { - var num = next?all_elems.length-1:0; - elem = all_elems[num]; - } else { - var i = all_elems.length; - while(i--) { - if(all_elems[i] == cur_elem) { - var num = next?i-1:i+1; - if(num >= all_elems.length) { - num = 0; - } else if(num < 0) { - num = all_elems.length-1; - } - elem = all_elems[num]; - break; - } - } - } - selectOnly([elem], true); - call("selected", selectedElements); -} - -this.clear(); - - -// DEPRECATED: getPrivateMethods -// Since all methods are/should be public somehow, this function should be removed - -// Being able to access private methods publicly seems wrong somehow, -// but currently appears to be the best way to allow testing and provide -// access to them to plugins. -this.getPrivateMethods = function() { - var obj = { - addCommandToHistory: addCommandToHistory, - setGradient: setGradient, - addSvgElementFromJson: addSvgElementFromJson, - assignAttributes: assignAttributes, - BatchCommand: BatchCommand, - call: call, - ChangeElementCommand: ChangeElementCommand, - copyElem: copyElem, - ffClone: ffClone, - findDefs: findDefs, - findDuplicateGradient: findDuplicateGradient, - getElem: getElem, - getId: getId, - getIntersectionList: getIntersectionList, - getMouseTarget: getMouseTarget, - getNextId: getNextId, - getPathBBox: getPathBBox, - getUrlFromAttr: getUrlFromAttr, - hasMatrixTransform: hasMatrixTransform, - identifyLayers: identifyLayers, - InsertElementCommand: InsertElementCommand, - isIdentity: svgedit.math.isIdentity, - logMatrix: logMatrix, - matrixMultiply: matrixMultiply, - MoveElementCommand: MoveElementCommand, - preventClickDefault: preventClickDefault, - recalculateAllSelectedDimensions: recalculateAllSelectedDimensions, - recalculateDimensions: recalculateDimensions, - remapElement: remapElement, - RemoveElementCommand: RemoveElementCommand, - removeUnusedDefElems: removeUnusedDefElems, - round: round, - runExtensions: runExtensions, - sanitizeSvg: sanitizeSvg, - SVGEditTransformList: svgedit.transformlist.SVGTransformList, - toString: toString, - transformBox: svgedit.math.transformBox, - transformListToTransform: transformListToTransform, - transformPoint: transformPoint, - walkTree: svgedit.utilities.walkTree - } - return obj; -}; - -} diff --git a/build/svg-edit-2.6/svgedit.compiled.css b/build/svg-edit-2.6/svgedit.compiled.css deleted file mode 100644 index 191f03b..0000000 --- a/build/svg-edit-2.6/svgedit.compiled.css +++ /dev/null @@ -1 +0,0 @@ -#svg_editor .jPicker .Icon{display:inline-block;height:24px;position:relative;text-align:left;width:25px;}#svg_editor .jPicker .Icon span.Color,#svg_editor .jPicker .Icon span.Alpha{background-position:2px 2px;display:block;height:100%;left:0;position:absolute;top:0;width:100%;}#svg_editor .jPicker .Icon span.Image{background-repeat:no-repeat;cursor:pointer;display:block;height:100%;left:0;position:absolute;top:0;width:100%;}#svg_editor .jPicker.Container{z-index:10;}table#svg_editor .jPicker{width:545px;z-index:20;}#svg_editor .jPicker .Move{background-color:#ddd;border-color:#fff #666 #666 #fff;border-style:solid;border-width:1px;cursor:move;height:12px;padding:0;}#svg_editor .jPicker .Title{display:none;}#svg_editor .jPicker div.Map{border:solid #000 1px;cursor:crosshair;height:260px;margin:0;overflow:hidden;padding:0;position:relative;width:260px;}#svg_editor .jPicker div[class="Map"]{height:256px;width:256px;}#svg_editor .jPicker div.Bar{border:solid #000 1px;cursor:n-resize;height:260px;margin:0 15px;overflow:hidden;padding:0;position:relative;width:24px;}#svg_editor .jPicker div[class="Bar"]{height:256px;width:20px;}#svg_editor .jPicker .Map .Map1,#svg_editor .jPicker .Map .Map2,#svg_editor .jPicker .Map .Map3,#svg_editor .jPicker .Bar .Map1,#svg_editor .jPicker .Bar .Map2,#svg_editor .jPicker .Bar .Map3,#svg_editor .jPicker .Bar .Map4,#svg_editor .jPicker .Bar .Map5,#svg_editor .jPicker .Bar .Map6{background-color:transparent;background-image:none;display:block;left:0;position:absolute;top:0;}#svg_editor .jPicker .Map .Map1,#svg_editor .jPicker .Map .Map2,#svg_editor .jPicker .Map .Map3{height:2596px;width:256px;}#svg_editor .jPicker .Bar .Map1,#svg_editor .jPicker .Bar .Map2,#svg_editor .jPicker .Bar .Map3,#svg_editor .jPicker .Bar .Map4{height:3896px;width:20px;}#svg_editor .jPicker .Bar .Map5,#svg_editor .jPicker .Bar .Map6{height:256px;width:20px;}#svg_editor .jPicker .Map .Map1,#svg_editor .jPicker .Map .Map2,#svg_editor .jPicker .Bar .Map6{background-repeat:no-repeat;}#svg_editor .jPicker .Map .Map3,#svg_editor .jPicker .Bar .Map5{background-repeat:repeat;}#svg_editor .jPicker .Bar .Map1,#svg_editor .jPicker .Bar .Map2,#svg_editor .jPicker .Bar .Map3,#svg_editor .jPicker .Bar .Map4{background-repeat:repeat-x;}#svg_editor .jPicker .Map .Arrow{display:block;position:absolute;}#svg_editor .jPicker .Bar .Arrow{display:block;left:0;position:absolute;}#svg_editor .jPicker .Preview{font-size:9px;text-align:center;}#svg_editor .jPicker .Preview div.bgt{height:62px;margin:0 auto;padding:0;width:62px;}#svg_editor .jPicker .Preview div span{border:1px solid #000;display:block;height:30px;margin:0 auto;padding:0;width:60px;}#svg_editor .jPicker .Preview .Active{border-bottom-width:0;}#svg_editor .jPicker .Preview .Current{border-top-width:0;cursor:pointer;}#svg_editor .jPicker .Button{text-align:center;width:115px;}#svg_editor .jPicker .Button input{width:100px;}#svg_editor .jPicker .Button .Ok{margin:0 0 5px 0;}#svg_editor .jPicker td.Radio{margin:0;padding:0;width:31px;}#svg_editor .jPicker td.Radio input{margin:0 5px 0 0;padding:0;}#svg_editor .jPicker td.Text{font-size:12px!important;height:22px;margin:0;padding:0;text-align:left;width:70px;}#svg_editor .jPicker tr.Hex td.Text{width:100px;color:#666;}#svg_editor .jPicker tr.Hex td.Text span{width:100px;color:#333;}#svg_editor .jPicker td.Text input{background-color:#fff;border:1px inset #aaa;height:15px;margin:0 0 0 5px;text-align:left;width:30px;color:#333;}#svg_editor #color_picker .jPicker tr.Hex td.Text input.Hex{width:50px;display:inline-block;float:none;}#svg_editor .jPicker tr.Hex td.Text input.AHex{width:20px;display:none;}#svg_editor .jPicker .Grid{text-align:center;float:right;width:108px;}#svg_editor .jPicker .Grid span.QuickColor{cursor:pointer;display:inline-block;height:15px;line-height:15px;margin:0;padding:0;width:18px;}#svg_editor .jPicker td{vertical-align:top;}#svg_editor .jPicker td.colorsquare{width:275px;}#svg_editor .jPicker .prev_div{margin-top:-15px;}#svg_editor .jPicker .actions{position:absolute;bottom:20px;left:20px;right:20px;}#svg_editor .jPicker .actions .Ok{position:absolute;top:0;right:0;}#svg_editor .jPicker .actions .Cancel{position:absolute;top:0;left:0;}#svg_editor .jPicker .color_preview{width:62px;margin:0 auto;} \ No newline at end of file diff --git a/build/svg-edit-2.6/svgedit.compiled.js b/build/svg-edit-2.6/svgedit.compiled.js deleted file mode 100644 index 744c26e..0000000 --- a/build/svg-edit-2.6/svgedit.compiled.js +++ /dev/null @@ -1,675 +0,0 @@ -(function(a){function n(f){if(typeof f.data==="string"){var c=f.handler,m=f.data.toLowerCase().split(" ");f.handler=function(p){if(!(this!==p.target&&(/textarea|select/i.test(p.target.nodeName)||p.target.type==="text"))){var b=p.type!=="keypress"&&a.hotkeys.specialKeys[p.which],d=String.fromCharCode(p.which).toLowerCase(),e="",l={};if(p.altKey&&b!=="alt")e+="alt+";if(p.ctrlKey&&b!=="ctrl")e+="ctrl+";if(p.metaKey&&!p.ctrlKey&&b!=="meta")e+="meta+";if(p.shiftKey&&b!=="shift")e+="shift+";if(b)l[e+b]= -true;else{l[e+d]=true;l[e+a.hotkeys.shiftNums[d]]=true;if(e==="shift+")l[a.hotkeys.shiftNums[d]]=true}b=0;for(d=m.length;b<d;b++)if(l[m[b]])return c.apply(this,arguments)}}}}a.hotkeys={version:"0.8",specialKeys:{8:"backspace",9:"tab",13:"return",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"del",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9", -106:"*",107:"+",109:"-",110:".",111:"/",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scroll",191:"/",224:"meta",219:"[",221:"]"},shiftNums:{"`":"~","1":"!","2":"@","3":"#","4":"$","5":"%","6":"^","7":"&","8":"*","9":"(","0":")","-":"_","=":"+",";":": ","'":'"',",":"<",".":">","/":"?","\\":"|"}};a.each(["keydown","keyup","keypress"],function(){a.event.special[this]={add:n}})})(jQuery);(function(a,n){function f(ba){return typeof ba==="string"}function c(ba){var S=e.call(arguments,1);return function(){return ba.apply(this,S.concat(e.call(arguments)))}}function m(ba,S,U,ra,la){var ma;if(ra!==d){S=U.match(ba?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);U=S[3]||"";if(la===2&&f(ra))ra=ra.replace(ba?ea:ca,"");else{ma=o(S[2]);ra=f(ra)?o[ba?fa:O](ra):ra;ra=la===2?ra:la===1?a.extend({},ra,ma):a.extend({},ma,ra);ra=u(ra);if(ba)ra=ra.replace(qa,l)}ba=S[1]+(ba?"#":ra||!S[1]?"?":"")+ra+U}else ba= -S(U!==d?U:n[sa][ja]);return ba}function p(ba,S,U){if(S===d||typeof S==="boolean"){U=S;S=u[ba?fa:O]()}else S=f(S)?S.replace(ba?ea:ca,""):S;return o(S,U)}function b(ba,S,U,ra){if(!f(U)&&typeof U!=="object"){ra=U;U=S;S=d}return this.each(function(){var la=a(this),ma=S||da()[(this.nodeName||"").toLowerCase()]||"",Y=ma&&la.attr(ma)||"";la.attr(ma,u[ba](Y,U,ra))})}var d,e=Array.prototype.slice,l=decodeURIComponent,u=a.param,z,o,L,T=a.bbq=a.bbq||{},N,J,da,V=a.event.special,O="querystring",fa="fragment", -sa="location",ja="href",ca=/^.*\?|#.*$/g,ea=/^.*\#/,qa,pa={};u[O]=c(m,0,function(ba){return ba.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")});u[fa]=z=c(m,1,function(ba){return ba.replace(/^[^#]*#?(.*)$/,"$1")});z.noEscape=function(ba){ba=ba||"";ba=a.map(ba.split(""),encodeURIComponent);qa=RegExp(ba.join("|"),"g")};z.noEscape(",/");a.deparam=o=function(ba,S){var U={},ra={"true":true,"false":false,"null":null};a.each(ba.replace(/\+/g," ").split("&"),function(la,ma){var Y=ma.split("="),za=l(Y[0]),Ia=U, -Qa=0,Ka=za.split("]["),Ua=Ka.length-1;if(/\[/.test(Ka[0])&&/\]$/.test(Ka[Ua])){Ka[Ua]=Ka[Ua].replace(/\]$/,"");Ka=Ka.shift().split("[").concat(Ka);Ua=Ka.length-1}else Ua=0;if(Y.length===2){Y=l(Y[1]);if(S)Y=Y&&!isNaN(Y)?+Y:Y==="undefined"?d:ra[Y]!==d?ra[Y]:Y;if(Ua)for(;Qa<=Ua;Qa++){za=Ka[Qa]===""?Ia.length:Ka[Qa];Ia=Ia[za]=Qa<Ua?Ia[za]||(Ka[Qa+1]&&isNaN(Ka[Qa+1])?{}:[]):Y}else if(a.isArray(U[za]))U[za].push(Y);else U[za]=U[za]!==d?[U[za],Y]:Y}else if(za)U[za]=S?d:""});return U};o[O]=c(p,0);o[fa]=L= -c(p,1);a.elemUrlAttr||(a.elemUrlAttr=function(ba){return a.extend(pa,ba)})({a:ja,base:ja,iframe:"src",img:"src",input:"src",form:"action",link:ja,script:"src"});da=a.elemUrlAttr;a.fn[O]=c(b,O);a.fn[fa]=c(b,fa);T.pushState=N=function(ba,S){if(f(ba)&&/^#/.test(ba)&&S===d)S=2;var U=ba!==d;U=z(n[sa][ja],U?ba:{},U?S:2);n[sa][ja]=U+(/#/.test(U)?"":"#")};T.getState=J=function(ba,S){return ba===d||typeof ba==="boolean"?L(ba):L(S)[ba]};T.removeState=function(ba){var S={};if(ba!==d){S=J();a.each(a.isArray(ba)? -ba:arguments,function(U,ra){delete S[ra]})}N(S,2)};V.hashchange=a.extend(V.hashchange,{add:function(ba){function S(ra){var la=ra[fa]=z();ra.getState=function(ma,Y){return ma===d||typeof ma==="boolean"?o(la,ma):o(la,Y)[ma]};U.apply(this,arguments)}var U;if(a.isFunction(ba)){U=ba;return S}else{U=ba.handler;ba.handler=S}}})})(jQuery,this); -(function(a,n,f){function c(z){z=z||n[b][d];return z.replace(/^[^#]*#?(.*)$/,"$1")}var m,p=a.event.special,b="location",d="href",e=document.documentMode,l=a.browser.msie&&(e===f||e<8),u="onhashchange"in n&&!l;a.hashchangeDelay=100;p.hashchange=a.extend(p.hashchange,{setup:function(){if(u)return false;a(m.start)},teardown:function(){if(u)return false;a(m.stop)}});m=function(){function z(){N=J=function(da){return da};if(l){T=a('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow; -J=function(){return c(T.document[b][d])};N=function(da,V){if(da!==V){var O=T.document;O.open().close();O[b].hash="#"+da}};N(c())}}var o={},L,T,N,J;o.start=function(){if(!L){var da=c();N||z();(function V(){var O=c(),fa=J(da);if(O!==da){N(da=O,fa);a(n).trigger("hashchange")}else if(fa!==da)n[b][d]=n[b][d].replace(/#.*/,"")+"#"+fa;L=setTimeout(V,a.hashchangeDelay)})()}};o.stop=function(){if(!T){L&&clearTimeout(L);L=0}};return o}()})(jQuery,this);(function(a){var n={},f;a.svgIcons=function(c,m){function p(ba,S){if(ba!=="ajax"){if(da)return;var U=(T=ja[0].contentDocument)&&T.getElementById("svg_eof");if(!U&&!(S&&U)){V++;if(V<50)setTimeout(p,20);else{d();da=true}return}da=true}L=a(T.firstChild).children();if(m.no_img)setTimeout(function(){J||b()},500);else{U=sa+"PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D";N=a(new Image).attr({src:U,width:0,height:0}).appendTo("body").load(function(){b(true)}).error(function(){b()})}} -function b(ba,S){if(!J){if(m.no_img)ba=false;if(ba){var U=a(document.createElement("div"));U.hide().appendTo("body")}if(S){var ra=m.fallback_path?m.fallback_path:"";a.each(S,function(Ua,Wa){a("#"+Ua);var La=a(new Image).attr({"class":"svg_icon",src:ra+Wa,width:z,height:o,alt:"icon"});pa(La,Ua)})}else for(var la=L.length,ma=0;ma<la;ma++){var Y=L[ma],za=Y.id;if(za==="svg_eof")break;a("#"+za);Y=Y.getElementsByTagNameNS(l,"svg")[0];var Ia=document.createElementNS(l,"svg");Ia.setAttributeNS(l,"viewBox", -[0,0,z,o].join(" "));var Qa=Y.getAttribute("width"),Ka=Y.getAttribute("height");Y.removeAttribute("width");Y.removeAttribute("height");Y.getAttribute("viewBox")||Y.setAttribute("viewBox",[0,0,Qa,Ka].join(" "));Ia.setAttribute("xmlns",l);Ia.setAttribute("width",z);Ia.setAttribute("height",o);Ia.setAttribute("xmlns:xlink",u);Ia.setAttribute("class","svg_icon");fa||(Y=Y.cloneNode(true));Ia.appendChild(Y);if(ba){fa||Ia.cloneNode(true);U.empty().append(Ia);Y=sa+e(U.html());Y=a(new Image).attr({"class":"svg_icon", -src:Y})}else Y=f(a(Ia),ma);pa(Y,za)}m.placement&&a.each(m.placement,function(Ua,Wa){n[Wa]&&a(Ua).each(function(La){var Ga=n[Wa].clone();if(La>0&&!ba)Ga=f(Ga,La,true);qa(a(this),Ga,Wa)})});if(!S){ba&&U.remove();ja&&ja.remove();N&&N.remove()}m.resize&&a.resizeSvgIcons(m.resize);J=true;m.callback&&m.callback(n)}}function d(){if(c.indexOf(".svgz")!=-1){var ba=c.replace(".svgz",".svg");window.console&&console.log(".svgz failed, trying with .svg");a.svgIcons(ba,m)}else m.fallback&&b(false,m.fallback)}function e(ba){if(window.btoa)return window.btoa(ba); -var S=Array(Math.floor((ba.length+2)/3)*4),U,ra,la,ma,Y,za,Ia=0,Qa=0;do{U=ba.charCodeAt(Ia++);ra=ba.charCodeAt(Ia++);la=ba.charCodeAt(Ia++);ma=U>>2;U=(U&3)<<4|ra>>4;Y=(ra&15)<<2|la>>6;za=la&63;if(isNaN(ra))Y=za=64;else if(isNaN(la))za=64;S[Qa++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(ma);S[Qa++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(U);S[Qa++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(Y);S[Qa++]= -"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(za)}while(Ia<ba.length);return S.join("")}var l="http://www.w3.org/2000/svg",u="http://www.w3.org/1999/xlink",z=m.w?m.w:24,o=m.h?m.h:24,L,T,N,J=false,da=false,V=0,O=navigator.userAgent,fa=!!window.opera;O.indexOf("Safari/")>-1&&O.indexOf("Chrome/");var sa="data:image/svg+xml;charset=utf-8;base64,";if(m.svgz){var ja=a('<object data="'+c+'" type=image/svg+xml>').appendTo("body").hide();try{T=ja[0].contentDocument;ja.load(p); -p(0,true)}catch(ca){d()}}else{var ea=new DOMParser;a.ajax({url:c,dataType:"string",success:function(ba){if(ba){T=ea.parseFromString(ba,"text/xml");a(function(){p("ajax")})}else a(d)},error:function(ba){if(window.opera)a(function(){d()});else if(ba.responseText){T=ea.parseFromString(ba.responseText,"text/xml");T.childNodes.length||a(d);a(function(){p("ajax")})}else a(d)}})}var qa=function(ba,S,U,ra){fa&&S.css("visibility","hidden");if(m.replace){ra&&S.attr("id",U);(U=ba.attr("class"))&&S.attr("class", -"svg_icon "+U);ba.replaceWith(S)}else ba.append(S);fa&&setTimeout(function(){S.removeAttr("style")},1)},pa=function(ba,S){if(m.id_match===undefined||m.id_match!==false)qa(holder,ba,S,true);n[S]=ba};f=function(ba,S){var U=ba.find("defs");if(!U.length)return ba;U=fa?U.find("*").filter(function(){return!!this.id}):U.find("[id]");var ra=ba[0].getElementsByTagName("*"),la=ra.length;U.each(function(ma){var Y=this.id;a(T).find("#"+Y);this.id=ma="x"+Y+S+ma;Y="url(#"+Y+")";var za="url(#"+ma+")";for(ma=0;ma< -la;ma++){var Ia=ra[ma];Ia.getAttribute("fill")===Y&&Ia.setAttribute("fill",za);Ia.getAttribute("stroke")===Y&&Ia.setAttribute("stroke",za);Ia.getAttribute("filter")===Y&&Ia.setAttribute("filter",za)}});return ba}};a.getSvgIcon=function(c,m){var p=n[c];if(m&&p)p=f(p,0,true).clone(true);return p};a.resizeSvgIcons=function(c){var m=!a(".svg_icon:first").length;a.each(c,function(p,b){var d=a.isArray(b),e=d?b[0]:b,l=d?b[1]:b;if(m)p=p.replace(/\.svg_icon/g,"svg");a(p).each(function(){this.setAttribute("width", -e);this.setAttribute("height",l);if(window.opera&&window.widget){this.parentNode.style.width=e+"px";this.parentNode.style.height=l+"px"}})})}})(jQuery);(function(){function a(c,m,p){c=document.createElementNS(n.svg,c);if(f)for(var b in m)c.setAttribute(b,m[b]);else for(b in m){var d=m[b],e=c[b];if(e&&e.constructor==="SVGLength")e.baseVal.value=d;else c.setAttribute(b,d)}p&&p.appendChild(c);return c}var n={svg:"http://www.w3.org/2000/svg",xlink:"http://www.w3.org/1999/xlink"};if(!window.console)window.console=new function(){this.log=function(){};this.dir=function(){}};$.jGraduate={Paint:function(c){c=c||{};this.alpha=isNaN(c.alpha)?100:c.alpha;if(c.copy){this.type= -c.copy.type;this.alpha=c.copy.alpha;this.radialGradient=this.linearGradient=this.solidColor=null;switch(this.type){case "solidColor":this.solidColor=c.copy.solidColor;break;case "linearGradient":this.linearGradient=c.copy.linearGradient.cloneNode(true);break;case "radialGradient":this.radialGradient=c.copy.radialGradient.cloneNode(true)}}else if(c.linearGradient){this.type="linearGradient";this.radialGradient=this.solidColor=null;this.linearGradient=c.linearGradient.cloneNode(true)}else if(c.radialGradient){this.type= -"radialGradient";this.linearGradient=this.solidColor=null;this.radialGradient=c.radialGradient.cloneNode(true)}else if(c.solidColor){this.type="solidColor";this.solidColor=c.solidColor}else{this.type="none";this.radialGradient=this.linearGradient=this.solidColor=null}}};jQuery.fn.jGraduateDefaults={paint:new $.jGraduate.Paint,window:{pickerTitle:"Drag markers to pick a paint"},images:{clientPath:"images/"},newstop:"inverse"};var f=navigator.userAgent.indexOf("Gecko/")>=0;jQuery.fn.jGraduate=function(c){var m= -arguments;return this.each(function(){function p(na,Z,ta,M,I){var X=I||a("stop",{"stop-color":Z,"stop-opacity":ta,offset:na},ea);if(I){Z=I.getAttribute("stop-color");ta=I.getAttribute("stop-opacity");na=I.getAttribute("offset")}else ea.appendChild(X);if(ta===null)ta=1;I=a("path",{d:"M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z",fill:"url(#jGraduate_trans)",transform:"translate("+(10+na*fa)+", 26)"},Gb);var Ma= -a("path",{d:"M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z",fill:Z,"fill-opacity":ta,transform:"translate("+(10+na*fa)+", 26)",stroke:"#000","stroke-width":1.5},Gb);$(Ma).mousedown(function(Xa){b(this);Sa=lb;da.mousemove(l).mouseup(d);Ea=Nb.offset();Xa.preventDefault();return false}).data("stop",X).data("bg",I).dblclick(function(){$("div.jGraduate_LightBox").show();for(var Xa=this,db=+X.getAttribute("stop-opacity")|| -1,tb=X.getAttribute("stop-color")||1,xb=(parseFloat(db)*255).toString(16);xb.length<2;)xb="0"+xb;Z=tb.substr(1)+xb;$("#"+o+"_jGraduate_stopPicker").css({left:100,bottom:15}).jPicker({window:{title:"Pick the start color and opacity for the gradient"},images:{clientPath:z.images.clientPath},color:{active:Z,alphaSupport:true}},function(Hb){tb=Hb.val("hex")?"#"+Hb.val("hex"):"none";db=Hb.val("a")!==null?Hb.val("a")/256:1;Xa.setAttribute("fill",tb);Xa.setAttribute("fill-opacity",db);X.setAttribute("stop-color", -tb);X.setAttribute("stop-opacity",db);$("div.jGraduate_LightBox").hide();$("#"+o+"_jGraduate_stopPicker").hide()},null,function(){$("div.jGraduate_LightBox").hide();$("#"+o+"_jGraduate_stopPicker").hide()})});$(ea).find("stop").each(function(){var Xa=$(this);if(+this.getAttribute("offset")>na){if(!Z){var db=this.getAttribute("stop-color"),tb=this.getAttribute("stop-opacity");X.setAttribute("stop-color",db);Ma.setAttribute("fill",db);X.setAttribute("stop-opacity",tb===null?1:tb);Ma.setAttribute("fill-opacity", -tb===null?1:tb)}Xa.before(X);return false}});M&&b(Ma);return X}function b(na){lb&&lb.setAttribute("stroke","#000");na.setAttribute("stroke","blue");lb=na;lb.parentNode.appendChild(lb)}function d(){da.unbind("mousemove",l);if(Ja.getAttribute("display")!=="none"){Ja.setAttribute("display","none");var na=$(lb),Z=na.data("stop");na=na.data("bg");$([lb,Z,na]).remove()}Sa=null}function e(){var na=$a?"rotate("+$a+","+Na+","+mb+") ":"";Za===1&&Ra===1?ea.removeAttribute("gradientTransform"):ea.setAttribute("gradientTransform", -na+"translate("+-Na*(Za-1)+","+-mb*(Ra-1)+") scale("+Za+","+Ra+")")}function l(na){var Z=na.pageX-Ea.left;na=na.pageY-Ea.top;Z=Z<10?10:Z>fa+10?fa+10:Z;var ta="translate("+Z+", 26)";if(na<-60||na>130){Ja.setAttribute("display","block");Ja.setAttribute("transform",ta)}else Ja.setAttribute("display","none");Sa.setAttribute("transform",ta);$.data(Sa,"bg").setAttribute("transform",ta);$.data(Sa,"stop").setAttribute("offset",(Z-10)/fa);var M=0;$(ea).find("stop").each(function(){var I=this.getAttribute("offset"), -X=$(this);if(I<M){X.prev().before(X);Fa=$(ea).find("stop")}M=I})}var u=$(this),z=$.extend(true,{},jQuery.fn.jGraduateDefaults,c),o=u.attr("id"),L="#"+u.attr("id")+" ";if(L){var T=function(){switch(u.paint.type){case "radialGradient":u.paint.linearGradient=null;break;case "linearGradient":u.paint.radialGradient=null;break;case "solidColor":u.paint.radialGradient=u.paint.linearGradient=null}$.isFunction(u.okCallback)&&u.okCallback(u.paint);u.hide()},N=function(){$.isFunction(u.cancelCallback)&&u.cancelCallback(); -u.hide()};$.extend(true,u,{paint:new $.jGraduate.Paint({copy:z.paint}),okCallback:$.isFunction(m[1])&&m[1]||null,cancelCallback:$.isFunction(m[2])&&m[2]||null});u.position();var J=null,da=$(window);if(u.paint.type=="none")u.paint=$.jGraduate.Paint({solidColor:"ffffff"});u.addClass("jGraduate_Picker");u.html('<ul class="jGraduate_tabs"><li class="jGraduate_tab_color jGraduate_tab_current" data-type="col">Solid Color</li><li class="jGraduate_tab_lingrad" data-type="lg">Linear Gradient</li><li class="jGraduate_tab_radgrad" data-type="rg">Radial Gradient</li></ul><div class="jGraduate_colPick"></div><div class="jGraduate_gradPick"></div><div class="jGraduate_LightBox"></div><div id="'+ -o+'_jGraduate_stopPicker" class="jGraduate_stopPicker"></div>');var V=$(L+"> .jGraduate_colPick"),O=$(L+"> .jGraduate_gradPick");O.html('<div id="'+o+'_jGraduate_Swatch" class="jGraduate_Swatch"><h2 class="jGraduate_Title">'+z.window.pickerTitle+'</h2><div id="'+o+'_jGraduate_GradContainer" class="jGraduate_GradContainer"></div><div id="'+o+'_jGraduate_StopSlider" class="jGraduate_StopSlider"></div></div><div class="jGraduate_Form jGraduate_Points jGraduate_lg_field"><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Begin Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+ -o+'_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+o+'_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/></div></div><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">End Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+o+'_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+ -o+'_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/></div></div></div><div class="jGraduate_Form jGraduate_Points jGraduate_rg_field"><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Center Point</label><div class="jGraduate_Form_Section"><label>x:</label><input type="text" id="'+o+'_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+o+'_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/></div></div><div class="jGraduate_StopSection"><label class="jGraduate_Form_Heading">Focal Point</label><div class="jGraduate_Form_Section"><label>Match center: <input type="checkbox" checked="checked" id="'+ -o+'_jGraduate_match_ctr"/></label><br/><label>x:</label><input type="text" id="'+o+'_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/><label> y:</label><input type="text" id="'+o+'_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/></div></div></div><div class="jGraduate_StopSection jGraduate_SpreadMethod"><label class="jGraduate_Form_Heading">Spread method</label><div class="jGraduate_Form_Section"><select class="jGraduate_spreadMethod"><option value=pad selected>Pad</option><option value=reflect>Reflect</option><option value=repeat>Repeat</option></select></div></div><div class="jGraduate_Form"><div class="jGraduate_Slider jGraduate_RadiusField jGraduate_rg_field"><label class="prelabel">Radius:</label><div id="'+ -o+'_jGraduate_Radius" class="jGraduate_SliderBar jGraduate_Radius" title="Click to set radius"><img id="'+o+'_jGraduate_RadiusArrows" class="jGraduate_RadiusArrows" src="'+z.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+o+'_jGraduate_RadiusInput" size="3" value="100"/>%</label></div><div class="jGraduate_Slider jGraduate_EllipField jGraduate_rg_field"><label class="prelabel">Ellip:</label><div id="'+o+'_jGraduate_Ellip" class="jGraduate_SliderBar jGraduate_Ellip" title="Click to set Ellip"><img id="'+ -o+'_jGraduate_EllipArrows" class="jGraduate_EllipArrows" src="'+z.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+o+'_jGraduate_EllipInput" size="3" value="0"/>%</label></div><div class="jGraduate_Slider jGraduate_AngleField jGraduate_rg_field"><label class="prelabel">Angle:</label><div id="'+o+'_jGraduate_Angle" class="jGraduate_SliderBar jGraduate_Angle" title="Click to set Angle"><img id="'+o+'_jGraduate_AngleArrows" class="jGraduate_AngleArrows" src="'+z.images.clientPath+ -'rangearrows2.gif"></div><label><input type="text" id="'+o+'_jGraduate_AngleInput" size="3" value="0"/>\u00ba </label></div><div class="jGraduate_Slider jGraduate_OpacField"><label class="prelabel">Opac:</label><div id="'+o+'_jGraduate_Opac" class="jGraduate_SliderBar jGraduate_Opac" title="Click to set Opac"><img id="'+o+'_jGraduate_OpacArrows" class="jGraduate_OpacArrows" src="'+z.images.clientPath+'rangearrows2.gif"></div><label><input type="text" id="'+o+'_jGraduate_OpacInput" size="3" value="100"/>%</label></div></div><div class="jGraduate_OkCancel"><input type="button" id="'+ -o+'_jGraduate_Ok" class="jGraduate_Ok" value="OK"/><input type="button" id="'+o+'_jGraduate_Cancel" class="jGraduate_Cancel" value="Cancel"/></div>');var fa=256,sa=fa-0,ja=fa-0,ca,ea,qa,pa={};$(".jGraduate_SliderBar").width(145);var ba=$("#"+o+"_jGraduate_GradContainer")[0],S=a("svg",{id:o+"_jgraduate_svg",width:fa,height:fa,xmlns:n.svg},ba);ca=ca||u.paint.type;var U=ea=u.paint[ca],ra=u.paint.alpha,la=ca==="solidColor";switch(ca){case "solidColor":case "linearGradient":if(!la){ea.id=o+"_lg_jgraduate_grad"; -U=ea=S.appendChild(ea)}a("radialGradient",{id:o+"_rg_jgraduate_grad"},S);if(ca==="linearGradient")break;case "radialGradient":if(!la){ea.id=o+"_rg_jgraduate_grad";U=ea=S.appendChild(ea)}a("linearGradient",{id:o+"_lg_jgraduate_grad"},S)}if(la){U=ea=$("#"+o+"_lg_jgraduate_grad")[0];J=u.paint[ca];p(0,"#"+J,1);var ma=typeof z.newstop;if(ma==="string")switch(z.newstop){case "same":p(1,"#"+J,1);break;case "inverse":ma="";for(var Y=0;Y<6;Y+=2){J.substr(Y,2);var za=(255-parseInt(J.substr(Y,2),16)).toString(16); -if(za.length<2)za=0+za;ma+=za}p(1,"#"+ma,1);break;case "white":p(1,"#ffffff",1);break;case "black":p(1,"#000000",1)}else if(ma==="object")p(1,z.newstop.color||"#"+J,"opac"in z.newstop?z.newstop.opac:1)}J=parseFloat(U.getAttribute("x1")||0);ma=parseFloat(U.getAttribute("y1")||0);Y=parseFloat(U.getAttribute("x2")||1);za=parseFloat(U.getAttribute("y2")||0);var Ia=parseFloat(U.getAttribute("cx")||0.5),Qa=parseFloat(U.getAttribute("cy")||0.5),Ka=parseFloat(U.getAttribute("fx")||Ia),Ua=parseFloat(U.getAttribute("fy")|| -Qa);qa=a("rect",{id:o+"_jgraduate_rect",x:0,y:0,width:sa,height:ja,fill:"url(#"+o+"_jgraduate_grad)","fill-opacity":ra/100},S);var Wa=$("<div/>").attr({"class":"grad_coord jGraduate_lg_field",title:"Begin Stop"}).text(1).css({top:ma*fa,left:J*fa}).data("coord","start").appendTo(ba),La=Wa.clone().text(2).css({top:za*fa,left:Y*fa}).attr("title","End stop").data("coord","end").appendTo(ba),Ga=$("<div/>").attr({"class":"grad_coord jGraduate_rg_field",title:"Center stop"}).text("C").css({top:Qa*fa,left:Ia* -fa}).data("coord","center").appendTo(ba),Oa=Ga.clone().text("F").css({top:Ua*fa,left:Ka*fa,display:"none"}).attr("title","Focus point").data("coord","focus").appendTo(ba);Oa[0].id=o+"_jGraduate_focusCoord";$(L+" .grad_coord");$.each(["x1","y1","x2","y2","cx","cy","fx","fy"],function(na,Z){var ta=ea.getAttribute(Z),M=isNaN(Z[1]);ta||(ta=M?"0.5":Z==="x2"?"1.0":"0.0");pa[Z]=$("#"+o+"_jGraduate_"+Z).val(ta).change(function(){if(isNaN(parseFloat(this.value))||this.value<0)this.value=0;else if(this.value> -1)this.value=1;if(!(Z[0]==="f"&&!nb))if(M&&ca==="radialGradient"||!M&&ca==="linearGradient")ea.setAttribute(Z,this.value);var I=M?Z[0]==="c"?Ga:Oa:Z[1]==="1"?Wa:La,X=Z.indexOf("x")>=0?"left":"top";I.css(X,this.value*fa)}).change()});var Fa,Gb,Nb=$("#"+o+"_jGraduate_StopSlider"),lb,ab,Sa,Ja=a("path",{d:"m9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5",fill:"none",stroke:"#D00","stroke-width":5,display:"none"},ab),Ea,Za=1,Ra=1,$a=0,Na=Ia,mb=Qa;ab=a("svg",{width:"100%",height:45},Nb[0]);ba=a("pattern",{width:16, -height:16,patternUnits:"userSpaceOnUse",id:"jGraduate_trans"},ab);a("image",{width:16,height:16},ba).setAttributeNS(n.xlink,"xlink:href",z.images.clientPath+"map-opacity.png");$(ab).click(function(na){Ea=Nb.offset();if(na.target.tagName!=="path"){var Z=na.pageX-Ea.left-8;Z=Z<10?10:Z>fa+10?fa+10:Z;p(Z/fa,0,0,true);na.stopPropagation()}});$(ab).mouseover(function(){ab.appendChild(Ja)});Gb=a("g",{},ab);a("line",{x1:10,y1:15,x2:fa+10,y2:15,"stroke-width":2,stroke:"#000"},ab);var Ab=O.find(".jGraduate_spreadMethod").change(function(){ea.setAttribute("spreadMethod", -$(this).val())}),cb=null,jb=function(na){var Z=na.pageX-wb.left,ta=na.pageY-wb.top;Z=Z<0?0:Z>fa?fa:Z;ta=ta<0?0:ta>fa?fa:ta;cb.css("left",Z).css("top",ta);Z/=sa;ta/=ja;var M=cb.data("coord"),I=ea;switch(M){case "start":pa.x1.val(Z);pa.y1.val(ta);I.setAttribute("x1",Z);I.setAttribute("y1",ta);break;case "end":pa.x2.val(Z);pa.y2.val(ta);I.setAttribute("x2",Z);I.setAttribute("y2",ta);break;case "center":pa.cx.val(Z);pa.cy.val(ta);I.setAttribute("cx",Z);I.setAttribute("cy",ta);Na=Z;mb=ta;e();break;case "focus":pa.fx.val(Z); -pa.fy.val(ta);I.setAttribute("fx",Z);I.setAttribute("fy",ta);e()}na.preventDefault()},kb=function(){cb=null;da.unbind("mousemove",jb).unbind("mouseup",kb)};Fa=ea.getElementsByTagNameNS(n.svg,"stop");if(Ca<2){for(;Ca<2;){ea.appendChild(document.createElementNS(n.svg,"stop"));++Ca}Fa=ea.getElementsByTagNameNS(n.svg,"stop")}var Ca=Fa.length;for(Y=0;Y<Ca;Y++)p(0,0,0,0,Fa[Y]);Ab.val(ea.getAttribute("spreadMethod")||"pad");var wb,nb=false;qa.setAttribute("fill-opacity",ra/100);$("#"+o+" div.grad_coord").mousedown(function(na){na.preventDefault(); -cb=$(this);cb.offset();wb=cb.parent().offset();da.mousemove(jb).mouseup(kb)});$("#"+o+"_jGraduate_Ok").bind("click",function(){u.paint.type=ca;u.paint[ca]=ea.cloneNode(true);u.paint.solidColor=null;T()});$("#"+o+"_jGraduate_Cancel").bind("click",function(){N()});if(ca==="radialGradient")if(nb)Oa.show();else{Oa.hide();pa.fx.val("");pa.fy.val("")}$("#"+o+"_jGraduate_match_ctr")[0].checked=!nb;var yb,Bb;$("#"+o+"_jGraduate_match_ctr").change(function(){nb=!this.checked;Oa.toggle(nb);pa.fx.val("");pa.fy.val(""); -var na=ea;if(nb){var Z=yb||0.5,ta=Bb||0.5;na.setAttribute("fx",Z);na.setAttribute("fy",ta);pa.fx.val(Z);pa.fy.val(ta)}else{yb=na.getAttribute("fx");Bb=na.getAttribute("fy");na.removeAttribute("fx");na.removeAttribute("fy")}});Fa=ea.getElementsByTagNameNS(n.svg,"stop");Ca=Fa.length;if(Ca<2){for(;Ca<2;){ea.appendChild(document.createElementNS(n.svg,"stop"));++Ca}Fa=ea.getElementsByTagNameNS(n.svg,"stop")}var ob;ra=O=0;if(ca==="radialGradient"){S=ea.gradientTransform.baseVal;if(S.numberOfItems===2){Ca= -S.getItem(0);S=S.getItem(1);if(Ca.type===2&&S.type===3){Ca=S.matrix;if(Ca.a!==1)O=Math.round(-(1-Ca.a)*100);else if(Ca.d!==1)O=Math.round((1-Ca.d)*100)}}else if(S.numberOfItems===3){ba=S.getItem(0);Ca=S.getItem(1);S=S.getItem(2);if(ba.type===4&&Ca.type===2&&S.type===3){ra=Math.round(ba.angle);Ca=S.matrix;if(Ca.a!==1)O=Math.round(-(1-Ca.a)*100);else if(Ca.d!==1)O=Math.round((1-Ca.d)*100)}}}O={radius:{handle:"#"+o+"_jGraduate_RadiusArrows",input:"#"+o+"_jGraduate_RadiusInput",val:(ea.getAttribute("r")|| -0.5)*100},opacity:{handle:"#"+o+"_jGraduate_OpacArrows",input:"#"+o+"_jGraduate_OpacInput",val:u.paint.alpha||100},ellip:{handle:"#"+o+"_jGraduate_EllipArrows",input:"#"+o+"_jGraduate_EllipInput",val:O},angle:{handle:"#"+o+"_jGraduate_AngleArrows",input:"#"+o+"_jGraduate_AngleInput",val:ra}};$.each(O,function(na,Z){var ta=$(Z.handle);ta.mousedown(function(M){var I=ta.parent();ob={type:na,elem:ta,input:$(Z.input),parent:I,offset:I.offset()};da.mousemove(Cb).mouseup(Kb);M.preventDefault()});$(Z.input).val(Z.val).change(function(){var M= -+this.value,I=0,X=ca==="radialGradient";switch(na){case "radius":X&&ea.setAttribute("r",M/100);I=Math.pow(M/100,0.4)/2*145;break;case "opacity":u.paint.alpha=M;qa.setAttribute("fill-opacity",M/100);I=M*1.45;break;case "ellip":Za=Ra=1;if(M===0){I=72.5;break}if(M>99.5)M=99.5;if(M>0)Ra=1-M/100;else Za=-(M/100)-1;I=145*((M+100)/2)/100;X&&e();break;case "angle":$a=M;I=$a/180;I+=0.5;I*=145;X&&e()}if(I>145)I=145;else if(I<0)I=0;ta.css({"margin-left":I-5})}).change()});var Cb=function(na){var Z=na.pageX- -ob.offset.left-parseInt(ob.parent.css("border-left-width"));if(Z>145)Z=145;if(Z<=0)Z=0;var ta=Z-5;Z/=145;switch(ob.type){case "radius":Z=Math.pow(Z*2,2.5);if(Z>0.98&&Z<1.02)Z=1;if(Z<=0.01)Z=0.01;ea.setAttribute("r",Z);break;case "opacity":u.paint.alpha=parseInt(Z*100);qa.setAttribute("fill-opacity",Z);break;case "ellip":Ra=Za=1;if(Z<0.5){Z/=0.5;Za=Z<=0?0.01:Z}else if(Z>0.5){Z/=0.5;Z=2-Z;Ra=Z<=0?0.01:Z}e();Z-=1;if(Ra===Z+1)Z=Math.abs(Z);break;case "angle":Z-=0.5;$a=Z*=180;e();Z/=100}ob.elem.css({"margin-left":ta}); -Z=Math.round(Z*100);ob.input.val(Z);na.preventDefault()},Kb=function(){da.unbind("mousemove",Cb).unbind("mouseup",Kb);ob=null};for(O=(u.paint.alpha*255/100).toString(16);O.length<2;)O="0"+O;O=O.split(".")[0];J=u.paint.solidColor=="none"?"":u.paint.solidColor+O;la||(J=Fa[0].getAttribute("stop-color"));$.extend($.fn.jPicker.defaults.window,{alphaSupport:true,effects:{type:"show",speed:0}});V.jPicker({window:{title:z.window.pickerTitle},images:{clientPath:z.images.clientPath},color:{active:J,alphaSupport:true}}, -function(na){u.paint.type="solidColor";u.paint.alpha=na.val("ahex")?Math.round(na.val("a")/255*100):100;u.paint.solidColor=na.val("hex")?na.val("hex"):"none";u.paint.radialGradient=null;T()},null,function(){N()});var Ib=$(L+" .jGraduate_tabs li");Ib.click(function(){Ib.removeClass("jGraduate_tab_current");$(this).addClass("jGraduate_tab_current");$(L+" > div").hide();var na=$(this).attr("data-type");$(L+" .jGraduate_gradPick").show();if(na==="rg"||na==="lg"){$(".jGraduate_"+na+"_field").show();$(".jGraduate_"+ -(na==="lg"?"rg":"lg")+"_field").hide();$("#"+o+"_jgraduate_rect")[0].setAttribute("fill","url(#"+o+"_"+na+"_jgraduate_grad)");ca=na==="lg"?"linearGradient":"radialGradient";$("#"+o+"_jGraduate_OpacInput").val(u.paint.alpha).change();var Z=$("#"+o+"_"+na+"_jgraduate_grad")[0];if(ea!==Z){var ta=$(ea).find("stop");$(Z).empty().append(ta);ea=Z;Z=Ab.val();ea.setAttribute("spreadMethod",Z)}nb=na==="rg"&&ea.getAttribute("fx")!=null&&!(Ia==Ka&&Qa==Ua);$("#"+o+"_jGraduate_focusCoord").toggle(nb);if(nb)$("#"+ -o+"_jGraduate_match_ctr")[0].checked=false}else{$(L+" .jGraduate_gradPick").hide();$(L+" .jGraduate_colPick").show()}});$(L+" > div").hide();Ib.removeClass("jGraduate_tab_current");var Rb;switch(u.paint.type){case "linearGradient":Rb=$(L+" .jGraduate_tab_lingrad");break;case "radialGradient":Rb=$(L+" .jGraduate_tab_radgrad");break;default:Rb=$(L+" .jGraduate_tab_color")}u.show();setTimeout(function(){Rb.addClass("jGraduate_tab_current").click()},10)}else alert("Container element must have an id attribute to maintain unique id strings for sub-elements.")})}})();$.fn.SpinButton=function(a){function n(f,c){for(var m=f[c],p=document.body;(f=f.offsetParent)&&f!=p;)if(!$.browser.msie||f.currentStyle.position!="relative")m+=f[c];return m}return this.each(function(){this.repeating=false;this.spinCfg={min:a&&!isNaN(parseFloat(a.min))?Number(a.min):null,max:a&&!isNaN(parseFloat(a.max))?Number(a.max):null,step:a&&a.step?Number(a.step):1,stepfunc:a&&a.stepfunc?a.stepfunc:false,page:a&&a.page?Number(a.page):10,upClass:a&&a.upClass?a.upClass:"up",downClass:a&&a.downClass? -a.downClass:"down",reset:a&&a.reset?a.reset:this.value,delay:a&&a.delay?Number(a.delay):500,interval:a&&a.interval?Number(a.interval):100,_btn_width:20,_direction:null,_delay:null,_repeat:null,callback:a&&a.callback?a.callback:null};this.spinCfg.smallStep=a&&a.smallStep?a.smallStep:this.spinCfg.step/2;this.adjustValue=function(f){f=isNaN(this.value)?this.spinCfg.reset:$.isFunction(this.spinCfg.stepfunc)?this.spinCfg.stepfunc(this,f):Number((Number(this.value)+Number(f)).toFixed(5));if(this.spinCfg.min!== -null)f=Math.max(f,this.spinCfg.min);if(this.spinCfg.max!==null)f=Math.min(f,this.spinCfg.max);this.value=f;$.isFunction(this.spinCfg.callback)&&this.spinCfg.callback(this)};$(this).addClass(a&&a.spinClass?a.spinClass:"spin-button").mousemove(function(f){var c=f.pageX||f.x,m=f.pageY||f.y;f=f.target||f.srcElement;var p=svgEditor.tool_scale||1,b=$(f).height()/2;c=c>n(f,"offsetLeft")+f.offsetWidth*p-this.spinCfg._btn_width?m<n(f,"offsetTop")+b*p?1:-1:0;if(c!==this.spinCfg._direction){switch(c){case 1:$(this).removeClass(this.spinCfg.downClass).addClass(this.spinCfg.upClass); -break;case -1:$(this).removeClass(this.spinCfg.upClass).addClass(this.spinCfg.downClass);break;default:$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass)}this.spinCfg._direction=c}}).mouseout(function(){$(this).removeClass(this.spinCfg.upClass).removeClass(this.spinCfg.downClass);this.spinCfg._direction=null;window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).mousedown(function(f){if(f.button===0&&this.spinCfg._direction!=0){var c=this, -m=f.shiftKey?c.spinCfg.smallStep:c.spinCfg.step,p=function(){c.adjustValue(c.spinCfg._direction*m)};p();c.spinCfg._delay=window.setTimeout(function(){p();c.spinCfg._repeat=window.setInterval(p,c.spinCfg.interval)},c.spinCfg.delay)}}).mouseup(function(){window.clearInterval(this.spinCfg._repeat);window.clearTimeout(this.spinCfg._delay)}).dblclick(function(){$.browser.msie&&this.adjustValue(this.spinCfg._direction*this.spinCfg.step)}).keydown(function(f){switch(f.keyCode){case 38:this.adjustValue(this.spinCfg.step); -break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}}).keypress(function(f){if(this.repeating)switch(f.keyCode){case 38:this.adjustValue(this.spinCfg.step);break;case 40:this.adjustValue(-this.spinCfg.step);break;case 33:this.adjustValue(this.spinCfg.page);break;case 34:this.adjustValue(-this.spinCfg.page)}else this.repeating=true}).keyup(function(f){this.repeating=false;switch(f.keyCode){case 38:case 40:case 33:case 34:case 13:this.adjustValue(0)}}).bind("mousewheel", -function(f){if(f.wheelDelta>=120)this.adjustValue(this.spinCfg.step);else f.wheelDelta<=-120&&this.adjustValue(-this.spinCfg.step);f.preventDefault()}).change(function(){this.adjustValue(0)});this.addEventListener&&this.addEventListener("DOMMouseScroll",function(f){if(f.detail>0)this.adjustValue(-this.spinCfg.step);else f.detail<0&&this.adjustValue(this.spinCfg.step);f.preventDefault()},false)})};function touchHandler(a){var n=a.changedTouches,f=n[0],c="";switch(a.type){case "touchstart":c="mousedown";break;case "touchmove":c="mousemove";break;case "touchend":c="mouseup";break;default:return}var m=document.createEvent("MouseEvent");m.initMouseEvent(c,true,true,window,1,f.screenX,f.screenY,f.clientX,f.clientY,false,false,false,false,0,null);if(n.length<2){f.target.dispatchEvent(m);a.preventDefault()}};jQuery&&function(){var a=$(window),n=$(document);$.extend($.fn,{contextMenu:function(f,c){if(f.menu==undefined)return false;if(f.inSpeed==undefined)f.inSpeed=150;if(f.outSpeed==undefined)f.outSpeed=75;if(f.inSpeed==0)f.inSpeed=-1;if(f.outSpeed==0)f.outSpeed=-1;$(this).each(function(){var m=$(this),p=$(m).offset(),b=$("#"+f.menu);b.addClass("contextMenu");$(this).bind("mousedown",function(d){$(this).mouseup(function(e){var l=$(this);l.unbind("mouseup");$(".contextMenu").hide();if(d.button===2||f.allowLeft|| -d.ctrlKey&&svgedit.browser.isMac()){e.stopPropagation();if(m.hasClass("disabled"))return false;var u=e.pageX,z=e.pageY;e=a.width()-b.width();var o=a.height()-b.height();if(u>e-15)u=e-15;if(z>o-30)z=o-30;n.unbind("click");b.css({top:z,left:u}).fadeIn(f.inSpeed);b.find("A").mouseover(function(){b.find("LI.hover").removeClass("hover");$(this).parent().addClass("hover")}).mouseout(function(){b.find("LI.hover").removeClass("hover")});n.keypress(function(L){switch(L.keyCode){case 38:if(b.find("LI.hover").length){b.find("LI.hover").removeClass("hover").prevAll("LI:not(.disabled)").eq(0).addClass("hover"); -b.find("LI.hover").length||b.find("LI:last").addClass("hover")}else b.find("LI:last").addClass("hover");break;case 40:if(b.find("LI.hover").length==0)b.find("LI:first").addClass("hover");else{b.find("LI.hover").removeClass("hover").nextAll("LI:not(.disabled)").eq(0).addClass("hover");b.find("LI.hover").length||b.find("LI:first").addClass("hover")}break;case 13:b.find("LI.hover A").trigger("click");break;case 27:n.trigger("click")}});b.find("A").unbind("mouseup");b.find("LI:not(.disabled) A").mouseup(function(){n.unbind("click").unbind("keypress"); -$(".contextMenu").hide();c&&c($(this).attr("href").substr(1),$(l),{x:u-p.left,y:z-p.top,docX:u,docY:z});return false});setTimeout(function(){n.click(function(){n.unbind("click").unbind("keypress");b.fadeOut(f.outSpeed);return false})},0)}})});if($.browser.mozilla)$("#"+f.menu).each(function(){$(this).css({MozUserSelect:"none"})});else $.browser.msie?$("#"+f.menu).each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})}):$("#"+f.menu).each(function(){$(this).bind("mousedown.disableTextSelect", -function(){return false})});$(m).add($("UL.contextMenu")).bind("contextmenu",function(){return false})});return $(this)},disableContextMenuItems:function(f){if(f==undefined){$(this).find("LI").addClass("disabled");return $(this)}$(this).each(function(){if(f!=undefined)for(var c=f.split(","),m=0;m<c.length;m++)$(this).find('A[href="'+c[m]+'"]').parent().addClass("disabled")});return $(this)},enableContextMenuItems:function(f){if(f==undefined){$(this).find("LI.disabled").removeClass("disabled");return $(this)}$(this).each(function(){if(f!= -undefined)for(var c=f.split(","),m=0;m<c.length;m++)$(this).find('A[href="'+c[m]+'"]').parent().removeClass("disabled")});return $(this)},disableContextMenu:function(){$(this).each(function(){$(this).addClass("disabled")});return $(this)},enableContextMenu:function(){$(this).each(function(){$(this).removeClass("disabled")});return $(this)},destroyContextMenu:function(){$(this).each(function(){$(this).unbind("mousedown").unbind("mouseup")});return $(this)}})}(jQuery);var svgedit=svgedit||{}; -(function(){if(!svgedit.browser)svgedit.browser={};var a=!!document.createElementNS&&!!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect;svgedit.browser.supportsSvg=function(){return a};if(svgedit.browser.supportsSvg()){var n=navigator.userAgent,f=document.createElementNS("http://www.w3.org/2000/svg","svg"),c=!!window.opera,m=n.indexOf("AppleWebKit")>=0,p=n.indexOf("Gecko/")>=0,b=n.indexOf("MSIE")>=0,d=n.indexOf("Chrome/")>=0,e=n.indexOf("Windows")>=0,l=n.indexOf("Macintosh")>= -0,u="ontouchstart"in window,z=!!f.querySelector,o=!!document.evaluate,L=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","path");sa.setAttribute("d","M0,0 10,10");var ja=sa.pathSegList;sa=sa.createSVGPathSegLinetoAbs(5,5);try{ja.replaceItem(sa,0);return true}catch(ca){}return false}(),T=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","path");sa.setAttribute("d","M0,0 10,10");var ja=sa.pathSegList;sa=sa.createSVGPathSegLinetoAbs(5,5);try{ja.insertItemBefore(sa, -0);return true}catch(ca){}return false}(),N=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","svg"),ja=document.createElementNS("http://www.w3.org/2000/svg","svg");document.documentElement.appendChild(sa);ja.setAttribute("x",5);sa.appendChild(ja);var ca=document.createElementNS("http://www.w3.org/2000/svg","text");ca.textContent="a";ja.appendChild(ca);ja=ca.getStartPositionOfChar(0).x;document.documentElement.removeChild(sa);return ja===0}(),J=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg", -"svg");document.documentElement.appendChild(sa);var ja=document.createElementNS("http://www.w3.org/2000/svg","path");ja.setAttribute("d","M0,0 C0,0 10,10 10,0");sa.appendChild(ja);ja=ja.getBBox();document.documentElement.removeChild(sa);return ja.height>4&&ja.height<5}(),da=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","svg");document.documentElement.appendChild(sa);var ja=document.createElementNS("http://www.w3.org/2000/svg","path");ja.setAttribute("d","M0,0 10,0");var ca= -document.createElementNS("http://www.w3.org/2000/svg","path");ca.setAttribute("d","M5,0 15,0");var ea=document.createElementNS("http://www.w3.org/2000/svg","g");ea.appendChild(ja);ea.appendChild(ca);sa.appendChild(ea);ja=ea.getBBox();document.documentElement.removeChild(sa);return ja.width==15}(),V=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","rect");sa.setAttribute("x",0.1);(sa=sa.cloneNode(false).getAttribute("x").indexOf(",")==-1)||$.alert("NOTE: This version of Opera is known to contain bugs in SVG-edit.\n\t\tPlease upgrade to the <a href='http://opera.com'>latest version</a> in which the problems have been fixed."); -return sa}(),O=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","rect");sa.setAttribute("style","vector-effect:non-scaling-stroke");return sa.style.vectorEffect==="non-scaling-stroke"}(),fa=function(){var sa=document.createElementNS("http://www.w3.org/2000/svg","rect").transform.baseVal,ja=f.createSVGTransform();sa.appendItem(ja);return sa.getItem(0)==ja}();svgedit.browser.isOpera=function(){return c};svgedit.browser.isWebkit=function(){return m};svgedit.browser.isGecko=function(){return p}; -svgedit.browser.isIE=function(){return b};svgedit.browser.isChrome=function(){return d};svgedit.browser.isWindows=function(){return e};svgedit.browser.isMac=function(){return l};svgedit.browser.isTouch=function(){return u};svgedit.browser.supportsSelectors=function(){return z};svgedit.browser.supportsXpath=function(){return o};svgedit.browser.supportsPathReplaceItem=function(){return L};svgedit.browser.supportsPathInsertItemBefore=function(){return T};svgedit.browser.supportsPathBBox=function(){return J}; -svgedit.browser.supportsHVLineContainerBBox=function(){return da};svgedit.browser.supportsGoodTextCharPos=function(){return N};svgedit.browser.supportsEditableText=function(){return c};svgedit.browser.supportsGoodDecimals=function(){return V};svgedit.browser.supportsNonScalingStroke=function(){return O};svgedit.browser.supportsNativeTransformLists=function(){return fa}}else window.location="browser-not-supported.html"})();svgedit=svgedit||{}; -(function(){if(!svgedit.transformlist)svgedit.transformlist={};var a=document.createElementNS("http://www.w3.org/2000/svg","svg"),n={};svgedit.transformlist.SVGTransformList=function(f){this._elem=f||null;this._xforms=[];this._update=function(){var c="";a.createSVGMatrix();for(var m=0;m<this.numberOfItems;++m){var p=this._list.getItem(m);c=c;p=p;var b=p.matrix,d="";switch(p.type){case 1:d="matrix("+[b.a,b.b,b.c,b.d,b.e,b.f].join(",")+")";break;case 2:d="translate("+b.e+","+b.f+")";break;case 3:d= -b.a==b.d?"scale("+b.a+")":"scale("+b.a+","+b.d+")";break;case 4:var e=0;d=0;if(p.angle!=0){e=1-b.a;d=(e*b.f+b.b*b.e)/(e*e+b.b*b.b);e=(b.e-b.b*d)/e}d="rotate("+p.angle+" "+e+","+d+")"}c=c+(d+" ")}this._elem.setAttribute("transform",c)};this._list=this;this._init=function(){var c=this._elem.getAttribute("transform");if(c)for(var m=/\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/,p=true;p;){p=c.match(m);c=c.replace(m,"");if(p&&p[1]){var b=p[1].split(/\s*\(/),d=b[0];b=b[1].match(/\s*(.*?)\s*\)/); -b[1]=b[1].replace(/(\d)-/g,"$1 -");var e=b[1].split(/[, ]+/),l="abcdef".split(""),u=a.createSVGMatrix();$.each(e,function(L,T){e[L]=parseFloat(T);if(d=="matrix")u[l[L]]=e[L]});b=a.createSVGTransform();var z="set"+d.charAt(0).toUpperCase()+d.slice(1),o=d=="matrix"?[u]:e;if(d=="scale"&&o.length==1)o.push(o[0]);else if(d=="translate"&&o.length==1)o.push(0);else if(d=="rotate"&&o.length==1){o.push(0);o.push(0)}b[z].apply(b,o);this._list.appendItem(b)}}};this._removeFromOtherLists=function(c){if(c){var m= -false,p;for(p in n){for(var b=n[p],d=0,e=b._xforms.length;d<e;++d)if(b._xforms[d]==c){m=true;b.removeItem(d);break}if(m)break}}};this.numberOfItems=0;this.clear=function(){this.numberOfItems=0;this._xforms=[]};this.initialize=function(c){this.numberOfItems=1;this._removeFromOtherLists(c);this._xforms=[c]};this.getItem=function(c){if(c<this.numberOfItems&&c>=0)return this._xforms[c];throw{code:1};};this.insertItemBefore=function(c,m){var p=null;if(m>=0)if(m<this.numberOfItems){this._removeFromOtherLists(c); -p=Array(this.numberOfItems+1);for(var b=0;b<m;++b)p[b]=this._xforms[b];p[b]=c;for(var d=b+1;b<this.numberOfItems;++d,++b)p[d]=this._xforms[b];this.numberOfItems++;this._xforms=p;p=c;this._list._update()}else p=this._list.appendItem(c);return p};this.replaceItem=function(c,m){var p=null;if(m<this.numberOfItems&&m>=0){this._removeFromOtherLists(c);p=this._xforms[m]=c;this._list._update()}return p};this.removeItem=function(c){if(c<this.numberOfItems&&c>=0){for(var m=this._xforms[c],p=Array(this.numberOfItems- -1),b=0;b<c;++b)p[b]=this._xforms[b];for(c=b;c<this.numberOfItems-1;++c,++b)p[c]=this._xforms[b+1];this.numberOfItems--;this._xforms=p;this._list._update();return m}else throw{code:1};};this.appendItem=function(c){this._removeFromOtherLists(c);this._xforms.push(c);this.numberOfItems++;this._list._update();return c}};svgedit.transformlist.resetListMap=function(){n={}};svgedit.transformlist.removeElementFromListMap=function(f){f.id&&n[f.id]&&delete n[f.id]};svgedit.transformlist.getTransformList=function(f){if(svgedit.browser.supportsNativeTransformLists())if(f.transform)return f.transform.baseVal; -else if(f.gradientTransform)return f.gradientTransform.baseVal;else{if(f.patternTransform)return f.patternTransform.baseVal}else{var c=f.id;c||(c="temp");var m=n[c];if(!m||c=="temp"){n[c]=new svgedit.transformlist.SVGTransformList(f);n[c]._init();m=n[c]}return m}return null}})();svgedit=svgedit||{}; -(function(){if(!svgedit.math)svgedit.math={};var a=document.createElementNS("http://www.w3.org/2000/svg","svg");svgedit.math.transformPoint=function(n,f,c){return{x:c.a*n+c.c*f+c.e,y:c.b*n+c.d*f+c.f}};svgedit.math.isIdentity=function(n){return n.a===1&&n.b===0&&n.c===0&&n.d===1&&n.e===0&&n.f===0};svgedit.math.matrixMultiply=function(){for(var n=arguments,f=n.length,c=n[f-1];f-- >1;)c=n[f-1].multiply(c);if(Math.abs(c.a)<1.0E-14)c.a=0;if(Math.abs(c.b)<1.0E-14)c.b=0;if(Math.abs(c.c)<1.0E-14)c.c=0;if(Math.abs(c.d)< -1.0E-14)c.d=0;if(Math.abs(c.e)<1.0E-14)c.e=0;if(Math.abs(c.f)<1.0E-14)c.f=0;return c};svgedit.math.hasMatrixTransform=function(n){if(!n)return false;for(var f=n.numberOfItems;f--;){var c=n.getItem(f);if(c.type==1&&!svgedit.math.isIdentity(c.matrix))return true}return false};svgedit.math.transformBox=function(n,f,c,m,p){var b={x:n,y:f},d={x:n+c,y:f};c={x:n+c,y:f+m};n={x:n,y:f+m};f=svgedit.math.transformPoint;b=f(b.x,b.y,p);var e=m=b.x,l=b.y,u=b.y;d=f(d.x,d.y,p);m=Math.min(m,d.x);e=Math.max(e,d.x); -l=Math.min(l,d.y);u=Math.max(u,d.y);n=f(n.x,n.y,p);m=Math.min(m,n.x);e=Math.max(e,n.x);l=Math.min(l,n.y);u=Math.max(u,n.y);c=f(c.x,c.y,p);m=Math.min(m,c.x);e=Math.max(e,c.x);l=Math.min(l,c.y);u=Math.max(u,c.y);return{tl:b,tr:d,bl:n,br:c,aabox:{x:m,y:l,width:e-m,height:u-l}}};svgedit.math.transformListToTransform=function(n,f,c){if(n==null)return a.createSVGTransformFromMatrix(a.createSVGMatrix());f=f==undefined?0:f;c=c==undefined?n.numberOfItems-1:c;f=parseInt(f);c=parseInt(c);if(f>c){var m=c;c=f; -f=m}m=a.createSVGMatrix();for(f=f;f<=c;++f){var p=f>=0&&f<n.numberOfItems?n.getItem(f).matrix:a.createSVGMatrix();m=svgedit.math.matrixMultiply(m,p)}return a.createSVGTransformFromMatrix(m)};svgedit.math.getMatrix=function(n){n=svgedit.transformlist.getTransformList(n);return svgedit.math.transformListToTransform(n).matrix};svgedit.math.snapToAngle=function(n,f,c,m){var p=Math.PI/4;c=c-n;var b=m-f;m=Math.sqrt(c*c+b*b);p=Math.round(Math.atan2(b,c)/p)*p;return{x:n+m*Math.cos(p),y:f+m*Math.sin(p),a:p}}; -svgedit.math.rectsIntersect=function(n,f){return f.x<n.x+n.width&&f.x+f.width>n.x&&f.y<n.y+n.height&&f.y+f.height>n.y}})();svgedit=svgedit||{}; -(function(){if(!svgedit.units)svgedit.units={};var a=["x","x1","cx","rx","width"],n=["y","y1","cy","ry","height"],f=$.merge(["r","radius"],a);$.merge(f,n);var c,m={px:1};svgedit.units.init=function(b){c=b;b=document.createElementNS("http://www.w3.org/2000/svg","svg");document.body.appendChild(b);var d=document.createElementNS("http://www.w3.org/2000/svg","rect");d.setAttribute("width","1em");d.setAttribute("height","1ex");d.setAttribute("x","1in");b.appendChild(d);d=d.getBBox();document.body.removeChild(b); -b=d.x;m.em=d.width;m.ex=d.height;m["in"]=b;m.cm=b/2.54;m.mm=b/25.4;m.pt=b/72;m.pc=b/6;m["%"]=0};svgedit.units.getTypeMap=function(){return m};svgedit.units.shortFloat=function(b){var d=c.getRoundDigits();if(isNaN(b)){if($.isArray(b))return svgedit.units.shortFloat(b[0])+","+svgedit.units.shortFloat(b[1])}else return+(+b).toFixed(d);return parseFloat(b).toFixed(d)-0};svgedit.units.convertUnit=function(b,d){d=d||c.getBaseUnit();return svgedit.unit.shortFloat(b/m[d])};svgedit.units.setUnitAttr=function(b, -d,e){isNaN(e)||b.getAttribute(d);b.setAttribute(d,e)};var p={line:["x1","x2","y1","y2"],circle:["cx","cy","r"],ellipse:["cx","cy","rx","ry"],foreignObject:["x","y","width","height"],rect:["x","y","width","height"],image:["x","y","width","height"],use:["x","y","width","height"],text:["x","y"]};svgedit.units.convertAttrs=function(b){var d=b.tagName,e=c.getBaseUnit();if(d=p[d])for(var l=d.length,u=0;u<l;u++){var z=d[u],o=b.getAttribute(z);if(o)isNaN(o)||b.setAttribute(z,o/m[e]+e)}};svgedit.units.convertToNum= -function(b,d){if(!isNaN(d))return d-0;if(d.substr(-1)==="%"){var e=d.substr(0,d.length-1)/100,l=c.getWidth(),u=c.getHeight();return a.indexOf(b)>=0?e*l:n.indexOf(b)>=0?e*u:e*Math.sqrt(l*l+u*u)/Math.sqrt(2)}else{l=d.substr(-2);e=d.substr(0,d.length-2);return e*m[l]}};svgedit.units.isValidUnit=function(b,d,e){var l=false;if(f.indexOf(b)>=0)if(isNaN(d)){d=d.toLowerCase();$.each(m,function(o){if(!l)if(RegExp("^-?[\\d\\.]+"+o+"$").test(d))l=true})}else l=true;else if(b=="id"){b=false;try{var u=c.getElement(d); -b=u==null||u===e}catch(z){}return b}else l=true;return l}})();svgedit=svgedit||{}; -(function(){function a(b){if(svgedit.browser.supportsHVLineContainerBBox())try{return b.getBBox()}catch(d){}var e=$.data(b,"ref"),l=null;if(e){var u=$(e).children().clone().attr("visibility","hidden");$(p).append(u);l=u.filter("line, path")}else l=$(b).find("line, path");var z=false;if(l.length){l.each(function(){var o=this.getBBox();if(!o.width||!o.height)z=true});if(z){b=e?u:$(b).children();ret=getStrokedBBox(b)}else ret=b.getBBox()}else ret=b.getBBox();e&&u.remove();return ret}if(!svgedit.utilities)svgedit.utilities= -{};var n="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use".split(","),f=null,c=null,m=null,p=null;svgedit.utilities.init=function(b){f=b;c=b.getDOMDocument();m=b.getDOMContainer();p=b.getSVGRoot()};svgedit.utilities.toXml=function(b){return $("<p/>").text(b).html()};svgedit.utilities.fromXml=function(b){return $("<p/>").html(b).text()};svgedit.utilities.encode64=function(b){b=svgedit.utilities.convertToXMLReferences(b);if(window.btoa)return window.btoa(b); -var d=Array(Math.floor((b.length+2)/3)*4),e,l,u,z,o,L,T=0,N=0;do{e=b.charCodeAt(T++);l=b.charCodeAt(T++);u=b.charCodeAt(T++);z=e>>2;e=(e&3)<<4|l>>4;o=(l&15)<<2|u>>6;L=u&63;if(isNaN(l))o=L=64;else if(isNaN(u))L=64;d[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(z);d[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(e);d[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(o);d[N++]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(L)}while(T< -b.length);return d.join("")};svgedit.utilities.decode64=function(b){if(window.atob)return window.atob(b);var d="",e,l,u="",z,o="",L=0;b=b.replace(/[^A-Za-z0-9\+\/\=]/g,"");do{e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(b.charAt(L++));l="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(b.charAt(L++));z="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(b.charAt(L++));o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".indexOf(b.charAt(L++)); -e=e<<2|l>>4;l=(l&15)<<4|z>>2;u=(z&3)<<6|o;d+=String.fromCharCode(e);if(z!=64)d+=String.fromCharCode(l);if(o!=64)d+=String.fromCharCode(u)}while(L<b.length);return unescape(d)};svgedit.utilities.convertToXMLReferences=function(b){for(var d="",e=0;e<b.length;e++){var l=b.charCodeAt(e);if(l<128)d+=b[e];else if(l>127)d+="&#"+l+";"}return d};svgedit.utilities.text2xml=function(b){if(b.indexOf("<svg:svg")>=0)b=b.replace(/<(\/?)svg:/g,"<$1").replace("xmlns:svg","xmlns");var d;try{var e=window.DOMParser? -new DOMParser:new ActiveXObject("Microsoft.XMLDOM");e.async=false}catch(l){throw Error("XML Parser could not be instantiated");}try{d=e.loadXML?e.loadXML(b)?e:false:e.parseFromString(b,"text/xml")}catch(u){throw Error("Error parsing XML string");}return d};svgedit.utilities.bboxToObj=function(b){return{x:b.x,y:b.y,width:b.width,height:b.height}};svgedit.utilities.walkTree=function(b,d){if(b&&b.nodeType==1){d(b);for(var e=b.childNodes.length;e--;)svgedit.utilities.walkTree(b.childNodes.item(e),d)}}; -svgedit.utilities.walkTreePost=function(b,d){if(b&&b.nodeType==1){for(var e=b.childNodes.length;e--;)svgedit.utilities.walkTree(b.childNodes.item(e),d);d(b)}};svgedit.utilities.getUrlFromAttr=function(b){if(b)if(b.indexOf('url("')===0)return b.substring(5,b.indexOf('"',6));else if(b.indexOf("url('")===0)return b.substring(5,b.indexOf("'",6));else if(b.indexOf("url(")===0)return b.substring(4,b.indexOf(")"));return null};svgedit.utilities.getHref=function(b){return b.getAttributeNS("http://www.w3.org/1999/xlink", -"href")};svgedit.utilities.setHref=function(b,d){b.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",d)};svgedit.utilities.findDefs=function(b){b=f.getSVGContent().documentElement;var d=b.getElementsByTagNameNS("http://www.w3.org/2000/svg","defs");return d=d.length>0?d[0]:b.insertBefore(b.ownerDocument.createElementNS("http://www.w3.org/2000/svg","defs"),b.firstChild.nextSibling)};svgedit.utilities.getPathBBox=function(b){var d=b.pathSegList,e=d.numberOfItems;b=[[],[]];var l=d.getItem(0), -u=[l.x,l.y];for(l=0;l<e;l++){var z=d.getItem(l);if(typeof z.x!="undefined"){b[0].push(u[0]);b[1].push(u[1]);if(z.x1){for(var o=[z.x1,z.y1],L=[z.x2,z.y2],T=[z.x,z.y],N=0;N<2;N++){z=function(fa){return Math.pow(1-fa,3)*u[N]+3*Math.pow(1-fa,2)*fa*o[N]+3*(1-fa)*Math.pow(fa,2)*L[N]+Math.pow(fa,3)*T[N]};var J=6*u[N]-12*o[N]+6*L[N],da=-3*u[N]+9*o[N]-9*L[N]+3*T[N],V=3*o[N]-3*u[N];if(da==0){if(J!=0){J=-V/J;0<J&&J<1&&b[N].push(z(J))}}else{V=Math.pow(J,2)-4*V*da;if(!(V<0)){var O=(-J+Math.sqrt(V))/(2*da);0<O&& -O<1&&b[N].push(z(O));J=(-J-Math.sqrt(V))/(2*da);0<J&&J<1&&b[N].push(z(J))}}}u=T}else{b[0].push(z.x);b[1].push(z.y)}}}d=Math.min.apply(null,b[0]);e=Math.max.apply(null,b[0])-d;l=Math.min.apply(null,b[1]);b=Math.max.apply(null,b[1])-l;return{x:d,y:l,width:e,height:b}};svgedit.utilities.getBBox=function(b){var d=b||f.geSelectedElements()[0];if(b.nodeType!=1)return null;b=null;var e=d.nodeName;switch(e){case "text":if(d.textContent===""){d.textContent="a";b=d.getBBox();d.textContent=""}else try{b=d.getBBox()}catch(l){}break; -case "path":if(svgedit.browser.supportsPathBBox())try{b=d.getBBox()}catch(u){}else b=svgedit.utilities.getPathBBox(d);break;case "g":case "a":b=a(d);break;default:if(e==="use")b=a(d,true);if(e==="use"){b||(b=d.getBBox());if(!svgedit.browser.isWebkit()){e={};e.width=b.width;e.height=b.height;e.x=b.x+parseFloat(d.getAttribute("x")||0);e.y=b.y+parseFloat(d.getAttribute("y")||0);b=e}}else if(~n.indexOf(e))try{b=d.getBBox()}catch(z){d=$(d).closest("foreignObject");if(d.length)try{b=d[0].getBBox()}catch(o){b= -null}else b=null}}if(b)b=svgedit.utilities.bboxToObj(b);return b};svgedit.utilities.getRotationAngle=function(b,d){var e=b||f.getSelectedElements()[0];e=svgedit.transformlist.getTransformList(e);if(!e)return 0;for(var l=e.numberOfItems,u=0;u<l;++u){var z=e.getItem(u);if(z.type==4)return d?z.angle*Math.PI/180:z.angle}return 0};svgedit.utilities.getElem=svgedit.browser.supportsSelectors()?function(b){return p.querySelector("#"+b)}:svgedit.browser.supportsXpath()?function(b){return c.evaluate('svg:svg[@id="svgroot"]//svg:*[@id="'+ -b+'"]',m,function(){return"http://www.w3.org/2000/svg"},9,null).singleNodeValue}:function(b){return $(p).find("[id="+b+"]")[0]};svgedit.utilities.assignAttributes=function(b,d,e,l){e||(e=0);svgedit.browser.isOpera()||p.suspendRedraw(e);for(var u in d)if(e=u.substr(0,4)==="xml:"?"http://www.w3.org/XML/1998/namespace":u.substr(0,6)==="xlink:"?"http://www.w3.org/1999/xlink":null)b.setAttributeNS(e,u,d[u]);else l?svgedit.units.setUnitAttr(b,u,d[u]):b.setAttribute(u,d[u]);svgedit.browser.isOpera()||p.unsuspendRedraw(null)}; -svgedit.utilities.cleanupElement=function(b){var d=p.suspendRedraw(60),e={"fill-opacity":1,"stop-opacity":1,opacity:1,stroke:"none","stroke-dasharray":"none","stroke-linejoin":"miter","stroke-linecap":"butt","stroke-opacity":1,"stroke-width":1,rx:0,ry:0},l;for(l in e){var u=e[l];b.getAttribute(l)==u&&b.removeAttribute(l)}p.unsuspendRedraw(d)}})();svgedit=svgedit||{}; -(function(){if(!svgedit.sanitize)svgedit.sanitize={};var a={};a["http://www.w3.org/1999/xlink"]="xlink";a["http://www.w3.org/XML/1998/namespace"]="xml";a["http://www.w3.org/2000/xmlns/"]="xmlns";a["http://svg-edit.googlecode.com"]="se";a["http://www.w3.org/1999/xhtml"]="xhtml";a["http://www.w3.org/1998/Math/MathML"]="mathml";var n={};$.each(a,function(m,p){n[p]=m});var f={a:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","id","mask","opacity","stroke","stroke-dasharray", -"stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","xlink:href","xlink:title"],circle:["class","clip-path","clip-rule","cx","cy","fill","fill-opacity","fill-rule","filter","id","mask","opacity","r","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],clipPath:["class", -"clipPathUnits","id"],defs:[],style:["type"],desc:[],ellipse:["class","clip-path","clip-rule","cx","cy","fill","fill-opacity","fill-rule","filter","id","mask","opacity","requiredFeatures","rx","ry","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],feGaussianBlur:["class","color-interpolation-filters","id","requiredFeatures","stdDeviation"],filter:["class","color-interpolation-filters", -"filterRes","filterUnits","height","id","primitiveUnits","requiredFeatures","width","x","xlink:href","y"],foreignObject:["class","font-size","height","id","opacity","requiredFeatures","style","transform","width","x","y"],g:["class","clip-path","clip-rule","id","display","fill","fill-opacity","fill-rule","filter","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage", -"transform","font-family","font-size","font-style","font-weight","text-anchor"],image:["class","clip-path","clip-rule","filter","height","id","mask","opacity","requiredFeatures","style","systemLanguage","transform","width","x","xlink:href","xlink:title","y"],line:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","id","marker-end","marker-mid","marker-start","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin", -"stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","x1","x2","y1","y2"],linearGradient:["class","id","gradientTransform","gradientUnits","requiredFeatures","spreadMethod","systemLanguage","x1","x2","xlink:href","y1","y2"],marker:["id","class","markerHeight","markerUnits","markerWidth","orient","preserveAspectRatio","refX","refY","systemLanguage","viewBox"],mask:["class","height","id","maskContentUnits","maskUnits","width","x","y"],metadata:["class","id"],path:["class", -"clip-path","clip-rule","d","fill","fill-opacity","fill-rule","filter","id","marker-end","marker-mid","marker-start","mask","opacity","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],pattern:["class","height","id","patternContentUnits","patternTransform","patternUnits","requiredFeatures","style","systemLanguage","viewBox","width","x","xlink:href","y"],polygon:["class", -"clip-path","clip-rule","id","fill","fill-opacity","fill-rule","filter","id","class","marker-end","marker-mid","marker-start","mask","opacity","points","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],polyline:["class","clip-path","clip-rule","id","fill","fill-opacity","fill-rule","filter","marker-end","marker-mid","marker-start","mask","opacity","points", -"requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform"],radialGradient:["class","cx","cy","fx","fy","gradientTransform","gradientUnits","id","r","requiredFeatures","spreadMethod","systemLanguage","xlink:href"],rect:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","height","id","mask","opacity","requiredFeatures","rx","ry","stroke","stroke-dasharray", -"stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","width","x","y"],stop:["class","id","offset","requiredFeatures","stop-color","stop-opacity","style","systemLanguage"],svg:["class","clip-path","clip-rule","filter","id","height","mask","preserveAspectRatio","requiredFeatures","style","systemLanguage","viewBox","width","x","xmlns","xmlns:se","xmlns:xlink","y"],"switch":["class","id","requiredFeatures","systemLanguage"], -symbol:["class","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight","id","opacity","preserveAspectRatio","requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","transform","viewBox"],text:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight","id","mask","opacity", -"requiredFeatures","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","text-anchor","transform","x","xml:space","y"],textPath:["class","id","method","requiredFeatures","spacing","startOffset","style","systemLanguage","transform","xlink:href"],title:[],tspan:["class","clip-path","clip-rule","dx","dy","fill","fill-opacity","fill-rule","filter","font-family","font-size","font-style","font-weight", -"id","mask","opacity","requiredFeatures","rotate","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","style","systemLanguage","text-anchor","textLength","transform","x","xml:space","y"],use:["class","clip-path","clip-rule","fill","fill-opacity","fill-rule","filter","height","id","mask","stroke","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width", -"style","transform","width","x","xlink:href","y"],annotation:["encoding"],"annotation-xml":["encoding"],maction:["actiontype","other","selection"],math:["class","id","display","xmlns"],menclose:["notation"],merror:[],mfrac:["linethickness"],mi:["mathvariant"],mmultiscripts:[],mn:[],mo:["fence","lspace","maxsize","minsize","rspace","stretchy"],mover:[],mpadded:["lspace","width","height","depth","voffset"],mphantom:[],mprescripts:[],mroot:[],mrow:["xlink:href","xlink:type","xmlns:xlink"],mspace:["depth", -"height","width"],msqrt:[],mstyle:["displaystyle","mathbackground","mathcolor","mathvariant","scriptlevel"],msub:[],msubsup:[],msup:[],mtable:["align","columnalign","columnlines","columnspacing","displaystyle","equalcolumns","equalrows","frame","rowalign","rowlines","rowspacing","width"],mtd:["columnalign","columnspan","rowalign","rowspan"],mtext:[],mtr:["columnalign","rowalign"],munder:[],munderover:[],none:[],semantics:[]},c={};$.each(f,function(m,p){var b={};$.each(p,function(d,e){if(e.indexOf(":")>= -0){var l=e.split(":");b[l[1]]=n[l[0]]}else b[e]=e=="xmlns"?"http://www.w3.org/2000/xmlns/":null});c[m]=b});svgedit.sanitize.getNSMap=function(){return a};svgedit.sanitize.sanitizeSvg=function(m){if(m.nodeType==3){m.nodeValue=m.nodeValue.replace(/^\s+|\s+$/g,"");m.nodeValue.length||m.parentNode.removeChild(m)}if(m.nodeType==1){var p=m.parentNode;if(m.ownerDocument&&p){var b=f[m.nodeName],d=c[m.nodeName];if(b!=undefined){for(var e=[],l=m.attributes.length;l--;){var u=m.attributes.item(l),z=u.nodeName, -o=u.localName,L=u.namespaceURI;if(!(d.hasOwnProperty(o)&&L==d[o]&&L!="http://www.w3.org/2000/xmlns/")&&!(L=="http://www.w3.org/2000/xmlns/"&&a[u.nodeValue])){z.indexOf("se:")==0&&e.push([z,u.nodeValue]);m.removeAttributeNS(L,o)}if(svgedit.browser.isGecko())switch(z){case "transform":case "gradientTransform":case "patternTransform":o=u.nodeValue.replace(/(\d)-/g,"$1 -");m.setAttribute(z,o)}if(z=="style"){u=u.nodeValue.split(";");for(z=u.length;z--;){o=u[z].split(":");b.indexOf(o[0])>=0&&m.setAttribute(o[0], -o[1])}m.removeAttribute("style")}}$.each(e,function(T,N){m.setAttributeNS("http://svg-edit.googlecode.com",N[0],N[1])});if((l=svgedit.utilities.getHref(m))&&["filter","linearGradient","pattern","radialGradient","textPath","use"].indexOf(m.nodeName)>=0)if(l[0]!="#"){svgedit.utilities.setHref(m,"");m.removeAttributeNS("http://www.w3.org/1999/xlink","href")}if(m.nodeName=="use"&&!svgedit.utilities.getHref(m))p.removeChild(m);else{$.each(["clip-path","fill","filter","marker-end","marker-mid","marker-start", -"mask","stroke"],function(T,N){var J=m.getAttribute(N);if(J)if((J=svgedit.utilities.getUrlFromAttr(J))&&J[0]!=="#"){m.setAttribute(N,"");m.removeAttribute(N)}});for(l=m.childNodes.length;l--;)svgedit.sanitize.sanitizeSvg(m.childNodes.item(l))}}else{for(b=[];m.hasChildNodes();)b.push(p.insertBefore(m.firstChild,m));p.removeChild(m);for(l=b.length;l--;)svgedit.sanitize.sanitizeSvg(b[l])}}}}})();svgedit=svgedit||{}; -(function(){if(!svgedit.history)svgedit.history={};svgedit.history.HistoryEventTypes={BEFORE_APPLY:"before_apply",AFTER_APPLY:"after_apply",BEFORE_UNAPPLY:"before_unapply",AFTER_UNAPPLY:"after_unapply"};svgedit.history.MoveElementCommand=function(a,n,f,c){this.elem=a;this.text=c?"Move "+a.tagName+" to "+c:"Move "+a.tagName;this.oldNextSibling=n;this.oldParent=f;this.newNextSibling=a.nextSibling;this.newParent=a.parentNode};svgedit.history.MoveElementCommand.type=function(){return"svgedit.history.MoveElementCommand"};svgedit.history.MoveElementCommand.prototype.type= -svgedit.history.MoveElementCommand.type;svgedit.history.MoveElementCommand.prototype.getText=function(){return this.text};svgedit.history.MoveElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);this.elem=this.newParent.insertBefore(this.elem,this.newNextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.MoveElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, -this);this.elem=this.oldParent.insertBefore(this.elem,this.oldNextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.MoveElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.InsertElementCommand=function(a,n){this.elem=a;this.text=n||"Create "+a.tagName;this.parent=a.parentNode;this.nextSibling=this.elem.nextSibling};svgedit.history.InsertElementCommand.type=function(){return"svgedit.history.InsertElementCommand"};svgedit.history.InsertElementCommand.prototype.type= -svgedit.history.InsertElementCommand.type;svgedit.history.InsertElementCommand.prototype.getText=function(){return this.text};svgedit.history.InsertElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);this.elem=this.parent.insertBefore(this.elem,this.nextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.InsertElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, -this);this.parent=this.elem.parentNode;this.elem=this.elem.parentNode.removeChild(this.elem);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.InsertElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.RemoveElementCommand=function(a,n,f,c){this.elem=a;this.text=c||"Delete "+a.tagName;this.nextSibling=n;this.parent=f;svgedit.transformlist.removeElementFromListMap(a)};svgedit.history.RemoveElementCommand.type=function(){return"svgedit.history.RemoveElementCommand"}; -svgedit.history.RemoveElementCommand.prototype.type=svgedit.history.RemoveElementCommand.type;svgedit.history.RemoveElementCommand.prototype.getText=function(){return this.text};svgedit.history.RemoveElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);svgedit.transformlist.removeElementFromListMap(this.elem);this.parent=this.elem.parentNode;this.elem=this.parent.removeChild(this.elem);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, -this)};svgedit.history.RemoveElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);svgedit.transformlist.removeElementFromListMap(this.elem);this.nextSibling==null&&window.console&&console.log("Error: reference element was lost");this.parent.insertBefore(this.elem,this.nextSibling);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this)};svgedit.history.RemoveElementCommand.prototype.elements=function(){return[this.elem]}; -svgedit.history.ChangeElementCommand=function(a,n,f){this.elem=a;this.text=f?"Change "+a.tagName+" "+f:"Change "+a.tagName;this.newValues={};this.oldValues=n;for(var c in n)this.newValues[c]=c=="#text"?a.textContent:c=="#href"?svgedit.utilities.getHref(a):a.getAttribute(c)};svgedit.history.ChangeElementCommand.type=function(){return"svgedit.history.ChangeElementCommand"};svgedit.history.ChangeElementCommand.prototype.type=svgedit.history.ChangeElementCommand.type;svgedit.history.ChangeElementCommand.prototype.getText= -function(){return this.text};svgedit.history.ChangeElementCommand.prototype.apply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);var n=false,f;for(f in this.newValues){if(this.newValues[f])if(f=="#text")this.elem.textContent=this.newValues[f];else f=="#href"?svgedit.utilities.setHref(this.elem,this.newValues[f]):this.elem.setAttribute(f,this.newValues[f]);else if(f=="#text")this.elem.textContent="";else{this.elem.setAttribute(f,"");this.elem.removeAttribute(f)}if(f== -"transform")n=true}if(!n)if(n=svgedit.utilities.getRotationAngle(this.elem)){f=elem.getBBox();n=["rotate(",n," ",f.x+f.width/2,",",f.y+f.height/2,")"].join("");n!=elem.getAttribute("transform")&&elem.setAttribute("transform",n)}a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this);return true};svgedit.history.ChangeElementCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);var n=false,f;for(f in this.oldValues){if(this.oldValues[f])if(f== -"#text")this.elem.textContent=this.oldValues[f];else f=="#href"?svgedit.utilities.setHref(this.elem,this.oldValues[f]):this.elem.setAttribute(f,this.oldValues[f]);else if(f=="#text")this.elem.textContent="";else this.elem.removeAttribute(f);if(f=="transform")n=true}if(!n)if(n=svgedit.utilities.getRotationAngle(this.elem)){f=elem.getBBox();n=["rotate(",n," ",f.x+f.width/2,",",f.y+f.height/2,")"].join("");n!=elem.getAttribute("transform")&&elem.setAttribute("transform",n)}svgedit.transformlist.removeElementFromListMap(this.elem); -a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY,this);return true};svgedit.history.ChangeElementCommand.prototype.elements=function(){return[this.elem]};svgedit.history.BatchCommand=function(a){this.text=a||"Batch Command";this.stack=[]};svgedit.history.BatchCommand.type=function(){return"svgedit.history.BatchCommand"};svgedit.history.BatchCommand.prototype.type=svgedit.history.BatchCommand.type;svgedit.history.BatchCommand.prototype.getText=function(){return this.text};svgedit.history.BatchCommand.prototype.apply= -function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY,this);for(var n=this.stack.length,f=0;f<n;++f)this.stack[f].apply(a);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY,this)};svgedit.history.BatchCommand.prototype.unapply=function(a){a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY,this);for(var n=this.stack.length-1;n>=0;n--)this.stack[n].unapply(a);a&&a.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, -this)};svgedit.history.BatchCommand.prototype.elements=function(){for(var a=[],n=this.stack.length;n--;)for(var f=this.stack[n].elements(),c=f.length;c--;)a.indexOf(f[c])==-1&&a.push(f[c]);return a};svgedit.history.BatchCommand.prototype.addSubCommand=function(a){this.stack.push(a)};svgedit.history.BatchCommand.prototype.isEmpty=function(){return this.stack.length==0};svgedit.history.UndoManager=function(a){this.handler_=a||null;this.undoStackPointer=0;this.undoStack=[];this.undoChangeStackPointer= --1;this.undoableChangeStack=[]};svgedit.history.UndoManager.prototype.resetUndoStack=function(){this.undoStack=[];this.undoStackPointer=0};svgedit.history.UndoManager.prototype.getUndoStackSize=function(){return this.undoStackPointer};svgedit.history.UndoManager.prototype.getRedoStackSize=function(){return this.undoStack.length-this.undoStackPointer};svgedit.history.UndoManager.prototype.getNextUndoCommandText=function(){return this.undoStackPointer>0?this.undoStack[this.undoStackPointer-1].getText(): -""};svgedit.history.UndoManager.prototype.getNextRedoCommandText=function(){return this.undoStackPointer<this.undoStack.length?this.undoStack[this.undoStackPointer].getText():""};svgedit.history.UndoManager.prototype.undo=function(){this.undoStackPointer>0&&this.undoStack[--this.undoStackPointer].unapply(this.handler_)};svgedit.history.UndoManager.prototype.redo=function(){this.undoStackPointer<this.undoStack.length&&this.undoStack.length>0&&this.undoStack[this.undoStackPointer++].apply(this.handler_)}; -svgedit.history.UndoManager.prototype.addCommandToHistory=function(a){if(this.undoStackPointer<this.undoStack.length&&this.undoStack.length>0)this.undoStack=this.undoStack.splice(0,this.undoStackPointer);this.undoStack.push(a);this.undoStackPointer=this.undoStack.length};svgedit.history.UndoManager.prototype.beginUndoableChange=function(a,n){for(var f=++this.undoChangeStackPointer,c=n.length,m=Array(c),p=Array(c);c--;){var b=n[c];if(b!=null){p[c]=b;m[c]=b.getAttribute(a)}}this.undoableChangeStack[f]= -{attrName:a,oldValues:m,elements:p}};svgedit.history.UndoManager.prototype.finishUndoableChange=function(){for(var a=this.undoChangeStackPointer--,n=this.undoableChangeStack[a],f=n.elements.length,c=n.attrName,m=new svgedit.history.BatchCommand("Change "+c);f--;){var p=n.elements[f];if(p!=null){var b={};b[c]=n.oldValues[f];b[c]!=p.getAttribute(c)&&m.addSubCommand(new svgedit.history.ChangeElementCommand(p,b,c))}}this.undoableChangeStack[a]=null;return m}})();svgedit=svgedit||{}; -(function(){if(!svgedit.select)svgedit.select={};var a,n,f;svgedit.select.Selector=function(c,m){this.id=c;this.selectedElement=m;this.locked=true;this.selectorGroup=a.createSVGElement({element:"g",attr:{id:"selectorGroup"+this.id}});this.selectorRect=this.selectorGroup.appendChild(a.createSVGElement({element:"path",attr:{id:"selectedBox"+this.id,fill:"none",stroke:"#4F80FF","stroke-width":"1",style:"pointer-events:none"}}));this.gripCoords={nw:null,n:null,ne:null,e:null,se:null,s:null,sw:null,w:null}; -this.reset(this.selectedElement)};svgedit.select.Selector.prototype.reset=function(c){this.locked=true;this.selectedElement=c;this.resize();this.selectorGroup.setAttribute("display","inline")};svgedit.select.Selector.prototype.updateGripCursors=function(c){var m=[];c=Math.round(c/45);if(c<0)c+=8;for(var p in f.selectorGrips)m.push(p);for(;c>0;){m.push(m.shift());c--}c=0;for(p in f.selectorGrips){f.selectorGrips[p].setAttribute("style","cursor:"+m[c]+"-resize");c++}};svgedit.select.Selector.prototype.showGrips= -function(c){f.selectorGripsGroup.setAttribute("display",c?"inline":"none");var m=this.selectedElement;this.hasGrips=c;if(m&&c){this.selectorGroup.appendChild(f.selectorGripsGroup);this.updateGripCursors(svgedit.utilities.getRotationAngle(m))}};svgedit.select.Selector.prototype.resize=function(){var c=this.selectorRect,m=f,p=m.selectorGrips,b=this.selectedElement,d=b.getAttribute("stroke-width"),e=a.currentZoom(),l=1/e;if(b.getAttribute("stroke")!=="none"&&!isNaN(d))l+=d/2;var u=b.tagName;if(u==="text")l+= -2/e;d=svgedit.transformlist.getTransformList(b);d=svgedit.math.transformListToTransform(d).matrix;d.e*=e;d.f*=e;var z=svgedit.utilities.getBBox(b);if(u==="g"&&!$.data(b,"gsvg"))if(u=a.getStrokedBBox(b.childNodes))z=u;u=z.x;var o=z.y,L=z.width;z=z.height;l*=e;e=svgedit.math.transformBox(u*e,o*e,L*e,z*e,d);d=e.aabox;u=d.x-l;o=d.y-l;L=d.width+l*2;var T=d.height+l*2;d=u+L/2;z=o+T/2;if(b=svgedit.utilities.getRotationAngle(b)){u=a.svgRoot().createSVGTransform();u.setRotate(-b,d,z);u=u.matrix;e.tl=svgedit.math.transformPoint(e.tl.x, -e.tl.y,u);e.tr=svgedit.math.transformPoint(e.tr.x,e.tr.y,u);e.bl=svgedit.math.transformPoint(e.bl.x,e.bl.y,u);e.br=svgedit.math.transformPoint(e.br.x,e.br.y,u);u=e.tl;L=u.x;T=u.y;var N=u.x,J=u.y;u=Math.min;o=Math.max;L=u(L,u(e.tr.x,u(e.bl.x,e.br.x)))-l;T=u(T,u(e.tr.y,u(e.bl.y,e.br.y)))-l;N=o(N,o(e.tr.x,o(e.bl.x,e.br.x)))+l;J=o(J,o(e.tr.y,o(e.bl.y,e.br.y)))+l;u=L;o=T;L=N-L;T=J-T}l=a.svgRoot().suspendRedraw(100);c.setAttribute("d","M"+u+","+o+" L"+(u+L)+","+o+" "+(u+L)+","+(o+T)+" "+u+","+(o+T)+"z"); -this.selectorGroup.setAttribute("transform",b?"rotate("+[b,d,z].join(",")+")":"");u-=3.5;o-=3.5;this.gripCoords={nw:[u,o],ne:[u+L,o],sw:[u,o+T],se:[u+L,o+T],n:[u+L/2,o],w:[u,o+T/2],e:[u+L,o+T/2],s:[u+L/2,o+T]};for(var da in this.gripCoords){c=this.gripCoords[da];p[da].setAttribute("x",c[0]);p[da].setAttribute("y",c[1])}this.rotateCoords={nw:[u,o],ne:[u+L+8,o],sw:[u,o+T+8],se:[u+L+8,o+T+8]};for(da in this.rotateCoords){c=this.rotateCoords[da];m.rotateGrips[da].setAttribute("cx",c[0]);m.rotateGrips[da].setAttribute("cy", -c[1])}a.svgRoot().unsuspendRedraw(l)};svgedit.select.SelectorManager=function(){this.rubberBandBox=this.selectorParentGroup=null;this.selectors=[];this.selectorMap={};this.selectorGrips={nw:null,n:null,ne:null,e:null,se:null,s:null,sw:null,w:null};this.selectorGripsGroup=null;this.rotateGrips={nw:null,ne:null,se:null,sw:null};this.initGroup()};svgedit.select.SelectorManager.prototype.initGroup=function(){this.selectorParentGroup&&this.selectorParentGroup.parentNode&&this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup); -this.selectorParentGroup=a.createSVGElement({element:"g",attr:{id:"selectorParentGroup"}});this.selectorGripsGroup=a.createSVGElement({element:"g",attr:{display:"none"}});this.selectorParentGroup.appendChild(this.selectorGripsGroup);a.svgRoot().appendChild(this.selectorParentGroup);this.selectorMap={};this.selectors=[];this.rubberBandBox=null;for(var c in this.rotateGrips){var m=a.createSVGElement({element:"circle",attr:{id:"selectorGrip_rotate_"+c,fill:"transparent",r:8,stroke:"transparent","stroke-width":0, -style:"cursor:url("+n.imgPath+"rotate.png) 12 12, auto;"}});$.data(m,"dir",c);$.data(m,"type","rotate");this.rotateGrips[c]=this.selectorGripsGroup.appendChild(m)}for(c in this.selectorGrips){m=a.createSVGElement({element:"rect",attr:{id:"selectorGrip_resize_"+c,width:7,height:7,fill:"#4F80FF",stroke:"transparent","stroke-width":2,style:"cursor:"+c+"-resize","pointer-events":"all"}});$.data(m,"dir",c);$.data(m,"type","resize");this.selectorGrips[c]=this.selectorGripsGroup.appendChild(m)}if(!$("#canvasBackground").length){c= -n.dimensions;c=a.createSVGElement({element:"svg",attr:{id:"canvasBackground",width:c[0],height:c[1],x:0,y:0,overflow:svgedit.browser.isWebkit()?"none":"visible",style:"pointer-events:none"}});m=a.createSVGElement({element:"rect",attr:{width:"100%",height:"100%",x:0,y:0,"stroke-width":1,stroke:"#000",fill:"#FFF",style:"pointer-events:none"}});c.appendChild(m);a.svgRoot().insertBefore(c,a.svgContent())}};svgedit.select.SelectorManager.prototype.requestSelector=function(c){if(c==null)return null;var m= -this.selectors.length;if(typeof this.selectorMap[c.id]=="object"){this.selectorMap[c.id].locked=true;return this.selectorMap[c.id]}for(var p=0;p<m;++p)if(this.selectors[p]&&!this.selectors[p].locked){this.selectors[p].locked=true;this.selectors[p].reset(c);this.selectorMap[c.id]=this.selectors[p];return this.selectors[p]}this.selectors[m]=new svgedit.select.Selector(m,c);this.selectorParentGroup.appendChild(this.selectors[m].selectorGroup);this.selectorMap[c.id]=this.selectors[m];return this.selectors[m]}; -svgedit.select.SelectorManager.prototype.releaseSelector=function(c){if(c!=null)for(var m=this.selectors.length,p=this.selectorMap[c.id],b=0;b<m;++b)if(this.selectors[b]&&this.selectors[b]==p){p.locked==false&&console.log("WARNING! selector was released but was already unlocked");delete this.selectorMap[c.id];p.locked=false;p.selectedElement=null;p.showGrips(false);try{p.selectorGroup.setAttribute("display","none")}catch(d){}break}};svgedit.select.SelectorManager.prototype.getRubberBandBox=function(){if(!this.rubberBandBox)this.rubberBandBox= -this.selectorParentGroup.appendChild(a.createSVGElement({element:"rect",attr:{id:"selectorRubberBand",fill:"transparent",stroke:"#666","stroke-width":1,"stroke-dasharray":"3,2",display:"none",style:"pointer-events:none"}}));return this.rubberBandBox};svgedit.select.init=function(c,m){n=c;a=m;f=new svgedit.select.SelectorManager};svgedit.select.getSelectorManager=function(){return f}})();svgedit=svgedit||{}; -(function(){if(!svgedit.draw)svgedit.draw={};var a="a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use".split(","),n={LET_DOCUMENT_DECIDE:0,ALWAYS_RANDOMIZE:1,NEVER_RANDOMIZE:2},f=n.LET_DOCUMENT_DECIDE;svgedit.draw.Layer=function(c,m){this.name_=c;this.group_=m};svgedit.draw.Layer.prototype.getName=function(){return this.name_};svgedit.draw.Layer.prototype.getGroup=function(){return this.group_};svgedit.draw.randomizeIds=function(c,m){f=c==false?n.NEVER_RANDOMIZE: -n.ALWAYS_RANDOMIZE;if(f==n.ALWAYS_RANDOMIZE&&!m.getNonce())m.setNonce(Math.floor(Math.random()*100001));else f==n.NEVER_RANDOMIZE&&m.getNonce()&&m.clearNonce()};svgedit.draw.Drawing=function(c,m){if(!c||!c.tagName||!c.namespaceURI||c.tagName!="svg"||c.namespaceURI!="http://www.w3.org/2000/svg")throw"Error: svgedit.draw.Drawing instance initialized without a <svg> element";this.svgElem_=c;this.obj_num=0;this.idPrefix=m||"svg_";this.releasedNums=[];this.all_layers=[];this.current_layer=null;this.nonce_= -"";var p=this.svgElem_.getAttributeNS("http://svg-edit.googlecode.com","nonce");if(p&&f!=n.NEVER_RANDOMIZE)this.nonce_=p;else f==n.ALWAYS_RANDOMIZE&&this.setNonce(Math.floor(Math.random()*100001))};svgedit.draw.Drawing.prototype.getElem_=function(c){return this.svgElem_.querySelector?this.svgElem_.querySelector("#"+c):$(this.svgElem_).find("[id="+c+"]")[0]};svgedit.draw.Drawing.prototype.getSvgElem=function(){return this.svgElem_};svgedit.draw.Drawing.prototype.getNonce=function(){return this.nonce_}; -svgedit.draw.Drawing.prototype.setNonce=function(c){this.svgElem_.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:se","http://svg-edit.googlecode.com");this.svgElem_.setAttributeNS("http://svg-edit.googlecode.com","se:nonce",c);this.nonce_=c};svgedit.draw.Drawing.prototype.clearNonce=function(){this.nonce_=""};svgedit.draw.Drawing.prototype.getId=function(){return this.nonce_?this.idPrefix+this.nonce_+"_"+this.obj_num:this.idPrefix+this.obj_num};svgedit.draw.Drawing.prototype.getNextId=function(){var c= -this.obj_num,m=false;if(this.releasedNums.length>0){this.obj_num=this.releasedNums.pop();m=true}else this.obj_num++;for(var p=this.getId();this.getElem_(p);){if(m){this.obj_num=c;m=false}this.obj_num++;p=this.getId()}if(m)this.obj_num=c;return p};svgedit.draw.Drawing.prototype.releaseId=function(c){var m=this.idPrefix+(this.nonce_?this.nonce_+"_":"");if(typeof c!="string"||c.indexOf(m)!=0)return false;c=parseInt(c.substr(m.length));if(typeof c!="number"||c<=0||this.releasedNums.indexOf(c)!=-1)return false; -this.releasedNums.push(c);return true};svgedit.draw.Drawing.prototype.getNumLayers=function(){return this.all_layers.length};svgedit.draw.Drawing.prototype.hasLayer=function(c){for(var m=0;m<this.getNumLayers();m++)if(this.all_layers[m][0]==c)return true;return false};svgedit.draw.Drawing.prototype.getLayerName=function(c){if(c>=0&&c<this.getNumLayers())return this.all_layers[c][0];return""};svgedit.draw.Drawing.prototype.getCurrentLayer=function(){return this.current_layer};svgedit.draw.Drawing.prototype.getCurrentLayerName= -function(){for(var c=0;c<this.getNumLayers();++c)if(this.all_layers[c][1]==this.current_layer)return this.getLayerName(c);return""};svgedit.draw.Drawing.prototype.setCurrentLayer=function(c){for(var m=0;m<this.getNumLayers();++m)if(c==this.getLayerName(m)){if(this.current_layer!=this.all_layers[m][1]){this.current_layer.setAttribute("style","pointer-events:none");this.current_layer=this.all_layers[m][1];this.current_layer.setAttribute("style","pointer-events:all")}return true}return false};svgedit.draw.Drawing.prototype.deleteCurrentLayer= -function(){if(this.current_layer&&this.getNumLayers()>1){var c=this.current_layer.parentNode.removeChild(this.current_layer);this.identifyLayers();return c}return null};svgedit.draw.Drawing.prototype.identifyLayers=function(){this.all_layers=[];for(var c=this.svgElem_.childNodes.length,m=[],p=[],b=null,d=false,e=0;e<c;++e){var l=this.svgElem_.childNodes.item(e);if(l&&l.nodeType==1)if(l.tagName=="g"){d=true;var u=$("title",l).text();if(!u&&svgedit.browser.isOpera()&&l.querySelectorAll)u=$(l.querySelectorAll("title")).text(); -if(u){p.push(u);this.all_layers.push([u,l]);b=l;svgedit.utilities.walkTree(l,function(z){z.setAttribute("style","pointer-events:inherit")});b.setAttribute("style","pointer-events:none")}else m.push(l)}else if(~a.indexOf(l.nodeName)){svgedit.utilities.getBBox(l);m.push(l)}}c=this.svgElem_.ownerDocument;if(m.length>0||!d){for(e=1;p.indexOf("Layer "+e)>=0;)e++;p="Layer "+e;b=c.createElementNS("http://www.w3.org/2000/svg","g");d=c.createElementNS("http://www.w3.org/2000/svg","title");d.textContent=p; -b.appendChild(d);for(d=0;d<m.length;++d)b.appendChild(m[d]);this.svgElem_.appendChild(b);this.all_layers.push([p,b])}svgedit.utilities.walkTree(b,function(z){z.setAttribute("style","pointer-events:inherit")});this.current_layer=b;this.current_layer.setAttribute("style","pointer-events:all")};svgedit.draw.Drawing.prototype.createLayer=function(c){var m=this.svgElem_.ownerDocument,p=m.createElementNS("http://www.w3.org/2000/svg","g");m=m.createElementNS("http://www.w3.org/2000/svg","title");m.textContent= -c;p.appendChild(m);this.svgElem_.appendChild(p);this.identifyLayers();return p};svgedit.draw.Drawing.prototype.getLayerVisibility=function(c){for(var m=null,p=0;p<this.getNumLayers();++p)if(this.getLayerName(p)==c){m=this.all_layers[p][1];break}if(!m)return false;return m.getAttribute("display")!="none"};svgedit.draw.Drawing.prototype.setLayerVisibility=function(c,m){if(typeof m!="boolean")return null;for(var p=null,b=0;b<this.getNumLayers();++b)if(this.getLayerName(b)==c){p=this.all_layers[b][1]; -break}if(!p)return null;p.getAttribute("display");p.setAttribute("display",m?"inline":"none");return p};svgedit.draw.Drawing.prototype.getLayerOpacity=function(c){for(var m=0;m<this.getNumLayers();++m)if(this.getLayerName(m)==c){(c=this.all_layers[m][1].getAttribute("opacity"))||(c="1.0");return parseFloat(c)}return null};svgedit.draw.Drawing.prototype.setLayerOpacity=function(c,m){if(!(typeof m!="number"||m<0||m>1))for(var p=0;p<this.getNumLayers();++p)if(this.getLayerName(p)==c){this.all_layers[p][1].setAttribute("opacity", -m);break}}})();svgedit=svgedit||{}; -(function(){if(!svgedit.path)svgedit.path={};var a={pathNodeTooltip:"Drag node to move it. Double-click node to change segment type",pathCtrlPtTooltip:"Drag control point to adjust curve properties"},n={2:["x","y"],4:["x","y"],6:["x","y","x1","y1","x2","y2"],8:["x","y","x1","y1"],10:["x","y","r1","r2","angle","largeArcFlag","sweepFlag"],12:["x"],14:["y"],16:["x","y","x2","y2"],18:["x","y"]},f=[],c=true,m={};svgedit.path.setLinkControlPoints=function(d){c=d};var p=svgedit.path.path=null;svgedit.path.init= -function(d){p=d;f=[0,"ClosePath"];$.each(["Moveto","Lineto","CurvetoCubic","CurvetoQuadratic","Arc","LinetoHorizontal","LinetoVertical","CurvetoCubicSmooth","CurvetoQuadraticSmooth"],function(e,l){f.push(l+"Abs");f.push(l+"Rel")})};svgedit.path.insertItemBefore=function(d,e,l){d=d.pathSegList;if(svgedit.browser.supportsPathInsertItemBefore())d.insertItemBefore(e,l);else{for(var u=d.numberOfItems,z=[],o=0;o<u;o++){var L=d.getItem(o);z.push(L)}d.clear();for(o=0;o<u;o++){o==l&&d.appendItem(e);d.appendItem(z[o])}}}; -svgedit.path.ptObjToArr=function(d,e){for(var l=n[d],u=l.length,z=Array(u),o=0;o<u;o++)z[o]=e[l[o]];return z};svgedit.path.getGripPt=function(d,e){var l={x:e?e.x:d.item.x,y:e?e.y:d.item.y},u=d.path;if(u.matrix)l=svgedit.math.transformPoint(l.x,l.y,u.matrix);l.x*=p.getCurrentZoom();l.y*=p.getCurrentZoom();return l};svgedit.path.getPointFromGrip=function(d,e){var l={x:d.x,y:d.y};if(e.matrix){d=svgedit.math.transformPoint(l.x,l.y,e.imatrix);l.x=d.x;l.y=d.y}l.x/=p.getCurrentZoom();l.y/=p.getCurrentZoom(); -return l};svgedit.path.addPointGrip=function(d,e,l){var u=svgedit.path.getGripContainer(),z=svgedit.utilities.getElem("pathpointgrip_"+d);if(!z){z=document.createElementNS("http://www.w3.org/2000/svg","rect");svgedit.utilities.assignAttributes(z,{id:"pathpointgrip_"+d,display:"none",width:5,height:5,fill:"#fff",stroke:"#4F80FF","stroke-width":1,cursor:"move",style:"pointer-events:all","xlink:title":a.pathNodeTooltip});z=u.appendChild(z);$("#pathpointgrip_"+d).dblclick(function(){svgedit.path.path&& -svgedit.path.path.setSegType()})}e&&l&&svgedit.utilities.assignAttributes(z,{x:e-2.5,y:l-2.5,display:"inline"});return z};svgedit.path.getGripContainer=function(){var d=svgedit.utilities.getElem("pathpointgrip_container");if(!d){d=svgedit.utilities.getElem("selectorParentGroup").appendChild(document.createElementNS("http://www.w3.org/2000/svg","g"));d.id="pathpointgrip_container"}return d};svgedit.path.addCtrlGrip=function(d){var e=svgedit.utilities.getElem("ctrlpointgrip_"+d);if(e)return e;e=document.createElementNS("http://www.w3.org/2000/svg", -"circle");svgedit.utilities.assignAttributes(e,{id:"ctrlpointgrip_"+d,display:"none",r:3,fill:"#4F80FF",cursor:"move",style:"pointer-events:all","xlink:title":a.pathCtrlPtTooltip});svgedit.path.getGripContainer().appendChild(e);return e};svgedit.path.getCtrlLine=function(d){var e=svgedit.utilities.getElem("ctrlLine_"+d);if(e)return e;e=document.createElementNS("http://www.w3.org/2000/svg","line");svgedit.utilities.assignAttributes(e,{id:"ctrlLine_"+d,stroke:"#4F80FF","stroke-width":1,style:"pointer-events:none"}); -svgedit.path.getGripContainer().appendChild(e);return e};svgedit.path.getPointGrip=function(d,e){var l=svgedit.path.addPointGrip(d.index);if(e){var u=svgedit.path.getGripPt(d);svgedit.utilities.assignAttributes(l,{x:u.x-2.5,y:u.y-2.5,display:"inline"})}return l};svgedit.path.getControlPoints=function(d){var e=d.item,l=d.index;if(!("x1"in e)||!("x2"in e))return null;var u={};svgedit.path.getGripContainer();for(var z=[svgedit.path.path.segs[l-1].item,e],o=1;o<3;o++){var L=l+"c"+o,T=u["c"+o+"_line"]= -svgedit.path.getCtrlLine(L),N=svgedit.path.getGripPt(d,{x:e["x"+o],y:e["y"+o]}),J=svgedit.path.getGripPt(d,{x:z[o-1].x,y:z[o-1].y});svgedit.utilities.assignAttributes(T,{x1:N.x,y1:N.y,x2:J.x,y2:J.y,display:"inline"});u["c"+o+"_line"]=T;pointGrip=u["c"+o]=svgedit.path.addCtrlGrip(L);svgedit.utilities.assignAttributes(pointGrip,{cx:N.x,cy:N.y,display:"inline"});u["c"+o]=pointGrip}return u};svgedit.path.replacePathSeg=function(d,e,l,u){u=u||svgedit.path.path.elem;d=u["createSVGPathSeg"+f[d]].apply(u, -l);if(svgedit.browser.supportsPathReplaceItem())u.pathSegList.replaceItem(d,e);else{l=u.pathSegList;u=l.numberOfItems;for(var z=[],o=0;o<u;o++){var L=l.getItem(o);z.push(L)}l.clear();for(o=0;o<u;o++)o==e?l.appendItem(d):l.appendItem(z[o])}};svgedit.path.getSegSelector=function(d,e){var l=d.index,u=svgedit.utilities.getElem("segline_"+l);if(!u){var z=svgedit.path.getGripContainer();u=document.createElementNS("http://www.w3.org/2000/svg","path");svgedit.utilities.assignAttributes(u,{id:"segline_"+l, -display:"none",fill:"none",stroke:"#0FF","stroke-width":2,style:"pointer-events:none",d:"M0,0 0,0"});z.appendChild(u)}if(e){l=d.prev;if(!l){u.setAttribute("display","none");return u}l=svgedit.path.getGripPt(l);svgedit.path.replacePathSeg(2,0,[l.x,l.y],u);z=svgedit.path.ptObjToArr(d.type,d.item,true);for(var o=0;o<z.length;o+=2){l=svgedit.path.getGripPt(d,{x:z[o],y:z[o+1]});z[o]=l.x;z[o+1]=l.y}svgedit.path.replacePathSeg(d.type,1,z,u)}return u};svgedit.path.smoothControlPoints=this.smoothControlPoints= -function(d,e,l){var u=d.x-l.x,z=d.y-l.y,o=e.x-l.x,L=e.y-l.y;if((u!=0||z!=0)&&(o!=0||L!=0)){d=Math.atan2(z,u);e=Math.atan2(L,o);u=Math.sqrt(u*u+z*z);o=Math.sqrt(o*o+L*L);z=p.getSVGRoot().createSVGPoint();L=p.getSVGRoot().createSVGPoint();if(d<0)d+=2*Math.PI;if(e<0)e+=2*Math.PI;var T=Math.abs(d-e),N=Math.abs(Math.PI-T)/2;if(d-e>0){d=T<Math.PI?d+N:d-N;e=T<Math.PI?e-N:e+N}else{d=T<Math.PI?d-N:d+N;e=T<Math.PI?e+N:e-N}z.x=u*Math.cos(d)+l.x;z.y=u*Math.sin(d)+l.y;L.x=o*Math.cos(e)+l.x;L.y=o*Math.sin(e)+l.y; -return[z,L]}};svgedit.path.Segment=function(d,e){this.selected=false;this.index=d;this.item=e;this.type=e.pathSegType;this.ctrlpts=[];this.segsel=this.ptgrip=null};svgedit.path.Segment.prototype.showCtrlPts=function(d){for(var e in this.ctrlpts)this.ctrlpts[e].setAttribute("display",d?"inline":"none")};svgedit.path.Segment.prototype.selectCtrls=function(){$("#ctrlpointgrip_"+this.index+"c1, #ctrlpointgrip_"+this.index+"c2").attr("fill","#4F80FF")};svgedit.path.Segment.prototype.show=function(d){if(this.ptgrip){this.ptgrip.setAttribute("display", -d?"inline":"none");this.segsel.setAttribute("display",d?"inline":"none");this.showCtrlPts(d)}};svgedit.path.Segment.prototype.select=function(d){if(this.ptgrip){this.ptgrip.setAttribute("stroke",d?"#0FF":"#00F");this.segsel.setAttribute("display",d?"inline":"none");this.ctrlpts&&this.selectCtrls(d);this.selected=d}};svgedit.path.Segment.prototype.addGrip=function(){this.ptgrip=svgedit.path.getPointGrip(this,true);this.ctrlpts=svgedit.path.getControlPoints(this,true);this.segsel=svgedit.path.getSegSelector(this, -true)};svgedit.path.Segment.prototype.update=function(d){if(this.ptgrip){var e=svgedit.path.getGripPt(this);svgedit.utilities.assignAttributes(this.ptgrip,this.ptgrip.nodeName=="rect"?{x:e.x-2.5,y:e.y-2.5}:{cx:e.x,cy:e.y});svgedit.path.getSegSelector(this,true);if(this.ctrlpts){if(d){this.item=svgedit.path.path.elem.pathSegList.getItem(this.index);this.type=this.item.pathSegType}svgedit.path.getControlPoints(this)}}};svgedit.path.Segment.prototype.move=function(d,e){var l=this.item;l=this.ctrlpts? -[l.x+=d,l.y+=e,l.x1,l.y1,l.x2+=d,l.y2+=e]:[l.x+=d,l.y+=e];svgedit.path.replacePathSeg(this.type,this.index,l);if(this.next&&this.next.ctrlpts){l=this.next.item;l=[l.x,l.y,l.x1+=d,l.y1+=e,l.x2,l.y2];svgedit.path.replacePathSeg(this.next.type,this.next.index,l)}if(this.mate){l=this.mate.item;l=[l.x+=d,l.y+=e];svgedit.path.replacePathSeg(this.mate.type,this.mate.index,l)}this.update(true);this.next&&this.next.update(true)};svgedit.path.Segment.prototype.setLinked=function(d){var e,l,u;if(d==2){l=1;e= -this.next;if(!e)return;u=this.item}else{l=2;e=this.prev;if(!e)return;u=e.item}var z=e.item;z["x"+l]=u.x+(u.x-this.item["x"+d]);z["y"+l]=u.y+(u.y-this.item["y"+d]);svgedit.path.replacePathSeg(e.type,e.index,[z.x,z.y,z.x1,z.y1,z.x2,z.y2]);e.update(true)};svgedit.path.Segment.prototype.moveCtrl=function(d,e,l){var u=this.item;u["x"+d]+=e;u["y"+d]+=l;svgedit.path.replacePathSeg(this.type,this.index,[u.x,u.y,u.x1,u.y1,u.x2,u.y2]);this.update(true)};svgedit.path.Segment.prototype.setType=function(d,e){svgedit.path.replacePathSeg(d, -this.index,e);this.type=d;this.item=svgedit.path.path.elem.pathSegList.getItem(this.index);this.showCtrlPts(d===6);this.ctrlpts=svgedit.path.getControlPoints(this);this.update(true)};svgedit.path.Path=function(d){if(!d||d.tagName!=="path")throw"svgedit.path.Path constructed without a <path> element";this.elem=d;this.segs=[];this.selected_pts=[];svgedit.path.path=this;this.init()};svgedit.path.Path.prototype.init=function(){$(svgedit.path.getGripContainer()).find("*").attr("display","none");var d= -this.elem.pathSegList,e=d.numberOfItems;this.segs=[];this.selected_pts=[];this.first_seg=null;for(var l=0;l<e;l++){var u=d.getItem(l);u=new svgedit.path.Segment(l,u);u.path=this;this.segs.push(u)}d=this.segs;u=null;for(l=0;l<e;l++){var z=d[l],o=l+1>=e?null:d[l+1],L=l-1<0?null:d[l-1];if(z.type===2){if(L&&L.type!==1){o=d[u];o.next=d[u+1];o.next.prev=o;o.addGrip()}u=l}else if(o&&o.type===1){z.next=d[u+1];z.next.prev=z;z.mate=d[u];z.addGrip();if(this.first_seg==null)this.first_seg=z}else if(o){if(z.type!== -1){z.addGrip();if(o&&o.type!==2){z.next=o;z.next.prev=z}}}else if(z.type!==1){o=d[u];o.next=d[u+1];o.next.prev=o;o.addGrip();z.addGrip();if(!this.first_seg)this.first_seg=d[u]}}return this};svgedit.path.Path.prototype.eachSeg=function(d){for(var e=this.segs.length,l=0;l<e;l++)if(d.call(this.segs[l],l)===false)break};svgedit.path.Path.prototype.addSeg=function(d){var e=this.segs[d];if(e.prev){var l=e.prev,u;switch(e.item.pathSegType){case 4:var z=(e.item.x+l.item.x)/2,o=(e.item.y+l.item.y)/2;u=this.elem.createSVGPathSegLinetoAbs(z, -o);break;case 6:u=(l.item.x+e.item.x1)/2;var L=(e.item.x1+e.item.x2)/2,T=(e.item.x2+e.item.x)/2,N=(u+L)/2;L=(L+T)/2;z=(N+L)/2;var J=(l.item.y+e.item.y1)/2,da=(e.item.y1+e.item.y2)/2;l=(e.item.y2+e.item.y)/2;var V=(J+da)/2;da=(da+l)/2;o=(V+da)/2;u=this.elem.createSVGPathSegCurvetoCubicAbs(z,o,u,J,N,V);svgedit.path.replacePathSeg(e.type,d,[e.item.x,e.item.y,L,da,T,l])}svgedit.path.insertItemBefore(this.elem,u,d)}};svgedit.path.Path.prototype.deleteSeg=function(d){var e=this.segs[d],l=this.elem.pathSegList; -e.show(false);var u=e.next;if(e.mate){var z=[u.item.x,u.item.y];svgedit.path.replacePathSeg(2,u.index,z);svgedit.path.replacePathSeg(4,e.index,z);l.removeItem(e.mate.index)}else{if(!e.prev){z=[u.item.x,u.item.y];svgedit.path.replacePathSeg(2,e.next.index,z)}l.removeItem(d)}};svgedit.path.Path.prototype.subpathIsClosed=function(d){var e=false;svgedit.path.path.eachSeg(function(l){if(l<=d)return true;if(this.type===2)return false;else if(this.type===1){e=true;return false}});return e};svgedit.path.Path.prototype.removePtFromSelection= -function(d){var e=this.selected_pts.indexOf(d);if(e!=-1){this.segs[d].select(false);this.selected_pts.splice(e,1)}};svgedit.path.Path.prototype.clearSelection=function(){this.eachSeg(function(){this.select(false)});this.selected_pts=[]};svgedit.path.Path.prototype.storeD=function(){this.last_d=this.elem.getAttribute("d")};svgedit.path.Path.prototype.show=function(d){this.eachSeg(function(){this.show(d)});d&&this.selectPt(this.first_seg.index);return this};svgedit.path.Path.prototype.movePts=function(d, -e){for(var l=this.selected_pts.length;l--;)this.segs[this.selected_pts[l]].move(d,e)};svgedit.path.Path.prototype.moveCtrl=function(d,e){var l=this.segs[this.selected_pts[0]];l.moveCtrl(this.dragctrl,d,e);c&&l.setLinked(this.dragctrl)};svgedit.path.Path.prototype.setSegType=function(d){this.storeD();for(var e=this.selected_pts.length,l;e--;){var u=this.segs[this.selected_pts[e]],z=u.prev;if(z){if(!d){l="Toggle Path Segment Type";d=u.type==6?4:6}d-=0;var o=u.item.x,L=u.item.y,T=z.item.x;z=z.item.y; -var N;switch(d){case 6:if(u.olditem){T=u.olditem;N=[o,L,T.x1,T.y1,T.x2,T.y2]}else{N=o-T;var J=L-z;N=[o,L,T+N/3,z+J/3,o-N/3,L-J/3]}break;case 4:N=[o,L];u.olditem=u.item}u.setType(d,N)}}svgedit.path.path.endChanges(l)};svgedit.path.Path.prototype.selectPt=function(d,e){this.clearSelection();d==null&&this.eachSeg(function(l){if(this.prev)d=l});this.addPtsToSelection(d);if(e){this.dragctrl=e;c&&this.segs[d].setLinked(e)}};svgedit.path.Path.prototype.update=function(){var d=this.elem;if(svgedit.utilities.getRotationAngle(d)){this.matrix= -svgedit.math.getMatrix(d);this.imatrix=this.matrix.inverse()}else this.imatrix=this.matrix=null;this.eachSeg(function(e){this.item=d.pathSegList.getItem(e);this.update()});return this};svgedit.path.getPath_=function(d){var e=m[d.id];e||(e=m[d.id]=new svgedit.path.Path(d));return e};svgedit.path.removePath_=function(d){d in m&&delete m[d]};var b=function(d,e){dx=d-oldcx;dy=e-oldcy;r=Math.sqrt(dx*dx+dy*dy);theta=Math.atan2(dy,dx)+angle;dx=r*Math.cos(theta)+oldcx;dy=r*Math.sin(theta)+oldcy;dx-=newcx; -dy-=newcy;r=Math.sqrt(dx*dx+dy*dy);theta=Math.atan2(dy,dx)-angle;return{x:(r*Math.cos(theta)+newcx)/1,y:(r*Math.sin(theta)+newcy)/1}};svgedit.path.recalcRotatedPath=function(){var d=svgedit.path.path.elem,e=svgedit.utilities.getRotationAngle(d,true);if(e){var l=svgedit.utilities.getBBox(d),u=svgedit.path.path.oldbbox,z=u.x+u.width/2,o=u.y+u.height/2;u=l.x+l.width/2;l=l.y+l.height/2;u=u-z;var L=l-o;l=Math.sqrt(u*u+L*L);L=Math.atan2(L,u)+e;u=l*Math.cos(L)+z;l=l*Math.sin(L)+o;z=d.pathSegList;for(o=z.numberOfItems;o;){o-= -1;L=z.getItem(o);var T=L.pathSegType;if(T!=1){var N=b(L.x,L.y);N=[N.x,N.y];if(L.x1!=null&&L.x2!=null){c_vals1=b(L.x1,L.y1);c_vals2=b(L.x2,L.y2);N.splice(N.length,0,c_vals1.x,c_vals1.y,c_vals2.x,c_vals2.y)}svgedit.path.replacePathSeg(T,o,N)}}svgedit.utilities.getBBox(d);z=svgroot.createSVGTransform();d=svgedit.transformlist.getTransformList(d);z.setRotate(e*180/Math.PI,u,l);d.replaceItem(z,0)}};svgedit.path.clearData=function(){m={}}})();if(!window.console){window.console={};window.console.log=function(){};window.console.dir=function(){}}if(window.opera){window.console.log=function(a){opera.postError(a)};window.console.dir=function(){}} -(function(){var a=jQuery.fn.attr;jQuery.fn.attr=function(n,f){var c=this.length;if(!c)return a.apply(this,arguments);for(var m=0;m<c;m++){var p=this[m];if(p.namespaceURI==="http://www.w3.org/2000/svg")if(f!==undefined)p.setAttribute(n,f);else if($.isArray(n)){c=n.length;for(m={};c--;){var b=n[c],d=p.getAttribute(b);if(d||d==="0")d=isNaN(d)?d:d-0;m[b]=d}return m}else if(typeof n==="object")for(b in n)p.setAttribute(b,n[b]);else{if((d=p.getAttribute(n))||d==="0")d=isNaN(d)?d:d-0;return d}else return a.apply(this, -arguments)}return this}})(); -$.SvgCanvas=function(a,n){function f(g,h){for(var k=svgedit.utilities.getBBox(g),v=0;v<2;v++){var t=v===0?"fill":"stroke",E=g.getAttribute(t);if(E&&E.indexOf("url(")===0){E=X(E);if(E.tagName==="linearGradient"){var w=E.getAttribute("x1")||0,s=E.getAttribute("y1")||0,A=E.getAttribute("x2")||1,F=E.getAttribute("y2")||0;w=k.width*w+k.x;s=k.height*s+k.y;A=k.width*A+k.x;F=k.height*F+k.y;w=O(w,s,h);F=O(A,F,h);A={};A.x1=(w.x-k.x)/k.width;A.y1=(w.y-k.y)/k.height;A.x2=(F.x-k.x)/k.width;A.y2=(F.y-k.y)/k.height; -E=E.cloneNode(true);$(E).attr(A);E.id=M();ub().appendChild(E);g.setAttribute(t,"url(#"+E.id+")")}}}}var c="http://www.w3.org/2000/svg",m={show_outside_canvas:true,selectNew:true,dimensions:[640,480]};n&&$.extend(m,n);var p=m.dimensions,b=this,d=a.ownerDocument,e=d.importNode(svgedit.utilities.text2xml('<svg id="svgroot" xmlns="'+c+'" xlinkns="http://www.w3.org/1999/xlink" width="'+p[0]+'" height="'+p[1]+'" x="'+p[0]+'" y="'+p[1]+'" overflow="visible"><defs><filter id="canvashadow" filterUnits="objectBoundingBox"><feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/><feOffset in="blur" dx="5" dy="5" result="offsetBlur"/><feMerge><feMergeNode in="offsetBlur"/><feMergeNode in="SourceGraphic"/></feMerge></filter></defs></svg>').documentElement, -true);a.appendChild(e);var l=d.createElementNS(c,"svg");(b.clearSvgContentElement=function(){for(;l.firstChild;)l.removeChild(l.firstChild);$(l).attr({id:"svgcontent",width:p[0],height:p[1],x:p[0],y:p[1],overflow:m.show_outside_canvas?"visible":"hidden",xmlns:c,"xmlns:se":"http://svg-edit.googlecode.com","xmlns:xlink":"http://www.w3.org/1999/xlink"}).appendTo(e);var g=d.createComment(" Created with SVG-edit - http://svg-edit.googlecode.com/ ");l.appendChild(g)})();var u="svg_";b.setIdPrefix=function(g){u= -g};b.current_drawing_=new svgedit.draw.Drawing(l,u);var z=b.getCurrentDrawing=function(){return b.current_drawing_},o=1,L=null,T={shape:{fill:(m.initFill.color=="none"?"":"#")+m.initFill.color,fill_paint:null,fill_opacity:m.initFill.opacity,stroke:"#"+m.initStroke.color,stroke_paint:null,stroke_opacity:m.initStroke.opacity,stroke_width:m.initStroke.width,stroke_dasharray:"none",stroke_linejoin:"miter",stroke_linecap:"butt",opacity:m.initOpacity}};T.text=$.extend(true,{},T.shape);$.extend(T.text,{fill:"#000000", -stroke_width:0,font_size:24,font_family:"Junction"});var N=T.shape,J=Array(1),da=this.addSvgElementFromJson=function(g){var h=svgedit.utilities.getElem(g.attr.id),k=z().getCurrentLayer();if(h&&g.element!=h.tagName){k.removeChild(h);h=null}if(!h){h=d.createElementNS(c,g.element);if(k)(L||k).appendChild(h)}g.curStyles&&svgedit.utilities.assignAttributes(h,{fill:N.fill,stroke:N.stroke,"stroke-width":N.stroke_width,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap, -"stroke-opacity":N.stroke_opacity,"fill-opacity":N.fill_opacity,opacity:N.opacity/2,style:"pointer-events:inherit"},100);svgedit.utilities.assignAttributes(h,g.attr,100);svgedit.utilities.cleanupElement(h);return h},V=b.getTransformList=svgedit.transformlist.getTransformList,O=svgedit.math.transformPoint,fa=b.matrixMultiply=svgedit.math.matrixMultiply,sa=b.hasMatrixTransform=svgedit.math.hasMatrixTransform,ja=b.transformListToTransform=svgedit.math.transformListToTransform,ca=svgedit.math.snapToAngle, -ea=svgedit.math.getMatrix;svgedit.units.init({getBaseUnit:function(){return m.baseUnit},getElement:svgedit.utilities.getElem,getHeight:function(){return l.getAttribute("height")/o},getWidth:function(){return l.getAttribute("width")/o},getRoundDigits:function(){return Za.round_digits}});var qa=b.convertToNum=svgedit.units.convertToNum;svgedit.utilities.init({getDOMDocument:function(){return d},getDOMContainer:function(){return a},getSVGRoot:function(){return e},getSelectedElements:function(){return J}, -getSVGContent:function(){return l}});var pa=b.getUrlFromAttr=svgedit.utilities.getUrlFromAttr,ba=b.getHref=svgedit.utilities.getHref,S=b.setHref=svgedit.utilities.setHref,U=svgedit.utilities.getPathBBox;b.getBBox=svgedit.utilities.getBBox;var ra=b.getRotationAngle=svgedit.utilities.getRotationAngle,la=b.getElem=svgedit.utilities.getElem,ma=b.assignAttributes=svgedit.utilities.assignAttributes,Y=this.cleanupElement=svgedit.utilities.cleanupElement,za=svgedit.sanitize.getNSMap(),Ia=b.sanitizeSvg=svgedit.sanitize.sanitizeSvg, -Qa=svgedit.history.MoveElementCommand,Ka=svgedit.history.InsertElementCommand,Ua=svgedit.history.RemoveElementCommand,Wa=svgedit.history.ChangeElementCommand,La=svgedit.history.BatchCommand;b.undoMgr=new svgedit.history.UndoManager({handleHistoryEvent:function(g,h){var k=svgedit.history.HistoryEventTypes;if(g==k.BEFORE_UNAPPLY||g==k.BEFORE_APPLY)b.clearSelection();else if(g==k.AFTER_APPLY||g==k.AFTER_UNAPPLY){var v=h.elements();b.pathActions.clear();I("changed",v);v=h.type();k=g==k.AFTER_APPLY;if(v== -Qa.type()){k=k?h.newParent:h.oldParent;k==l&&b.identifyLayers()}else if(v==Ka.type()||v==Ua.type()){h.parent==l&&b.identifyLayers();if(v==Ka.type())k&&ab(h.elem);else k||ab(h.elem);h.elem.tagName==="use"&&Ub(h.elem)}else if(v==Wa.type()){h.elem.tagName=="title"&&h.elem.parentNode.parentNode==l&&b.identifyLayers();k=k?h.newValues:h.oldValues;k.stdDeviation&&b.setBlurOffsets(h.elem.parentNode,k.stdDeviation);if(h.elem.tagName==="use"&&svgedit.browser.isWebkit()){v=h.elem;if(!v.getAttribute("x")&&!v.getAttribute("y")){k= -v.parentNode;var t=v.nextSibling;k.removeChild(v);k.insertBefore(v,t)}}}}}});var Ga=function(g){b.undoMgr.addCommandToHistory(g)};svgedit.select.init(m,{createSVGElement:function(g){return b.addSvgElementFromJson(g)},svgRoot:function(){return e},svgContent:function(){return l},currentZoom:function(){return o},getStrokedBBox:function(g){return b.getStrokedBBox([g])}});var Oa=this.selectorManager=svgedit.select.getSelectorManager();svgedit.path.init({getCurrentZoom:function(){return o},getSVGRoot:function(){return e}}); -svgedit.utilities.snapToGrid=function(g){var h=m.snappingStep,k=m.baseUnit;if(k!=="px")h*=svgedit.units.getTypeMap()[k];return g=Math.round(g/h)*h};var Fa=svgedit.utilities.snapToGrid,Gb={exportNoBlur:"Blurred elements will appear as un-blurred",exportNoforeignObject:"foreignObject elements will not appear",exportNoDashArray:"Strokes will appear filled",exportNoText:"Text may not appear as expected"},Nb=["clip-path","fill","filter","marker-end","marker-mid","marker-start","mask","stroke"],lb=$.data, -ab=function(g){var h=$(g).attr(Nb),k;for(k in h){var v=h[k];if(v&&v.indexOf("url(")===0){v=pa(v).substr(1);if(!la(v)){ub().appendChild(Bb[v]);delete Bb[v]}}}g=g.getElementsByTagName("*");if(g.length){h=0;for(k=g.length;h<k;h++)ab(g[h])}},Sa={},Ja=m.imgPath+"logo.png",Ea=[],Za={round_digits:5},Ra=false,$a=null,Na="select",mb="none",Ab={},cb=T.text,jb=N,kb=null,Ca=null,wb=[],nb={},yb=null,Bb={};b.clipBoard=[];var ob=this.runExtensions=function(g,h,k){var v=false;if(k)v=[];$.each(nb,function(t,E){if(g in -E)if(k)v.push(E[g](h));else v=E[g](h)});return v};this.addExtension=function(g,h){if(g in nb)console.log('Cannot add extension "'+g+'", an extension by that name already exists"');else{var k=$.isFunction(h)?h($.extend(b.getPrivateMethods(),{svgroot:e,svgcontent:l,nonce:z().getNonce(),selectorManager:Oa})):h;nb[g]=k;I("extension_added",k)}};var Cb=this.round=function(g){return parseInt(g*o)/o},Kb=this.getIntersectionList=function(g){if(Ca==null)return null;var h=L||z().getCurrentLayer();wb.length|| -(wb=Rb(h));var k=null;try{k=h.getIntersectionList(g,null)}catch(v){}if(k==null||typeof k.item!="function"){k=[];if(g)g=g;else{g=Ca.getBBox();h={};for(var t in g)h[t]=g[t]/o;g=h}for(t=wb.length;t--;)g.width&&g.width&&svgedit.math.rectsIntersect(g,wb[t].bbox)&&k.push(wb[t].elem)}return k};getStrokedBBox=this.getStrokedBBox=function(g){g||(g=Ib());if(!g.length)return false;var h=function(F){try{var C=svgedit.utilities.getBBox(F),D=svgedit.utilities.getRotationAngle(F);if(D&&D%90||svgedit.math.hasMatrixTransform(svgedit.transformlist.getTransformList(F))){D= -false;if(["ellipse","path","line","polyline","polygon"].indexOf(F.tagName)>=0)C=D=b.convertToPath(F,true);else if(F.tagName=="rect"){var G=F.getAttribute("rx"),H=F.getAttribute("ry");if(G||H)C=D=b.convertToPath(F,true)}if(!D){var P=F.cloneNode(true),R=document.createElementNS(c,"g"),aa=F.parentNode;aa.appendChild(R);R.appendChild(P);C=svgedit.utilities.bboxToObj(R.getBBox());aa.removeChild(R)}}return C}catch(ua){console.log(F,ua);return null}},k;$.each(g,function(){if(!k)if(this.parentNode)k=h(this)}); -if(k==null)return null;var v=k.x+k.width,t=k.y+k.height,E=k.x,w=k.y,s=function(F){var C=F.getAttribute("stroke-width"),D=0;if(F.getAttribute("stroke")!="none"&&!isNaN(C))D+=C/2;return D},A=[];$.each(g,function(F,C){var D=h(C);if(D){var G=s(C);E=Math.min(E,D.x-G);w=Math.min(w,D.y-G);A.push(D)}});k.x=E;k.y=w;$.each(g,function(F,C){var D=A[F];if(D&&C.nodeType==1){var G=s(C);v=Math.max(v,D.x+D.width+G);t=Math.max(t,D.y+D.height+G)}});k.width=v-E;k.height=t-w;return k};var Ib=this.getVisibleElements=function(g){g|| -(g=$(l).children());var h=[];$(g).children().each(function(k,v){try{v.getBBox()&&h.push(v)}catch(t){}});return h.reverse()},Rb=this.getVisibleElementsAndBBoxes=function(g){g||(g=$(l).children());var h=[];$(g).children().each(function(k,v){try{v.getBBox()&&h.push({elem:v,bbox:getStrokedBBox([v])})}catch(t){}});return h.reverse()},na=this.groupSvgElem=function(g){var h=document.createElementNS(c,"g");g.parentNode.replaceChild(h,g);$(h).append(g).data("gsvg",g)[0].id=M()},Z=function(g){var h=document.createElementNS(g.namespaceURI, -g.nodeName);h.removeAttribute("id");$.each(g.attributes,function(v,t){t.localName!="-moz-math-font-style"&&h.setAttributeNS(t.namespaceURI,t.nodeName,t.nodeValue)});if(svgedit.browser.isWebkit()&&g.nodeName=="path"){var k=Va.convertPath(g);h.setAttribute("d",k)}$.each(g.childNodes,function(v,t){switch(t.nodeType){case 1:h.appendChild(Z(t));break;case 3:h.textContent=t.nodeValue}});if($(g).data("gsvg"))$(h).data("gsvg",h.firstChild);else if($(g).data("symbol")){g=$(g).data("symbol");$(h).data("ref", -g).data("symbol",g)}else h.tagName=="image"&&Zb(h);h.id=M();console.log(h);return h},ta,M,I;(function(g){var h={};ta=g.getId=function(){return z().getId()};M=g.getNextId=function(){return z().getNextId()};I=g.call=function(k,v){if(h[k])return h[k](this,v)};g.bind=function(k,v){var t=h[k];h[k]=v;return t}})(b);this.prepareSvg=function(g){this.sanitizeSvg(g.documentElement);g=g.getElementsByTagNameNS(c,"path");for(var h=0,k=g.length;h<k;++h){var v=g[h];v.setAttribute("d",Va.convertPath(v));Va.fixEnd(v)}}; -var X=this.getRefElem=function(g){return la(pa(g).substr(1))},Ma=function(g){if(!svgedit.browser.isGecko())return g;var h=g.cloneNode(true);g.parentNode.insertBefore(h,g);g.parentNode.removeChild(g);Oa.releaseSelector(g);J[0]=h;Oa.requestSelector(h).showGrips(true);return h};this.setRotationAngle=function(g,h){g=parseFloat(g);var k=J[0],v=k.getAttribute("transform"),t=svgedit.utilities.getBBox(k),E=t.x+t.width/2,w=t.y+t.height/2;t=V(k);t.numberOfItems>0&&t.getItem(0).type==4&&t.removeItem(0);if(g!= -0){E=O(E,w,ja(t).matrix);w=e.createSVGTransform();w.setRotate(g,E.x,E.y);t.numberOfItems?t.insertItemBefore(w,0):t.appendItem(w)}else t.numberOfItems==0&&k.removeAttribute("transform");if(!h){t=k.getAttribute("transform");k.setAttribute("transform",v);vb("transform",t,J);I("changed",J)}la("pathpointgrip_container");k=Oa.requestSelector(J[0]);k.resize();k.updateGripCursors(g)};var Xa=this.recalculateAllSelectedDimensions=function(){for(var g=new La(mb=="none"?"position":"size"),h=J.length;h--;){var k= -pb(J[h]);k&&g.addSubCommand(k)}if(!g.isEmpty()){Ga(g);I("changed",J)}},db=[0,"z","M","m","L","l","C","c","Q","q","A","a","H","h","V","v","S","s","T","t"],tb=function(g){console.log([g.a,g.b,g.c,g.d,g.e,g.f])},xb=this.remapElement=function(g,h,k){var v=m.gridSnapping&&g.parentNode.parentNode.localName==="svg",t=function(){if(v)for(var D in h)h[D]=Fa(h[D]);ma(g,h,1E3,true)};box=svgedit.utilities.getBBox(g);for(var E=0;E<2;E++){var w=E===0?"fill":"stroke",s=g.getAttribute(w);if(s&&s.indexOf("url(")=== -0)if(k.a<0||k.d<0){s=X(s).cloneNode(true);if(k.a<0){var A=s.getAttribute("x1"),F=s.getAttribute("x2");s.setAttribute("x1",-(A-1));s.setAttribute("x2",-(F-1))}if(k.d<0){A=s.getAttribute("y1");F=s.getAttribute("y2");s.setAttribute("y1",-(A-1));s.setAttribute("y2",-(F-1))}s.id=M();ub().appendChild(s);g.setAttribute(w,"url(#"+s.id+")")}}E=g.tagName;if(E==="g"||E==="text"||E==="use")if(k.a==1&&k.b==0&&k.c==0&&k.d==1&&(k.e!=0||k.f!=0)){w=ja(g).matrix;w=fa(w.inverse(),k,w);h.x=parseFloat(h.x)+w.e;h.y=parseFloat(h.y)+ -w.f}else{w=V(g);s=e.createSVGTransform();s.setMatrix(fa(ja(w).matrix,k));w.clear();w.appendItem(s)}switch(E){case "foreignObject":case "rect":case "image":if(E==="image"&&(k.a<0||k.d<0)){w=V(g);s=e.createSVGTransform();s.setMatrix(fa(ja(w).matrix,k));w.clear();w.appendItem(s)}else{w=O(h.x,h.y,k);h.width=k.a*h.width;h.height=k.d*h.height;h.x=w.x+Math.min(0,h.width);h.y=w.y+Math.min(0,h.height);h.width=Math.abs(h.width);h.height=Math.abs(h.height)}t();break;case "ellipse":E=O(h.cx,h.cy,k);h.cx=E.x; -h.cy=E.y;h.rx=k.a*h.rx;h.ry=k.d*h.ry;h.rx=Math.abs(h.rx);h.ry=Math.abs(h.ry);t();break;case "circle":E=O(h.cx,h.cy,k);h.cx=E.x;h.cy=E.y;E=svgedit.math.transformBox(box.x,box.y,box.width,box.height,k);h.r=Math.min((E.tr.x-E.tl.x)/2,(E.bl.y-E.tl.y)/2);if(h.r)h.r=Math.abs(h.r);t();break;case "line":w=O(h.x1,h.y1,k);A=O(h.x2,h.y2,k);h.x1=w.x;h.y1=w.y;h.x2=A.x;h.y2=A.y;case "text":k=g.querySelectorAll("tspan");for(E=k.length;E--;){w=qa("x",g.getAttribute("x"));s=qa("x",k[E].getAttribute("x"));A=qa("y", -g.getAttribute("y"));F=qa("y",k[E].getAttribute("y"));var C={};if(!isNaN(w)&&!isNaN(s)&&w!=0&&s!=0&&h.x)C.x=h.x-(w-s);if(!isNaN(A)&&!isNaN(F)&&A!=0&&F!=0&&h.y)C.y=h.y-(A-F);if(C.x||C.y)ma(k[E],C,1E3,true)}t();break;case "use":t();break;case "g":(t=$(g).data("gsvg"))&&ma(t,h,1E3,true);break;case "polyline":case "polygon":t=h.points.length;for(E=0;E<t;++E){F=h.points[E];F=O(F.x,F.y,k);h.points[E].x=F.x;h.points[E].y=F.y}t=h.points.length;k="";for(E=0;E<t;++E){F=h.points[E];k+=F.x+","+F.y+" "}g.setAttribute("points", -k);break;case "path":w=g.pathSegList;t=w.numberOfItems;h.d=Array(t);for(E=0;E<t;++E){s=w.getItem(E);h.d[E]={type:s.pathSegType,x:s.x,y:s.y,x1:s.x1,y1:s.y1,x2:s.x2,y2:s.y2,r1:s.r1,r2:s.r2,angle:s.angle,largeArcFlag:s.largeArcFlag,sweepFlag:s.sweepFlag}}t=h.d.length;E=h.d[0];C=O(E.x,E.y,k);h.d[0].x=C.x;h.d[0].y=C.y;for(E=1;E<t;++E){s=h.d[E];w=s.type;if(w%2==0){F=O(s.x!=undefined?s.x:C.x,s.y!=undefined?s.y:C.y,k);w=O(s.x1,s.y1,k);A=O(s.x2,s.y2,k);s.x=F.x;s.y=F.y;s.x1=w.x;s.y1=w.y;s.x2=A.x;s.y2=A.y}else{s.x= -k.a*s.x;s.y=k.d*s.y;s.x1=k.a*s.x1;s.y1=k.d*s.y1;s.x2=k.a*s.x2;s.y2=k.d*s.y2}s.r1=k.a*s.r1;s.r2=k.d*s.r2}k="";t=h.d.length;for(E=0;E<t;++E){s=h.d[E];w=s.type;k+=db[w];switch(w){case 13:case 12:k+=s.x+" ";break;case 15:case 14:k+=s.y+" ";break;case 3:case 5:case 19:case 2:case 4:case 18:k+=s.x+","+s.y+" ";break;case 7:case 6:k+=s.x1+","+s.y1+" "+s.x2+","+s.y2+" "+s.x+","+s.y+" ";break;case 9:case 8:k+=s.x1+","+s.y1+" "+s.x+","+s.y+" ";break;case 11:case 10:k+=s.r1+","+s.r2+" "+s.angle+" "+ +s.largeArcFlag+ -" "+ +s.sweepFlag+" "+s.x+","+s.y+" ";break;case 17:case 16:k+=s.x2+","+s.y2+" "+s.x+","+s.y+" "}}g.setAttribute("d",k)}},Hb=function(g,h,k){g=X(g).firstChild;var v=V(g),t=e.createSVGTransform();t.setTranslate(h,k);v.appendItem(t);pb(g)},pb=this.recalculateDimensions=function(g){if(g==null)return null;var h=V(g);if(h&&h.numberOfItems>0){for(var k=h.numberOfItems;k--;){var v=h.getItem(k);if(v.type===0)h.removeItem(k);else if(v.type===1)svgedit.math.isIdentity(v.matrix)&&h.removeItem(k);else v.type=== -4&&v.angle===0&&h.removeItem(k)}if(h.numberOfItems===1&&ra(g))return null}if(!h||h.numberOfItems==0){g.removeAttribute("transform");return null}if(h){k=h.numberOfItems;for(var t=[];k--;){v=h.getItem(k);if(v.type===1)t.push([v.matrix,k]);else if(t.length)t=[]}if(t.length===2){k=e.createSVGTransformFromMatrix(fa(t[1][0],t[0][0]));h.removeItem(t[0][1]);h.removeItem(t[1][1]);h.insertItemBefore(k,t[1][1])}k=h.numberOfItems;if(k>=2&&h.getItem(k-2).type===1&&h.getItem(k-1).type===2){t=e.createSVGTransform(); -v=fa(h.getItem(k-2).matrix,h.getItem(k-1).matrix);t.setMatrix(v);h.removeItem(k-2);h.removeItem(k-2);h.appendItem(t)}}switch(g.tagName){case "line":case "polyline":case "polygon":case "path":break;default:if(h.numberOfItems===1&&h.getItem(0).type===1||h.numberOfItems===2&&h.getItem(0).type===1&&h.getItem(0).type===4)return null}var E=$(g).data("gsvg");k=new La("Transform");var w={},s=null;v=[];switch(g.tagName){case "line":v=["x1","y1","x2","y2"];break;case "circle":v=["cx","cy","r"];break;case "ellipse":v= -["cx","cy","rx","ry"];break;case "foreignObject":case "rect":case "image":v=["width","height","x","y"];break;case "use":case "text":case "tspan":v=["x","y"];break;case "polygon":case "polyline":s={};s.points=g.getAttribute("points");t=g.points;var A=t.numberOfItems;w.points=Array(A);for(var F=0;F<A;++F){var C=t.getItem(F);w.points[F]={x:C.x,y:C.y}}break;case "path":s={};s.d=g.getAttribute("d");w.d=g.getAttribute("d")}if(v.length){w=$(g).attr(v);$.each(w,function(Jb,Ob){w[Jb]=qa(Jb,Ob)})}else if(E)w= -{x:$(E).attr("x")||0,y:$(E).attr("y")||0};if(s==null){s=$.extend(true,{},w);$.each(s,function(Jb,Ob){s[Jb]=qa(Jb,Ob)})}s.transform=$a?$a:"";if(g.tagName=="g"&&!E||g.tagName=="a"){t=svgedit.utilities.getBBox(g);var D={x:t.x+t.width/2,y:t.y+t.height/2},G=O(t.x+t.width/2,t.y+t.height/2,ja(h).matrix);v=e.createSVGMatrix();if(t=ra(g)){F=t*Math.PI/180;A=Math.abs(F)>1.0E-10?Math.sin(F)/(1-Math.cos(F)):2/F;for(F=0;F<h.numberOfItems;++F){v=h.getItem(F);if(v.type==4){v=v.matrix;D.y=(A*v.e+v.f)/2;D.x=(v.e-A* -v.f)/2;h.removeItem(F);break}}}F=v=E=0;var H=h.numberOfItems;if(H)var P=h.getItem(0).matrix;if(H>=3&&h.getItem(H-2).type==3&&h.getItem(H-3).type==2&&h.getItem(H-1).type==2){F=3;var R=h.getItem(H-3).matrix,aa=h.getItem(H-2).matrix,ua=h.getItem(H-1).matrix;A=g.childNodes;for(C=A.length;C--;){var wa=A.item(C);v=E=0;if(wa.nodeType==1){var ha=V(wa);if(ha){v=ja(ha).matrix;E=ra(wa);var ka=$a,oa=[];$a=wa.getAttribute("transform");if(E||sa(ha)){var xa=e.createSVGTransform();xa.setMatrix(fa(R,aa,ua,v));ha.clear(); -ha.appendItem(xa);oa.push(xa)}else{E=fa(v.inverse(),ua,v);xa=e.createSVGMatrix();xa.e=-E.e;xa.f=-E.f;v=fa(xa.inverse(),v.inverse(),R,aa,ua,v,E.inverse());var eb=e.createSVGTransform(),Db=e.createSVGTransform(),Pb=e.createSVGTransform();eb.setTranslate(E.e,E.f);Db.setScale(v.a,v.d);Pb.setTranslate(xa.e,xa.f);ha.appendItem(Pb);ha.appendItem(Db);ha.appendItem(eb);oa.push(Pb);oa.push(Db);oa.push(eb)}k.addSubCommand(pb(wa));$a=ka}}}h.removeItem(H-1);h.removeItem(H-2);h.removeItem(H-3)}else if(H>=3&&h.getItem(H- -1).type==1){F=3;v=ja(h).matrix;xa=e.createSVGTransform();xa.setMatrix(v);h.clear();h.appendItem(xa)}else if((H==1||H>1&&h.getItem(1).type!=3)&&h.getItem(0).type==2){F=2;E=ja(h).matrix;h.removeItem(0);v=ja(h).matrix.inverse();v=fa(v,E);E=v.e;v=v.f;if(E!=0||v!=0){A=g.childNodes;C=A.length;for(H=[];C--;){wa=A.item(C);if(wa.nodeType==1){if(wa.getAttribute("clip-path")){ka=wa.getAttribute("clip-path");if(H.indexOf(ka)===-1){Hb(ka,E,v);H.push(ka)}}ka=$a;$a=wa.getAttribute("transform");if(ha=V(wa)){R=e.createSVGTransform(); -R.setTranslate(E,v);ha.numberOfItems?ha.insertItemBefore(R,0):ha.appendItem(R);k.addSubCommand(pb(wa));ha=g.getElementsByTagNameNS(c,"use");wa="#"+wa.id;for(R=ha.length;R--;){aa=ha.item(R);if(wa==ba(aa)){ua=e.createSVGTransform();ua.setTranslate(-E,-v);V(aa).insertItemBefore(ua,0);k.addSubCommand(pb(aa))}}$a=ka}}}H=[];$a=ka}}else if(H==1&&h.getItem(0).type==1&&!t){F=1;v=h.getItem(0).matrix;A=g.childNodes;for(C=A.length;C--;){wa=A.item(C);if(wa.nodeType==1){ka=$a;$a=wa.getAttribute("transform");if(ha= -V(wa)){E=fa(v,ja(ha).matrix);H=e.createSVGTransform();H.setMatrix(E);ha.clear();ha.appendItem(H,0);k.addSubCommand(pb(wa));$a=ka;ka=wa.getAttribute("stroke-width");wa.getAttribute("stroke")!=="none"&&!isNaN(ka)&&wa.setAttribute("stroke-width",ka*((Math.abs(E.a)+Math.abs(E.d))/2))}}}h.clear()}else{if(t){D=e.createSVGTransform();D.setRotate(t,G.x,G.y);h.numberOfItems?h.insertItemBefore(D,0):h.appendItem(D)}h.numberOfItems==0&&g.removeAttribute("transform");return null}if(F==2){if(t){G={x:D.x+P.e,y:D.y+ -P.f};D=e.createSVGTransform();D.setRotate(t,G.x,G.y);h.numberOfItems?h.insertItemBefore(D,0):h.appendItem(D)}}else if(F==3){v=ja(h).matrix;P=e.createSVGTransform();P.setRotate(t,D.x,D.y);P=P.matrix;D=e.createSVGTransform();D.setRotate(t,G.x,G.y);G=D.matrix.inverse();ka=v.inverse();G=fa(ka,G,P,v);E=G.e;v=G.f;if(E!=0||v!=0){A=g.childNodes;for(C=A.length;C--;){wa=A.item(C);if(wa.nodeType==1){ka=$a;$a=wa.getAttribute("transform");ha=V(wa);R=e.createSVGTransform();R.setTranslate(E,v);ha.numberOfItems? -ha.insertItemBefore(R,0):ha.appendItem(R);k.addSubCommand(pb(wa));$a=ka}}}if(t)h.numberOfItems?h.insertItemBefore(D,0):h.appendItem(D)}}else{t=svgedit.utilities.getBBox(g);if(!t&&g.tagName!="path")return null;v=e.createSVGMatrix();if(E=ra(g)){D={x:t.x+t.width/2,y:t.y+t.height/2};G=O(t.x+t.width/2,t.y+t.height/2,ja(h).matrix);F=E*Math.PI/180;A=Math.abs(F)>1.0E-10?Math.sin(F)/(1-Math.cos(F)):2/F;for(F=0;F<h.numberOfItems;++F){v=h.getItem(F);if(v.type==4){v=v.matrix;D.y=(A*v.e+v.f)/2;D.x=(v.e-A*v.f)/ -2;h.removeItem(F);break}}}F=0;H=h.numberOfItems;if(!svgedit.browser.isWebkit())if((P=g.getAttribute("fill"))&&P.indexOf("url(")===0){P=X(P);ka="pattern";if(P.tagName!==ka)ka="gradient";if(P.getAttribute(ka+"Units")==="userSpaceOnUse"){v=ja(h).matrix;t=V(P);t=ja(t).matrix;v=fa(v,t);t="matrix("+[v.a,v.b,v.c,v.d,v.e,v.f].join(",")+")";P.setAttribute(ka+"Transform",t)}}if(H>=3&&h.getItem(H-2).type==3&&h.getItem(H-3).type==2&&h.getItem(H-1).type==2){F=3;v=ja(h,H-3,H-1).matrix;h.removeItem(H-1);h.removeItem(H- -2);h.removeItem(H-3)}else if(H==4&&h.getItem(H-1).type==1){F=3;v=ja(h).matrix;xa=e.createSVGTransform();xa.setMatrix(v);h.clear();h.appendItem(xa);v=e.createSVGMatrix()}else if((H==1||H>1&&h.getItem(1).type!=3)&&h.getItem(0).type==2){F=2;P=h.getItem(0).matrix;ka=ja(h,1).matrix;t=ka.inverse();v=fa(t,P,ka);h.removeItem(0)}else if(H==1&&h.getItem(0).type==1&&!E){v=ja(h).matrix;switch(g.tagName){case "line":w=$(g).attr(["x1","y1","x2","y2"]);case "polyline":case "polygon":w.points=g.getAttribute("points"); -if(w.points){t=g.points;A=t.numberOfItems;w.points=Array(A);for(F=0;F<A;++F){C=t.getItem(F);w.points[F]={x:C.x,y:C.y}}}case "path":w.d=g.getAttribute("d");F=1;h.clear()}}else{F=4;if(E){D=e.createSVGTransform();D.setRotate(E,G.x,G.y);h.numberOfItems?h.insertItemBefore(D,0):h.appendItem(D)}h.numberOfItems==0&&g.removeAttribute("transform");return null}if(F==1||F==2||F==3)xb(g,w,v);if(F==2){if(E){sa(h)||(G={x:D.x+v.e,y:D.y+v.f});D=e.createSVGTransform();D.setRotate(E,G.x,G.y);h.numberOfItems?h.insertItemBefore(D, -0):h.appendItem(D)}}else if(F==3&&E){v=ja(h).matrix;P=e.createSVGTransform();P.setRotate(E,D.x,D.y);P=P.matrix;D=e.createSVGTransform();D.setRotate(E,G.x,G.y);G=D.matrix.inverse();ka=v.inverse();G=fa(ka,G,P,v);xb(g,w,G);if(E)h.numberOfItems?h.insertItemBefore(D,0):h.appendItem(D)}}h.numberOfItems==0&&g.removeAttribute("transform");k.addSubCommand(new Wa(g,s));return k},Lb=null,bb=this.clearSelection=function(g){if(J[0]!=null)for(var h=J.length,k=0;k<h;++k){var v=J[k];if(v==null)break;Oa.releaseSelector(v); -J[k]=null}g||I("selected",J)},qb=this.addToSelection=function(g,h){if(g.length!=0){for(var k=0;k<J.length;){if(J[k]==null)break;++k}for(var v=g.length;v--;){var t=g[v];if(t&&svgedit.utilities.getBBox(t)){if(t.tagName==="a"&&t.childNodes.length===1)t=t.firstChild;if(J.indexOf(t)==-1){J[k]=t;k++;t=Oa.requestSelector(t);J.length>1&&t.showGrips(false)}}}I("selected",J);h||J.length==1?Oa.requestSelector(J[0]).showGrips(true):Oa.requestSelector(J[0]).showGrips(false);for(J.sort(function(E,w){if(E&&w&&E.compareDocumentPosition)return 3- -(w.compareDocumentPosition(E)&6);else if(E==null)return 1});J[0]==null;)J.shift(0)}},Qb=this.selectOnly=function(g,h){bb(true);qb(g,h)};this.removeFromSelection=function(g){if(J[0]!=null)if(g.length!=0){var h=Array(J.length);j=0;len=J.length;for(var k=0;k<len;++k){var v=J[k];if(v)if(g.indexOf(v)==-1){h[j]=v;j++}else Oa.releaseSelector(v)}J=h}};this.selectAllInCurrentLayer=function(){var g=z().getCurrentLayer();if(g){Na="select";Qb($(L||g).children())}};var $b=this.getMouseTarget=function(g){if(g== -null)return null;g=g.target;if(g.correspondingUseElement)g=g.correspondingUseElement;if(["http://www.w3.org/1998/Math/MathML","http://www.w3.org/1999/xhtml"].indexOf(g.namespaceURI)>=0&&g.id!="svgcanvas")for(;g.nodeName!="foreignObject";){g=g.parentNode;if(!g)return e}var h=z().getCurrentLayer();if([e,a,l,h].indexOf(g)>=0)return e;if($(g).closest("#selectorParentGroup").length)return Oa.selectorParentGroup;for(;g.parentNode!==(L||h);)g=g.parentNode;return g};(function(){var g=null,h=null,k=null,v= -null,t=null,E={},w={minx:null,miny:null,maxx:null,maxy:null};$(a).mousedown(function(s){if(!(b.spaceKey||s.button===1)){var A=s.button===2;s.altKey&&svgCanvas.cloneSelectedElements(0,0);Lb=l.getScreenCTM().inverse();var F=O(s.pageX,s.pageY,Lb),C=F.x*o,D=F.y*o;s.preventDefault();if(A){Na="select";yb=F}F=C/o;D=D/o;var G=$b(s);if(G.tagName==="a"&&G.childNodes.length===1)G=G.firstChild;C=v=h=F;var H=t=k=D;if(m.gridSnapping){F=Fa(F);D=Fa(D);h=Fa(h);k=Fa(k)}if(G==Oa.selectorParentGroup&&J[0]!=null){G=s.target; -var P=lb(G,"type");if(P=="rotate"){Na="rotate";current_rotate_mode=lb(G,"dir")}else if(P=="resize"){Na="resize";mb=lb(G,"dir")}G=J[0]}$a=G.getAttribute("transform");P=V(G);switch(Na){case "select":Ra=true;mb="none";if(A)Ra=false;if(G!=e){if(J.indexOf(G)==-1){s.shiftKey||bb(true);qb([G]);kb=G;Va.clear()}if(!A)for(A=0;A<J.length;++A)if(J[A]!=null){var R=V(J[A]);R.numberOfItems?R.insertItemBefore(e.createSVGTransform(),0):R.appendItem(e.createSVGTransform())}}else if(!A){bb();Na="multiselect";if(Ca== -null)Ca=Oa.getRubberBandBox();v*=o;t*=o;ma(Ca,{x:v,y:t,width:0,height:0,display:"inline"},100)}break;case "zoom":Ra=true;if(Ca==null)Ca=Oa.getRubberBandBox();ma(Ca,{x:C*o,y:C*o,width:0,height:0,display:"inline"},100);break;case "resize":Ra=true;h=F;k=D;E=svgedit.utilities.getBBox($("#selectedBox0")[0]);var aa={};$.each(E,function(ua,wa){aa[ua]=wa/o});E=aa;A=ra(G)?1:0;if(sa(P)){P.insertItemBefore(e.createSVGTransform(),A);P.insertItemBefore(e.createSVGTransform(),A);P.insertItemBefore(e.createSVGTransform(), -A)}else{P.appendItem(e.createSVGTransform());P.appendItem(e.createSVGTransform());P.appendItem(e.createSVGTransform());if(svgedit.browser.supportsNonScalingStroke()){if(F=svgedit.browser.isChrome())R=function(ua){var wa=ua.getAttributeNS(null,"stroke");ua.removeAttributeNS(null,"stroke");setTimeout(function(){ua.setAttributeNS(null,"stroke",wa)},1)};G.style.vectorEffect="non-scaling-stroke";F&&R(G);D=G.getElementsByTagName("*");C=D.length;for(A=0;A<C;A++){D[A].style.vectorEffect="non-scaling-stroke"; -F&&R(D[A])}}}break;case "fhellipse":case "fhrect":case "fhpath":Ra=true;g=C+","+H+" ";R=N.stroke_width==0?1:N.stroke_width;da({element:"polyline",curStyles:true,attr:{points:g,id:M(),fill:"none",opacity:N.opacity/2,"stroke-linecap":"round",style:"pointer-events:none"}});w.minx=C;w.maxx=C;w.miny=H;w.maxy=H;break;case "image":Ra=true;R=da({element:"image",attr:{x:F,y:D,width:0,height:0,id:M(),opacity:N.opacity/2,style:"pointer-events:inherit"}});S(R,Ja);Zb(R);break;case "square":case "rect":Ra=true; -h=F;k=D;da({element:"rect",curStyles:true,attr:{x:F,y:D,width:0,height:0,id:M(),opacity:N.opacity/2}});break;case "line":Ra=true;R=N.stroke_width==0?1:N.stroke_width;da({element:"line",curStyles:true,attr:{x1:F,y1:D,x2:F,y2:D,id:M(),stroke:N.stroke,"stroke-width":R,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,fill:"none",opacity:N.opacity/2,style:"pointer-events:none"}});break;case "circle":Ra=true;da({element:"circle", -curStyles:true,attr:{cx:F,cy:D,r:0,id:M(),opacity:N.opacity/2}});break;case "ellipse":Ra=true;da({element:"ellipse",curStyles:true,attr:{cx:F,cy:D,rx:0,ry:0,id:M(),opacity:N.opacity/2}});break;case "text":Ra=true;da({element:"text",curStyles:true,attr:{x:F,y:D,id:M(),fill:cb.fill,"stroke-width":cb.stroke_width,"font-size":cb.font_size,"font-family":cb.font_family,"text-anchor":"left","xml:space":"preserve",opacity:N.opacity}});break;case "path":case "pathedit":h*=o;k*=o;Va.mouseDown(s,G,h,k);Ra=true; -break;case "textedit":h*=o;k*=o;rb.mouseDown(s,G,h,k);Ra=true;break;case "rotate":Ra=true;b.undoMgr.beginUndoableChange("transform",J);document.getElementById("workarea").className="rotate"}s=ob("mouseDown",{event:s,start_x:h,start_y:k,selectedElements:J},true);$.each(s,function(ua,wa){if(wa&&wa.started)Ra=true})}}).mousemove(function(s){if(Ra)if(!(s.button===1||b.spaceKey)){var A=J[0],F=O(s.pageX,s.pageY,Lb),C=F.x*o;F=F.y*o;var D=la(ta()),G=x=C/o,H=y=F/o;if(m.gridSnapping){x=Fa(x);y=Fa(y)}s.preventDefault(); -switch(Na){case "select":if(J[0]!==null){G=x-h;var P=y-k;if(m.gridSnapping){G=Fa(G);P=Fa(P)}if(s.shiftKey){var R=ca(h,k,x,y);x=R.x;y=R.y}if(G!=0||P!=0){R=J.length;for(H=0;H<R;++H){A=J[H];if(A==null)break;var aa=e.createSVGTransform();D=V(A);aa.setTranslate(G,P);D.numberOfItems?D.replaceItem(aa,0):D.appendItem(aa);Oa.requestSelector(A).resize()}I("transition",J)}}break;case "multiselect":G*=o;H*=o;ma(Ca,{x:Math.min(v,G),y:Math.min(t,H),width:Math.abs(G-v),height:Math.abs(H-t)},100);D=[];G=[];aa=Kb(); -R=J.length;for(H=0;H<R;++H){P=aa.indexOf(J[H]);if(P==-1)D.push(J[H]);else aa[P]=null}R=aa.length;for(H=0;H<R;++H)aa[H]&&G.push(aa[H]);D.length>0&&b.removeFromSelection(D);G.length>0&&qb(G);break;case "resize":D=V(A);G=(R=sa(D))?E:svgedit.utilities.getBBox(A);H=G.x;aa=G.y;var ua=G.width,wa=G.height;G=x-h;P=y-k;if(m.gridSnapping){G=Fa(G);P=Fa(P);wa=Fa(wa);ua=Fa(ua)}var ha=ra(A);if(ha){var ka=Math.sqrt(G*G+P*P);P=Math.atan2(P,G)-ha*Math.PI/180;G=ka*Math.cos(P);P=ka*Math.sin(P)}if(mb.indexOf("n")==-1&& -mb.indexOf("s")==-1)P=0;if(mb.indexOf("e")==-1&&mb.indexOf("w")==-1)G=0;var oa=ka=0,xa=wa?(wa+P)/wa:1,eb=ua?(ua+G)/ua:1;if(mb.indexOf("n")>=0){xa=wa?(wa-P)/wa:1;oa=wa}if(mb.indexOf("w")>=0){eb=ua?(ua-G)/ua:1;ka=ua}G=e.createSVGTransform();P=e.createSVGTransform();ua=e.createSVGTransform();if(m.gridSnapping){H=Fa(H);ka=Fa(ka);aa=Fa(aa);oa=Fa(oa)}G.setTranslate(-(H+ka),-(aa+oa));if(s.shiftKey)if(eb==1)eb=xa;else xa=eb;P.setScale(eb,xa);ua.setTranslate(H+ka,aa+oa);if(R){R=ha?1:0;D.replaceItem(G,2+R); -D.replaceItem(P,1+R);D.replaceItem(ua,0+R)}else{R=D.numberOfItems;D.replaceItem(ua,R-3);D.replaceItem(P,R-2);D.replaceItem(G,R-1)}Oa.requestSelector(A).resize();I("transition",J);break;case "zoom":G*=o;H*=o;ma(Ca,{x:Math.min(v*o,G),y:Math.min(t*o,H),width:Math.abs(G-v*o),height:Math.abs(H-t*o)},100);break;case "text":ma(D,{x:x,y:y},1E3);break;case "line":G=null;window.opera||e.suspendRedraw(1E3);if(m.gridSnapping){x=Fa(x);y=Fa(y)}H=x;R=y;if(s.shiftKey){R=ca(h,k,H,R);H=R.x;R=R.y}D.setAttributeNS(null, -"x2",H);D.setAttributeNS(null,"y2",R);window.opera||e.unsuspendRedraw(G);break;case "foreignObject":case "square":case "rect":case "image":G=Math.abs(x-h);R=Math.abs(y-k);if(Na=="square"||s.shiftKey){G=R=Math.max(G,R);H=h<x?h:h-G;aa=k<y?k:k-R}else{H=Math.min(h,x);aa=Math.min(k,y)}if(m.gridSnapping){G=Fa(G);R=Fa(R);H=Fa(H);aa=Fa(aa)}ma(D,{width:G,height:R,x:H,y:aa},1E3);break;case "circle":G=$(D).attr(["cx","cy"]);R=G.cx;H=G.cy;G=Math.sqrt((x-R)*(x-R)+(y-H)*(y-H));if(m.gridSnapping)G=Fa(G);D.setAttributeNS(null, -"r",G);break;case "ellipse":G=$(D).attr(["cx","cy"]);R=G.cx;H=G.cy;G=null;window.opera||e.suspendRedraw(1E3);if(m.gridSnapping){x=Fa(x);R=Fa(R);y=Fa(y);H=Fa(H)}D.setAttributeNS(null,"rx",Math.abs(x-R));D.setAttributeNS(null,"ry",Math.abs(s.shiftKey?x-R:y-H));window.opera||e.unsuspendRedraw(G);break;case "fhellipse":case "fhrect":w.minx=Math.min(G,w.minx);w.maxx=Math.max(G,w.maxx);w.miny=Math.min(H,w.miny);w.maxy=Math.max(H,w.maxy);case "fhpath":g+=+G+","+H+" ";D.setAttributeNS(null,"points",g);break; -case "path":case "pathedit":x*=o;y*=o;if(m.gridSnapping){x=Fa(x);y=Fa(y);h=Fa(h);k=Fa(k)}if(s.shiftKey){if(R=svgedit.path.path){D=R.dragging?R.dragging[0]:h;R=R.dragging?R.dragging[1]:k}else{D=h;R=k}R=ca(D,R,x,y);x=R.x;y=R.y}if(Ca&&Ca.getAttribute("display")!=="none"){G*=o;H*=o;ma(Ca,{x:Math.min(v*o,G),y:Math.min(t*o,H),width:Math.abs(G-v*o),height:Math.abs(H-t*o)},100)}Va.mouseMove(s,x,y);break;case "textedit":x*=o;y*=o;rb.mouseMove(C,F);break;case "rotate":G=svgedit.utilities.getBBox(A);R=G.x+G.width/ -2;H=G.y+G.height/2;D=ea(A);D=O(R,H,D);R=D.x;H=D.y;D=G.x;aa=G.y;if(current_rotate_mode=="nw")D=G.x+G.width;if(current_rotate_mode=="se")aa=G.y+G.height;if(current_rotate_mode=="sw"){D=G.x+G.width;aa=G.y+G.height}compensation_angle=(Math.atan2(H-aa,R-D)*(180/Math.PI)-90)%360;ha=(Math.atan2(H-y,R-x)*(180/Math.PI)-90)%360;ha+=compensation_angle;if(m.gridSnapping)ha=Fa(ha);if(s.shiftKey)ha=Math.round(ha/45)*45;b.setRotationAngle(ha<-180?360+ha:ha,true);I("transition",J)}ob("mouseMove",{event:s,mouse_x:C, -mouse_y:F,selected:A})}}).click(function(s){s.preventDefault();return false}).dblclick(function(s){var A=s.target.parentNode;if(A!==L){var F=$b(s),C=F.tagName;if(C==="text"&&Na!=="textedit"){s=O(s.pageX,s.pageY,Lb);rb.select(F,s.x,s.y)}if((C==="g"||C==="a")&&ra(F)){fc(F);F=J[0];bb(true)}L&&ac();A.tagName!=="g"&&A.tagName!=="a"||A===z().getCurrentLayer()||F===Oa.selectorParentGroup||nc(F)}}).mouseup(function(s){if(s.button!==2){var A=kb;kb=null;if(Ra){var F=O(s.pageX,s.pageY,Lb),C=F.x*o;F=F.y*o;var D= -C/o,G=F/o,H=la(ta()),P=false;Ra=false;switch(Na){case "resize":case "multiselect":if(Ca!=null){Ca.setAttribute("display","none");wb=[]}Na="select";case "select":if(J[0]!=null){if(J[1]==null){C=J[0];switch(C.tagName){case "g":case "use":case "image":case "foreignObject":break;default:jb.fill=C.getAttribute("fill");jb.fill_opacity=C.getAttribute("fill-opacity");jb.stroke=C.getAttribute("stroke");jb.stroke_opacity=C.getAttribute("stroke-opacity");jb.stroke_width=C.getAttribute("stroke-width");jb.stroke_dasharray= -C.getAttribute("stroke-dasharray");jb.stroke_linejoin=C.getAttribute("stroke-linejoin");jb.stroke_linecap=C.getAttribute("stroke-linecap")}if(C.tagName=="text"){cb.font_size=C.getAttribute("font-size");cb.font_family=C.getAttribute("font-family")}Oa.requestSelector(C).showGrips(true)}Xa();if(D!=v||G!=t){s=J.length;for(C=0;C<s;++C){if(J[C]==null)break;J[C].firstChild||Oa.requestSelector(J[C]).resize()}}else{C=s.target;if(J[0].nodeName==="path"&&J[1]==null)Va.select(J[0]);else s.shiftKey&&A!=C&&b.removeFromSelection([C])}if(svgedit.browser.supportsNonScalingStroke())if(s= -J[0]){s.removeAttribute("style");svgedit.utilities.walkTree(s,function(ua){ua.removeAttribute("style")})}}return;case "zoom":Ca!=null&&Ca.setAttribute("display","none");I("zoomed",{x:Math.min(v,D),y:Math.min(t,G),width:Math.abs(D-v),height:Math.abs(G-t),factor:s.altKey?0.5:2});return;case "fhpath":A=H.getAttribute("points");D=A.indexOf(",");if(P=D>=0?A.indexOf(",",D+1)>=0:A.indexOf(" ",A.indexOf(" ")+1)>=0)H=Va.smoothPolylineIntoPath(H);break;case "line":A=$(H).attr(["x1","x2","y1","y2"]);P=A.x1!= -A.x2||A.y1!=A.y2;break;case "foreignObject":case "square":case "rect":case "image":A=$(H).attr(["width","height"]);P=A.width!=0||A.height!=0||Na==="image";break;case "circle":P=H.getAttribute("r")!=0;break;case "ellipse":A=$(H).attr(["rx","ry"]);P=A.rx!=null||A.ry!=null;break;case "fhellipse":if(w.maxx-w.minx>0&&w.maxy-w.miny>0){H=da({element:"ellipse",curStyles:true,attr:{cx:(w.minx+w.maxx)/2,cy:(w.miny+w.maxy)/2,rx:(w.maxx-w.minx)/2,ry:(w.maxy-w.miny)/2,id:ta()}});I("changed",[H]);P=true}break; -case "fhrect":if(w.maxx-w.minx>0&&w.maxy-w.miny>0){H=da({element:"rect",curStyles:true,attr:{x:w.minx,y:w.miny,width:w.maxx-w.minx,height:w.maxy-w.miny,id:ta()}});I("changed",[H]);P=true}break;case "text":P=true;Qb([H]);rb.start(H);break;case "path":H=null;Ra=true;A=Va.mouseUp(s,H,C,F);H=A.element;P=A.keep;break;case "pathedit":P=true;H=null;Va.mouseUp(s);break;case "textedit":P=false;H=null;rb.mouseUp(s,C,F);break;case "rotate":P=true;H=null;Na="select";A=b.undoMgr.finishUndoableChange();A.isEmpty()|| -Ga(A);Xa();I("changed",J)}C=ob("mouseUp",{event:s,mouse_x:C,mouse_y:F},true);$.each(C,function(ua,wa){if(wa){P=wa.keep||P;H=wa.element;Ra=wa.started||Ra}});if(!P&&H!=null){z().releaseId(ta());H.parentNode.removeChild(H);H=null;for(C=s.target;C.parentNode.parentNode.tagName=="g";)C=C.parentNode;if((Na!="path"||!drawn_path)&&C.parentNode.id!="selectorParentGroup"&&C.id!="svgcanvas"&&C.id!="svgroot"){b.setMode("select");Qb([C],true)}}else if(H!=null){b.addedNew=true;s=0.2;var R;if(false.beginElement&& -H.getAttribute("opacity")!=N.opacity){R=$(false).clone().attr({to:N.opacity,dur:s}).appendTo(H);try{R[0].beginElement()}catch(aa){}}else s=0;setTimeout(function(){R&&R.remove();H.setAttribute("opacity",N.opacity);H.setAttribute("style","pointer-events:inherit");Y(H);if(Na==="path")Va.toEditMode(H);else m.selectNew&&Qb([H],true);Ga(new Ka(H));I("changed",[H])},s*1E3)}$a=null}}});$(a).bind("mousewheel DOMMouseScroll",function(s){if(s.shiftKey){s.preventDefault();Lb=l.getScreenCTM().inverse();var A= -O(s.pageX,s.pageY,Lb);A={x:A.x,y:A.y,width:0,height:0};if(s.wheelDelta)if(s.wheelDelta>=120)A.factor=2;else{if(s.wheelDelta<=-120)A.factor=0.5}else if(s.detail)if(s.detail>0)A.factor=0.5;else if(s.detail<0)A.factor=2;A.factor&&I("zoomed",A)}})})();var Zb=function(g){$(g).click(function(h){h.preventDefault()})},rb=b.textActions=function(){function g(ha){var ka=F.value==="";$(F).focus();if(!arguments.length)if(ka)ha=0;else{if(F.selectionEnd!==F.selectionStart)return;ha=F.selectionEnd}var oa;oa=H[ha]; -ka||F.setSelectionRange(ha,ha);C=la("text_cursor");if(!C){C=document.createElementNS(c,"line");ma(C,{id:"text_cursor",stroke:"#333","stroke-width":1});C=la("selectorParentGroup").appendChild(C)}G||(G=setInterval(function(){var xa=C.getAttribute("display")==="none";C.setAttribute("display",xa?"inline":"none")},600));ka=E(oa.x,P.y);oa=E(oa.x,P.y+P.height);ma(C,{x1:ka.x,y1:ka.y,x2:oa.x,y2:oa.y,visibility:"visible",display:"inline"});D&&D.setAttribute("d","")}function h(ha,ka,oa){if(ha===ka)g(ka);else{oa|| -F.setSelectionRange(ha,ka);D=la("text_selectblock");if(!D){D=document.createElementNS(c,"path");ma(D,{id:"text_selectblock",fill:"green",opacity:0.5,style:"pointer-events:none"});la("selectorParentGroup").appendChild(D)}ha=H[ha];var xa=H[ka];C.setAttribute("visibility","hidden");ka=E(ha.x,P.y);oa=E(ha.x+(xa.x-ha.x),P.y);var eb=E(ha.x,P.y+P.height);ha=E(ha.x+(xa.x-ha.x),P.y+P.height);ma(D,{d:"M"+ka.x+","+ka.y+" L"+oa.x+","+oa.y+" "+ha.x+","+ha.y+" "+eb.x+","+eb.y+"z",display:"inline"})}}function k(ha, -ka){var oa=e.createSVGPoint();oa.x=ha;oa.y=ka;if(H.length==1)return 0;oa=A.getCharNumAtPosition(oa);if(oa<0){oa=H.length-2;if(ha<=H[0].x)oa=0}else if(oa>=H.length-2)oa=H.length-2;var xa=H[oa];ha>xa.x+xa.width/2&&oa++;return oa}function v(ha,ka,oa){var xa=F.selectionStart;ha=k(ha,ka);h(Math.min(xa,ha),Math.max(xa,ha),!oa)}function t(ha,ka){var oa={x:ha,y:ka};oa.x/=o;oa.y/=o;if(R){var xa=O(oa.x,oa.y,R.inverse());oa.x=xa.x;oa.y=xa.y}return oa}function E(ha,ka){var oa={x:ha,y:ka};if(R){var xa=O(oa.x, -oa.y,R);oa.x=xa.x;oa.y=xa.y}oa.x*=o;oa.y*=o;return oa}function w(ha){h(0,A.textContent.length);$(this).unbind(ha)}function s(ha){if(wa&&A){var ka=O(ha.pageX,ha.pageY,Lb);ka=t(ka.x*o,ka.y*o);ka=k(ka.x,ka.y);var oa=A.textContent,xa=oa.substr(0,ka).replace(/[a-z0-9]+$/i,"").length;oa=oa.substr(ka).match(/^[a-z0-9]+/i);h(xa,(oa?oa[0].length:0)+ka);$(ha.target).click(w);setTimeout(function(){$(ha.target).unbind("click",w)},300)}}var A,F,C,D,G,H=[],P,R,aa,ua,wa;return{select:function(ha,ka,oa){A=ha;rb.toEditMode(ka, -oa)},start:function(ha){A=ha;rb.toEditMode()},mouseDown:function(ha,ka,oa,xa){ha=t(oa,xa);F.focus();g(k(ha.x,ha.y));aa=oa;ua=xa},mouseMove:function(ha,ka){var oa=t(ha,ka);v(oa.x,oa.y)},mouseUp:function(ha,ka,oa){var xa=t(ka,oa);v(xa.x,xa.y,true);ha.target!==A&&ka<aa+2&&ka>aa-2&&oa<ua+2&&oa>ua-2&&rb.toSelectMode(true)},setCursor:g,toEditMode:function(ha,ka){wa=false;Na="textedit";Oa.requestSelector(A).showGrips(false);Oa.requestSelector(A);rb.init();$(A).css("cursor","text");if(arguments.length){var oa= -t(ha,ka);g(k(oa.x,oa.y))}else g();setTimeout(function(){wa=true},300)},toSelectMode:function(ha){Na="select";clearInterval(G);G=null;D&&$(D).attr("display","none");C&&$(C).attr("visibility","hidden");$(A).css("cursor","move");if(ha){bb();$(A).css("cursor","move");I("selected",[A]);qb([A],true)}A&&!A.textContent.length&&b.deleteSelectedElements();$(F).blur();A=false},setInputElem:function(ha){F=ha},clear:function(){Na=="textedit"&&rb.toSelectMode()},init:function(){if(A){if(!A.parentNode){A=J[0];Oa.requestSelector(A).showGrips(false)}var ha= -A.textContent.length,ka=A.getAttribute("transform");P=svgedit.utilities.getBBox(A);R=ka?ea(A):null;H=Array(ha);F.focus();$(A).unbind("dblclick",s).dblclick(s);if(!ha)var oa={x:P.x+P.width/2,width:0};for(ka=0;ka<ha;ka++){var xa=A.getStartPositionOfChar(ka);oa=A.getEndPositionOfChar(ka);if(!svgedit.browser.supportsGoodTextCharPos()){var eb=b.contentW*o;xa.x-=eb;oa.x-=eb;xa.x/=o;oa.x/=o}H[ka]={x:xa.x,y:P.y,width:oa.x-xa.x,height:P.height}}H.push({x:oa.x,width:0});h(F.selectionStart,F.selectionEnd,true)}}}}(), -Va=b.pathActions=function(){var g=false,h,k,v;svgedit.path.Path.prototype.endChanges=function(w){if(svgedit.browser.isWebkit()){var s=this.elem;s.setAttribute("d",Va.convertPath(s))}w=new Wa(this.elem,{d:this.last_d},w);Ga(w);I("changed",[this.elem])};svgedit.path.Path.prototype.addPtsToSelection=function(w){$.isArray(w)||(w=[w]);for(var s=0;s<w.length;s++){var A=w[s],F=this.segs[A];F.ptgrip&&this.selected_pts.indexOf(A)==-1&&A>=0&&this.selected_pts.push(A)}this.selected_pts.sort();s=this.selected_pts.length; -for(w=Array(s);s--;){F=this.segs[this.selected_pts[s]];F.select(true);w[s]=F.ptgrip}Va.canDeleteNodes=true;Va.closed_subpath=this.subpathIsClosed(this.selected_pts[0]);I("selected",w)};var t=h=null,E=false;return{mouseDown:function(w,s,A,F){if(Na==="path"){mouse_x=A;mouse_y=F;F=mouse_x/o;s=mouse_y/o;A=la("path_stretch_line");k=[F,s];if(m.gridSnapping){F=Fa(F);s=Fa(s);mouse_x=Fa(mouse_x);mouse_y=Fa(mouse_y)}if(!A){A=document.createElementNS(c,"path");ma(A,{id:"path_stretch_line",stroke:"#22C","stroke-width":"0.5", -fill:"none"});A=la("selectorParentGroup").appendChild(A)}A.setAttribute("display","inline");var C=null;if(t){C=t.pathSegList;for(var D=C.numberOfItems,G=6/o,H=false;D;){D--;var P=C.getItem(D),R=P.x;P=P.y;if(F>=R-G&&F<=R+G&&s>=P-G&&s<=P+G){H=true;break}}G=ta();svgedit.path.removePath_(G);G=la(G);R=C.numberOfItems;if(H){if(D<=1&&R>=2){F=C.getItem(0).x;s=C.getItem(0).y;w=A.pathSegList.getItem(1);w=w.pathSegType===4?t.createSVGPathSegLinetoAbs(F,s):t.createSVGPathSegCurvetoCubicAbs(F,s,w.x1/o,w.y1/o, -F,s);F=t.createSVGPathSegClosePath();C.appendItem(w);C.appendItem(F)}else if(R<3)return C=false;$(A).remove();element=G;t=null;Ra=false;if(g){svgedit.path.path.matrix&&xb(G,{},svgedit.path.path.matrix.inverse());A=G.getAttribute("d");w=$(svgedit.path.path.elem).attr("d");$(svgedit.path.path.elem).attr("d",w+A);$(G).remove();svgedit.path.path.matrix&&svgedit.path.recalcRotatedPath();svgedit.path.path.init();Va.toEditMode(svgedit.path.path.elem);svgedit.path.path.selectPt();return false}}else{if(!$.contains(a, -$b(w))){console.log("Clicked outside canvas");return false}C=t.pathSegList.numberOfItems;D=t.pathSegList.getItem(C-1);G=D.x;D=D.y;if(w.shiftKey){w=ca(G,D,F,s);F=w.x;s=w.y}w=A.pathSegList.getItem(1);w=w.pathSegType===4?t.createSVGPathSegLinetoAbs(Cb(F),Cb(s)):t.createSVGPathSegCurvetoCubicAbs(Cb(F),Cb(s),w.x1/o,w.y1/o,w.x2/o,w.y2/o);t.pathSegList.appendItem(w);F*=o;s*=o;A.setAttribute("d",["M",F,s,F,s].join(" "));A=C;if(g)A+=svgedit.path.path.segs.length;svgedit.path.addPointGrip(A,F,s)}}else{d_attr= -"M"+F+","+s+" ";t=da({element:"path",curStyles:true,attr:{d:d_attr,id:M(),opacity:N.opacity/2}});A.setAttribute("d",["M",mouse_x,mouse_y,mouse_x,mouse_y].join(" "));A=g?svgedit.path.path.segs.length:0;svgedit.path.addPointGrip(A,mouse_x,mouse_y)}}else if(svgedit.path.path){svgedit.path.path.storeD();G=w.target.id;if(G.substr(0,14)=="pathpointgrip_"){s=svgedit.path.path.cur_pt=parseInt(G.substr(14));svgedit.path.path.dragging=[A,F];C=svgedit.path.path.segs[s];if(w.shiftKey)C.selected?svgedit.path.path.removePtFromSelection(s): -svgedit.path.path.addPtsToSelection(s);else{if(svgedit.path.path.selected_pts.length<=1||!C.selected)svgedit.path.path.clearSelection();svgedit.path.path.addPtsToSelection(s)}}else if(G.indexOf("ctrlpointgrip_")==0){svgedit.path.path.dragging=[A,F];w=G.split("_")[1].split("c");s=w[0]-0;svgedit.path.path.selectPt(s,w[1]-0)}if(!svgedit.path.path.dragging){if(Ca==null)Ca=Oa.getRubberBandBox();ma(Ca,{x:A*o,y:F*o,width:0,height:0,display:"inline"},100)}}},mouseMove:function(w,s,A){E=true;if(Na==="path"){if(t){var F= -t.pathSegList;w=F.numberOfItems-1;if(k){var C=svgedit.path.addCtrlGrip("1c1"),D=svgedit.path.addCtrlGrip("0c2");D.getAttribute("cx");D.getAttribute("cy");C.setAttribute("cx",s);C.setAttribute("cy",A);C.setAttribute("display","inline");C=k[0];var G=k[1];F.getItem(w);var H=C+(C-s/o),P=G+(G-A/o);D.setAttribute("cx",H*o);D.setAttribute("cy",P*o);D.setAttribute("display","inline");D=svgedit.path.getCtrlLine(1);var R=svgedit.path.getCtrlLine(2);ma(D,{x1:s,y1:A,x2:C*o,y2:G*o,display:"inline"});ma(R,{x1:H* -o,y1:P*o,x2:C*o,y2:G*o,display:"inline"});if(w===0)v=[s,A];else{F=F.getItem(w-1);s=F.x;A=F.y;if(F.pathSegType===6){s+=s-F.x2;A+=A-F.y2}else if(v){s=v[0]/o;A=v[1]/o}svgedit.path.replacePathSeg(6,w,[C,G,s,A,H,P],t)}}else if(C=la("path_stretch_line")){w=F.getItem(w);if(w.pathSegType===6)svgedit.path.replacePathSeg(6,1,[s,A,(w.x+(w.x-w.x2))*o,(w.y+(w.y-w.y2))*o,s,A],C);else v?svgedit.path.replacePathSeg(6,1,[s,A,v[0],v[1],s,A],C):svgedit.path.replacePathSeg(4,1,[s,A],C)}}}else if(svgedit.path.path.dragging){C= -svgedit.path.getPointFromGrip({x:svgedit.path.path.dragging[0],y:svgedit.path.path.dragging[1]},svgedit.path.path);G=svgedit.path.getPointFromGrip({x:s,y:A},svgedit.path.path);w=G.x-C.x;C=G.y-C.y;svgedit.path.path.dragging=[s,A];svgedit.path.path.dragctrl?svgedit.path.path.moveCtrl(w,C):svgedit.path.path.movePts(w,C)}else{svgedit.path.path.selected_pts=[];svgedit.path.path.eachSeg(function(){if(this.next||this.prev){var aa=Ca.getBBox(),ua=svgedit.path.getGripPt(this);aa=svgedit.math.rectsIntersect(aa, -{x:ua.x,y:ua.y,width:0,height:0});this.select(aa);aa&&svgedit.path.path.selected_pts.push(this.index)}})}},mouseUp:function(w,s){if(Na==="path"){k=null;if(!t){s=la(ta());Ra=false;v=null}return{keep:true,element:s}}if(svgedit.path.path.dragging){var A=svgedit.path.path.cur_pt;svgedit.path.path.dragging=false;svgedit.path.path.dragctrl=false;svgedit.path.path.update();E&&svgedit.path.path.endChanges("Move path point(s)");!w.shiftKey&&!E&&svgedit.path.path.selectPt(A)}else if(Ca&&Ca.getAttribute("display")!= -"none"){Ca.setAttribute("display","none");Ca.getAttribute("width")<=2&&Ca.getAttribute("height")<=2&&Va.toSelectMode(w.target)}else Va.toSelectMode(w.target);E=false},toEditMode:function(w){svgedit.path.path=svgedit.path.getPath_(w);Na="pathedit";bb();svgedit.path.path.show(true).update();svgedit.path.path.oldbbox=svgedit.utilities.getBBox(svgedit.path.path.elem);g=false},toSelectMode:function(w){var s=w==svgedit.path.path.elem;Na="select";svgedit.path.path.show(false);h=false;bb();svgedit.path.path.matrix&& -svgedit.path.recalcRotatedPath();if(s){I("selected",[w]);qb([w],true)}},addSubPath:function(w){if(w){Na="path";g=true}else{Va.clear(true);Va.toEditMode(svgedit.path.path.elem)}},select:function(w){if(h===w){Va.toEditMode(w);Na="pathedit"}else h=w},reorient:function(){var w=J[0];if(w)if(ra(w)!=0){var s=new La("Reorient path"),A={d:w.getAttribute("d"),transform:w.getAttribute("transform")};s.addSubCommand(new Wa(w,A));bb();this.resetOrientation(w);Ga(s);svgedit.path.getPath_(w).show(false).matrix=null; -this.clear();qb([w],true);I("changed",J)}},clear:function(){h=null;if(t){var w=la(ta());$(la("path_stretch_line")).remove();$(w).remove();$(la("pathpointgrip_container")).find("*").attr("display","none");t=v=null;Ra=false}else Na=="pathedit"&&this.toSelectMode();svgedit.path.path&&svgedit.path.path.init().show(false)},resetOrientation:function(w){if(w==null||w.nodeName!="path")return false;var s=V(w),A=ja(s).matrix;s.clear();w.removeAttribute("transform");s=w.pathSegList;for(var F=s.numberOfItems, -C=0;C<F;++C){var D=s.getItem(C),G=D.pathSegType;if(G!=1){var H=[];$.each(["",1,2],function(P,R){var aa=D["x"+R],ua=D["y"+R];if(aa!==undefined&&ua!==undefined){aa=O(aa,ua,A);H.splice(H.length,0,aa.x,aa.y)}});svgedit.path.replacePathSeg(G,C,H,w)}}f(w,A)},zoomChange:function(){Na=="pathedit"&&svgedit.path.path.update()},getNodePoint:function(){var w=svgedit.path.path.segs[svgedit.path.path.selected_pts.length?svgedit.path.path.selected_pts[0]:1];return{x:w.item.x,y:w.item.y,type:w.type}},linkControlPoints:function(w){svgedit.path.setLinkControlPoints(w)}, -clonePathNode:function(){svgedit.path.path.storeD();for(var w=svgedit.path.path.selected_pts,s=w.length,A=[];s--;){var F=w[s];svgedit.path.path.addSeg(F);A.push(F+s);A.push(F+s+1)}svgedit.path.path.init().addPtsToSelection(A);svgedit.path.path.endChanges("Clone path node(s)")},opencloseSubPath:function(){var w=svgedit.path.path.selected_pts;if(w.length===1){var s=svgedit.path.path.elem,A=s.pathSegList,F=w[0],C=null,D=null;svgedit.path.path.eachSeg(function(R){if(this.type===2&&R<=F)D=this.item;if(R<= -F)return true;if(this.type===2){C=R;return false}else if(this.type===1)return C=false});if(C==null)C=svgedit.path.path.segs.length-1;if(C!==false){var G=s.createSVGPathSegLinetoAbs(D.x,D.y),H=s.createSVGPathSegClosePath();if(C==svgedit.path.path.segs.length-1){A.appendItem(G);A.appendItem(H)}else{svgedit.path.insertItemBefore(s,H,C);svgedit.path.insertItemBefore(s,G,C)}svgedit.path.path.init().selectPt(C+1)}else if(svgedit.path.path.segs[F].mate){A.removeItem(F);A.removeItem(F);svgedit.path.path.init().selectPt(F- -1)}else{for(w=0;w<A.numberOfItems;w++){var P=A.getItem(w);if(P.pathSegType===2)G=w;else if(w===F)A.removeItem(G);else if(P.pathSegType===1&&F<w){H=w-1;A.removeItem(w);break}}for(w=F-G-1;w--;)svgedit.path.insertItemBefore(s,A.getItem(G),H);s=A.getItem(G);svgedit.path.replacePathSeg(2,G,[s.x,s.y]);w=F;svgedit.path.path.init().selectPt(0)}}},deletePathNode:function(){if(Va.canDeleteNodes){svgedit.path.path.storeD();for(var w=svgedit.path.path.selected_pts,s=w.length;s--;)svgedit.path.path.deleteSeg(w[s]); -var A=function(){var F=svgedit.path.path.elem.pathSegList,C=F.numberOfItems,D=function(P,R){for(;R--;)F.removeItem(P)};if(C<=1)return true;for(;C--;){var G=F.getItem(C);if(G.pathSegType===1){G=F.getItem(C-1);var H=F.getItem(C-2);if(G.pathSegType===2){D(C-1,2);A();break}else if(H.pathSegType===2){D(C-2,3);A();break}}else if(G.pathSegType===2)if(C>0){G=F.getItem(C-1).pathSegType;if(G===2){D(C-1,1);A();break}else if(G===1&&F.numberOfItems-1===C){D(C,1);A();break}}}return false};A();if(svgedit.path.path.elem.pathSegList.numberOfItems<= -1){Va.toSelectMode(svgedit.path.path.elem);b.deleteSelectedElements()}else{svgedit.path.path.init();svgedit.path.path.clearSelection();if(window.opera){w=$(svgedit.path.path.elem);w.attr("d",w.attr("d"))}svgedit.path.path.endChanges("Delete path node(s)")}}},smoothPolylineIntoPath:function(w){var s=w.points,A=s.numberOfItems;if(A>=4){var F=s.getItem(0),C=null;w=[];w.push(["M",F.x,",",F.y," C"].join(""));for(var D=1;D<=A-4;D+=3){var G=s.getItem(D),H=s.getItem(D+1),P=s.getItem(D+2);if(C)if((F=svgedit.path.smoothControlPoints(C, -G,F))&&F.length==2){G=w[w.length-1].split(",");G[2]=F[0].x;G[3]=F[0].y;w[w.length-1]=G.join(",");G=F[1]}w.push([G.x,G.y,H.x,H.y,P.x,P.y].join(","));F=P;C=H}for(w.push("L");D<A;++D){H=s.getItem(D);w.push([H.x,H.y].join(","))}w=w.join(" ");w=da({element:"path",curStyles:true,attr:{id:ta(),d:w,fill:"none"}})}return w},setSegType:function(w){svgedit.path.path.setSegType(w)},moveNode:function(w,s){var A=svgedit.path.path.selected_pts;if(A.length){svgedit.path.path.storeD();A=svgedit.path.path.segs[A[0]]; -var F={x:0,y:0};F[w]=s-A.item[w];A.move(F.x,F.y);svgedit.path.path.endChanges("Move path point")}},fixEnd:function(w){for(var s=w.pathSegList,A=s.numberOfItems,F,C=0;C<A;++C){var D=s.getItem(C);if(D.pathSegType===2)F=D;if(D.pathSegType===1){D=s.getItem(C-1);if(D.x!=F.x||D.y!=F.y){s=w.createSVGPathSegLinetoAbs(F.x,F.y);svgedit.path.insertItemBefore(w,s,C);Va.fixEnd(w);break}}}svgedit.browser.isWebkit()&&w.setAttribute("d",Va.convertPath(w))},convertPath:function(w,s){for(var A=w.pathSegList,F=A.numberOfItems, -C=0,D=0,G="",H=null,P=0;P<F;++P){var R=A.getItem(P),aa=R.x||0,ua=R.y||0,wa=R.x1||0,ha=R.y1||0,ka=R.x2||0,oa=R.y2||0,xa=R.pathSegType,eb=db[xa]["to"+(s?"Lower":"Upper")+"Case"](),Db=function(Pb,Jb,Ob){Jb=Jb?" "+Jb.join(" "):"";Ob=Ob?" "+svgedit.units.shortFloat(Ob):"";$.each(Pb,function(bc,kc){Pb[bc]=svgedit.units.shortFloat(kc)});G+=eb+Pb.join(" ")+Jb+Ob};switch(xa){case 1:G+="z";break;case 12:aa-=C;case 13:if(s){C+=aa;eb="l"}else{aa+=C;C=aa;eb="L"}Db([[aa,D]]);break;case 14:ua-=D;case 15:if(s){D+= -ua;eb="l"}else{ua+=D;D=ua;eb="L"}Db([[C,ua]]);break;case 2:case 4:case 18:aa-=C;ua-=D;case 5:case 3:if(H&&A.getItem(P-1).pathSegType===1&&!s){C=H[0];D=H[1]}case 19:if(s){C+=aa;D+=ua}else{aa+=C;ua+=D;C=aa;D=ua}if(xa===3)H=[C,D];Db([[aa,ua]]);break;case 6:aa-=C;wa-=C;ka-=C;ua-=D;ha-=D;oa-=D;case 7:if(s){C+=aa;D+=ua}else{aa+=C;wa+=C;ka+=C;ua+=D;ha+=D;oa+=D;C=aa;D=ua}Db([[wa,ha],[ka,oa],[aa,ua]]);break;case 8:aa-=C;wa-=C;ua-=D;ha-=D;case 9:if(s){C+=aa;D+=ua}else{aa+=C;wa+=C;ua+=D;ha+=D;C=aa;D=ua}Db([[wa, -ha],[aa,ua]]);break;case 10:aa-=C;ua-=D;case 11:if(s){C+=aa;D+=ua}else{aa+=C;ua+=D;C=aa;D=ua}Db([[R.r1,R.r2]],[R.angle,R.largeArcFlag?1:0,R.sweepFlag?1:0],[aa,ua]);break;case 16:aa-=C;ka-=C;ua-=D;oa-=D;case 17:if(s){C+=aa;D+=ua}else{aa+=C;ka+=C;ua+=D;oa+=D;C=aa;D=ua}Db([[ka,oa],[aa,ua]])}}return G}}}(),gc=this.removeUnusedDefElems=function(){var g=l.getElementsByTagNameNS(c,"defs");if(!g||!g.length)return 0;for(var h=[],k=0,v=["fill","stroke","filter","marker-start","marker-mid","marker-end"],t=v.length, -E=l.getElementsByTagNameNS(c,"*"),w=E.length,s=0;s<w;s++){for(var A=E[s],F=0;F<t;F++){var C=pa(A.getAttribute(v[F]));C&&h.push(C.substr(1))}(A=ba(A))&&A.indexOf("#")===0&&h.push(A.substr(1))}g=$(g).find("linearGradient, radialGradient, filter, marker, svg, symbol");defelem_ids=[];for(s=g.length;s--;){v=g[s];t=v.id;if(h.indexOf(t)<0){Bb[t]=v;v.parentNode.removeChild(v);k++}}return k};this.svgCanvasToString=function(){for(;gc()>0;);Va.clear(true);$.each(l.childNodes,function(k,v){k&&v.nodeType===8&& -v.data.indexOf("Created with")>=0&&l.insertBefore(v,l.firstChild)});if(L){ac();Qb([L])}var g=[];$(l).find("g:data(gsvg)").each(function(){for(var k=this.attributes,v=k.length,t=0;t<v;t++)if(k[t].nodeName=="id"||k[t].nodeName=="style")v--;if(v<=0){k=this.firstChild;g.push(k);$(this).replaceWith(k)}});var h=this.svgToString(l,0);g.length&&$(g).each(function(){na(this)});return h};this.svgToString=function(g,h){var k=[],v=svgedit.utilities.toXml,t=m.baseUnit,E=RegExp("^-?[\\d\\.]+"+t+"$");if(g){Y(g); -var w=g.attributes,s,A,F=g.childNodes;for(A=0;A<h;A++)k.push(" ");k.push("<");k.push(g.nodeName);if(g.id==="svgcontent"){A=Vb();if(t!=="px"){A.w=svgedit.units.convertUnit(A.w,t)+t;A.h=svgedit.units.convertUnit(A.h,t)+t}k.push(' width="'+A.w+'" height="'+A.h+'" xmlns="'+c+'"');var C={};$(g).find("*").andSelf().each(function(){$.each(this.attributes,function(P,R){var aa=R.namespaceURI;if(aa&&!C[aa]&&za[aa]!=="xmlns"&&za[aa]!=="xml"){C[aa]=true;k.push(" xmlns:"+za[aa]+'="'+aa+'"')}})});A=w.length;for(t= -["width","height","xmlns","x","y","viewBox","id","overflow"];A--;){s=w.item(A);var D=v(s.nodeValue);if(s.nodeName.indexOf("xmlns:")!==0)if(D!=""&&t.indexOf(s.localName)==-1)if(!s.namespaceURI||za[s.namespaceURI]){k.push(" ");k.push(s.nodeName);k.push('="');k.push(D);k.push('"')}}}else{if(g.nodeName==="defs"&&!g.firstChild)return;var G=["-moz-math-font-style","_moz-math-font-style"];for(A=w.length-1;A>=0;A--){s=w.item(A);D=v(s.nodeValue);if(!(G.indexOf(s.localName)>=0))if(D!="")if(D.indexOf("pointer-events")!== -0)if(!(s.localName==="class"&&D.indexOf("se_")===0)){k.push(" ");if(s.localName==="d")D=Va.convertPath(g,true);if(isNaN(D)){if(E.test(D))D=svgedit.units.shortFloat(D)+t}else D=svgedit.units.shortFloat(D);if(Za.apply&&g.nodeName==="image"&&s.localName==="href"&&Za.images&&Za.images==="embed"){var H=Sa[D];if(H)D=H}if(!s.namespaceURI||s.namespaceURI==c||za[s.namespaceURI]){k.push(s.nodeName);k.push('="');k.push(D);k.push('"')}}}}if(g.hasChildNodes()){k.push(">");h++;w=false;for(A=0;A<F.length;A++){t= -F.item(A);switch(t.nodeType){case 1:k.push("\n");k.push(this.svgToString(F.item(A),h));break;case 3:t=t.nodeValue.replace(/^\s+|\s+$/g,"");if(t!=""){w=true;k.push(v(t)+"")}break;case 4:k.push("\n");k.push(Array(h+1).join(" "));k.push("<![CDATA[");k.push(t.nodeValue);k.push("]]\>");break;case 8:k.push("\n");k.push(Array(h+1).join(" "));k.push("<!--");k.push(t.data);k.push("--\>")}}h--;if(!w){k.push("\n");for(A=0;A<h;A++)k.push(" ")}k.push("</");k.push(g.nodeName);k.push(">")}else k.push("/>")}return k.join("")}; -this.embedImage=function(g,h){$(new Image).load(function(){var k=document.createElement("canvas");k.width=this.width;k.height=this.height;k.getContext("2d").drawImage(this,0,0);try{var v=";svgedit_url="+encodeURIComponent(g);v=k.toDataURL().replace(";base64",v+";base64");Sa[g]=v}catch(t){Sa[g]=false}Ja=g;h&&h(Sa[g])}).attr("src",g)};this.setGoodImage=function(g){Ja=g};this.open=function(){};this.save=function(g){bb();g&&$.extend(Za,g);Za.apply=true;g=this.svgCanvasToString();I("saved",g)};this.rasterExport= -function(){bb();var g=[],h={feGaussianBlur:Gb.exportNoBlur,foreignObject:Gb.exportNoforeignObject,"[stroke-dasharray]":Gb.exportNoDashArray},k=$(l);if(!("font"in $("<canvas>")[0].getContext("2d")))h.text=Gb.exportNoText;$.each(h,function(v,t){k.find(v).length&&g.push(t)});h=this.svgCanvasToString();I("exported",{svg:h,issues:g})};this.getSvgString=function(){Za.apply=false;return this.svgCanvasToString()};this.randomizeIds=function(){arguments.length>0&&arguments[0]==false?svgedit.draw.randomizeIds(false, -z()):svgedit.draw.randomizeIds(true,z())};var cc=this.uniquifyElems=function(g){var h={},k=["filter","linearGradient","pattern","radialGradient","symbol","textPath","use"];svgedit.utilities.walkTree(g,function(s){if(s.nodeType==1){if(s.id){s.id in h||(h[s.id]={elem:null,attrs:[],hrefs:[]});h[s.id].elem=s}$.each(Nb,function(F,C){var D=s.getAttributeNode(C);if(D){var G=svgedit.utilities.getUrlFromAttr(D.value);if(G=G?G.substr(1):null){G in h||(h[G]={elem:null,attrs:[],hrefs:[]});h[G].attrs.push(D)}}}); -var A=svgedit.utilities.getHref(s);if(A&&k.indexOf(s.nodeName)>=0)if(A=A.substr(1)){A in h||(h[A]={elem:null,attrs:[],hrefs:[]});h[A].hrefs.push(s)}}});for(var v in h)if(v){var t=h[v].elem;if(t){g=M();t.id=g;t=h[v].attrs;for(var E=t.length;E--;){var w=t[E];w.ownerElement.setAttribute(w.name,"url(#"+g+")")}t=h[v].hrefs;for(E=t.length;E--;)svgedit.utilities.setHref(t[E],"#"+g)}}},Ub=this.setUseData=function(g){var h=$(g);if(g.tagName!=="use")h=h.find("use");h.each(function(){var k=ba(this).substr(1); -if(k=la(k)){$(this).data("ref",k);if(k.tagName=="symbol"||k.tagName=="svg")$(this).data("symbol",k).data("ref",k)}})},hc=this.convertGradients=function(g){var h=$(g).find("linearGradient, radialGradient");if(!h.length&&svgedit.browser.isWebkit())h=$(g).find("*").filter(function(){return this.tagName.indexOf("Gradient")>=0});h.each(function(){if($(this).attr("gradientUnits")==="userSpaceOnUse"){var k=$(l).find('[fill="url(#'+this.id+')"],[stroke="url(#'+this.id+')"]');if(k.length)if(k=svgedit.utilities.getBBox(k[0]))if(this.tagName=== -"linearGradient"){var v=$(this).attr(["x1","y1","x2","y2"]),t=this.gradientTransform.baseVal;if(t&&t.numberOfItems>0){var E=ja(t).matrix;t=O(v.x1,v.y1,E);E=O(v.x2,v.y2,E);v.x1=t.x;v.y1=t.y;v.x2=E.x;v.y2=E.y;this.removeAttribute("gradientTransform")}$(this).attr({x1:(v.x1-k.x)/k.width,y1:(v.y1-k.y)/k.height,x2:(v.x2-k.x)/k.width,y2:(v.y2-k.y)/k.height});this.removeAttribute("gradientUnits")}}})},lc=this.convertToGroup=function(g){g||(g=J[0]);var h=$(g),k=new La,v;if(h.data("gsvg")){k=$(g.firstChild).attr(["x", -"y"]);$(g.firstChild.firstChild).unwrap();$(g).removeData("gsvg");v=V(g);var t=e.createSVGTransform();t.setTranslate(k.x,k.y);v.appendItem(t);pb(g);I("selected",[g])}else if(h.data("symbol")){g=h.data("symbol");v=h.attr("transform");t=h.attr(["x","y"]);var E=g.getAttribute("viewBox");if(E){E=E.split(" ");t.x-=+E[0];t.y-=+E[1]}v+=" translate("+(t.x||0)+","+(t.y||0)+")";t=h.prev();k.addSubCommand(new Ua(h[0],h[0].nextSibling,h[0].parentNode));h.remove();E=$(l).find("use:data(symbol)").length;h=d.createElementNS(c, -"g");for(var w=g.childNodes,s=0;s<w.length;s++)h.appendChild(w[s].cloneNode(true));if(svgedit.browser.isGecko()){w=$(ub()).children("linearGradient,radialGradient,pattern").clone();$(h).append(w)}v&&h.setAttribute("transform",v);v=g.parentNode;cc(h);svgedit.browser.isGecko()&&$(ub()).append($(h).find("linearGradient,radialGradient,pattern"));h.id=M();t.after(h);if(v){if(!E){t=g.nextSibling;v.removeChild(g);k.addSubCommand(new Ua(g,t,v))}k.addSubCommand(new Ka(h))}Ub(h);svgedit.browser.isGecko()?hc(ub()): -hc(h);svgedit.utilities.walkTreePost(h,function(A){try{pb(A)}catch(F){console.log(F)}});$(h).find("a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use").each(function(){if(!this.id)this.id=M()});Qb([h]);(g=fc(h,true))&&k.addSubCommand(g);Ga(k)}else console.log("Unexpected element to ungroup:",g)};this.setSvgString=function(g){try{var h=svgedit.utilities.text2xml(g);this.prepareSvg(h);var k=new La("Change Source"),v=l.nextSibling,t=e.removeChild(l);k.addSubCommand(new Ua(t, -v,e));l=d.adoptNode?d.adoptNode(h.documentElement):d.importNode(h.documentElement,true);e.appendChild(l);var E=$(l);b.current_drawing_=new svgedit.draw.Drawing(l,u);var w=z().getNonce();w?I("setnonce",w):I("unsetnonce");E.find("image").each(function(){var H=this;Zb(H);var P=ba(this);if(P.indexOf("data:")===0){var R=P.match(/svgedit_url=(.*?);/);if(R){var aa=decodeURIComponent(R[1]);$(new Image).load(function(){H.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",aa)}).attr("src",aa)}}b.embedImage(P)}); -E.find("svg").each(function(){if(!$(this).closest("defs").length){cc(this);var H=this.parentNode;if(H.childNodes.length===1&&H.nodeName==="g"){$(H).data("gsvg",this);H.id=H.id||M()}else na(this)}});svgedit.browser.isGecko()&&E.find("linearGradient, radialGradient, pattern").appendTo(ub());Ub(E);hc(E[0]);svgedit.utilities.walkTreePost(l,function(H){try{pb(H)}catch(P){console.log(P)}});var s={id:"svgcontent",overflow:m.show_outside_canvas?"visible":"hidden"},A=false;if(E.attr("viewBox")){var F=E.attr("viewBox").split(" "); -s.width=F[2];s.height=F[3]}else $.each(["width","height"],function(H,P){var R=E.attr(P);R||(R="100%");if((R+"").substr(-1)==="%")A=true;else s[P]=qa(P,R)});Wb();E.children().find("a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use").each(function(){if(!this.id)this.id=M()});if(A){var C=getStrokedBBox();s.width=C.width+C.x;s.height=C.height+C.y}if(s.width<=0)s.width=100;if(s.height<=0)s.height=100;E.attr(s);this.contentW=s.width;this.contentH=s.height;k.addSubCommand(new Ka(l)); -var D=E.attr(["width","height"]);k.addSubCommand(new Wa(e,D));o=1;svgedit.transformlist.resetListMap();bb();svgedit.path.clearData();e.appendChild(Oa.selectorParentGroup);Ga(k);I("changed",[l])}catch(G){console.log(G);return false}return true};this.importSvgString=function(g){try{var h=svgedit.utilities.encode64(g.length+g).substr(0,32),k=false;if(Ab[h])if($(Ab[h].symbol).parents("#svgroot").length)k=true;var v=new La("Import SVG");if(k)var t=Ab[h].symbol,E=Ab[h].xform;else{var w=svgedit.utilities.text2xml(g); -this.prepareSvg(w);var s;s=d.adoptNode?d.adoptNode(w.documentElement):d.importNode(w.documentElement,true);cc(s);var A=qa("width",s.getAttribute("width")),F=qa("height",s.getAttribute("height")),C=s.getAttribute("viewBox"),D=C?C.split(" "):[0,0,A,F];for(g=0;g<4;++g)D[g]=+D[g];l.getAttribute("width");var G=+l.getAttribute("height");E=F>A?"scale("+G/3/D[3]+")":"scale("+G/3/D[2]+")";E="translate(0) "+E+" translate(0)";t=d.createElementNS(c,"symbol");var H=ub();for(svgedit.browser.isGecko()&&$(s).find("linearGradient, radialGradient, pattern").appendTo(H);s.firstChild;)t.appendChild(s.firstChild); -var P=s.attributes;for(s=0;s<P.length;s++){var R=P[s];t.setAttribute(R.nodeName,R.nodeValue)}t.id=M();Ab[h]={symbol:t,xform:E};ub().appendChild(t);v.addSubCommand(new Ka(t))}var aa=d.createElementNS(c,"use");aa.id=M();S(aa,"#"+t.id);(L||z().getCurrentLayer()).appendChild(aa);v.addSubCommand(new Ka(aa));bb();aa.setAttribute("transform",E);pb(aa);$(aa).data("symbol",t).data("ref",t);qb([aa]);Ga(v);I("changed",[l])}catch(ua){console.log(ua);return false}return true};var Wb=b.identifyLayers=function(){ac(); -z().identifyLayers()};this.createLayer=function(g){var h=new La("Create Layer");g=z().createLayer(g);h.addSubCommand(new Ka(g));Ga(h);bb();I("changed",[g])};this.cloneLayer=function(g){var h=new La("Duplicate Layer"),k=d.createElementNS(c,"g"),v=d.createElementNS(c,"title");v.textContent=g;k.appendChild(v);v=z().getCurrentLayer();$(v).after(k);v=v.childNodes;for(var t=0;t<v.length;t++){var E=v[t];E.localName!="title"&&k.appendChild(Z(E))}bb();Wb();h.addSubCommand(new Ka(k));Ga(h);b.setCurrentLayer(g); -I("changed",[k])};this.deleteCurrentLayer=function(){var g=z().getCurrentLayer(),h=g.nextSibling,k=g.parentNode;if(g=z().deleteCurrentLayer()){var v=new La("Delete Layer");v.addSubCommand(new Ua(g,h,k));Ga(v);bb();I("changed",[k]);return true}return false};this.setCurrentLayer=function(g){(g=z().setCurrentLayer(svgedit.utilities.toXml(g)))&&bb();return g};this.renameCurrentLayer=function(g){var h=z();if(h.current_layer){var k=h.current_layer;if(!b.setCurrentLayer(g)){for(var v=new La("Rename Layer"), -t=0;t<h.getNumLayers();++t)if(h.all_layers[t][1]==k)break;var E=h.getLayerName(t);h.all_layers[t][0]=svgedit.utilities.toXml(g);var w=k.childNodes.length;for(t=0;t<w;++t){var s=k.childNodes.item(t);if(s&&s.tagName=="title"){for(;s.firstChild;)s.removeChild(s.firstChild);s.textContent=g;v.addSubCommand(new Wa(s,{"#text":E}));Ga(v);I("changed",[k]);return true}}}h.current_layer=k}return false};this.setCurrentLayerPosition=function(g){var h=z();if(h.current_layer&&g>=0&&g<h.getNumLayers()){for(var k= -0;k<h.getNumLayers();++k)if(h.all_layers[k][1]==h.current_layer)break;if(k==h.getNumLayers())return false;if(k!=g){var v=null,t=h.current_layer.nextSibling;if(g>k){if(g<h.getNumLayers()-1)v=h.all_layers[g+1][1]}else v=h.all_layers[g][1];l.insertBefore(h.current_layer,v);Ga(new Qa(h.current_layer,t,l));Wb();b.setCurrentLayer(h.getLayerName(g));return true}}return false};this.setLayerVisibility=function(g,h){var k=z(),v=k.getLayerVisibility(g),t=k.setLayerVisibility(g,h);if(t)Ga(new Wa(t,{display:v? -"inline":"none"},"Layer Visibility"));else return false;if(t==k.getCurrentLayer()){bb();Va.clear()}return true};this.moveSelectedToLayer=function(g){for(var h=null,k=z(),v=0;v<k.getNumLayers();++v)if(k.getLayerName(v)==g){h=k.all_layers[v][1];break}if(!h)return false;g=new La("Move Elements to Layer");k=J;for(v=k.length;v--;){var t=k[v];if(t){var E=t.nextSibling,w=t.parentNode;h.appendChild(t);g.addSubCommand(new Qa(t,E,w))}}Ga(g);return true};this.mergeLayer=function(g){var h=new La("Merge Layer"), -k=z(),v=$(k.current_layer).prev()[0];if(v){for(h.addSubCommand(new Ua(k.current_layer,k.current_layer.nextSibling,l));k.current_layer.firstChild;){var t=k.current_layer.firstChild;if(t.localName=="title"){h.addSubCommand(new Ua(t,t.nextSibling,k.current_layer));k.current_layer.removeChild(t)}else{var E=t.nextSibling;v.appendChild(t);h.addSubCommand(new Qa(t,E,k.current_layer))}}l.removeChild(k.current_layer);if(!g){bb();Wb();I("changed",[l]);Ga(h)}k.current_layer=v;return h}};this.mergeAllLayers= -function(){var g=new La("Merge all Layers"),h=z();for(h.current_layer=h.all_layers[h.getNumLayers()-1][1];$(l).children("g").length>1;)g.addSubCommand(b.mergeLayer(true));bb();Wb();I("changed",[l]);Ga(g)};var ac=this.leaveContext=function(){var g=Ea.length;if(g){for(var h=0;h<g;h++){var k=Ea[h],v=lb(k,"orig_opac");v!==1?k.setAttribute("opacity",v):k.removeAttribute("opacity");k.setAttribute("style","pointer-events: inherit")}Ea=[];bb(true);I("contextset",null)}L=null},nc=this.setContext=function(g){ac(); -if(typeof g==="string")g=la(g);L=g;$(g).parentsUntil("#svgcontent").andSelf().siblings().each(function(){var h=this.getAttribute("opacity")||1;lb(this,"orig_opac",h);this.setAttribute("opacity",h*0.33);this.setAttribute("style","pointer-events: none");Ea.push(this)});bb();I("contextset",L)};this.clear=function(){Va.clear();bb();b.clearSvgContentElement();b.current_drawing_=new svgedit.draw.Drawing(l);b.createLayer("Layer 1");b.undoMgr.resetUndoStack();Oa.initGroup();Ca=Oa.getRubberBandBox();I("cleared")}; -this.linkControlPoints=Va.linkControlPoints;this.getContentElem=function(){return l};this.getRootElem=function(){return e};this.getSelectedElems=function(){return J};var Vb=this.getResolution=function(){var g=l.getAttribute("width")/o,h=l.getAttribute("height")/o;return{w:g,h:h,zoom:o}};this.getZoom=function(){return o};this.getVersion=function(){return"svgcanvas.js ($Rev: 2082 $)"};this.setUiStrings=function(g){$.extend(Gb,g.notification)};this.setConfig=function(g){$.extend(m,g)};this.getTitle= -function(g){if(g=g||J[0]){g=$(g).data("gsvg")||$(g).data("symbol")||g;g=g.childNodes;for(var h=0;h<g.length;h++)if(g[h].nodeName=="title")return g[h].textContent;return""}};this.setGroupTitle=function(g){var h=J[0];h=$(h).data("gsvg")||h;var k=$(h).children("title"),v=new La("Set Label");if(g.length)if(k.length){k=k[0];v.addSubCommand(new Wa(k,{"#text":k.textContent}));k.textContent=g}else{k=d.createElementNS(c,"title");k.textContent=g;$(h).prepend(k);v.addSubCommand(new Ka(k))}else{v.addSubCommand(new Ua(k[0], -k.nextSibling,h));k.remove()}Ga(v)};this.getDocumentTitle=function(){return b.getTitle(l)};this.setDocumentTitle=function(g){for(var h=l.childNodes,k=false,v="",t=new La("Change Image Title"),E=0;E<h.length;E++)if(h[E].nodeName=="title"){k=h[E];v=k.textContent;break}if(!k){k=d.createElementNS(c,"title");l.insertBefore(k,l.firstChild)}if(g.length)k.textContent=g;else k.parentNode.removeChild(k);t.addSubCommand(new Wa(k,{"#text":v}));Ga(t)};this.getEditorNS=function(g){g&&l.setAttribute("xmlns:se", -"http://svg-edit.googlecode.com");return"http://svg-edit.googlecode.com"};this.setResolution=function(g,h){var k=Vb(),v=k.w;k=k.h;var t;if(g=="fit"){var E=getStrokedBBox();if(E){t=new La("Fit Canvas to Content");var w=Ib();qb(w);var s=[],A=[];$.each(w,function(){s.push(E.x*-1);A.push(E.y*-1)});w=b.moveSelectedElements(s,A,true);t.addSubCommand(w);bb();g=Math.round(E.width);h=Math.round(E.height)}else return false}if(g!=v||h!=k){w=e.suspendRedraw(1E3);t||(t=new La("Change Image Dimensions"));g=qa("width", -g);h=qa("height",h);l.setAttribute("width",g);l.setAttribute("height",h);this.contentW=g;this.contentH=h;t.addSubCommand(new Wa(l,{width:v,height:k}));l.setAttribute("viewBox",[0,0,g/o,h/o].join(" "));t.addSubCommand(new Wa(l,{viewBox:["0 0",v,k].join(" ")}));Ga(t);e.unsuspendRedraw(w);I("changed",[l])}return true};this.getOffset=function(){return $(l).attr(["x","y"])};this.setBBoxZoom=function(g,h,k){var v=0.85,t=function(E){if(!E)return false;var w=Math.min(Math.round(h/E.width*100*v)/100,Math.round(k/ -E.height*100*v)/100);b.setZoom(w);return{zoom:w,bbox:E}};if(typeof g=="object"){g=g;if(g.width==0||g.height==0){b.setZoom(g.zoom?g.zoom:o*g.factor);return{zoom:o,bbox:g}}return t(g)}switch(g){case "selection":if(!J[0])return;g=$.map(J,function(E){if(E)return E});g=getStrokedBBox(g);break;case "canvas":g=Vb();v=0.95;g={width:g.w,height:g.h,x:0,y:0};break;case "content":g=getStrokedBBox();break;case "layer":g=getStrokedBBox(Ib(z().getCurrentLayer()));break;default:return}return t(g)};this.setZoom=function(g){var h= -Vb();l.setAttribute("viewBox","0 0 "+h.w/g+" "+h.h/g);o=g;$.each(J,function(k,v){v&&Oa.requestSelector(v).resize()});Va.zoomChange();ob("zoomChanged",g)};this.getMode=function(){return Na};this.setMode=function(g){Va.clear(true);rb.clear();$("#workarea").attr("class",g);jb=J[0]&&J[0].nodeName=="text"?cb:N;Na=g};this.getColor=function(g){return jb[g]};this.setColor=function(g,h,k){N[g]=h;jb[g+"_paint"]={type:"solidColor"};for(var v=[],t=J.length;t--;){var E=J[t];if(E)if(E.tagName=="g")svgedit.utilities.walkTree(E, -function(w){w.nodeName!="g"&&v.push(w)});else if(g=="fill")E.tagName!="polyline"&&E.tagName!="line"&&v.push(E);else v.push(E)}if(v.length>0)if(k)Sb(g,h,v);else{vb(g,h,v);I("changed",v)}};var ub=function(){var g=l.getElementsByTagNameNS(c,"defs");if(g.length>0)g=g[0];else{g=d.createElementNS(c,"defs");l.firstChild?l.insertBefore(g,l.firstChild.nextSibling):l.appendChild(g)}return g},ic=this.setGradient=function(g){if(!(!jb[g+"_paint"]||jb[g+"_paint"].type=="solidColor")){var h=b[g+"Grad"],k=dc(h), -v=ub();if(k)h=k;else{h=v.appendChild(d.importNode(h,true));h.id=M()}b.setColor(g,"url(#"+h.id+")")}},dc=function(g){var h=ub();h=$(h).find("linearGradient, radialGradient");for(var k=h.length,v=["r","cx","cy","fx","fy"];k--;){var t=h[k];if(g.tagName=="linearGradient"){if(g.getAttribute("x1")!=t.getAttribute("x1")||g.getAttribute("y1")!=t.getAttribute("y1")||g.getAttribute("x2")!=t.getAttribute("x2")||g.getAttribute("y2")!=t.getAttribute("y2"))continue}else{var E=$(g).attr(v),w=$(t).attr(v),s=false; -$.each(v,function(H,P){if(E[P]!=w[P])s=true});if(s)continue}var A=g.getElementsByTagNameNS(c,"stop"),F=t.getElementsByTagNameNS(c,"stop");if(A.length==F.length){for(var C=A.length;C--;){var D=A[C],G=F[C];if(D.getAttribute("offset")!=G.getAttribute("offset")||D.getAttribute("stop-opacity")!=G.getAttribute("stop-opacity")||D.getAttribute("stop-color")!=G.getAttribute("stop-color"))break}if(C==-1)return t}}return null};this.setPaint=function(g,h){var k=new $.jGraduate.Paint(h);this.setPaintOpacity(g, -k.alpha/100,true);jb[g+"_paint"]=k;switch(k.type){case "solidColor":if(k.solidColor!="none")this.setColor(g,"#"+k.solidColor);else{this.setColor(g,"none");document.querySelector(g=="fill"?"#fill_color rect":"#stroke_color rect").setAttribute("fill","transparent")}break;case "linearGradient":case "radialGradient":b[g+"Grad"]=k[k.type];ic(g)}};this.getStrokeWidth=function(){return jb.stroke_width};this.setStrokeWidth=function(g){if(g==0&&["line","path"].indexOf(Na)>=0)b.setStrokeWidth(1);else{jb.stroke_width= -g;for(var h=[],k=J.length;k--;){var v=J[k];if(v)v.tagName=="g"?svgedit.utilities.walkTree(v,function(t){t.nodeName!="g"&&h.push(t)}):h.push(v)}if(h.length>0){vb("stroke-width",g,h);I("changed",J)}}};this.setStrokeAttr=function(g,h){N[g.replace("-","_")]=h;for(var k=[],v=J.length;v--;){var t=J[v];if(t)t.tagName=="g"?svgedit.utilities.walkTree(t,function(E){E.nodeName!="g"&&k.push(E)}):k.push(t)}if(k.length>0){vb(g,h,k);I("changed",J)}};this.getStyle=function(){return N};this.getOpacity=function(){return N.opacity}; -this.setOpacity=function(g){N.opacity=g;vb("opacity",g)};this.getFillOpacity=function(){return N.fill_opacity};this.getStrokeOpacity=function(){return N.stroke_opacity};this.setPaintOpacity=function(g,h,k){N[g+"_opacity"]=h;k?Sb(g+"-opacity",h):vb(g+"-opacity",h)};this.getBlur=function(g){var h=0;if(g)if(g.getAttribute("filter"))if(g=la(g.id+"_blur"))h=g.firstChild.getAttribute("stdDeviation");return h};(function(){function g(){var t=b.undoMgr.finishUndoableChange();h.addSubCommand(t);Ga(h);k=h=null} -var h=null,k=null,v=false;b.setBlurNoUndo=function(t){if(k)if(t===0){Sb("filter","");v=true}else{var E=J[0];v&&Sb("filter","url(#"+E.id+"_blur)");if(svgedit.browser.isWebkit()){E.removeAttribute("filter");E.setAttribute("filter","url(#"+E.id+"_blur)")}Sb("stdDeviation",t,[k.firstChild]);b.setBlurOffsets(k,t)}else b.setBlur(t)};b.setBlurOffsets=function(t,E){if(E>3)ma(t,{x:"-50%",y:"-50%",width:"200%",height:"200%"},100);else if(!svgedit.browser.isWebkit()){t.removeAttribute("x");t.removeAttribute("y"); -t.removeAttribute("width");t.removeAttribute("height")}};b.setBlur=function(t,E){if(h)g();else{var w=J[0],s=w.id;k=la(s+"_blur");t-=0;var A=new La;if(k){if(t===0)k=null}else{var F=da({element:"feGaussianBlur",attr:{"in":"SourceGraphic",stdDeviation:t}});k=da({element:"filter",attr:{id:s+"_blur"}});k.appendChild(F);ub().appendChild(k);A.addSubCommand(new Ka(k))}F={filter:w.getAttribute("filter")};if(t===0){w.removeAttribute("filter");A.addSubCommand(new Wa(w,F))}else{vb("filter","url(#"+s+"_blur)"); -A.addSubCommand(new Wa(w,F));b.setBlurOffsets(k,t);h=A;b.undoMgr.beginUndoableChange("stdDeviation",[k?k.firstChild:null]);if(E){b.setBlurNoUndo(t);g()}}}}})();this.getBold=function(){var g=J[0];if(g!=null&&g.tagName=="text"&&J[1]==null)return g.getAttribute("font-weight")=="bold";return false};this.setBold=function(g){var h=J[0];if(h!=null&&h.tagName=="text"&&J[1]==null)vb("font-weight",g?"bold":"normal");J[0].textContent||rb.setCursor()};this.getItalic=function(){var g=J[0];if(g!=null&&g.tagName== -"text"&&J[1]==null)return g.getAttribute("font-style")=="italic";return false};this.setItalic=function(g){var h=J[0];if(h!=null&&h.tagName=="text"&&J[1]==null)vb("font-style",g?"italic":"normal");J[0].textContent||rb.setCursor()};this.getFontFamily=function(){return cb.font_family};this.setFontFamily=function(g){cb.font_family=g;vb("font-family",g);J[0]&&!J[0].textContent&&rb.setCursor()};this.setFontColor=function(g){cb.fill=g;vb("fill",g)};this.getFontSize=function(){return cb.fill};this.getFontSize= -function(){return cb.font_size};this.setFontSize=function(g){cb.font_size=g;vb("font-size",g);J[0].textContent||rb.setCursor()};this.getText=function(){var g=J[0];if(g==null)return"";return g.textContent};this.setTextContent=function(g){vb("#text",g);rb.init(g);rb.setCursor()};this.setImageURL=function(g){var h=J[0];if(h){var k=$(h).attr(["width","height"]);k=!k.width||!k.height;var v=ba(h);if(v!==g)k=true;else if(!k)return;var t=new La("Change Image URL");S(h,g);t.addSubCommand(new Wa(h,{"#href":v})); -k?$(new Image).load(function(){var E=$(h).attr(["width","height"]);$(h).attr({width:this.width,height:this.height});Oa.requestSelector(h).resize();t.addSubCommand(new Wa(h,E));Ga(t);I("changed",[h])}).attr("src",g):Ga(t)}};this.setLinkURL=function(g){var h=J[0];if(h){if(h.tagName!=="a"){h=$(h).parents("a");if(h.length)h=h[0];else return}var k=ba(h);if(k!==g){var v=new La("Change Link URL");S(h,g);v.addSubCommand(new Wa(h,{"#href":k}));Ga(v)}}};this.setRectRadius=function(g){var h=J[0];if(h!=null&& -h.tagName=="rect"){var k=h.getAttribute("rx");if(k!=g){h.setAttribute("rx",g);h.setAttribute("ry",g);Ga(new Wa(h,{rx:k,ry:k},"Radius"));I("changed",[h])}}};this.makeHyperlink=function(g){b.groupSelectedElements("a",g)};this.removeHyperlink=function(){b.ungroupSelectedElement()};this.setSegType=function(g){Va.setSegType(g)};this.convertToPath=function(g,h){if(g==null)$.each(J,function(wa,ha){ha&&b.convertToPath(ha)});else{if(!h)var k=new La("Convert element to Path");var v=h?{}:{fill:N.fill,"fill-opacity":N.fill_opacity, -stroke:N.stroke,"stroke-width":N.stroke_width,"stroke-dasharray":N.stroke_dasharray,"stroke-linejoin":N.stroke_linejoin,"stroke-linecap":N.stroke_linecap,"stroke-opacity":N.stroke_opacity,opacity:N.opacity,visibility:"hidden"};$.each(["marker-start","marker-end","marker-mid","filter","clip-path"],function(){if(g.getAttribute(this))v[this]=g.getAttribute(this)});var t=da({element:"path",attr:v}),E=g.getAttribute("transform");E&&t.setAttribute("transform",E);var w=g.id,s=g.parentNode;g.nextSibling? -s.insertBefore(t,g):s.appendChild(t);var A="",F=function(wa){$.each(wa,function(ha,ka){var oa=ka[1];A+=ka[0];for(var xa=0;xa<oa.length;xa+=2)A+=oa[xa]+","+oa[xa+1]+" "})},C=1.81;switch(g.tagName){case "ellipse":case "circle":var D=$(g).attr(["rx","ry","cx","cy"]),G=D.cx,H=D.cy,P=D.rx;D=D.ry;if(g.tagName=="circle")P=D=$(g).attr("r");F([["M",[G-P,H]],["C",[G-P,H-D/C,G-P/C,H-D,G,H-D]],["C",[G+P/C,H-D,G+P,H-D/C,G+P,H]],["C",[G+P,H+D/C,G+P/C,H+D,G,H+D]],["C",[G-P/C,H+D,G-P,H+D/C,G-P,H]],["Z",[]]]);break; -case "path":A=g.getAttribute("d");break;case "line":D=$(g).attr(["x1","y1","x2","y2"]);A="M"+D.x1+","+D.y1+"L"+D.x2+","+D.y2;break;case "polyline":case "polygon":A="M"+g.getAttribute("points");break;case "rect":D=$(g).attr(["rx","ry"]);P=D.rx;D=D.ry;var R=g.getBBox();G=R.x;H=R.y;var aa=R.width;R=R.height;C=4-C;!P&&!D?F([["M",[G,H]],["L",[G+aa,H]],["L",[G+aa,H+R]],["L",[G,H+R]],["L",[G,H]],["Z",[]]]):F([["M",[G,H+D]],["C",[G,H+D/C,G+P/C,H,G+P,H]],["L",[G+aa-P,H]],["C",[G+aa-P/C,H,G+aa,H+D/C,G+aa,H+ -D]],["L",[G+aa,H+R-D]],["C",[G+aa,H+R-D/C,G+aa-P/C,H+R,G+aa-P,H+R]],["L",[G+P,H+R]],["C",[G+P/C,H+R,G,H+R-D/C,G,H+R-D]],["L",[G,H+D]],["Z",[]]]);break;default:t.parentNode.removeChild(t)}A&&t.setAttribute("d",A);if(h){Va.resetOrientation(t);k=false;try{k=t.getBBox()}catch(ua){}t.parentNode.removeChild(t);return k}else{if(E){E=V(t);sa(E)&&Va.resetOrientation(t)}k.addSubCommand(new Ua(g,g.nextSibling,s));k.addSubCommand(new Ka(t));bb();g.parentNode.removeChild(g);t.setAttribute("id",w);t.removeAttribute("visibility"); -qb([t],true);Ga(k)}}};var Sb=function(g,h,k){var v=e.suspendRedraw(1E3);Na=="pathedit"&&Va.moveNode(g,h);k=k||J;for(var t=k.length,E=["g","polyline","path"];t--;){var w=k[t];if(w!=null){Na==="textedit"&&g!=="#text"&&w.textContent.length&&rb.toSelectMode(w);if((g==="x"||g==="y")&&E.indexOf(w.tagName)>=0){var s=getStrokedBBox([w]);b.moveSelectedElements((g==="x"?h-s.x:0)*o,(g==="y"?h-s.y:0)*o,true)}else{s=g==="#text"?w.textContent:w.getAttribute(g);if(s==null)s="";if(s!==String(h)){if(g=="#text"){svgedit.utilities.getBBox(w); -w.textContent=h;if(/rotate/.test(w.getAttribute("transform")))w=Ma(w)}else g=="#href"?S(w,h):w.setAttribute(g,h);if(svgedit.browser.isGecko()&&w.nodeName==="text"&&/rotate/.test(w.getAttribute("transform")))if((h+"").indexOf("url")===0||["font-size","font-family","x","y"].indexOf(g)>=0&&w.textContent)w=Ma(w);J.indexOf(w)>=0&&setTimeout(function(){w.parentNode&&Oa.requestSelector(w).resize()},0);s=ra(w);if(s!=0&&g!="transform")for(var A=V(w),F=A.numberOfItems;F--;)if(A.getItem(F).type==4){A.removeItem(F); -var C=svgedit.utilities.getBBox(w),D=O(C.x+C.width/2,C.y+C.height/2,ja(A).matrix);C=D.x;D=D.y;var G=e.createSVGTransform();G.setRotate(s,C,D);A.insertItemBefore(G,F);break}}}}}e.unsuspendRedraw(v)},vb=this.changeSelectedAttribute=function(g,h,k){k=k||J;b.undoMgr.beginUndoableChange(g,k);Sb(g,h,k);g=b.undoMgr.finishUndoableChange();g.isEmpty()||Ga(g)};this.deleteSelectedElements=function(){for(var g=new La("Delete Elements"),h=J.length,k=[],v=0;v<h;++v){var t=J[v];if(t==null)break;var E=t.parentNode, -w=t;Oa.releaseSelector(w);svgedit.path.removePath_(w.id);if(E.tagName==="a"&&E.childNodes.length===1){w=E;E=E.parentNode}var s=w.nextSibling;w=E.removeChild(w);k.push(t);J[v]=null;g.addSubCommand(new Ua(w,s,E))}g.isEmpty()||Ga(g);I("changed",k);bb()};this.cutSelectedElements=function(){for(var g=new La("Cut Elements"),h=J.length,k=[],v=0;v<h;++v){var t=J[v];if(t==null)break;var E=t.parentNode,w=t;Oa.releaseSelector(w);svgedit.path.removePath_(w.id);var s=w.nextSibling;w=E.removeChild(w);k.push(t); -J[v]=null;g.addSubCommand(new Ua(w,s,E))}g.isEmpty()||Ga(g);I("changed",k);bb();b.clipBoard=k};this.copySelectedElements=function(){b.clipBoard=$.merge([],J)};this.pasteElements=function(g,h,k){var v=b.clipBoard,t=v.length;if(t){for(var E=[],w=new La("Paste elements");t--;){var s=v[t];if(s){var A=Z(s);if(!la(s.id))A.id=s.id;E.push(A);(L||z().getCurrentLayer()).appendChild(A);w.addSubCommand(new Ka(A))}}Qb(E);if(g!="in_place"){if(yb==null){yb.x=0;yb.y=0}var F,C;if(g){if(g==="point"){F=h;C=k}}else{F= -yb.x;C=yb.y}g=getStrokedBBox(E);var D=F-(g.x+g.width/2),G=C-(g.y+g.height/2),H=[],P=[];$.each(E,function(){H.push(D);P.push(G)});F=b.moveSelectedElements(H,P,false);w.addSubCommand(F)}Ga(w);I("changed",E)}};this.groupSelectedElements=function(g){g||(g="g");var h="";switch(g){case "a":h="Make hyperlink";var k="";if(arguments.length>1)k=arguments[1];break;default:g="g";h="Group Elements"}h=new La(h);var v=da({element:g,attr:{id:M()}});g==="a"&&S(v,k);h.addSubCommand(new Ka(v));for(k=J.length;k--;){var t= -J[k];if(t!=null){if(t.parentNode.tagName==="a"&&t.parentNode.childNodes.length===1)t=t.parentNode;var E=t.nextSibling,w=t.parentNode;v.appendChild(t);h.addSubCommand(new Qa(t,E,w))}}h.isEmpty()||Ga(h);Qb([v],true)};var fc=this.pushGroupProperties=function(g,h){var k=g.childNodes,v=k.length,t=g.getAttribute("transform"),E=V(g),w=ja(E).matrix,s=new La("Push group properties"),A=0,F=ra(g),C=$(g).attr(["filter","opacity"]),D,G;for(A=0;A<v;A++){var H=k[A];if(H.nodeType===1){if(C.opacity!==null&&C.opacity!== -1){H.getAttribute("opacity");var P=Math.round((H.getAttribute("opacity")||1)*C.opacity*100)/100;vb("opacity",P,[H])}if(C.filter){var R=P=this.getBlur(H);G||(G=this.getBlur(g));if(P)P=G-0+(P-0);else if(P===0)P=G;if(R)D=X(H.getAttribute("filter"));else if(D){D=Z(D);ub().appendChild(D)}else D=X(C.filter);D.id=H.id+"_"+(D.firstChild.tagName==="feGaussianBlur"?"blur":"filter");vb("filter","url(#"+D.id+")",[H]);if(P){vb("stdDeviation",P,[D.firstChild]);b.setBlurOffsets(D,P)}}P=V(H);if(~H.tagName.indexOf("Gradient"))P= -null;if(P)if(H.tagName!=="defs")if(E.numberOfItems){if(F&&E.numberOfItems==1){var aa=E.getItem(0).matrix,ua=e.createSVGMatrix();if(R=ra(H))ua=P.getItem(0).matrix;var wa=svgedit.utilities.getBBox(H),ha=ja(P).matrix,ka=O(wa.x+wa.width/2,wa.y+wa.height/2,ha);wa=F+R;ha=e.createSVGTransform();ha.setRotate(wa,ka.x,ka.y);aa=fa(aa,ua,ha.matrix.inverse());R&&P.removeItem(0);if(wa)P.numberOfItems?P.insertItemBefore(ha,0):P.appendItem(ha);if(aa.e||aa.f){R=e.createSVGTransform();R.setTranslate(aa.e,aa.f);P.numberOfItems? -P.insertItemBefore(R,0):P.appendItem(R)}}else{R=H.getAttribute("transform");aa={};aa.transform=R?R:"";R=e.createSVGTransform();aa=ja(P).matrix;ua=aa.inverse();aa=fa(ua,w,aa);R.setMatrix(aa);P.appendItem(R)}(H=pb(H))&&s.addSubCommand(H)}}}if(t){aa={};aa.transform=t;g.setAttribute("transform","");g.removeAttribute("transform");s.addSubCommand(new Wa(g,aa))}if(h&&!s.isEmpty())return s};this.ungroupSelectedElement=function(){var g=J[0];if($(g).data("gsvg")||$(g).data("symbol"))lc(g);else if(g.tagName=== -"use"){var h=la(ba(g).substr(1));$(g).data("symbol",h).data("ref",h);lc(g)}else{h=$(g).parents("a");if(h.length)g=h[0];if(g.tagName==="g"||g.tagName==="a"){h=new La("Ungroup Elements");var k=fc(g,true);k&&h.addSubCommand(k);k=g.parentNode;for(var v=g.nextSibling,t=Array(g.childNodes.length),E=0;g.firstChild;){var w=g.firstChild,s=w.nextSibling,A=w.parentNode;if(w.tagName==="title"){h.addSubCommand(new Ua(w,w.nextSibling,A));A.removeChild(w)}else{t[E++]=w=k.insertBefore(w,v);h.addSubCommand(new Qa(w, -s,A))}}bb();v=g.nextSibling;g=k.removeChild(g);h.addSubCommand(new Ua(g,v,k));h.isEmpty()||Ga(h);qb(t)}}};this.moveToTopSelectedElement=function(){var g=J[0];if(g!=null){g=g;var h=g.parentNode,k=g.nextSibling;g=g.parentNode.appendChild(g);if(k!=g.nextSibling){Ga(new Qa(g,k,h,"top"));I("changed",[g])}}};this.moveToBottomSelectedElement=function(){var g=J[0];if(g!=null){g=g;var h=g.parentNode,k=g.nextSibling,v=g.parentNode.firstChild;if(v.tagName=="title")v=v.nextSibling;if(v.tagName=="defs")v=v.nextSibling; -g=g.parentNode.insertBefore(g,v);if(k!=g.nextSibling){Ga(new Qa(g,k,h,"bottom"));I("changed",[g])}}};this.moveUpDownSelected=function(g){var h=J[0];if(h){wb=[];var k,v,t=$(Kb(getStrokedBBox([h]))).toArray();g=="Down"&&t.reverse();$.each(t,function(){if(v){k=this;return false}else if(this==h)v=true});if(k){t=h.parentNode;var E=h.nextSibling;$(k)[g=="Down"?"before":"after"](h);if(E!=h.nextSibling){Ga(new Qa(h,E,t,"Move "+g));I("changed",[h])}}}};this.moveSelectedElements=function(g,h,k){if(g.constructor!= -Array){g/=o;h/=o}k=k||true;for(var v=new La("position"),t=J.length;t--;){var E=J[t];if(E!=null){var w=e.createSVGTransform(),s=V(E);g.constructor==Array?w.setTranslate(g[t],h[t]):w.setTranslate(g,h);s.numberOfItems?s.insertItemBefore(w,0):s.appendItem(w);(w=pb(E))&&v.addSubCommand(w);Oa.requestSelector(E).resize()}}if(!v.isEmpty()){k&&Ga(v);I("changed",J);return v}};this.cloneSelectedElements=function(g,h){for(var k=new La("Clone Elements"),v=J.length,t=0;t<v;++t){var E=J[t];if(E==null)break}v=J.slice(0, -t);this.clearSelection(true);for(t=v.length;t--;){E=v[t]=Z(v[t]);(L||z().getCurrentLayer()).appendChild(E);k.addSubCommand(new Ka(E))}if(!k.isEmpty()){qb(v.reverse());this.moveSelectedElements(g,h,false);Ga(k)}};this.alignSelectedElements=function(g,h){var k=[],v=Number.MAX_VALUE,t=Number.MIN_VALUE,E=Number.MAX_VALUE,w=Number.MIN_VALUE,s=Number.MIN_VALUE,A=Number.MIN_VALUE,F=J.length;if(F){for(var C=0;C<F;++C){if(J[C]==null)break;k[C]=getStrokedBBox([J[C]]);switch(h){case "smallest":if((g=="l"||g== -"c"||g=="r")&&(s==Number.MIN_VALUE||s>k[C].width)||(g=="t"||g=="m"||g=="b")&&(A==Number.MIN_VALUE||A>k[C].height)){v=k[C].x;E=k[C].y;t=k[C].x+k[C].width;w=k[C].y+k[C].height;s=k[C].width;A=k[C].height}break;case "largest":if((g=="l"||g=="c"||g=="r")&&(s==Number.MIN_VALUE||s<k[C].width)||(g=="t"||g=="m"||g=="b")&&(A==Number.MIN_VALUE||A<k[C].height)){v=k[C].x;E=k[C].y;t=k[C].x+k[C].width;w=k[C].y+k[C].height;s=k[C].width;A=k[C].height}break;default:if(k[C].x<v)v=k[C].x;if(k[C].y<E)E=k[C].y;if(k[C].x+ -k[C].width>t)t=k[C].x+k[C].width;if(k[C].y+k[C].height>w)w=k[C].y+k[C].height}}if(h=="page"){E=v=0;t=b.contentW;w=b.contentH}s=Array(F);A=Array(F);for(C=0;C<F;++C){if(J[C]==null)break;var D=k[C];s[C]=0;A[C]=0;switch(g){case "l":s[C]=v-D.x;break;case "c":s[C]=(v+t)/2-(D.x+D.width/2);break;case "r":s[C]=t-(D.x+D.width);break;case "t":A[C]=E-D.y;break;case "m":A[C]=(E+w)/2-(D.y+D.height/2);break;case "b":A[C]=w-(D.y+D.height)}}this.moveSelectedElements(s,A)}};this.contentW=Vb().w;this.contentH=Vb().h; -this.updateCanvas=function(g,h){e.setAttribute("width",g);e.setAttribute("height",h);var k=$("#canvasBackground")[0],v=l.getAttribute("x"),t=l.getAttribute("y"),E=g/2-this.contentW*o/2,w=h/2-this.contentH*o/2;ma(l,{width:this.contentW*o,height:this.contentH*o,x:E,y:w,viewBox:"0 0 "+this.contentW+" "+this.contentH});ma(k,{width:l.getAttribute("width"),height:l.getAttribute("height"),x:E,y:w});(k=la("background_image"))&&ma(k,{width:"100%",height:"100%"});Oa.selectorParentGroup.setAttribute("transform", -"translate("+E+","+w+")");return{x:E,y:w,old_x:v,old_y:t,d_x:E-v,d_y:w-t}};this.setBackground=function(g,h){var k=la("canvasBackground"),v=$(k).find("rect")[0],t=la("background_image");v.setAttribute("fill",g);if(h){if(!t){t=d.createElementNS(c,"image");ma(t,{id:"background_image",width:"100%",height:"100%",preserveAspectRatio:"xMinYMin",style:"pointer-events:none"})}S(t,h);k.appendChild(t)}else t&&t.parentNode.removeChild(t)};this.cycleElement=function(g){var h=J[0],k=false,v=Ib(L||z().getCurrentLayer()); -if(v.length){if(h==null){g=g?v.length-1:0;k=v[g]}else for(var t=v.length;t--;)if(v[t]==h){g=g?t-1:t+1;if(g>=v.length)g=0;else if(g<0)g=v.length-1;k=v[g];break}Qb([k],true);I("selected",J)}};this.clear();this.getPrivateMethods=function(){return{addCommandToHistory:Ga,setGradient:ic,addSvgElementFromJson:da,assignAttributes:ma,BatchCommand:La,call:I,ChangeElementCommand:Wa,copyElem:Z,ffClone:Ma,findDefs:ub,findDuplicateGradient:dc,getElem:la,getId:ta,getIntersectionList:Kb,getMouseTarget:$b,getNextId:M, -getPathBBox:U,getUrlFromAttr:pa,hasMatrixTransform:sa,identifyLayers:Wb,InsertElementCommand:Ka,isIdentity:svgedit.math.isIdentity,logMatrix:tb,matrixMultiply:fa,MoveElementCommand:Qa,preventClickDefault:Zb,recalculateAllSelectedDimensions:Xa,recalculateDimensions:pb,remapElement:xb,RemoveElementCommand:Ua,removeUnusedDefElems:gc,round:Cb,runExtensions:ob,sanitizeSvg:Ia,SVGEditTransformList:svgedit.transformlist.SVGTransformList,toString:toString,transformBox:svgedit.math.transformBox,transformListToTransform:ja, -transformPoint:O,walkTree:svgedit.utilities.walkTree}}};(function(){document.addEventListener("touchstart",touchHandler,true);document.addEventListener("touchmove",touchHandler,true);document.addEventListener("touchend",touchHandler,true);document.addEventListener("touchcancel",touchHandler,true);if(!window.svgEditor)window.svgEditor=function(a){function n(z,o){var L=f.setSvgString(z)!==false;o=o||a.noop;L?o(true):a.alert(e.notification.errorLoadingSVG,function(){o(false)})}var f,c={},m=false,p={lang:"en",iconsize:"m",bkgd_color:"FFF",bkgd_url:"",img_save:"embed"}, -b={},d={canvas_expansion:1,dimensions:[640,480],initFill:{color:"fff",opacity:1},initStroke:{width:1.5,color:"000",opacity:1},initOpacity:1,imgPath:"images/",langPath:"locale/",extPath:"extensions/",jGraduatePath:"jgraduate/images/",extensions:["ext-markers.js","ext-eyedropper.js","ext-shapes.js","ext-grid.js"],initTool:"select",wireframe:false,colorPickerCSS:false,gridSnapping:false,gridColor:"#000",baseUnit:"px",snappingStep:10,showRulers:true,show_outside_canvas:false},e=c.uiStrings={common:{ok:"OK", -cancel:"Cancel",key_up:"Up",key_down:"Down",key_backspace:"Backspace",key_del:"Del"},layers:{layer:"Layer"},notification:{invalidAttrValGiven:"Invalid value given",noContentToFitTo:"No content to fit to",dupeLayerName:"There is already a layer named that!",enterUniqueLayerName:"Please enter a unique layer name",enterNewLayerName:"Please enter the new layer name",layerHasThatName:"Layer already has that name",QmoveElemsToLayer:'Move selected elements to layer "%s"?',QwantToClear:"Do you want to clear the drawing?\nThis will also erase your undo history!", -QwantToOpen:"Do you want to open a new file?\nThis will also erase your undo history!",QerrorsRevertToSource:"There were parsing errors in your SVG source.\nRevert back to original SVG source?",QignoreSourceChanges:"Ignore changes made to SVG source?",featNotSupported:"Feature not supported",enterNewImgURL:"Enter the new image URL",defsFailOnSave:"NOTE: Due to a bug in your browser, this image may appear wrong (missing gradients or elements). It will however appear correct once actually saved.",loadingImage:"Loading image, please wait...", -saveFromBrowser:'Select "Save As..." in your browser to save this image as a %s file.',noteTheseIssues:"Also note the following issues: ",unsavedChanges:"There are unsaved changes.",enterNewLinkURL:"Enter the new hyperlink URL",errorLoadingSVG:"Error: Unable to load SVG data",URLloadFail:"Unable to load from URL",retrieving:'Retrieving "%s" ...'}};b={};var l={};c.curConfig=d;c.tool_scale=1;a.pref=function(z,o){if(o)b[z]=o;z="svg-edit-"+z;var L=location.hostname,T=L&&L.indexOf(".")>=0,N=o!=undefined, -J=false;try{if(window.localStorage)J=localStorage}catch(da){}try{if(window.globalStorage&&T)J=globalStorage[L]}catch(V){}if(J)if(N)J.setItem(z,o);else{if(J.getItem(z))return J.getItem(z)+""}else if(window.widget)if(N)widget.setPreferenceForKey(o,z);else return widget.preferenceForKey(z);else if(N){L=new Date;L.setTime(L.getTime()+31536E6);o=encodeURIComponent(o);document.cookie=z+"="+o+"; expires="+L.toUTCString()}else return(L=document.cookie.match(RegExp(z+"=([^;]+)")))?decodeURIComponent(L[1]): -""};c.setConfig=function(z){a.each(z,function(o,L){o in p&&a.pref(o,L)});a.extend(true,d,z);if(z.extensions)d.extensions=z.extensions};c.setCustomHandlers=function(z){c.ready(function(){if(z.open){a('#tool_open > input[type="file"]').remove();a("#tool_open").show();f.open=z.open}if(z.save){c.show_save_warning=false;f.bind("saved",z.save)}z.pngsave&&f.bind("exported",z.pngsave);l=z})};c.randomizeIds=function(){f.randomizeIds(arguments)};c.init=function(){function z(q,B){var K=q.id,Q=K.split("_"),W= -Q[0];Q=Q[1];B&&f.setStrokeAttr("stroke-"+W,Q);cb();H("#cur_"+W,K,20);a(q).addClass("current").siblings().removeClass("current")}function o(q,B){a.pref("bkgd_color",q);a.pref("bkgd_url",B);f.setBackground(q,B)}function L(){var q=f.getHref(Y);q=q.indexOf("data:")===0?"":q;a.prompt(e.notification.enterNewImgURL,q,function(B){B&&Ja(B)})}function T(){if(f.deleteCurrentLayer()){Za();Eb();a("#layerlist tr.layer").removeClass("layersel");a("#layerlist tr.layer:first").addClass("layersel")}}function N(){var q= -f.getCurrentDrawing().getCurrentLayerName()+" copy";a.prompt(e.notification.enterUniqueLayerName,q,function(B){if(B)if(f.getCurrentDrawing().hasLayer(B))a.alert(e.notification.dupeLayerName);else{f.cloneLayer(B);Za();Eb()}})}function J(q){var B=a("#layerlist tr.layersel").index(),K=f.getCurrentDrawing().getNumLayers();if(B>0||B<K-1){B+=q;f.setCurrentLayerPosition(K-B-1);Eb()}}function da(q,B){var K=document.getElementById("ruler_x_cursor"),Q=document.getElementById("ruler_y_cursor"),W=document.getElementById("workarea"), -ia=document.getElementById("title_show");a("#workarea").unbind("mousemove.rulers").bind("mousemove.rulers",function(Xb){Xb.stopPropagation();K.style.left=Xb.pageX-66+W.scrollLeft+"px";Q.style.top=Xb.pageY-48+W.scrollTop+"px";Xb=Xb.target.getAttribute("title");typeof Xb!="undefined"&&Xb&&ia.innerHTML(Xb)});B||(B=f.getZoom());q||(q=a("#svgcanvas"));for(var va=f.getContentElem(),ya=svgedit.units.getTypeMap()[d.baseUnit],Da=0;Da<2;Da++){var Ha=Da===0,Aa=Ha?"x":"y",fb=Ha?"width":"height",gb=va.getAttribute(Aa)- -0;Aa=a("#ruler_"+Aa+" canvas:first");$hcanv=Aa.clone();Aa.replaceWith($hcanv);var ga=$hcanv[0];var zb=Aa=q[fb]()*2;ga.parentNode.style[fb]=zb+"px";var hb=0,Ta,Pa=ga.getContext("2d");Pa.fillStyle="rgb(200,0,0)";Pa.fillRect(0,0,ga.width,ga.height);$hcanv.siblings().remove();if(Aa>=3E4){var Ya=parseInt(Aa/3E4)+1;Ta=Array(Ya);Ta[0]=Pa;for(var Ba=1;Ba<Ya;Ba++){ga[fb]=3E4;var ib=ga.cloneNode(true);ga.parentNode.appendChild(ib);Ta[Ba]=ib.getContext("2d")}ib[fb]=Aa%3E4;Aa=3E4}ga[fb]=Aa;fb=ya*B;var sb=50/ -fb;ga=1;for(Ba=0;Ba<jc.length;Ba++){ga=Ya=jc[Ba];if(sb<=Ya)break}sb=ga*fb;Pa.font="normal 9px 'Lucida Grande', sans-serif";Pa.fillStyle="#777";for(var Fb=gb/fb%ga*fb,Yb=Fb-sb;Fb<zb;Fb+=sb){Yb+=sb;Ba=Math.round(Fb)+0.5;if(Ha){Pa.moveTo(Ba,15);Pa.lineTo(Ba,0)}else{Pa.moveTo(15,Ba);Pa.lineTo(0,Ba)}Ya=(Yb-gb)/fb;if(ga>=1)Ba=Math.round(Ya);else{Ba=(ga+"").split(".")[1].length;Ba=Ya.toFixed(Ba)-0}if(Ba!==0&&Ba!==1E3&&Ba%1E3===0)Ba=Ba/1E3+"K";if(Ha){Pa.fillText(Ba,Fb+2,8);Pa.fillStyle="#777"}else{Ya=(Ba+ -"").split("");for(Ba=0;Ba<Ya.length;Ba++){Pa.fillText(Ya[Ba],1,Fb+9+Ba*9);Pa.fillStyle="#777"}}Ya=sb/10;for(Ba=1;Ba<10;Ba++){var Mb=Math.round(Fb+Ya*Ba)+0.5;if(Ta&&Mb>Aa){hb++;Pa.stroke();if(hb>=Ta.length){Ba=10;Fb=zb;continue}Pa=Ta[hb];Fb-=3E4;Mb=Math.round(Fb+Ya*Ba)+0.5}var qc=Ba%2?12:10;if(Ha){Pa.moveTo(Mb,15);Pa.lineTo(Mb,qc)}else{Pa.moveTo(15,Mb);Pa.lineTo(qc,Mb)}}}Pa.strokeStyle="#666";Pa.stroke()}}(function(){var q=window.opener;if(q)try{var B=q.document.createEvent("Event");B.initEvent("svgEditorReady", -true,true);q.document.documentElement.dispatchEvent(B)}catch(K){}})();(function(){var q=a.deparam.querystring(true);if(!a.isEmptyObject(q)){if(q.dimensions)q.dimensions=q.dimensions.split(",");if(q.extensions)q.extensions=q.extensions.split(",");if(q.bkgd_color)q.bkgd_color="#"+q.bkgd_color;svgEditor.setConfig(q);var B=q.source,K=a.param.querystring();if(!B)if(K.indexOf("source=data:")>=0)B=K.match(/source=(data:[^&]*)/)[1];if(B)if(B.indexOf("data:")===0){B=B.replace(/ /g,"+");c.loadFromDataURI(B)}else c.loadFromString(B); -else if(K.indexOf("paramurl=")!==-1)svgEditor.loadFromURL(K.substr(9));else q.url&&svgEditor.loadFromURL(q.url)}})();var V=function(){a.each(d.extensions,function(){var B=this;a.getScript(d.extPath+B,function(K){if(!K){K=document.createElement("script");K.src=d.extPath+B;document.querySelector("head").appendChild(K)}})});var q=[];a("#lang_select option").each(function(){q.push(this.value)});c.putLocale(null,q)};document.location.protocol==="file:"?setTimeout(V,100):V();a.svgIcons(d.imgPath+"svg_edit_icons.svg", -{w:24,h:24,id_match:false,no_img:!svgedit.browser.isWebkit(),fallback_path:d.imgPath,fallback:{new_image:"clear.png",save:"save.png",open:"open.png",source:"source.png",docprops:"document-properties.png",wireframe:"wireframe.png",undo:"undo.png",redo:"redo.png",select:"select.png",select_node:"select_node.png",pencil:"fhpath.png",pen:"line.png",square:"square.png",rect:"rect.png",fh_rect:"freehand-square.png",circle:"circle.png",ellipse:"ellipse.png",fh_ellipse:"freehand-circle.png",path:"path.png", -text:"text.png",image:"image.png",zoom:"zoom.png",clone:"clone.png",node_clone:"node_clone.png","delete":"delete.png",node_delete:"node_delete.png",move_top:"move_top.png",move_bottom:"move_bottom.png",to_path:"to_path.png",link_controls:"link_controls.png",reorient:"reorient.png",align_left:"align-left.png",align_center:"align-center",align_right:"align-right",align_top:"align-top",align_middle:"align-middle",align_bottom:"align-bottom",go_up:"go-up.png",go_down:"go-down.png",ok:"save.png",cancel:"cancel.png", -arrow_right:"flyouth.png",arrow_down:"dropdown.gif"},placement:{"#tool_docprops > div":"docprops","#tool_select":"select","#tool_fhpath":"pencil","#tool_line":"pen","#tool_rect,#tools_rect_show":"rect","#tool_square":"square","#tool_fhrect":"fh_rect","#tool_ellipse,#tools_ellipse_show":"ellipse","#tool_circle":"circle","#tool_fhellipse":"fh_ellipse","#tool_path":"path","#tool_text,#layer_rename":"text","#tool_image":"image","#tool_zoom":"zoom","#tool_node_clone":"node_clone","#tool_node_delete":"node_delete", -"#tool_add_subpath":"add_subpath","#tool_openclose_path":"open_path","#tool_alignleft, #tool_posleft":"align_left","#tool_aligncenter, #tool_poscenter":"align_center","#tool_alignright, #tool_posright":"align_right","#tool_aligntop, #tool_postop":"align_top","#tool_alignmiddle, #tool_posmiddle":"align_middle","#tool_alignbottom, #tool_posbottom":"align_bottom","#cur_position":"align","#linecap_butt,#cur_linecap":"linecap_butt","#linecap_round":"linecap_round","#linecap_square":"linecap_square","#linejoin_miter,#cur_linejoin":"linejoin_miter", -"#linejoin_round":"linejoin_round","#linejoin_bevel":"linejoin_bevel","#url_notice":"warning","#layer_up":"go_up","#layer_down":"go_down","#layer_moreopts":"context_menu","#layerlist td.layervis":"eye","#tool_source_save,#tool_docprops_save,#tool_prefs_save":"ok","#tool_source_cancel,#tool_docprops_cancel,#tool_prefs_cancel":"cancel","#rwidthLabel, #iwidthLabel":"width","#rheightLabel, #iheightLabel":"height","#angleLabel":"angle","#linkLabel,#tool_make_link,#tool_make_link_multi":"globe_link","#zoomLabel":"zoom", -"#blurLabel":"blur",".flyout_arrow_horiz":"arrow_right","#palette .palette_item:first, #fill_bg, #stroke_bg":"no_color"},resize:{"#logo .svg_icon":32,".flyout_arrow_horiz .svg_icon":5,".layer_button .svg_icon, #layerlist td.layervis .svg_icon":14,"#main_button .dropdown .svg_icon":9,"#fill_bg .svg_icon, #stroke_bg .svg_icon":24,".palette_item:first .svg_icon":16,".toolbar_button button .svg_icon":16,".stroke_tool div div .svg_icon":20,"#tools_bottom label .svg_icon":18,"#zoom_dropdown .svg_icon":7}, -callback:function(){a(".toolbar_button button > svg, .toolbar_button button > img").each(function(){a(this).parent().prepend(this)});var q=a("#tools_left");if(q.length!=0){q.offset();q.outerHeight()}a(".tools_flyout").each(function(){var B=a("#"+this.id+"_show"),K=B.attr("data-curopt");if(!B.children("svg, img").length){K=a(K).children().clone();if(K.length){K[0].removeAttribute("style");B.append(K)}}});svgEditor.runCallbacks();setTimeout(function(){a(".flyout_arrow_horiz:empty").each(function(){a(this).append(a.getSvgIcon("arrow_right").width(5).height(5))})}, -1)}});c.canvas=f=new a.SvgCanvas(document.getElementById("svgcanvas"),d);c.show_save_warning=false;V=navigator.platform.indexOf("Mac")>=0;var O=navigator.userAgent.indexOf("AppleWebKit")>=0,fa=V?"meta+":"ctrl+",sa=f.pathActions,ja=f.undoMgr,ca=svgedit.utilities,ea=d.imgPath+"placeholder.svg",qa=a("#workarea"),pa=a("#cmenu_canvas");a("#cmenu_layers");var ba=null,S=1,U="toolbars",ra="",la={fill:null,stroke:null};(function(){a("#dialog_container").draggable({cancel:"#dialog_content, #dialog_buttons *", -containment:"window"});var q=a("#dialog_box"),B=a("#dialog_buttons"),K=function(Q,W,ia,va){a("#dialog_content").html("<p>"+W.replace(/\n/g,"</p><p>")+"</p>").toggleClass("prompt",Q=="prompt");B.empty();var ya=a('<input type="button" value="'+e.common.ok+'">').appendTo(B);Q!="alert"&&a('<input type="button" value="'+e.common.cancel+'">').appendTo(B).click(function(){q.hide();ia(false)});if(Q=="prompt"){var Da=a('<input type="text">').prependTo(B);Da.val(va||"");Da.bind("keydown","return",function(){ya.click()})}Q== -"process"&&ya.hide();q.show();ya.click(function(){q.hide();var Ha=Q=="prompt"?Da.val():true;ia&&ia(Ha)}).focus();Q=="prompt"&&Da.focus()};a.alert=function(Q,W){K("alert",Q,W)};a.confirm=function(Q,W){K("confirm",Q,W)};a.process_cancel=function(Q,W){K("process",Q,W)};a.prompt=function(Q,W,ia){K("prompt",Q,ia,W)}})();var ma=function(){var q=a(".tool_button_current");if(q.length&&q[0].id!=="tool_select"){q.removeClass("tool_button_current").addClass("tool_button");a("#tool_select").addClass("tool_button_current").removeClass("tool_button"); -a("#styleoverrides").text("#svgcanvas svg *{cursor:move;pointer-events:all} #svgcanvas svg{cursor:default}")}f.setMode("select")},Y=null,za=false,Ia=false,Qa=false,Ka=false,Ua="",Wa=a("title:first").text(),La=function(q,B,K){f.getResolution();a("#svgcanvas").position();if(B=f.setBBoxZoom(B,qa.width()-15,qa.height()-15)){q=B.zoom;B=B.bbox;if(q<0.0010)Na({value:0.1});else{a("#zoom").val(q*100);K?Tb():Tb(false,{x:B.x*q+B.width*q/2,y:B.y*q+B.height*q/2});f.getMode()=="zoom"&&B.width&&ma();t()}}};a("#cur_context_panel").delegate("a", -"click",function(){var q=a(this);q.attr("data-root")?f.leaveContext():f.setContext(q.text());return false});var Ga={},Oa=function(q){a.each(q,function(B,K){var Q=a(B).children(),W=B+"_show",ia=a(W),va=false;Q.addClass("tool_button").unbind("click mousedown mouseup").each(function(Ha){var Aa=K[Ha];Ga[Aa.sel]=Aa.fn;if(Aa.isDefault)va=Ha;Ha=function(fb){var gb=Aa;if(fb.type==="keydown"){var ga=a(gb.parent+"_show").hasClass("tool_button_current"),zb=a(gb.parent+"_show").attr("data-curopt");a.each(q[Aa.parent], -function(Ta,Pa){if(Pa.sel==zb)gb=!fb.shiftKey||!ga?Pa:q[Aa.parent][Ta+1]||q[Aa.parent][0]})}if(a(this).hasClass("disabled"))return false;kb(W)&&gb.fn();var hb=gb.icon?a.getSvgIcon(gb.icon,true):a(gb.sel).children().eq(0).clone();hb[0].setAttribute("width",ia.width());hb[0].setAttribute("height",ia.height());ia.children(":not(.flyout_arrow_horiz)").remove();ia.append(hb).attr("data-curopt",gb.sel)};a(this).mouseup(Ha);Aa.key&&a(document).bind("keydown",Aa.key[0]+" shift+"+Aa.key[0],Ha)});if(va)ia.attr("data-curopt", -K[va].sel);else ia.attr("data-curopt")||ia.attr("data-curopt",K[0].sel);var ya,Da=a(W).position();a(B).css({left:Da.left+34,top:Da.top+77});ia.mousedown(function(Ha){a("#tools_shapelib").is(":visible")&&kb(W,false);if(ia.hasClass("disabled"))return false;var Aa=a(B),fb=Da.left+34,gb=Aa.width()*-1,ga=Aa.data("shown_popop")?200:0;ya=setTimeout(function(){ia.data("isLibrary")?Aa.css("left",fb).show():Aa.css("left",gb).show().animate({left:fb},150);Aa.data("shown_popop",true)},ga);Ha.preventDefault()}).mouseup(function(){clearTimeout(ya); -var Ha=a(this).attr("data-curopt");if(ia.data("isLibrary")&&a(W.replace("_show","")).is(":visible"))kb(W,true);else kb(W)&&Ha in Ga&&Ga[Ha]()})});Nb()},Fa=function(q,B){return a("<div>",{"class":"tools_flyout",id:q}).appendTo("#svg_editor").append(B)},Gb=function(){a(".tools_flyout").each(function(){var q=a("#"+this.id+"_show"),B=q.offset();q=q.outerWidth();a(this).css({left:(B.left+q)*S,top:B.top})})},Nb=function(){a(".tools_flyout").each(function(){var q=a("#"+this.id+"_show");if(!q.data("isLibrary")){var B= -[];a(this).children().each(function(){B.push(this.title)});q[0].title=B.join(" / ")}})},lb,ab=function(q,B,K){var Q=null;if(q.indexOf("url(#")===0){q=(q=f.getRefElem(q))?q.cloneNode(true):a("#"+K+"_color defs *")[0];Q={alpha:B};Q[q.tagName]=q}else Q=q.indexOf("#")===0?{alpha:B,solidColor:q.substr(1)}:{alpha:B,solidColor:"none"};return new a.jGraduate.Paint(Q)},Sa=f.getResolution();if(d.baseUnit!=="px"){Sa.w=svgedit.units.convertUnit(Sa.w)+d.baseUnit;Sa.h=svgedit.units.convertUnit(Sa.h)+d.baseUnit}a(".canvas_width").val(Sa.w); -a(".canvas_height").val(Sa.h);a("#docprops_button").on("click",function(){w()});var Ja=c.setImageURL=function(q){q||(q=ea);f.setImageURL(q);a("#image_url").val(q);if(q.indexOf("data:")===0){a("#image_url").hide();a("#change_image_url").show()}else{f.embedImage(q,function(B){B?a("#url_notice").hide():a("#url_notice").show();ea=q});a("#image_url").show();a("#change_image_url").hide()}},Ea=function(q){var B=Math.min(Math.max(12+q.value.length*6,50),300);a(q).width(B)},Za=function(){var q=Y;if(q!=null&& -!q.parentNode)q=null;var B=f.getCurrentDrawing().getCurrentLayerName(),K=f.getMode(),Q=d.baseUnit!=="px"?d.baseUnit:null,W=K=="pathedit",ia=a("#cmenu_canvas li");a("#selected_panel, #multiselected_panel, #g_panel, #path_panel, #rect_panel, #canvas_panel, #circle_panel,\t\t\t\t\t#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel, #use_panel, #a_panel").hide();a(".menu_item","#edit_menu").addClass("disabled");a(".menu_item","#object_menu").addClass("disabled");!q&&!za&&a("#canvas_panel").show(); -if(q!=null){var va=q.nodeName,ya=f.getRotationAngle(q);a("#angle").val(Math.round(ya));ya=f.getBlur(q);a("#blur").val(ya);a("#blur_slider").slider("option","value",ya);f.addedNew&&va==="image"&&f.getHref(q).indexOf("data:")!==0&&L();if(!W&&K!="pathedit"){a("#selected_panel").show();a(".action_selected").removeClass("disabled");if(["line","circle","ellipse"].indexOf(va)>=0)a("#xy_panel").hide();else{var Da,Ha;if(["g","polyline","path"].indexOf(va)>=0){if(K=f.getStrokedBBox([q])){Da=K.x;Ha=K.y}}else{Da= -q.getAttribute("x");Ha=q.getAttribute("y")}if(Q){Da=svgedit.units.convertUnit(Da);Ha=svgedit.units.convertUnit(Ha)}a("#selected_x").val(Da||0);a("#selected_y").val(Ha||0);a("#xy_panel").show()}["image","text","path","g","use"].indexOf(va)==-1&&a(".action_path_convert_selected").removeClass("disabled");va==="path"&&a(".action_path_selected").removeClass("disabled")}else{B=sa.getNodePoint();a("#tool_add_subpath").removeClass("push_button_pressed").addClass("tool_button");a("#tool_node_delete").toggleClass("disabled", -!sa.canDeleteNodes);H("#tool_openclose_path",sa.closed_subpath?"open_path":"close_path");if(B){W=a("#seg_type");if(Q){B.x=svgedit.units.convertUnit(B.x);B.y=svgedit.units.convertUnit(B.y)}a("#path_node_x").val(B.x);a("#path_node_y").val(B.y);B.type?W.val(B.type).removeAttr("disabled"):W.val(4).attr("disabled","disabled")}return}Q={g:[],a:[],rect:["rx","width","height"],image:["width","height"],circle:["cx","cy","r"],ellipse:["cx","cy","rx","ry"],line:["x1","y1","x2","y2"],text:[],use:[]};var Aa=q.tagName; -a(q).data("gsvg")&&a("#g_panel").show();Aa=="path"&&a("#path_panel").show();if(Q[Aa]){Q=Q[Aa];a("#"+Aa+"_panel").show();a.each(Q,function(fb,gb){var ga=q.getAttribute(gb);if(d.baseUnit!=="px"&&q[gb])ga=svgedit.units.convertUnit(q[gb].baseVal.value);a("#"+Aa+"_"+gb).val(ga||0)});if(Aa=="text"){a("#text_panel").css("display","inline");f.getItalic()?a("#tool_italic").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_italic").removeClass("push_button_pressed").addClass("tool_button"); -f.getBold()?a("#tool_bold").addClass("push_button_pressed").removeClass("tool_button"):a("#tool_bold").removeClass("push_button_pressed").addClass("tool_button");a("#font_family").val(q.getAttribute("font-family"));a("#font_size").val(q.getAttribute("font-size"));a("#text").val(q.textContent);f.addedNew&&setTimeout(function(){a("#text").focus().select()},100)}else if(Aa=="image")Ja(f.getHref(q));else if(Aa==="g"||Aa==="use"){a("#container_panel").show();a(".action_group_selected").removeClass("disabled"); -Q=f.getTitle();va=a("#g_title")[0];va.value=Q;Ea(va);Aa=="use"?va.setAttribute("disabled","disabled"):va.removeAttribute("disabled")}}ia[(Aa==="g"?"en":"dis")+"ableContextMenuItems"]("#ungroup");ia[(Aa==="g"||!za?"dis":"en")+"ableContextMenuItems"]("#group")}else if(za){a("#multiselected_panel").show();a(".action_multi_selected").removeClass("disabled");ia.enableContextMenuItems("#group").disableContextMenuItems("#ungroup")}else ia.disableContextMenuItems("#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back"); -ja.getUndoStackSize()>0?a("#tool_undo").removeClass("disabled"):a("#tool_undo").addClass("disabled");ja.getRedoStackSize()>0?a("#tool_redo").removeClass("disabled"):a("#tool_redo").addClass("disabled");f.addedNew=false;if(q&&!W||za){a("#selLayerNames").removeAttr("disabled").val(B);pa.enableContextMenuItems("#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back")}else a("#selLayerNames").attr("disabled","disabled")};a("#text").focus(function(){});a("#text").blur(function(){});f.bind("selected", -function(q,B){var K=f.getMode();K==="select"&&ma();K=K=="pathedit";Y=B.length==1||B[1]==null?B[0]:null;za=B.length>=2&&B[1]!=null;if(Y!=null)if(!K){if(Y!=null)switch(Y.tagName){case "use":case "image":case "foreignObject":break;case "g":case "a":for(var Q=null,W=Y.getElementsByTagName("*"),ia=0,va=W.length;ia<va;ia++){var ya=W[ia].getAttribute("stroke-width");if(ia===0)Q=ya;else if(Q!==ya)Q=null}a("#stroke_width").val(Q===null?"":Q);la.fill.update(true);la.stroke.update(true);break;default:la.fill.update(true); -la.stroke.update(true);a("#stroke_width").val(Y.getAttribute("stroke-width")||1);a("#stroke_style").val(Y.getAttribute("stroke-dasharray")||"none");Q=Y.getAttribute("stroke-linejoin")||"miter";a("#linejoin_"+Q).length!=0&&z(a("#linejoin_"+Q)[0]);Q=Y.getAttribute("stroke-linecap")||"butt";a("#linecap_"+Q).length!=0&&z(a("#linecap_"+Q)[0])}if(Y!=null){Q=(Y.getAttribute("opacity")||1)*100;a("#group_opacity").val(Q);a("#opac_slider").slider("option","value",Q);a("#elem_id").val(Y.id)}bc()}a("#path_node_panel").toggle(K); -a("#tools_bottom_2,#tools_bottom_3").toggle(!K);if(K){a(".tool_button_current").removeClass("tool_button_current").addClass("tool_button");a("#tool_select").addClass("tool_button_current").removeClass("tool_button");H("#tool_select","select_node");za=false;if(B.length)Y=B[0]}else H("#tool_select","select");Za();f.runExtensions("selectedChanged",{elems:B,selectedElement:Y,multiselected:za})});f.bind("transition",function(q,B){var K=f.getMode(),Q=B[0];if(Q){za=B.length>=2&&B[1]!=null;if(!za)switch(K){case "rotate":K= -f.getRotationAngle(Q);a("#angle").val(Math.round(K));a("#tool_reorient").toggleClass("disabled",K==0)}f.runExtensions("elementTransition",{elems:B})}});f.bind("changed",function(q,B){var K=f.getMode();K==="select"&&ma();for(var Q=0;Q<B.length;++Q){var W=B[Q];if(W&&W.tagName==="svg"){Eb();Tb()}else if(W&&Y&&Y.parentNode==null)Y=W}c.show_save_warning=true;Za();if(Y&&K==="select"){la.fill.update();la.stroke.update()}f.runExtensions("elementChanged",{elems:B})});f.bind("saved",function(q,B){c.show_save_warning= -false;B='<?xml version="1.0"?>\n'+B;var K=navigator.userAgent;if(~K.indexOf("Chrome")&&a.browser.version>=533||~K.indexOf("MSIE"))E(0,true);else{var Q=q.open("data:image/svg+xml;base64,"+ca.encode64(B)),W=a.pref("save_notice_done");if(W!=="all"){var ia=e.notification.saveFromBrowser.replace("%s","SVG");if(K.indexOf("Gecko/")!==-1)if(B.indexOf("<defs")!==-1){ia+="\n\n"+e.notification.defsFailOnSave;a.pref("save_notice_done","all");W="all"}else a.pref("save_notice_done","part");else a.pref("save_notice_done", -"all");W!=="part"&&Q.alert(ia)}}});f.bind("exported",function(q,B){var K=B.issues;a("#export_canvas").length||a("<canvas>",{id:"export_canvas"}).hide().appendTo("body");var Q=a("#export_canvas")[0];Q.width=f.contentW;Q.height=f.contentH;canvg(Q,B.svg,{renderCallback:function(){var W=Q.toDataURL("image/png");ba.location.href=W;if(a.pref("export_notice_done")!=="all"){W=e.notification.saveFromBrowser.replace("%s","PNG");if(K.length)W+="\n\n"+e.notification.noteTheseIssues+"\n \u2022 "+K.join("\n \u2022 "); -a.pref("export_notice_done","all");ba.alert(W)}}})});f.bind("zoomed",La);f.bind("contextset",function(q,B){var K="";if(B){var Q="";K='<a href="#" data-root="y">'+f.getCurrentDrawing().getCurrentLayerName()+"</a>";a(B).parentsUntil("#svgcontent > g").andSelf().each(function(){if(this.id){Q+=" > "+this.id;K+=this!==B?' > <a href="#">'+this.id+"</a>":" > "+this.id}});Ua=Q}else Ua=null;a("#cur_context_panel").toggle(!!B).html(K);C()});f.bind("extension_added",function(q,B){function K(){if(lb){clearTimeout(lb); -lb=null}W||(lb=setTimeout(function(){W=true;aa(b.iconsize)},50))}var Q=false,W=false,ia=true,va=function(){if(B.callback&&!Q&&ia){Q=true;B.callback()}},ya=[];B.context_tools&&a.each(B.context_tools,function(gb,ga){var zb=ga.container_id?' id="'+ga.container_id+'"':"",hb=a("#"+ga.panel);hb.length||(hb=a("<div>",{id:ga.panel}).appendTo("#tools_top"));switch(ga.type){case "tool_button":var Ta='<div class="tool_button">'+ga.id+"</div>",Pa=a(Ta).appendTo(hb);ga.events&&a.each(ga.events,function(ib,sb){a(Pa).bind(ib, -sb)});break;case "select":Ta="<label"+zb+'><select id="'+ga.id+'">';a.each(ga.options,function(ib,sb){Ta+='<option value="'+ib+'"'+(ib==ga.defval?" selected":"")+">"+sb+"</option>"});Ta+="</select></label>";var Ya=a(Ta).appendTo(hb).find("select");a.each(ga.events,function(ib,sb){a(Ya).bind(ib,sb)});break;case "button-select":Ta='<div id="'+ga.id+'" class="dropdown toolset" title="'+ga.title+'"><div id="cur_'+ga.id+'" class="icon_label"></div><button></button></div>';zb=a('<ul id="'+ga.id+'_opts"></ul>').appendTo("#option_lists"); -ga.colnum&&zb.addClass("optcols"+ga.colnum);a(Ta).appendTo(hb).children();ya.push({elem:"#"+ga.id,list:"#"+ga.id+"_opts",title:ga.title,callback:ga.events.change,cur:"#cur_"+ga.id});break;case "input":Ta="<label"+zb+'><span id="'+ga.id+'_label">'+ga.label+':</span><input id="'+ga.id+'" title="'+ga.title+'" size="'+(ga.size||"4")+'" value="'+(ga.defval||"")+'" type="text"/></label>';var Ba=a(Ta).appendTo(hb).find("input");ga.spindata&&Ba.SpinButton(ga.spindata);ga.events&&a.each(ga.events,function(ib, -sb){Ba.bind(ib,sb)})}});if(B.buttons){var Da={},Ha={},Aa=B.svgicons,fb={};a.each(B.buttons,function(gb,ga){for(var zb,hb=ga.id,Ta=gb;a("#"+hb).length;)hb=ga.id+"_"+ ++Ta;if(Aa){Da[hb]=ga.icon;Ta=ga.svgicon?ga.svgicon:ga.id;if(ga.type=="app_menu")Ha["#"+hb+" > div"]=Ta;else Ha["#"+hb]=Ta}else zb=ga.type=="menu"?"":a('<img src="'+ga.icon+'">');var Pa,Ya;switch(ga.type){case "mode_flyout":case "mode":Pa="tool_button";if(ga.cls)Pa+=" "+ga.cls;Ya="#tools_left";break;case "context":Pa="tool_button";Ya= -"#"+ga.panel;a(Ya).length||a("<div>",{id:ga.panel}).appendTo("#tools_top");break;case "menu":Pa="menu_item tool_button";Ya="#"+(ga.after||ga.panel);break;case "app_menu":Pa="";Ya=ga.parent||"#main_menu ul";a(Ya).length||a("<div>",{id:ga.panel}).appendTo("#tools_top")}var Ba=a(ga.list||ga.type=="app_menu"?"<li/>":"<div/>").attr("id",hb).attr("title",ga.title).addClass(Pa);if(!ga.includeWith&&!ga.list){if("position"in ga)a(Ya).children().eq(ga.position).before(Ba);else ga.type!="menu"||!ga.after?Ba.appendTo(Ya): -a(Ya).after(Ba);if(ga.type=="mode_flyout"){Ta=a(Ba);Pa=Ta.parent();if(!Ta.parent().hasClass("tools_flyout")){var ib=Ta[0].id.replace("tool_","tools_"),sb=Ta.clone().attr("id",ib+"_show").append(a("<div>",{"class":"flyout_arrow_horiz"}));Ta.before(sb);Pa=Fa(ib,Ta);Pa.data("isLibrary",true);sb.data("isLibrary",true)}Ha["#"+ib+"_show"]=ga.id;hb=fb["#"+Pa[0].id]=[{sel:"#"+hb,fn:ga.events.click,icon:ga.id,isDefault:true},Fb]}else if(ga.type=="app_menu"||ga.type=="menu")Ba.append(ga.title)}else if(ga.list){Ba.addClass("push_button"); -a("#"+ga.list+"_opts").append(Ba);if(ga.isDefault){a("#cur_"+ga.list).append(Ba.children().clone());Ta=ga.svgicon?ga.svgicon:ga.id;Ha["#cur_"+ga.list]=Ta}}else if(ga.includeWith){Ya=ga.includeWith;Ta=a(Ya.button);Pa=Ta.parent();if(!Ta.parent().hasClass("tools_flyout")){ib=Ta[0].id.replace("tool_","tools_");sb=Ta.clone().attr("id",ib+"_show").append(a("<div>",{"class":"flyout_arrow_horiz"}));Ta.before(sb);Pa=Fa(ib,Ta)}var Fb=oc.getButtonData(Ya.button);if(Ya.isDefault)Ha["#"+ib+"_show"]=ga.id;hb=fb["#"+ -Pa[0].id]=[{sel:"#"+hb,fn:ga.events.click,icon:ga.id,key:ga.key,isDefault:ga.includeWith?ga.includeWith.isDefault:0},Fb];ib="position"in Ya?Ya.position:"last";Fb=Pa.children().length;if(!isNaN(ib)&&ib>=0&&ib<Fb)Pa.children().eq(ib).before(Ba);else{Pa.append(Ba);hb.reverse()}}Aa||Ba.append(zb);ga.list||a.each(ga.events,function(Yb,Mb){if(Yb=="click")if(ga.type=="mode"){ga.includeWith?Ba.bind(Yb,Mb):Ba.bind(Yb,function(){kb(Ba)&&Mb()});if(ga.key){a(document).bind("keydown",ga.key,Mb);ga.title&&Ba.attr("title", -ga.title+" ["+ga.key+"]")}}else Ba.bind(Yb,Mb);else Ba.bind(Yb,Mb)});Oa(fb)});a.each(ya,function(){nb(this.elem,this.list,this.callback,{seticon:true})});if(Aa)ia=false;a.svgIcons(Aa,{w:24,h:24,id_match:false,no_img:!O,fallback:Da,placement:Ha,callback:function(){b.iconsize&&b.iconsize!="m"&&K();ia=true;va()}})}va()});f.textActions.setInputElem(a("#text")[0]);var Ra='<div class="palette_item" data-rgb="#none"></div>';a.each(["#000000","#3f3f3f","#7f7f7f","#bfbfbf","#ffffff","#ff0000","#ff7f00","#ffff00", -"#7fff00","#00ff00","#00ff7f","#00ffff","#007fff","#0000ff","#7f00ff","#ff00ff","#ff007f","#7f0000","#7f3f00","#7f7f00","#3f7f00","#007f00","#007f3f","#007f7f","#003f7f","#00007f","#3f007f","#7f007f","#7f003f","#ffaaaa","#ffd4aa","#ffffaa","#d4ffaa","#aaffaa","#aaffd4","#aaffff","#aad4ff"],function(q,B){Ra+='<div class="palette_item" style="background-color: '+B+';" data-rgb="'+B+'"></div>'});a("#palette").append(Ra);Ra="";a.each(["#FFF","#888","#000"],function(){Ra+='<div class="color_block" style="background-color:'+ -this+';"></div>'});a("#bg_blocks").append(Ra);var $a=a("#bg_blocks div");$a.each(function(){a(this).click(function(){$a.removeClass("cur_background");a(this).addClass("cur_background")})});if(a.pref("bkgd_color"))o(a.pref("bkgd_color"),a.pref("bkgd_url"));else a.pref("bkgd_url")&&o(p.bkgd_color,a.pref("bkgd_url"));if(a.pref("img_save")){b.img_save=a.pref("img_save");a("#image_save_opts input").val([b.img_save])}var Na=function(q){var B=q.value/100;if(B<0.0010)q.value=0.1;else{q=f.getZoom();La(window, -{width:0,height:0,x:(qa[0].scrollLeft+qa.width()/2)/q,y:(qa[0].scrollTop+qa.height()/2)/q,zoom:B},true)}},mb=function(q,B){if(B==null)B=q.value;a("#group_opacity").val(B);if(!q||!q.handle)a("#opac_slider").slider("option","value",B);f.setOpacity(B/100)},Ab=function(q,B,K){if(B==null)B=q.value;a("#blur").val(B);var Q=false;if(!q||!q.handle){a("#blur_slider").slider("option","value",B);Q=true}K?f.setBlurNoUndo(B):f.setBlur(B,Q)},cb=function(){window.opera&&a("<p/>").hide().appendTo("body").remove()}; -a("#stroke_style").change(function(){f.setStrokeAttr("stroke-dasharray",a(this).val());cb()});a("#stroke_linejoin").change(function(){f.setStrokeAttr("stroke-linejoin",a(this).val());cb()});a("select").change(function(){a(this).blur()});var jb=false;a("#selLayerNames").change(function(){var q=this.options[this.selectedIndex].value,B=e.notification.QmoveElemsToLayer.replace("%s",q),K=function(Q){if(Q){jb=true;f.moveSelectedToLayer(q);f.clearSelection();Eb()}};if(q)jb?K(true):a.confirm(B,K)});a("#font_family").change(function(){f.setFontFamily(this.value)}); -a("#seg_type").change(function(){f.setSegType(a(this).val())});a("#text").keyup(function(){f.setTextContent(this.value)});a("#image_url").change(function(){Ja(this.value)});a("#link_url").change(function(){this.value.length?f.setLinkURL(this.value):f.removeHyperlink()});a("#g_title").change(function(){f.setGroupTitle(this.value)});a(".attr_changer").change(function(){var q=this.getAttribute("data-attr"),B=this.value;if(svgedit.units.isValidUnit(q,B,Y))this.blur();else{a.alert(e.notification.invalidAttrValGiven); -this.value=Y.getAttribute(q);return false}if(q!=="id")if(isNaN(B))B=f.convertToNum(q,B);else if(d.baseUnit!=="px"){var K=svgedit.units.getTypeMap();if(Y[q]||f.getMode()==="pathedit"||q==="x"||q==="y")B*=K[d.baseUnit]}if(q==="id"){q=Y;f.clearSelection();q.id=B;f.addToSelection([q],true)}else f.changeSelectedAttribute(q,B);this.blur()});a("#palette").mouseover(function(){var q=a('<input type="hidden">');a(this).append(q);q.focus().remove()});a(".palette_item").mousedown(function(){var q=a("#tool_stroke").hasClass("active"), -B=q?"stroke":"fill",K=a(this).attr("data-rgb"),Q=null;console.log(K);if(K==="transparent"||K==="initial"||K==="#none"){K="none";Q=new a.jGraduate.Paint}else Q=new a.jGraduate.Paint({alpha:100,solidColor:K.substr(1)});la[B].setPaint(Q);if(q){f.setColor("stroke",K);K!="none"&&f.getStrokeOpacity()!=1&&f.setPaintOpacity("stroke",1)}else{f.setColor("fill",K);K!="none"&&f.getFillOpacity()!=1&&f.setPaintOpacity("fill",1)}bc()}).bind("contextmenu",function(q){q.preventDefault()});a("#toggle_stroke_tools").toggle(function(){a(".stroke_tool").css("display", -"table-cell");a(this).addClass("expanded");xa()},function(){a(".stroke_tool").css("display","none");a(this).removeClass("expanded");xa()});var kb=function(q,B){if(a(q).hasClass("disabled"))return false;if(a(q).parent().hasClass("tools_flyout"))return true;var K=K||"normal";B||a(".tools_flyout").fadeOut(K);a("#styleoverrides").text("");a(".tool_button_current").removeClass("tool_button_current").addClass("tool_button");a(q).addClass("tool_button_current").removeClass("tool_button");return true};(function(){var q= -null,B=null,K=qa[0],Q=false,W=false;a("#svgcanvas").bind("mousemove mouseup",function(ia){if(Q!==false){K.scrollLeft-=ia.clientX-q;K.scrollTop-=ia.clientY-B;q=ia.clientX;B=ia.clientY;if(ia.type==="mouseup")Q=false;return false}}).mousedown(function(ia){if(ia.button===1||W===true){Q=true;q=ia.clientX;B=ia.clientY;return false}});a(window).mouseup(function(){Q=false});a(document).bind("keydown","space",function(ia){f.spaceKey=W=true;ia.preventDefault()}).bind("keyup","space",function(ia){ia.preventDefault(); -f.spaceKey=W=false}).bind("keydown","alt",function(){f.getMode()==="zoom"&&qa.addClass("out")}).bind("keyup","alt",function(){f.getMode()==="zoom"&&qa.removeClass("out")})})();var Ca=a(".menu"),wb=function(q){q.target.style.background="#fff";setTimeout(function(){q.target.style.background="#ddd"},50);setTimeout(function(){q.target.style.background="#fff"},150);setTimeout(function(){q.target.style.background="#ddd"},200);setTimeout(function(){q.target.style.background=""},200);setTimeout(function(){a("#menu_bar").removeClass("active")}, -220);return false};a(".menu_item").live("click",function(q){wb(q)});a("svg, body").on("click",function(q){if(!a(q.target).hasClass("menu_title")&&a("#menu_bar").hasClass("active"))if(!a(q.target).hasClass("disabled")&&a(q.target).hasClass("menu_item"))wb(q);else{a("#menu_bar").removeClass("active");a(".tools_flyout").hide();a("input").blur()}});a(".menu_title").on("click",function(){a("#menu_bar").toggleClass("active")});a(".menu_title").on("mouseover",function(){Ca.removeClass("open");a(this).parent().addClass("open")}); -c.addDropDown=function(q,B,K){if(a(q).length!=0){var Q=a(q).find("button"),W=a(q).find("ul").attr("id",a(q)[0].id+"-list");K||a("#option_lists").append(W);var ia=false;K&&a(q).addClass("dropup");W.find("li").bind("mouseup",B);a(window).mouseup(function(){if(!ia){Q.removeClass("down");W.hide()}ia=false});Q.bind("mousedown",function(){if(Q.hasClass("down")){Q.removeClass("down");W.hide()}else{Q.addClass("down");if(!K){var va=a(q).offset();W.css({top:va.top,left:va.left-110})}W.show();ia=true}}).hover(function(){ia= -true}).mouseout(function(){ia=false})}};var nb=function(q,B,K,Q){var W=a(q);B=a(B);var ia=false,va=Q.dropUp;va&&a(q).addClass("dropup");B.find("li").bind("mouseup",function(){if(Q.seticon){H("#cur_"+W[0].id,a(this).children());a(this).addClass("current").siblings().removeClass("current")}K.apply(this,arguments)});a(window).mouseup(function(){if(!ia){W.removeClass("down");B.hide();B.css({top:0,left:0})}ia=false});B.height();a(q).bind("mousedown",function(){var ya=a(q).offset();if(va){ya.top-=B.height(); -ya.left+=8}else ya.top+=a(q).height();a(B).offset(ya);if(W.hasClass("down")){W.removeClass("down");B.hide();B.css({top:0,left:0})}else{W.addClass("down");B.show();ia=true;return false}}).hover(function(){ia=true}).mouseout(function(){ia=false});Q.multiclick&&B.mousedown(function(){ia=true})};c.addDropDown("#font_family_dropdown",function(){a(this).text();a("#font_family").val(a(this).text()).change()});c.addDropDown("#opacity_dropdown",function(){if(!a(this).find("div").length){var q=parseInt(a(this).text().split("%")[0]); -mb(false,q)}},false);a("#opac_slider").slider({start:function(){a("#opacity_dropdown li:not(.special)").hide()},stop:function(){a("#opacity_dropdown li").show();a(window).mouseup()},slide:function(q,B){mb(B)}});c.addDropDown("#blur_dropdown",a.noop);var yb=false;a("#blur_slider").slider({max:10,step:0.1,stop:function(q,B){yb=false;Ab(B);a("#blur_dropdown li").show();a(window).mouseup()},start:function(){yb=true},slide:function(q,B){Ab(B,null,yb)}});c.addDropDown("#zoom_dropdown",function(){var q= -a(this),B=q.attr("data-val");B?La(window,B):Na({value:parseInt(q.text())})},true);nb("#stroke_linecap","#linecap_opts",function(){z(this,true)},{dropUp:true});nb("#stroke_linejoin","#linejoin_opts",function(){z(this,true)},{dropUp:true});a("div","#position_opts").each(function(){this.addEventListener("mouseup",function(){var q=this.id.replace("tool_pos","").charAt(0);f.alignSelectedElements(q,"page")})});(function(){var q,B=function(){a(q).blur()};a("#svg_editor").find("button, select, input:not(#text)").focus(function(){q= -this;U="toolbars";qa.mousedown(B)}).blur(function(){U="canvas";qa.unbind("mousedown",B);f.getMode()=="textedit"&&a("#text").focus()})})();var Bb=function(){if(kb("#tool_select")){f.setMode("select");a("#styleoverrides").text("#svgcanvas svg *{cursor:move;pointer-events:all}, #svgcanvas svg{cursor:default}")}},ob=function(){kb("#tool_fhpath")&&f.setMode("fhpath")},Cb=function(){kb("#tool_line")&&f.setMode("line")},Kb=function(){kb("#tool_rect")&&f.setMode("rect")},Ib=function(){kb("#tool_ellipse")&& -f.setMode("ellipse")},Rb=function(){kb("#tool_image")&&f.setMode("image")},na=function(){kb("#tool_zoom")&&f.setMode("zoom")},Z=function(){if(kb("#tool_zoom")){h();ma()}},ta=function(){kb("#tool_text")&&f.setMode("text")},M=function(){kb("#tool_path")&&f.setMode("path")},I=function(){if(Y!=null||za)f.deleteSelectedElements()},X=function(){if(Y!=null||za)f.cutSelectedElements()},Ma=function(){if(Y!=null||za)f.copySelectedElements()},Xa=function(){var q=f.getZoom(),B=(qa[0].scrollLeft+qa.width()/2)/ -q-f.contentW;q=(qa[0].scrollTop+qa.height()/2)/q-f.contentH;f.pasteElements("point",B,q)},db=function(){Y!=null&&f.moveToTopSelectedElement()},tb=function(){Y!=null&&f.moveToBottomSelectedElement()},xb=function(){Y!=null&&f.moveUpDownSelected("Up")},Hb=function(){Y!=null&&f.moveUpDownSelected("Down")},pb=function(){Y!=null&&f.convertToPath()},Lb=function(){Y!=null&&sa.reorient()},bb=function(){if(Y!=null||za)a.prompt(e.notification.enterNewLinkURL,"http://",function(q){q&&f.makeHyperlink(q)})},qb= -function(q,B){if(Y!=null||za){if(d.gridSnapping){var K=f.getZoom()*d.snappingStep;q*=K;B*=K}f.moveSelectedElements(q,B)}},Qb=function(){var q=!a("#tool_node_link").hasClass("push_button_pressed");q?a("#tool_node_link").addClass("push_button_pressed").removeClass("tool_button").find("input").attr("checked",true):a("#tool_node_link").removeClass("push_button_pressed").addClass("tool_button").find("input").attr("checked",false);sa.linkControlPoints(q)},$b=function(){sa.getNodePoint()&&sa.clonePathNode()}, -Zb=function(){sa.getNodePoint()&&sa.deletePathNode()},rb=function(){var q=a("#tool_add_subpath"),B=!q.hasClass("push_button_pressed");B?q.addClass("push_button_pressed").removeClass("tool_button"):q.removeClass("push_button_pressed").addClass("tool_button");sa.addSubPath(B)},Va=function(){sa.opencloseSubPath()},gc=function(){f.cycleElement(1)},cc=function(){f.cycleElement(0)},Ub=function(q,B){if(!(Y==null||za)){q||(B*=-1);var K=a("#angle").val()*1+B;f.setRotationAngle(K);Za()}},hc=function(){var q= -d.dimensions;a.confirm(e.notification.QwantToClear,function(B){if(B){ma();f.clear();f.setResolution(q[0],q[1]);Tb(true);h();Eb();Za();la.fill.prep();la.stroke.prep();f.runExtensions("onNewDocument")}})},lc=function(){f.setBold(!f.getBold());Za();return false},Wb=function(){f.setItalic(!f.getItalic());Za();return false},ac=function(){if(!l.pngsave){var q=e.notification.loadingImage;ba=window.open("data:text/html;charset=utf-8,<title>"+q+"

            "+q+"

            ")}window.canvg?f.rasterExport():a.getScript("canvg/rgbcolor.js", -function(){a.getScript("canvg/canvg.js",function(){f.rasterExport()})})},nc=function(){f.open()},Vb=function(){},ub=function(q){var B=q.prev();B.css("background","#09f");setTimeout(function(){B.css("background","")},200)},ic=function(){if(ja.getUndoStackSize()>0){window.event.type==="keydown"&&ub(a("#edit_menu"));ja.undo();Eb()}},dc=function(){if(ja.getRedoStackSize()>0){window.event.type==="keydown"&&ub(a("#edit_menu"));ja.redo();Eb()}},Sb=function(){if(za)f.groupSelectedElements();else Y&&f.ungroupSelectedElement()}, -vb=function(){window.event.type==="keydown"&&ub(a("#edit_menu"));f.cloneSelectedElements(20,20)},fc=function(){var q=this.id.replace("tool_align","").charAt(0);f.alignSelectedElements(q,a("#align_relative_to").val())},g=function(){var q=document.querySelector("#tool_stroke rect"),B=document.querySelector("#tool_fill rect"),K=B.getAttribute("fill"),Q=q.getAttribute("fill");q=parseFloat(q.getAttribute("stroke-opacity"));if(isNaN(q))q=100;B=parseFloat(B.getAttribute("fill-opacity"));if(isNaN(B))B=100; -Q=ab(Q,q,"stroke");K=ab(K,B,"fill");la.fill.setPaint(Q,true);la.stroke.setPaint(K,true)},h=function(q){var B=f.getResolution();q=q?B.zoom*q:1;a("#zoom").val(q*100);f.setZoom(q);t();Tb(true)},k=function(){!a("#tool_wireframe").hasClass("push_button_pressed")?a("#tool_wireframe").addClass("push_button_pressed"):a("#tool_wireframe").removeClass("push_button_pressed");qa.toggleClass("wireframe");if(!kc){var q=a("#wireframe_rules");q.length?q.empty():a('').appendTo("head"); -t()}},v=function(){if(a("#tool_rulers").hasClass("push_button_pressed")){a("#tool_rulers").removeClass("push_button_pressed");a("#show_rulers").attr("checked",false);d.showRulers=false}else{a("#tool_rulers").addClass("push_button_pressed");a("#show_rulers").attr("checked",true);d.showRulers=true}a("#rulers").toggle(!!d.showRulers)},t=function(){if(!kc){var q="#workarea.wireframe #svgcontent * { stroke-width: "+1/f.getZoom()+"px; }";a("#wireframe_rules").text(qa.hasClass("wireframe")?q:"")}},E=function(q, -B){if(!Ia){Ia=true;a("#save_output_btns").toggle(!!B);a("#tool_source_back").toggle(!B);var K=ra=f.getSvgString();a("#svg_source_textarea").val(K);a("#svg_source_editor").fadeIn();A();a("#svg_source_textarea").focus()}},w=function(){if(!Qa){Qa=true;a("#image_save_opts input").val([b.img_save]);var q=f.getResolution();if(d.baseUnit!=="px"){q.w=svgedit.units.convertUnit(q.w)+d.baseUnit;q.h=svgedit.units.convertUnit(q.h)+d.baseUnit}a(".canvas_width").val(q.w);a(".canvas_height").val(q.h);a("#canvas_title").val(f.getDocumentTitle()); -a("#svg_docprops").show()}},s=function(){if(!Ka){Ka=true;var q=a("#bg_blocks div"),B=a.pref("bkgd_color"),K=a.pref("bkgd_url");q.each(function(){var Q=a(this),W=Q.css("background-color")==B;Q.toggleClass("cur_background",W);W&&a("#canvas_bg_url").removeClass("cur_background")});B||q.eq(0).addClass("cur_background");K&&a("#canvas_bg_url").val(K);a("grid_snapping_step").attr("value",d.snappingStep);d.gridSnapping==true?a("#grid_snapping_on").attr("checked","checked"):a("#grid_snapping_on").removeAttr("checked"); -a("#svg_prefs").show()}},A=function(){var q=a("#svg_source_container").height()-50;a("#svg_source_textarea").css("height",q)},F=function(){if(Ia){var q=function(){f.clearSelection();wa();h();Eb();C();la.fill.prep();la.stroke.prep()};f.setSvgString(a("#svg_source_textarea").val())?q():a.confirm(e.notification.QerrorsRevertToSource,function(B){if(!B)return false;q()});ma()}},C=function(q){q=q||f.getDocumentTitle();q=Wa+(q?": "+q:"");a("title:first").text(q)},D=function(){var q=a("#canvas_width"),B= -q.val(),K=a("#canvas_height"),Q=K.val();if(B!="fit"&&!svgedit.units.isValidUnit("width",B)){a.alert(e.notification.invalidAttrValGiven);q.parent().addClass("error");return false}q.parent().removeClass("error");if(Q!="fit"&&!svgedit.units.isValidUnit("height",Q)){a.alert(e.notification.invalidAttrValGiven);K.parent().addClass("error");return false}K.parent().removeClass("error");if(!f.setResolution(B,Q)){a.alert(e.notification.noContentToFitTo);return false}b.img_save=a("#image_save_opts :checked").val(); -a.pref("img_save",b.img_save);Tb();ha()},G=function(){var q=a("#bg_blocks div.cur_background").css("background-color")||"#FFF";o(q,a("#canvas_bg_url").val());q=a("#lang_select").val();q!=b.lang&&c.putLocale(q);aa(a("#iconsize").val());d.gridSnapping=a("#grid_snapping_on")[0].checked;d.snappingStep=a("#grid_snapping_step").val();d.showRulers=a("#show_rulers")[0].checked;a("#rulers").toggle(d.showRulers);d.showRulers&&da();d.baseUnit=a("#base_unit").val();f.setConfig(d);Tb();ka()},H=c.setIcon=function(q, -B){var K=typeof B==="string"?a.getSvgIcon(B,true):B.clone();K?a(q).append(K):console.log("NOTE: Icon image missing: "+B)},P;P=function(){var q=/^(Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/,B=document.getElementsByTagName("script")[0],K;for(K in B.style)if(q.test(K))return K.match(q)[0];if("WebkitOpacity"in B.style)return"Webkit";if("KhtmlOpacity"in B.style)return"Khtml";return""}();var R=function(q,B){P.toLowerCase();var K=["top","left","bottom","right"];q.each(function(){for(var Q=a(this),W=Q.outerWidth()* -(B-1),ia=Q.outerHeight()*(B-1),va=0;va<4;va++){var ya=K[va],Da=Q.data("orig_margin-"+ya);if(Da==null){Da=parseInt(Q.css("margin-"+ya));Q.data("orig_margin-"+ya,Da)}Da=Da*B;if(ya==="right")Da+=W;else if(ya==="bottom")Da+=ia;Q.css("margin-"+ya,Da)}})},aa=c.setIconSize=function(q,B){if(!(q==b.size&&!B)){console.log("size",q);var K=a("#tools_top .toolset, #editor_panel > *, #history_panel > *,\t\t\t\t#main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\t\t\t\t#g_panel > *, #tool_font_size > *, .tools_flyout"), -Q=1;Q=typeof q=="number"?q:{s:0.75,m:1,l:1.25,xl:1.5}[q];c.tool_scale=S=Q;Gb();var W=K.parents(":hidden");W.css("visibility","hidden").show();R(K,Q);W.css("visibility","visible").hide();a.pref("iconsize",q);a("#iconsize").val(q);W={"#tools_top":{left:50,height:72},"#tools_left":{width:31,top:74},"div#workarea":{left:38,top:74}};K=a("#tool_size_rules");if(K.length)K.empty();else K=a('').appendTo("head");if(q!="m"){var ia="";a.each(W,function(va,ya){va="#svg_editor "+ -va.replace(/,/g,", #svg_editor");ia+=va+"{";a.each(ya,function(Da,Ha){if(typeof Ha==="number")var Aa=Ha*Q+"px";else if(Ha[q]||Ha.all)Aa=Ha[q]||Ha.all;ia+=Da+":"+Aa+";"});ia+="}"});W="-"+P.toLowerCase()+"-";ia+="#tools_top .toolset, #editor_panel > *, #history_panel > *,\t\t\t\t#main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,\t\t\t\t#g_panel > *, #tool_font_size > *, .tools_flyout{"+W+"transform: scale("+Q+");} #svg_editor div.toolset .toolset {"+W+"transform: scale(1); margin: 1px !important;} #svg_editor .ui-slider {"+ -W+"transform: scale("+1/Q+");}";K.text(ia)}Gb()}},ua=function(){a("#dialog_box").hide();if(!Ia&&!Qa&&!Ka)Ua&&f.leaveContext();else{if(Ia)ra!==a("#svg_source_textarea").val()?a.confirm(e.notification.QignoreSourceChanges,function(q){q&&wa()}):wa();else if(Qa)ha();else Ka&&ka();xa()}},wa=function(){a("#svg_source_editor").hide();Ia=false;a("#svg_source_textarea").blur()},ha=function(){a("#svg_docprops").hide();a("#canvas_width,#canvas_height").removeAttr("disabled");a("#resolution")[0].selectedIndex= -0;a("#image_save_opts input").val([b.img_save]);Qa=false},ka=function(){a("#svg_prefs").hide();Ka=false},oa={width:a(window).width(),height:a(window).height()},xa=a.noop,eb;svgedit.browser.isIE()&&function(){xa=function(){if(qa[0].scrollLeft===0&&qa[0].scrollTop===0){qa[0].scrollLeft=eb.left;qa[0].scrollTop=eb.top}};eb={left:qa[0].scrollLeft,top:qa[0].scrollTop};a(window).resize(xa);svgEditor.ready(function(){setTimeout(function(){xa()},500)});qa.scroll(function(){eb={left:qa[0].scrollLeft,top:qa[0].scrollTop}})}(); -a(window).resize(function(){Ia&&A();a.each(oa,function(q,B){var K=a(window)[q]();qa[0]["scroll"+(q==="width"?"Left":"Top")]-=(K-B)/2;oa[q]=K})});(function(){qa.scroll(function(){if(a("#ruler_x").length!=0)a("#ruler_x")[0].scrollLeft=qa[0].scrollLeft;if(a("#ruler_y").length!=0)a("#ruler_y")[0].scrollTop=qa[0].scrollTop})})();a("#url_notice").click(function(){a.alert(this.title)});a("#change_image_url").click(L);(function(){var q=["clear","open","save","source","delete","delete_multi","paste","clone", -"clone_multi","move_top","move_bottom"],B="";a.each(q,function(K,Q){B+="#tool_"+Q+(K==q.length-1?",":"")});a(B).mousedown(function(){a(this).addClass("tool_button_current")}).bind("mousedown mouseout",function(){a(this).removeClass("tool_button_current")});a("#tool_undo, #tool_redo").mousedown(function(){a(this).hasClass("disabled")||a(this).addClass("tool_button_current")}).bind("mousedown mouseout",function(){a(this).removeClass("tool_button_current")})})();if(V&&!window.opera){V=["tool_clear", -"tool_save","tool_source","tool_undo","tool_redo","tool_clone"];for(Sa=V.length;Sa--;){var Db=document.getElementById(V[Sa]);if(Db!=null){var Pb=Db.title,Jb=Pb.indexOf("Ctrl+");Db.title=[Pb.substr(0,Jb),"Cmd+",Pb.substr(Jb+5)].join("")}}}var Ob=function(q){var B=q.attr("id")=="stroke_color"?"stroke":"fill",K=la[B].paint,Q=B=="stroke"?"Pick a Stroke Paint and Opacity":"Pick a Fill Paint and Opacity";q=q.position();a("#color_picker").draggable({cancel:".jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker", -containment:"window"}).css(d.colorPickerCSS||{left:q.left,bottom:50-q.top}).jGraduate({paint:K,window:{pickerTitle:Q},images:{clientPath:d.jGraduatePath},newstop:"inverse"},function(W){K=new a.jGraduate.Paint(W);la[B].setPaint(K);f.setPaint(B,K);a("#color_picker").hide()},function(){a("#color_picker").hide()})},bc=function(){var q=f.getColor("fill")=="none",B=f.getColor("stroke")=="none",K=["#tool_fhpath","#tool_line"],Q=["#tools_rect .tool_button","#tools_ellipse .tool_button","#tool_text","#tool_path"]; -if(B)for(var W in K){var ia=K[W];a(ia).hasClass("tool_button_current")&&Bb();a(ia).addClass("disabled")}else for(W in K){ia=K[W];a(ia).removeClass("disabled")}if(B&&q)for(W in Q){ia=Q[W];a(ia).hasClass("tool_button_current")&&Bb();a(ia).addClass("disabled")}else for(W in Q){ia=Q[W];a(ia).removeClass("disabled")}f.runExtensions("toolButtonStateUpdate",{nofill:q,nostroke:B});a(".tools_flyout").each(function(){var va=a("#"+this.id+"_show"),ya=false;a(this).children().each(function(){a(this).hasClass("disabled")|| -(ya=true)});va.toggleClass("disabled",!ya)});cb()};V=function(q,B){var K=d[B==="fill"?"initFill":"initStroke"],Q=(new DOMParser).parseFromString('\t\t\t\t\t',"text/xml").documentElement;Q=a(q)[0].appendChild(document.importNode(Q,true));Q.setAttribute("width",24.5);this.rect=Q.firstChild;this.defs=Q.getElementsByTagName("defs")[0]; -this.grad=this.defs.firstChild;this.paint=new a.jGraduate.Paint({solidColor:K.color});this.type=B;this.setPaint=function(W,ia){this.paint=W;var va="none",ya=W.type,Da=W.alpha/100;switch(ya){case "solidColor":va="#"+W[ya];break;case "linearGradient":case "radialGradient":this.defs.removeChild(this.grad);this.grad=this.defs.appendChild(W[ya]);va="url(#"+(this.grad.id="gradbox_"+this.type)+")"}this.rect.setAttribute("fill",va);this.rect.setAttribute("opacity",Da);if(ia){f.setColor(this.type,va,true); -f.setPaintOpacity(this.type,Da,true)}};this.update=function(W){if(Y){var ia=this.type;switch(Y.tagName){case "use":case "image":case "foreignObject":return;case "g":case "a":for(var va=null,ya=Y.getElementsByTagName("*"),Da=0,Ha=ya.length;Da300)q=300-K;else if(K+q<2)q=2-K;if(q!=0){ec-=q;K=a("#layerpanel");qa.css("right",parseInt(qa.css("right"))+q);B.css("width", -parseInt(B.css("width"))+q);K.css("width",parseInt(K.css("width"))+q);B=a("#ruler_x");B.css("right",parseInt(B.css("right"))+q)}}};a("#sidepanel_handle").mousedown(function(q){ec=q.pageX;a(window).mousemove(rc);pc=false;setTimeout(function(){pc=true},20)}).mouseup(function(){mc||sc();ec=-1;mc=false});a(window).mouseup(function(){ec=-1;mc=false;a("#svg_editor").unbind("mousemove",rc)});var sc=function(q){var B=parseInt(a("#sidepanels").css("width"));q=(B>2||q?2:150)-B;B=a("#sidepanels");var K=a("#layerpanel"), -Q=a("#ruler_x");qa.css("right",parseInt(qa.css("right"))+q);B.css("width",parseInt(B.css("width"))+q);K.css("width",parseInt(K.css("width"))+q);Q.css("right",parseInt(Q.css("right"))+q)},tc=function(q){for(var B=Array(f.getCurrentDrawing().getNumLayers()),K=0;K'+ia+"":''+ia+"";q.append(va);B.append('")}if(W!==undefined){W.clone();a("td.layervis",q).append(W.clone());a.resizeSvgIcons({"td.layervis .svg_icon":14})}a("#layerlist td.layername").mouseup(function(ya){a("#layerlist tr.layer").removeClass("layersel");a(this.parentNode).addClass("layersel");f.setCurrentLayer(this.textContent);ya.preventDefault()}).mouseover(function(){a(this).css({"font-style":"italic",color:"blue"});tc(this.textContent)}).mouseout(function(){a(this).css({"font-style":"normal",color:"black"});tc()});a("#layerlist td.layervis").click(function(){var ya= -a(this.parentNode).prevAll().length;ya=a("#layerlist tr.layer:eq("+ya+") td.layername").text();var Da=a(this).hasClass("layerinvis");f.setLayerVisibility(ya,Da);Da?a(this).removeClass("layerinvis"):a(this).addClass("layerinvis")});for(B=5-a("#layerlist tr.layer").size();B-- >0;)q.append('_')};Eb();a(window).bind("load resize",function(){qa.css("line-height",qa.height()+"px")});a("#resolution").change(function(){var q=a("#canvas_width,#canvas_height");if(this.selectedIndex)if(this.value== -"content")q.val("fit").attr("disabled","disabled");else{var B=this.value.split("x");a("#canvas_width").val(B[0]);a("#canvas_height").val(B[1]);q.removeAttr("disabled")}else a("#canvas_width").val()=="fit"&&q.removeAttr("disabled").val(100)});a("input,select").attr("autocomplete","off");var oc=function(){var q=[{sel:"#tool_select",fn:Bb,evt:"click",key:["V",true]},{sel:"#tool_fhpath",fn:ob,evt:"click",key:["Q",true]},{sel:"#tool_line",fn:Cb,evt:"click",key:["L",true]},{sel:"#tool_rect",fn:Kb,evt:"click", -key:["R",true],icon:"rect"},{sel:"#tool_ellipse",fn:Ib,evt:"mouseup",key:["C",true],icon:"ellipse"},{sel:"#tool_path",fn:M,evt:"click",key:["P",true]},{sel:"#tool_text",fn:ta,evt:"click",key:["T",true]},{sel:"#tool_image",fn:Rb,evt:"mouseup"},{sel:"#tool_zoom",fn:na,evt:"mouseup",key:["Z",true]},{sel:"#tool_clear",fn:hc,evt:"mouseup",key:[fa+"N",true]},{sel:"#tool_save",fn:function(){Ia?F():f.save({images:b.img_save,round_digits:6})},evt:"mouseup",key:[fa+"S",true]},{sel:"#tool_export",fn:ac,evt:"mouseup"}, -{sel:"#tool_open",fn:nc,evt:"mouseup"},{sel:"#tool_import",fn:Vb,evt:"mouseup"},{sel:"#tool_source",fn:E,evt:"click",key:[fa+"U",true]},{sel:"#tool_wireframe",fn:k,evt:"click"},{sel:"#tool_rulers",fn:v,evt:"click"},{sel:"#tool_source_cancel,#svg_source_overlay,#tool_docprops_cancel,#tool_prefs_cancel",fn:ua,evt:"click",key:["esc",false,false],hidekey:true},{sel:"#tool_source_save",fn:F,evt:"click"},{sel:"#tool_docprops_save",fn:D,evt:"click"},{sel:"#tool_docprops",fn:w,evt:"mouseup"},{sel:"#tool_prefs_save", -fn:G,evt:"click"},{sel:"#tool_prefs_option",fn:function(){s();return false},evt:"mouseup"},{sel:"#tool_delete,#tool_delete_multi",fn:I,evt:"click",key:["del/backspace",true]},{sel:"#tool_reorient",fn:Lb,evt:"click"},{sel:"#tool_node_link",fn:Qb,evt:"click"},{sel:"#tool_node_clone",fn:$b,evt:"click"},{sel:"#tool_node_delete",fn:Zb,evt:"click"},{sel:"#tool_openclose_path",fn:Va,evt:"click"},{sel:"#tool_add_subpath",fn:rb,evt:"click"},{sel:"#tool_move_top",fn:db,evt:"click",key:fa+"shift+up"},{sel:"#tool_move_bottom", -fn:tb,evt:"click",key:fa+"shift+down"},{sel:"#tool_move_up",fn:xb,evt:"click",key:[fa+"up",true]},{sel:"#tool_move_down",fn:Hb,evt:"click",key:[fa+"down",true]},{sel:"#tool_topath",fn:pb,evt:"click"},{sel:"#tool_make_link,#tool_make_link_multi",fn:bb,evt:"click"},{sel:"#tool_undo",fn:ic,evt:"click",key:[fa+"Z",true]},{sel:"#tool_redo",fn:dc,evt:"click",key:["Y",true]},{sel:"#tool_clone,#tool_clone_multi",fn:vb,evt:"click",key:[fa+"D",true]},{sel:"#tool_group",fn:Sb,evt:"click",key:[fa+"G",true]}, -{sel:"#tool_ungroup",fn:Sb,evt:"click",key:fa+"shift+G"},{sel:"#tool_unlink_use",fn:Sb,evt:"click"},{sel:"[id^=tool_align]",fn:fc,evt:"click"},{sel:"#tool_switch",fn:g,evt:"click",key:["X",true]},{sel:"#tool_bold",fn:lc,evt:"mousedown",key:[fa+"B",true]},{sel:"#tool_italic",fn:Wb,evt:"mousedown",key:[fa+"I",true]},{sel:"#copy_save_done",fn:ua,evt:"click"},{key:"ctrl+left",fn:function(){Ub(0,1)}},{key:"ctrl+right",fn:function(){Ub(1,1)}},{key:"ctrl+shift+left",fn:function(){Ub(0,5)}},{key:"ctrl+shift+right", -fn:function(){Ub(1,5)}},{key:"shift+O",fn:cc},{key:"shift+P",fn:gc},{key:[fa+"+",true],fn:function(){h(2)}},{key:[fa+"-",true],fn:function(){h(0.5)}},{key:["up",true],fn:function(){qb(0,-1)}},{key:["down",true],fn:function(){qb(0,1)}},{key:["left",true],fn:function(){qb(-1,0)}},{key:["right",true],fn:function(){qb(1,0)}},{key:"shift+up",fn:function(){qb(0,-10)}},{key:"shift+down",fn:function(){qb(0,10)}},{key:"shift+left",fn:function(){qb(-10,0)}},{key:"shift+right",fn:function(){qb(10,0)}},{key:["alt+up", -true],fn:function(){f.cloneSelectedElements(0,-1)}},{key:["alt+down",true],fn:function(){f.cloneSelectedElements(0,1)}},{key:["alt+left",true],fn:function(){f.cloneSelectedElements(-1,0)}},{key:["alt+right",true],fn:function(){f.cloneSelectedElements(1,0)}},{key:["alt+shift+up",true],fn:function(){f.cloneSelectedElements(0,-10)}},{key:["alt+shift+down",true],fn:function(){f.cloneSelectedElements(0,10)}},{key:["alt+shift+left",true],fn:function(){f.cloneSelectedElements(-10,0)}},{key:["alt+shift+right", -true],fn:function(){f.cloneSelectedElements(10,0)}},{key:fa+"A",fn:function(){f.selectAllInCurrentLayer()}},{key:fa+"z",fn:ic},{key:fa+"shift+z",fn:dc},{key:fa+"y",fn:dc},{key:fa+"x",fn:X},{key:fa+"c",fn:Ma},{key:fa+"v",fn:Xa}],B={"4/Shift+4":"#tools_rect_show","5/Shift+5":"#tools_ellipse_show"};return{setAll:function(){var K={};a.each(q,function(Q,W){if(W.sel){var ia=a(W.sel);if(ia.length==0)return true;if(W.evt){if(svgedit.browser.isTouch()&&W.evt==="click")W.evt="mousedown";ia[W.evt](W.fn)}if(W.parent&& -a(W.parent+"_show").length!=0){var va=a(W.parent);va.length||(va=Fa(W.parent.substr(1)));va.append(ia);a.isArray(K[W.parent])||(K[W.parent]=[]);K[W.parent].push(W)}}if(W.key){var ya=W.fn,Da=false;if(a.isArray(W.key)){va=W.key[0];if(W.key.length>1)Da=W.key[1]}else va=W.key;va+="";svgedit.browser.isMac&&va.indexOf("+")!=-1&&va.split("+")[0]=="ctrl"&&va.replace("ctrl","cmd");a.each(va.split("/"),function(Aa,fb){a(document).bind("keydown",fb,function(gb){ya();Da&&gb.preventDefault();return false})}); -if(W.sel&&!W.hidekey&&ia.attr("title")){var Ha=ia.attr("title").split("[")[0]+" ("+va+")";B[va]=W.sel;ia.parents("#main_menu").length||ia.attr("title",Ha)}}});Oa(K);a(".attr_changer, #image_url").bind("keydown","return",function(Q){a(this).change();Q.preventDefault()});a(window).bind("keydown","tab",function(Q){if(U==="canvas"){Q.preventDefault();gc()}}).bind("keydown","shift+tab",function(Q){if(U==="canvas"){Q.preventDefault();cc()}});a("#tool_zoom").dblclick(Z)},setTitles:function(){a.each(B,function(K, -Q){var W=a(Q).parents("#main_menu").length;a(Q).each(function(){var ia=W?a(this).text().split(" [")[0]:this.title.split(" [")[0],va="";a.each(K.split("/"),function(ya,Da){var Ha=Da.split("+"),Aa="";if(Ha.length>1){Aa=Ha[0]+"+";Da=Ha[1]}va+=(ya?"/":"")+Aa+(e["key_"+Da]||Da)});if(W)this.lastChild.textContent=ia+" ["+va+"]";else this.title=ia+" ["+va+"]"})})},getButtonData:function(K){var Q;a.each(q,function(W,ia){if(ia.sel===K)Q=ia});return Q}}}();oc.setAll();c.ready(function(){var q=d.initTool,B=a("#tools_left, #svg_editor .tools_flyout"), -K=B.find("#tool_"+q);q=B.find("#"+q);(K.length?K:q.length?q:a("#tool_select")).click().mouseup();d.wireframe&&a("#tool_wireframe").click();d.showlayers&&sc();a("#rulers").toggle(!!d.showRulers);if(d.showRulers)a("#show_rulers")[0].checked=true;if(d.gridSnapping)a("#grid_snapping_on")[0].checked=true;d.baseUnit&&a("#base_unit").val(d.baseUnit);d.snappingStep&&a("#grid_snapping_step").val(d.snappingStep)});a("#rect_rx").SpinButton({min:0,max:1E3,step:1,callback:function(q){f.setRectRadius(q.value)}}); -a("#stroke_width").SpinButton({min:0,max:99,step:1,smallStep:0.1,callback:function(q){var B=q.value;if(B==0&&Y&&["line","polyline"].indexOf(Y.nodeName)>=0)B=q.value=1;f.setStrokeWidth(B)}});a("#angle").SpinButton({min:-180,max:180,step:5,callback:function(q){f.setRotationAngle(q.value);a("#tool_reorient").toggleClass("disabled",q.value==0)}});a("#font_size").SpinButton({step:1,min:0.0010,stepfunc:function(q,B){var K=q.value-0,Q=K+B,W=Q>=K;if(B===0)return K;return K>=24?W?Math.round(K*1.1):Math.round(K/ -1.1):K<=1?W?K*2:K/2:Q},callback:function(q){f.setFontSize(q.value)}});a("#group_opacity").SpinButton({step:5,min:0,max:100,callback:mb});a("#blur").SpinButton({step:0.1,min:0,max:10,callback:Ab});a("#zoom").SpinButton({min:0.0010,max:1E4,step:50,stepfunc:function(q,B){var K=q.value-0;if(K===0)return 100;var Q=K+B;if(B===0)return K;return K>=100?Q:Q>=K?K*2:K/2},callback:Na}).val(f.getZoom()*100);a("#workarea").contextMenu({menu:"cmenu_canvas",inSpeed:0},function(q){switch(q){case "delete":I();break; -case "cut":X();break;case "copy":Ma();break;case "paste":f.pasteElements();break;case "paste_in_place":f.pasteElements("in_place");break;case "group":f.groupSelectedElements();break;case "ungroup":f.ungroupSelectedElement();break;case "move_front":db();break;case "move_up":Y!=null&&f.moveUpDownSelected("Up");break;case "move_down":Y!=null&&f.moveUpDownSelected("Down");break;case "move_back":tb();break;default:svgedit.contextmenu&&svgedit.contextmenu.hasCustomHandler(q)&&svgedit.contextmenu.getCustomHandler(q).call()}f.clipBoard.length&& -pa.enableContextMenuItems("#paste,#paste_in_place")});V=function(q){switch(q){case "dupe":N();break;case "delete":T();break;case "merge_down":if(a("#layerlist tr.layersel").index()!=f.getCurrentDrawing().getNumLayers()-1){f.mergeLayer();Za();Eb()}break;case "merge_all":f.mergeAllLayers();Za();Eb()}};a("#layerlist").contextMenu({menu:"cmenu_layers",inSpeed:0},V);a("#layer_moreopts").contextMenu({menu:"cmenu_layers",inSpeed:0,allowLeft:true},V);a(".contextMenu li").mousedown(function(q){q.preventDefault()}); -a("#cmenu_canvas li").disableContextMenu();pa.enableContextMenuItems("#delete,#cut,#copy");window.onbeforeunload=function(){if(ja.getUndoStackSize()===0)c.show_save_warning=false;if(!d.no_save_warning&&c.show_save_warning)return e.notification.unsavedChanges};c.openPrep=function(q){a("#main_menu").hide();ja.getUndoStackSize()===0?q(true):a.confirm(e.notification.QwantToOpen,q)};if(window.FileReader){V=a('').change(function(){var q=this;c.openPrep(function(B){if(B){f.clear();if(q.files.length== -1){B=new FileReader;B.onloadend=function(K){n(K.target.result);Tb()};B.readAsText(q.files[0])}}})});a("#tool_open").show().prepend(V);V=a('').change(function(){a("#main_menu").hide();if(this.files.length==1){var q=new FileReader;q.onloadend=function(B){f.importSvgString(B.target.result,true);Tb()};q.readAsText(this.files[0])}});a("#tool_import").show().prepend(V)}var Tb=c.updateCanvas=function(q,B){var K=qa.width(),Q=qa.height(),W=K,ia=Q,va=f.getZoom(),ya=a("#svgcanvas"),Da={x:qa[0].scrollLeft+ -W/2,y:qa[0].scrollTop+ia/2},Ha=d.canvas_expansion;K=Math.max(W,f.contentW*va*Ha);Q=Math.max(ia,f.contentH*va*Ha);K==W&&Q==ia?qa.css("overflow","hidden"):qa.css("overflow","scroll");Ha=ya.height()/2;var Aa=ya.width()/2;ya.width(K).height(Q);var fb=Q/2,gb=K/2,ga=f.updateCanvas(K,Q),zb=gb/Aa;K=K/2-W/2;Q=Q/2-ia/2;if(B){B.x+=ga.x;B.y+=ga.y}else B={x:gb+(Da.x-Aa)*zb,y:fb+(Da.y-Ha)*zb};if(q)if(f.contentW>qa.width()){qa[0].scrollLeft=ga.x-10;qa[0].scrollTop=ga.y-10}else{qa[0].scrollLeft=K;qa[0].scrollTop= -Q}else{qa[0].scrollLeft=B.x-W/2;qa[0].scrollTop=B.y-ia/2}if(d.showRulers){da(ya,va);qa.scroll()}},jc=[];for(Sa=0.1;Sa<1E5;Sa*=10){jc.push(1*Sa);jc.push(2*Sa);jc.push(5*Sa)}Tb(true);try{var uc=function(q){if(window.JSON&&JSON.stringify)return JSON.stringify(q);var B=arguments.callee;if(typeof q=="boolean"||typeof q=="number")return q+"";else if(typeof q=="string")return'"'+q.replace(/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, -function(W){return"\\u"+("0000"+W.charCodeAt(0).toString(16)).slice(-4)})+'"';else if(q.length){for(var K=0;K");var f=n.shortcut||"";$("#cmenu_canvas").append("
          • "+n.label+""+f+"
          • ")}});svgedit.contextmenu.resetCustomMenus=function(){a.contextMenuExtensions= -{}};svgedit.contextmenu.add=function(n){if(n&&n.id&&n.label&&n.action&&typeof n.action=="function")if(n.id in a.contextMenuExtensions)console.error('Cannot add extension "'+n.id+'", an extension by that name already exists"');else{console.log("Registed contextmenu item: {id:"+n.id+", label:"+n.label+"}");a.contextMenuExtensions[n.id]=n}else console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function")};svgedit.contextmenu.hasCustomHandler= -function(n){return a.contextMenuExtensions[n]&&true};svgedit.contextmenu.getCustomHandler=function(n){return a.contextMenuExtensions[n].action}})();var svgEditor=function(a,n){function f(m,p,b){var d=a("#svg_editor").parent(),e;for(e in p){var l=p[e];l||console.log(e);if(b)e="#"+e;if(d.find(e).length){var u=d.find(e)[0];switch(m){case "content":for(var z=0;z=0)&&c(m,!b)}}),a(function(){var m=document.body,p=m.appendChild(p=document.createElement("div"));a.extend(p.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});a.support.minHeight=p.offsetHeight===100;a.support.selectstart="onselectstart"in p;m.removeChild(p).style.display="none"}),a.extend(a.ui,{plugin:{add:function(m,p,b){m=a.ui[m].prototype;for(var d in b){m.plugins[d]=m.plugins[d]||[];m.plugins[d].push([p,b[d]])}},call:function(m,p,b){if((p=m.plugins[p])&& -m.element[0].parentNode)for(var d=0;d0)return true;m[b]=1;d=m[b]>0;m[b]=0;return d},isOverAxis:function(m,p,b){return m>p&&m=9)&&!f.button)return this._mouseUp(f);if(this._mouseStarted){this._mouseDrag(f);return f.preventDefault()}this._mouseDistanceMet(f)&&this._mouseDelayMet(f)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,f)!==false,this._mouseStarted?this._mouseDrag(f):this._mouseUp(f));return!this._mouseStarted},_mouseUp:function(f){a(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);this._mouseStarted&& -(this._mouseStarted=false,f.target==this._mouseDownEvent.target&&a.data(f.target,this.widgetName+".preventClickEvent",true),this._mouseStop(f));return false},_mouseDistanceMet:function(f){return Math.max(Math.abs(this._mouseDownEvent.pageX-f.pageX),Math.abs(this._mouseDownEvent.pageY-f.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery); -(function(a){a.widget("ui.draggable",a.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){this.options.helper=="original"&& -!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative");this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(n){var f=this.options; -if(this.helper||f.disabled||a(n.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(n);if(!this.handle)return false;f.iframeFix&&a(f.iframeFix===true?"iframe":f.iframeFix).each(function(){a('
            ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(a(this).offset()).appendTo("body")});return true},_mouseStart:function(n){var f=this.options;this.helper= -this._createHelper(n);this._cacheHelperProportions();a.ui.ddmanager&&(a.ui.ddmanager.current=this);this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:n.pageX-this.offset.left,top:n.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}); -this.originalPosition=this.position=this._generatePosition(n);this.originalPageX=n.pageX;this.originalPageY=n.pageY;f.cursorAt&&this._adjustOffsetFromHelper(f.cursorAt);f.containment&&this._setContainment();if(this._trigger("start",n)===false){this._clear();return false}this._cacheHelperProportions();a.ui.ddmanager&&!f.dropBehaviour&&a.ui.ddmanager.prepareOffsets(this,n);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(n,true);a.ui.ddmanager&&a.ui.ddmanager.dragStart(this,n);return true}, -_mouseDrag:function(n,f){this.position=this._generatePosition(n);this.positionAbs=this._convertPositionTo("absolute");if(!f){var c=this._uiHash();if(this._trigger("drag",n,c)===false){this._mouseUp({});return false}this.position=c.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";a.ui.ddmanager&&a.ui.ddmanager.drag(this,n);return false},_mouseStop:function(n){var f= -false;a.ui.ddmanager&&!this.options.dropBehaviour&&(f=a.ui.ddmanager.drop(this,n));this.dropped&&(f=this.dropped,this.dropped=false);if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!f||this.options.revert=="valid"&&f||this.options.revert===true||a.isFunction(this.options.revert)&&this.options.revert.call(this.element,f)){var c=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10), -function(){c._trigger("stop",n)!==false&&c._clear()})}else this._trigger("stop",n)!==false&&this._clear();return false},_mouseUp:function(n){this.options.iframeFix===true&&a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)});a.ui.ddmanager&&a.ui.ddmanager.dragStop(this,n);return a.ui.mouse.prototype._mouseUp.call(this,n)},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(n){var f=!this.options.handle|| -!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){this==n.target&&(f=true)});return f},_createHelper:function(n){var f=this.options;n=a.isFunction(f.helper)?a(f.helper.apply(this.element[0],[n])):f.helper=="clone"?this.element.clone().removeAttr("id"):this.element;n.parents("body").length||n.appendTo(f.appendTo=="parent"?this.element[0].parentNode:f.appendTo);n[0]!=this.element[0]&&!/(fixed|absolute)/.test(n.css("position"))&& -n.css("position","absolute");return n},_adjustOffsetFromHelper:function(n){typeof n=="string"&&(n=n.split(" "));a.isArray(n)&&(n={left:+n[0],top:+n[1]||0});"left"in n&&(this.offset.click.left=n.left+this.margins.left);"right"in n&&(this.offset.click.left=this.helperProportions.width-n.right+this.margins.left);"top"in n&&(this.offset.click.top=n.top+this.margins.top);"bottom"in n&&(this.offset.click.top=this.helperProportions.height-n.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent= -this.helper.offsetParent();var n=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])&&(n.left+=this.scrollParent.scrollLeft(),n.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)n={top:0,left:0};return{top:n.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:n.left+(parseInt(this.offsetParent.css("borderLeftWidth"), -10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var n=this.element.position();return{top:n.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:n.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"), -10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var n=this.options;n.containment=="parent"&&(n.containment=this.helper[0].parentNode);if(n.containment=="document"||n.containment=="window")this.containment=[n.containment=="document"?0:a(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,n.containment=="document"?0:a(window).scrollTop()-this.offset.relative.top-this.offset.parent.top, -(n.containment=="document"?0:a(window).scrollLeft())+a(n.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(n.containment=="document"?0:a(window).scrollTop())+(a(n.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(n.containment)&&n.containment.constructor!=Array){n=a(n.containment);var f=n[0];if(f){n.offset();var c=a(f).css("overflow")!= -"hidden";this.containment=[(parseInt(a(f).css("borderLeftWidth"),10)||0)+(parseInt(a(f).css("paddingLeft"),10)||0),(parseInt(a(f).css("borderTopWidth"),10)||0)+(parseInt(a(f).css("paddingTop"),10)||0),(c?Math.max(f.scrollWidth,f.offsetWidth):f.offsetWidth)-(parseInt(a(f).css("borderLeftWidth"),10)||0)-(parseInt(a(f).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(c?Math.max(f.scrollHeight,f.offsetHeight):f.offsetHeight)-(parseInt(a(f).css("borderTopWidth"), -10)||0)-(parseInt(a(f).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom];this.relative_container=n}}else n.containment.constructor==Array&&(this.containment=n.containment)},_convertPositionTo:function(n,f){f||(f=this.position);var c=n=="absolute"?1:-1,m=this.cssPosition=="absolute"&&(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,p=/(html|body)/i.test(m[0].tagName);return{top:f.top+ -this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():p?0:m.scrollTop())*c),left:f.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&a.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():p?0:m.scrollLeft())*c)}},_generatePosition:function(n){var f=this.options,c=this.cssPosition=="absolute"&& -(this.scrollParent[0]==document||!a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,m=/(html|body)/i.test(c[0].tagName),p=n.pageX,b=n.pageY;if(this.originalPosition){var d;if(this.containment){if(this.relative_container){d=this.relative_container.offset();d=[this.containment[0]+d.left,this.containment[1]+d.top,this.containment[2]+d.left,this.containment[3]+d.top]}else d=this.containment;n.pageX-this.offset.click.leftd[2]&&(p=d[2]+this.offset.click.left);n.pageY-this.offset.click.top>d[3]&&(b=d[3]+this.offset.click.top)}if(f.grid){b=f.grid[1]?this.originalPageY+Math.round((b-this.originalPageY)/f.grid[1])*f.grid[1]:this.originalPageY;b=d?b-this.offset.click.topd[3]?b-this.offset.click.topd[2]?p-this.offset.click.left=0;u--){var z=c.snapElements[u].left,o=z+c.snapElements[u].width,L=c.snapElements[u].top,T=L+c.snapElements[u].height;if(z-p
            ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(f.range==="min"||f.range==="max"?" ui-slider-range-"+f.range:"")));for(var b=c.length;b"); -this.handles=c.add(a(p.join("")).appendTo(n.element));this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(d){d.preventDefault()}).hover(function(){f.disabled||a(this).addClass("ui-state-hover")},function(){a(this).removeClass("ui-state-hover")}).focus(function(){f.disabled?a(this).blur():(a(".ui-slider .ui-state-focus").removeClass("ui-state-focus"),a(this).addClass("ui-state-focus"))}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(d){a(this).data("index.ui-slider-handle", -d)});this.handles.keydown(function(d){var e=true,l=a(this).data("index.ui-slider-handle"),u,z,o;if(!n.options.disabled){switch(d.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.PAGE_UP:case a.ui.keyCode.PAGE_DOWN:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:e=false;if(!n._keySliding){n._keySliding=true;a(this).addClass("ui-state-active");u=n._start(d,l);if(u===false)return}}u=n.options.step;n.options.values&&n.options.values.length? -z=o=n.values(l):z=o=n.value();switch(d.keyCode){case a.ui.keyCode.HOME:o=n._valueMin();break;case a.ui.keyCode.END:o=n._valueMax();break;case a.ui.keyCode.PAGE_UP:o=n._trimAlignValue(z+(n._valueMax()-n._valueMin())/5);break;case a.ui.keyCode.PAGE_DOWN:o=n._trimAlignValue(z-(n._valueMax()-n._valueMin())/5);break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(z===n._valueMax())return;o=n._trimAlignValue(z+u);break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(z===n._valueMin())return;o=n._trimAlignValue(z- -u)}n._slide(d,l,o);return e}}).keyup(function(d){var e=a(this).data("index.ui-slider-handle");n._keySliding&&(n._keySliding=false,n._stop(d,e),n._change(d,e),a(this).removeClass("ui-state-active"))});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy(); -return this},_mouseCapture:function(n){var f=this.options,c,m,p,b,d;if(f.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:n.pageX,y:n.pageY});m=this._valueMax()-this._valueMin()+1;b=this;this.handles.each(function(e){var l=Math.abs(c-b.values(e));m>l&&(m=l,p=a(this),d=e)});f.range===true&&this.values(1)===f.min&&(d+=1,p=a(this.handles[d]));if(this._start(n,d)===false)return false; -this._mouseSliding=true;b._handleIndex=d;p.addClass("ui-state-active").focus();f=p.offset();this._clickOffset=!a(n.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:n.pageX-f.left-p.width()/2,top:n.pageY-f.top-p.height()/2-(parseInt(p.css("borderTopWidth"),10)||0)-(parseInt(p.css("borderBottomWidth"),10)||0)+(parseInt(p.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(n,d,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(n){var f= -this._normValueFromMouse({x:n.pageX,y:n.pageY});this._slide(n,this._handleIndex,f);return false},_mouseStop:function(n){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(n,this._handleIndex);this._change(n,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(n){var f,c;this.orientation==="horizontal"? -(f=this.elementSize.width,c=n.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(f=this.elementSize.height,c=n.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0));n=c/f;n>1&&(n=1);n<0&&(n=0);this.orientation==="vertical"&&(n=1-n);f=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+n*f)},_start:function(n,f){var c={handle:this.handles[f],value:this.value()};this.options.values&&this.options.values.length&&(c.value=this.values(f), -c.values=this.values());return this._trigger("start",n,c)},_slide:function(n,f,c){var m,p,b;this.options.values&&this.options.values.length?(m=this.values(f?0:1),this.options.values.length===2&&this.options.range===true&&(f===0&&c>m||f===1&&c1){this.options.values[n]=this._trimAlignValue(f);this._refreshValue();this._change(null,n)}else{if(!arguments.length)return this._values();if(!a.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(n):this.value();c=this.options.values;m=arguments[0];for(p=0;p=this._valueMax())return this._valueMax();var f=this.options.step>0?this.options.step:1,c=(n-this._valueMin())%f;n=n-c;Math.abs(c)*2>=f&&(n+=c>0?f:-f);return parseFloat(n.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var n= -this.options.range,f=this.options,c=this,m=this._animateOff?false:f.animate,p,b={},d,e,l,u;this.options.values&&this.options.values.length?this.handles.each(function(z){p=(c.values(z)-c._valueMin())/(c._valueMax()-c._valueMin())*100;b[c.orientation==="horizontal"?"left":"bottom"]=p+"%";a(this).stop(1,1)[m?"animate":"css"](b,f.animate);c.options.range===true&&(c.orientation==="horizontal"?(z===0&&c.range.stop(1,1)[m?"animate":"css"]({left:p+"%"},f.animate),z===1&&c.range[m?"animate":"css"]({width:p- -d+"%"},{queue:false,duration:f.animate})):(z===0&&c.range.stop(1,1)[m?"animate":"css"]({bottom:p+"%"},f.animate),z===1&&c.range[m?"animate":"css"]({height:p-d+"%"},{queue:false,duration:f.animate})));d=p}):(e=this.value(),l=this._valueMin(),u=this._valueMax(),p=u!==l?(e-l)/(u-l)*100:0,b[c.orientation==="horizontal"?"left":"bottom"]=p+"%",this.handle.stop(1,1)[m?"animate":"css"](b,f.animate),n==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[m?"animate":"css"]({width:p+"%"},f.animate), -n==="max"&&this.orientation==="horizontal"&&this.range[m?"animate":"css"]({width:100-p+"%"},{queue:false,duration:f.animate}),n==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[m?"animate":"css"]({height:p+"%"},f.animate),n==="max"&&this.orientation==="vertical"&&this.range[m?"animate":"css"]({height:100-p+"%"},{queue:false,duration:f.animate}))}});a.extend(a.ui.slider,{version:"1.8.17"})})(jQuery);(function(a){Math.precision=function(b,d){if(d===undefined)d=0;return Math.round(b*Math.pow(10,d))/Math.pow(10,d)};var n=function(b,d){var e=this,l=b.find("img:first"),u=0,z=100,o=100,L=0,T=100,N=100,J=0,da=0,V,O,fa=[],sa=function(S){for(var U=0;Ura)U=ra;if(S<0)S=0;else if(S>la)S=la;pa.call(e,"xy",{x:U/ra*o+u,y:S/la*N+L})},pa=function(S,U,ra){if(U===undefined){if(S===undefined||S==null)S="xy";switch(S.toLowerCase()){case "x":return J;case "y":return da;default:return{x:J,y:da}}}if(!(ra!= -null&&ra==e)){var la=false,ma,Y;if(S==null)S="xy";switch(S.toLowerCase()){case "x":ma=U&&(U.x&&U.x|0||U|0)||0;break;case "y":Y=U&&(U.y&&U.y|0||U|0)||0;break;default:ma=U&&U.x&&U.x|0||0;Y=U&&U.y&&U.y|0||0}if(ma!=null){if(maz)ma=z;if(J!=ma){J=ma;la=true}}if(Y!=null){if(YT)Y=T;if(da!=Y){da=Y;la=true}}la&&sa.call(e,ra||e)}},ba=function(S){a.isFunction(S)&&fa.push(S)};a.extend(true,e,{val:pa,range:function(S,U){if(U===undefined){if(S===undefined||S==null)S="all";switch(S.toLowerCase()){case "minx":return u; -case "maxx":return z;case "rangex":return{minX:u,maxX:z,rangeX:o};case "miny":return L;case "maxy":return T;case "rangey":return{minY:L,maxY:T,rangeY:N};default:return{minX:u,maxX:z,rangeX:o,minY:L,maxY:T,rangeY:N}}}var ra,la,ma,Y;if(S==null)S="all";switch(S.toLowerCase()){case "minx":ra=U&&(U.minX&&U.minX|0||U|0)||0;break;case "maxx":la=U&&(U.maxX&&U.maxX|0||U|0)||0;break;case "rangex":ra=U&&U.minX&&U.minX|0||0;la=U&&U.maxX&&U.maxX|0||0;break;case "miny":ma=U&&(U.minY&&U.minY|0||U|0)||0;break;case "maxy":Y= -U&&(U.maxY&&U.maxY|0||U|0)||0;break;case "rangey":ma=U&&U.minY&&U.minY|0||0;Y=U&&U.maxY&&U.maxY|0||0;break;default:ra=U&&U.minX&&U.minX|0||0;la=U&&U.maxX&&U.maxX|0||0;ma=U&&U.minY&&U.minY|0||0;Y=U&&U.maxY&&U.maxY|0||0}if(ra!=null&&u!=ra){u=ra;o=z-u}if(la!=null&&z!=la){z=la;o=z-u}if(ma!=null&&L!=ma){L=ma;N=T-L}if(Y!=null&&T!=Y){T=Y;N=T-L}},bind:ba,unbind:function(S){if(a.isFunction(S))for(var U;(U=a.inArray(S,fa))!=-1;)fa.splice(U,1)},destroy:function(){a(document).unbind("mouseup",ea).unbind("mousemove", -ca);b.unbind("mousedown",ja);fa=l=b=null}});l.src=d.arrow&&d.arrow.image;l.w=d.arrow&&d.arrow.width||l.width();l.h=d.arrow&&d.arrow.height||l.height();b.w=d.map&&d.map.width||b.width();b.h=d.map&&d.map.height||b.height();b.bind("mousedown",ja);ba.call(e,function(){var S=0,U=0,ra=b.w,la=b.h,ma=l.w,Y=l.h;setTimeout(function(){if(o>0)S=J==z?ra:J/o*ra|0;if(N>0)U=da==T?la:da/N*la|0;if(ma>=ra)S=(ra>>1)-(ma>>1);else S-=ma>>1;if(Y>=la)U=(la>>1)-(Y>>1);else U-=Y>>1;l.css({left:S+"px",top:U+"px"})},0)})},f= -function(b,d,e,l){var u=this;b=b.find("td.Text input");var z=b.eq(3),o=b.eq(4),L=b.eq(5),T=b.length>7?b.eq(6):null,N=b.eq(0),J=b.eq(1),da=b.eq(2),V=b.eq(b.length>7?7:6),O=b.length>7?b.eq(8):null,fa=function(pa){if(!(pa.target.value==""&&pa.target!=V.get(0)&&(e!=null&&pa.target!=e.get(0)||e==null))){if(!ca(pa))return pa;switch(pa.target){case z.get(0):switch(pa.keyCode){case 38:z.val(ea.call(u,(z.val()<<0)+1,0,255));d.val("r",z.val(),pa.target);return false;case 40:z.val(ea.call(u,(z.val()<<0)-1,0, -255));d.val("r",z.val(),pa.target);return false}break;case o.get(0):switch(pa.keyCode){case 38:o.val(ea.call(u,(o.val()<<0)+1,0,255));d.val("g",o.val(),pa.target);return false;case 40:o.val(ea.call(u,(o.val()<<0)-1,0,255));d.val("g",o.val(),pa.target);return false}break;case L.get(0):switch(pa.keyCode){case 38:L.val(ea.call(u,(L.val()<<0)+1,0,255));d.val("b",L.val(),pa.target);return false;case 40:L.val(ea.call(u,(L.val()<<0)-1,0,255));d.val("b",L.val(),pa.target);return false}break;case T&&T.get(0):switch(pa.keyCode){case 38:T.val(ea.call(u, -parseFloat(T.val())+1,0,100));d.val("a",Math.precision(T.val()*255/100,l),pa.target);return false;case 40:T.val(ea.call(u,parseFloat(T.val())-1,0,100));d.val("a",Math.precision(T.val()*255/100,l),pa.target);return false}break;case N.get(0):switch(pa.keyCode){case 38:N.val(ea.call(u,(N.val()<<0)+1,0,360));d.val("h",N.val(),pa.target);return false;case 40:N.val(ea.call(u,(N.val()<<0)-1,0,360));d.val("h",N.val(),pa.target);return false}break;case J.get(0):switch(pa.keyCode){case 38:J.val(ea.call(u,(J.val()<< -0)+1,0,100));d.val("s",J.val(),pa.target);return false;case 40:J.val(ea.call(u,(J.val()<<0)-1,0,100));d.val("s",J.val(),pa.target);return false}break;case da.get(0):switch(pa.keyCode){case 38:da.val(ea.call(u,(da.val()<<0)+1,0,100));d.val("v",da.val(),pa.target);return false;case 40:da.val(ea.call(u,(da.val()<<0)-1,0,100));d.val("v",da.val(),pa.target);return false}}}},sa=function(pa){if(!(pa.target.value==""&&pa.target!=V.get(0)&&(e!=null&&pa.target!=e.get(0)||e==null))){if(!ca(pa))return pa;switch(pa.target){case z.get(0):z.val(ea.call(u, -z.val(),0,255));d.val("r",z.val(),pa.target);break;case o.get(0):o.val(ea.call(u,o.val(),0,255));d.val("g",o.val(),pa.target);break;case L.get(0):L.val(ea.call(u,L.val(),0,255));d.val("b",L.val(),pa.target);break;case T&&T.get(0):T.val(ea.call(u,T.val(),0,100));d.val("a",Math.precision(T.val()*255/100,l),pa.target);break;case N.get(0):N.val(ea.call(u,N.val(),0,360));d.val("h",N.val(),pa.target);break;case J.get(0):J.val(ea.call(u,J.val(),0,100));d.val("s",J.val(),pa.target);break;case da.get(0):da.val(ea.call(u, -da.val(),0,100));d.val("v",da.val(),pa.target);break;case V.get(0):V.val(V.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,6));e&&e.val(V.val());d.val("hex",V.val()!=""?V.val():null,pa.target);break;case e&&e.get(0):e.val(e.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,6));V.val(e.val());d.val("hex",e.val()!=""?e.val():null,pa.target);break;case O&&O.get(0):O.val(O.val().replace(/[^a-fA-F0-9]/g,"").toLowerCase().substring(0,2));d.val("a",O.val()!=null?parseInt(O.val(),16): -null,pa.target)}}},ja=function(pa){if(d.val()!=null)switch(pa.target){case z.get(0):z.val(d.val("r"));break;case o.get(0):o.val(d.val("g"));break;case L.get(0):L.val(d.val("b"));break;case T&&T.get(0):T.val(Math.precision(d.val("a")*100/255,l));break;case N.get(0):N.val(d.val("h"));break;case J.get(0):J.val(d.val("s"));break;case da.get(0):da.val(d.val("v"));break;case V.get(0):case e&&e.get(0):V.val(d.val("hex"));e&&e.val(d.val("hex"));break;case O&&O.get(0):O.val(d.val("ahex").substring(6))}},ca= -function(pa){switch(pa.keyCode){case 9:case 16:case 29:case 37:case 39:return false;case "c".charCodeAt():case "v".charCodeAt():if(pa.ctrlKey)return false}return true},ea=function(pa,ba,S){if(pa==""||isNaN(pa))return ba;if(pa>S)return S;if(pa255)ca.r=255;if(e!=ca.r){e=ca.r;ja=true}break;case "g":if(qa)continue;ea=true;ca.g=O&&O.g&&O.g|0||O&&O|0||0;if(ca.g<0)ca.g=0;else if(ca.g>255)ca.g=255;if(l!=ca.g){l=ca.g;ja=true}break;case "b":if(qa)continue;ea=true;ca.b=O&&O.b&&O.b|0||O&&O|0||0;if(ca.b<0)ca.b=0;else if(ca.b>255)ca.b=255;if(u!=ca.b){u=ca.b;ja=true}break;case "a":ca.a=O&&O.a!=null?O.a|0:O!=null?O|0:255;if(ca.a<0)ca.a=0;else if(ca.a>255)ca.a=255;if(z!=ca.a){z=ca.a;ja=true}break;case "h":if(ea)continue; -qa=true;ca.h=O&&O.h&&O.h|0||O&&O|0||0;if(ca.h<0)ca.h=0;else if(ca.h>360)ca.h=360;if(o!=ca.h){o=ca.h;ja=true}break;case "s":if(ea)continue;qa=true;ca.s=O&&O.s!=null?O.s|0:O!=null?O|0:100;if(ca.s<0)ca.s=0;else if(ca.s>100)ca.s=100;if(L!=ca.s){L=ca.s;ja=true}break;case "v":if(ea)continue;qa=true;ca.v=O&&O.v!=null?O.v|0:O!=null?O|0:100;if(ca.v<0)ca.v=0;else if(ca.v>100)ca.v=100;if(T!=ca.v){T=ca.v;ja=true}}if(ja){if(ea){e=e||0;l=l||0;u=u||0;O=p.rgbToHsv({r:e,g:l,b:u});o=O.h;L=O.s;T=O.v}else if(qa){o=o|| -0;L=L!=null?L:100;T=T!=null?T:100;O=p.hsvToRgb({h:o,s:L,v:T});e=O.r;l=O.g;u=O.b}z=z!=null?z:255;J.call(d,fa||d)}}}};a.extend(true,d,{val:da,bind:function(V){a.isFunction(V)&&N.push(V)},unbind:function(V){if(a.isFunction(V))for(var O;(O=a.inArray(V,N))!=-1;)N.splice(O,1)},destroy:function(){N=null}});if(b)if(b.ahex!=null)da("ahex",b);else if(b.hex!=null)da((b.a!=null?"a":"")+"hex",b.a!=null?{ahex:b.hex+p.intToHex(b.a)}:b);else if(b.r!=null&&b.g!=null&&b.b!=null)da("rgb"+(b.a!=null?"a":""),b);else if(b.h!= -null&&b.s!=null&&b.v!=null)da("hsv"+(b.a!=null?"a":""),b)},ColorMethods:{hexToRgba:function(b){b=this.validateHex(b);if(b=="")return{r:null,g:null,b:null,a:null};var d="00",e="00",l="00",u="255";if(b.length==6)b+="ff";if(b.length>6){d=b.substring(0,2);e=b.substring(2,4);l=b.substring(4,6);u=b.substring(6,b.length)}else{if(b.length>4){d=b.substring(4,b.length);b=b.substring(0,4)}if(b.length>2){e=b.substring(2,b.length);b=b.substring(0,2)}if(b.length>0)l=b.substring(0,b.length)}return{r:this.hexToInt(d), -g:this.hexToInt(e),b:this.hexToInt(l),a:this.hexToInt(u)}},validateHex:function(b){if(typeof b=="object")return"";b=b.toLowerCase().replace(/[^a-f0-9]/g,"");if(b.length>8)b=b.substring(0,8);return b},rgbaToHex:function(b){return this.intToHex(b.r)+this.intToHex(b.g)+this.intToHex(b.b)+this.intToHex(b.a)},intToHex:function(b){b=(b|0).toString(16);if(b.length==1)b="0"+b;return b.toLowerCase()},hexToInt:function(b){return parseInt(b,16)},rgbToHsv:function(b){var d=b.r/255,e=b.g/255;b=b.b/255;var l={h:0, -s:0,v:0},u=0,z=0;if(d>=e&&d>=b){z=d;u=e>b?b:e}else if(e>=b&&e>=d){z=e;u=d>b?b:d}else{z=b;u=e>d?d:e}l.v=z;l.s=z?(z-u)/z:0;if(l.s){u=z-u;l.h=d==z?(e-b)/u:e==z?2+(b-d)/u:4+(d-e)/u;l.h=parseInt(l.h*60);if(l.h<0)l.h+=360}else l.h=0;l.s=l.s*100|0;l.v=l.v*100|0;return l},hsvToRgb:function(b){var d={r:0,g:0,b:0,a:100},e=b.h,l=b.s;b=b.v;if(l==0)d.r=b==0?d.g=d.b=0:d.g=d.b=b*255/100|0;else{if(e==360)e=0;e/=60;l/=100;b/=100;var u=e|0,z=e-u;e=b*(1-l);var o=b*(1-l*z);l=b*(1-l*(1-z));switch(u){case 0:d.r=b;d.g= -l;d.b=e;break;case 1:d.r=o;d.g=b;d.b=e;break;case 2:d.r=e;d.g=b;d.b=l;break;case 3:d.r=e;d.g=o;d.b=b;break;case 4:d.r=l;d.g=e;d.b=b;break;case 5:d.r=b;d.g=e;d.b=o}d.r=d.r*255|0;d.g=d.g*255|0;d.b=d.b*255|0}return d}}};var c=a.jPicker.Color,m=a.jPicker.List,p=a.jPicker.ColorMethods;a.fn.jPicker=function(b){var d=arguments;return this.each(function(){var e=this,l=a.extend(true,{},a.fn.jPicker.defaults,b);if(a(e).get(0).nodeName.toLowerCase()=="input"){a.extend(true,l,{window:{bindToInput:true,expandable:true, -input:a(e)}});if(a(e).val()==""){l.color.active=new c({hex:null});l.color.current=new c({hex:null})}else if(p.validateHex(a(e).val())){l.color.active=new c({hex:a(e).val(),a:l.color.active.val("a")});l.color.current=new c({hex:a(e).val(),a:l.color.active.val("a")})}}if(l.window.expandable)a(e).after('    '); -else l.window.liveUpdate=false;var u=parseFloat(navigator.appVersion.split("MSIE")[1])<7&&document.body.filters,z=null,o=null,L=null,T=null,N=null,J=null,da=null,V=null,O=null,fa=null,sa=null,ja=null,ca=null,ea=null,qa=null,pa=null,ba=null,S=null,U=null,ra=null,la=null,ma=null,Y=null,za=null,Ia=null,Qa=null,Ka=null,Ua=null,Wa=function(M){var I=ta.active,X=I.val("hex"),Ma,Xa;l.color.mode=M;switch(M){case "h":setTimeout(function(){ab.call(e,o,"transparent");Ja.call(e,T,0);Ea.call(e,T,100);Ja.call(e, -N,260);Ea.call(e,N,100);ab.call(e,L,"transparent");Ja.call(e,da,0);Ea.call(e,da,100);Ja.call(e,V,260);Ea.call(e,V,100);Ja.call(e,O,260);Ea.call(e,O,100);Ja.call(e,fa,260);Ea.call(e,fa,100);Ja.call(e,ja,260);Ea.call(e,ja,100)},0);ca.range("all",{minX:0,maxX:100,minY:0,maxY:100});ea.range("rangeY",{minY:0,maxY:360});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("s"),y:100-I.val("v")},ca);ea.val("y",360-I.val("h"),ea);break;case "s":setTimeout(function(){ab.call(e,o,"transparent");Ja.call(e,T,-260); -Ja.call(e,N,-520);Ja.call(e,da,-260);Ja.call(e,V,-520);Ja.call(e,ja,260);Ea.call(e,ja,100)},0);ca.range("all",{minX:0,maxX:360,minY:0,maxY:100});ea.range("rangeY",{minY:0,maxY:100});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("h"),y:100-I.val("v")},ca);ea.val("y",100-I.val("s"),ea);break;case "v":setTimeout(function(){ab.call(e,o,"000000");Ja.call(e,T,-780);Ja.call(e,N,260);ab.call(e,L,X);Ja.call(e,da,-520);Ja.call(e,V,260);Ea.call(e,V,100);Ja.call(e,ja,260);Ea.call(e,ja,100)},0);ca.range("all", -{minX:0,maxX:360,minY:0,maxY:100});ea.range("rangeY",{minY:0,maxY:100});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("h"),y:100-I.val("s")},ca);ea.val("y",100-I.val("v"),ea);break;case "r":Ma=-1040;Xa=-780;ca.range("all",{minX:0,maxX:255,minY:0,maxY:255});ea.range("rangeY",{minY:0,maxY:255});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("b"),y:255-I.val("g")},ca);ea.val("y",255-I.val("r"),ea);break;case "g":Ma=-1560;Xa=-1820;ca.range("all",{minX:0,maxX:255,minY:0,maxY:255});ea.range("rangeY", -{minY:0,maxY:255});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("b"),y:255-I.val("r")},ca);ea.val("y",255-I.val("g"),ea);break;case "b":Ma=-2080;Xa=-2860;ca.range("all",{minX:0,maxX:255,minY:0,maxY:255});ea.range("rangeY",{minY:0,maxY:255});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("r"),y:255-I.val("g")},ca);ea.val("y",255-I.val("b"),ea);break;case "a":setTimeout(function(){ab.call(e,o,"transparent");Ja.call(e,T,-260);Ja.call(e,N,-520);Ja.call(e,da,260);Ja.call(e,V,260);Ea.call(e,V,100); -Ja.call(e,ja,0);Ea.call(e,ja,100)},0);ca.range("all",{minX:0,maxX:360,minY:0,maxY:100});ea.range("rangeY",{minY:0,maxY:255});if(I.val("ahex")==null)break;ca.val("xy",{x:I.val("h"),y:100-I.val("v")},ca);ea.val("y",255-I.val("a"),ea);break;default:throw"Invalid Mode";}switch(M){case "s":case "v":case "a":setTimeout(function(){Ea.call(e,T,100);Ea.call(e,da,100);Ja.call(e,O,260);Ea.call(e,O,100);Ja.call(e,fa,260);Ea.call(e,fa,100)},0);break;case "r":case "g":case "b":setTimeout(function(){ab.call(e,o, -"transparent");ab.call(e,L,"transparent");Ea.call(e,da,100);Ea.call(e,T,100);Ja.call(e,T,Ma);Ja.call(e,N,Ma-260);Ja.call(e,da,Xa-780);Ja.call(e,V,Xa-520);Ja.call(e,O,Xa);Ja.call(e,fa,Xa-260);Ja.call(e,ja,260);Ea.call(e,ja,100)},0)}I.val("ahex")!=null&&La.call(e,I)},La=function(M,I){if(I==null||I!=ea&&I!=ca)Fa.call(e,M,I);setTimeout(function(){Gb.call(e,M);Nb.call(e,M);lb.call(e,M)},0)},Ga=function(M,I){var X=ta.active;if(!(I!=ca&&X.val()==null)){var Ma=M.val("all");switch(l.color.mode){case "h":X.val("sv", -{s:Ma.x,v:100-Ma.y},I);break;case "s":case "a":X.val("hv",{h:Ma.x,v:100-Ma.y},I);break;case "v":X.val("hs",{h:Ma.x,s:100-Ma.y},I);break;case "r":X.val("gb",{g:255-Ma.y,b:Ma.x},I);break;case "g":X.val("rb",{r:255-Ma.y,b:Ma.x},I);break;case "b":X.val("rg",{r:Ma.x,g:255-Ma.y},I)}}},Oa=function(M,I){var X=ta.active;if(!(I!=ea&&X.val()==null))switch(l.color.mode){case "h":X.val("h",{h:360-M.val("y")},I);break;case "s":X.val("s",{s:100-M.val("y")},I);break;case "v":X.val("v",{v:100-M.val("y")},I);break; -case "r":X.val("r",{r:255-M.val("y")},I);break;case "g":X.val("g",{g:255-M.val("y")},I);break;case "b":X.val("b",{b:255-M.val("y")},I);break;case "a":X.val("a",255-M.val("y"),I)}},Fa=function(M,I){if(I!=ca)switch(l.color.mode){case "h":var X=M.val("sv");ca.val("xy",{x:X!=null?X.s:100,y:100-(X!=null?X.v:100)},I);break;case "s":case "a":X=M.val("hv");ca.val("xy",{x:X&&X.h||0,y:100-(X!=null?X.v:100)},I);break;case "v":X=M.val("hs");ca.val("xy",{x:X&&X.h||0,y:100-(X!=null?X.s:100)},I);break;case "r":X= -M.val("bg");ca.val("xy",{x:X&&X.b||0,y:255-(X&&X.g||0)},I);break;case "g":X=M.val("br");ca.val("xy",{x:X&&X.b||0,y:255-(X&&X.r||0)},I);break;case "b":X=M.val("rg");ca.val("xy",{x:X&&X.r||0,y:255-(X&&X.g||0)},I)}if(I!=ea)switch(l.color.mode){case "h":ea.val("y",360-(M.val("h")||0),I);break;case "s":X=M.val("s");ea.val("y",100-(X!=null?X:100),I);break;case "v":X=M.val("v");ea.val("y",100-(X!=null?X:100),I);break;case "r":ea.val("y",255-(M.val("r")||0),I);break;case "g":ea.val("y",255-(M.val("g")||0), -I);break;case "b":ea.val("y",255-(M.val("b")||0),I);break;case "a":X=M.val("a");ea.val("y",255-(X!=null?X:255),I)}},Gb=function(M){try{var I=M.val("all");ra.css({backgroundColor:I&&"#"+I.hex||"transparent"});Ea.call(e,ra,I&&Math.precision(I.a*100/255,4)||0)}catch(X){}},Nb=function(M){switch(l.color.mode){case "h":ab.call(e,o,(new c({h:M.val("h")||0,s:100,v:100})).val("hex"));break;case "s":case "a":var I=M.val("s");Ea.call(e,N,100-(I!=null?I:100));break;case "v":I=M.val("v");Ea.call(e,T,I!=null?I: -100);break;case "r":Ea.call(e,N,Math.precision((M.val("r")||0)/255*100,4));break;case "g":Ea.call(e,N,Math.precision((M.val("g")||0)/255*100,4));break;case "b":Ea.call(e,N,Math.precision((M.val("b")||0)/255*100))}M=M.val("a");Ea.call(e,J,Math.precision((255-(M||0))*100/255,4))},lb=function(M){switch(l.color.mode){case "h":var I=M.val("a");Ea.call(e,sa,Math.precision((255-(I||0))*100/255,4));break;case "s":I=M.val("hva");var X=new c({h:I&&I.h||0,s:100,v:I!=null?I.v:100});ab.call(e,L,X.val("hex")); -Ea.call(e,V,100-(I!=null?I.v:100));Ea.call(e,sa,Math.precision((255-(I&&I.a||0))*100/255,4));break;case "v":I=M.val("hsa");X=new c({h:I&&I.h||0,s:I!=null?I.s:100,v:100});ab.call(e,L,X.val("hex"));Ea.call(e,sa,Math.precision((255-(I&&I.a||0))*100/255,4));break;case "r":case "g":case "b":X=I=0;M=M.val("rgba");if(l.color.mode=="r"){I=M&&M.b||0;X=M&&M.g||0}else if(l.color.mode=="g"){I=M&&M.b||0;X=M&&M.r||0}else if(l.color.mode=="b"){I=M&&M.r||0;X=M&&M.g||0}var Ma=X>I?I:X;Ea.call(e,V,I>X?Math.precision((I- -X)/(255-X)*100,4):0);Ea.call(e,O,X>I?Math.precision((X-I)/(255-I)*100,4):0);Ea.call(e,fa,Math.precision(Ma/255*100,4));Ea.call(e,sa,Math.precision((255-(M&&M.a||0))*100/255,4));break;case "a":I=M.val("a");ab.call(e,L,M.val("hex")||"000000");Ea.call(e,sa,I!=null?0:100);Ea.call(e,ja,I!=null?100:0)}},ab=function(M,I){M.css({backgroundColor:I&&I.length==6&&"#"+I||"transparent"})},Sa=function(M,I){if(u&&(I.indexOf("AlphaBar.png")!=-1||I.indexOf("Bars.png")!=-1||I.indexOf("Maps.png")!=-1)){M.attr("pngSrc", -I);M.css({backgroundImage:"none",filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+I+"', sizingMethod='scale')"})}else M.css({backgroundImage:"url('"+I+"')"})},Ja=function(M,I){M.css({top:I+"px"})},Ea=function(M,I){M.css({visibility:I>0?"visible":"hidden"});if(I>0&&I<100)if(u){var X=M.attr("pngSrc");X!=null&&(X.indexOf("AlphaBar.png")!=-1||X.indexOf("Bars.png")!=-1||X.indexOf("Maps.png")!=-1)?M.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+X+"', sizingMethod='scale') progid:DXImageTransform.Microsoft.Alpha(opacity="+ -I+")"}):M.css({opacity:Math.precision(I/100,4)})}else M.css({opacity:Math.precision(I/100,4)});else if(I==0||I==100)if(u){X=M.attr("pngSrc");X!=null&&(X.indexOf("AlphaBar.png")!=-1||X.indexOf("Bars.png")!=-1||X.indexOf("Maps.png")!=-1)?M.css({filter:"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+X+"', sizingMethod='scale')"}):M.css({opacity:""})}else M.css({opacity:""})},Za=function(){ta.active.val("ahex",ta.current.val("ahex"))},Ra=function(){ta.current.val("ahex",ta.active.val("ahex"))}, -$a=function(M){a(this).parents("tbody:first").find('input:radio[value!="'+M.target.value+'"]').removeAttr("checked");Wa.call(e,M.target.value)},Na=function(){Za.call(e)},mb=function(){Za.call(e);l.window.expandable&&Ib.call(e);a.isFunction(Cb)&&Cb.call(e,ta.active,Y)},Ab=function(){Ra.call(e);l.window.expandable&&Ib.call(e);a.isFunction(Bb)&&Bb.call(e,ta.active,ma)},cb=function(){Kb.call(e)},jb=function(M){var I=M.val("hex");la.css({backgroundColor:I&&"#"+I||"transparent"});Ea.call(e,la,Math.precision((M.val("a")|| -0)*100/255,4))},kb=function(M){var I=M.val("hex");M=M.val("va");Ia.css({backgroundColor:I&&"#"+I||"transparent"});Ea.call(e,Qa,Math.precision((255-(M&&M.a||0))*100/255,4));if(l.window.bindToInput&&l.window.updateInputColor)l.window.input.css({backgroundColor:I&&"#"+I||"transparent",color:M==null||M.v>75?"#000000":"#ffffff"})},Ca=function(M){pa=parseInt(z.css("left"));ba=parseInt(z.css("top"));S=M.pageX;U=M.pageY;a(document).bind("mousemove",wb).bind("mouseup",nb);M.preventDefault()},wb=function(M){z.css({left:pa- -(S-M.pageX)+"px",top:ba-(U-M.pageY)+"px"});l.window.expandable&&!a.support.boxModel&&z.prev().css({left:z.css("left"),top:z.css("top")});M.stopPropagation();M.preventDefault();return false},nb=function(M){a(document).unbind("mousemove",wb).unbind("mouseup",nb);M.stopPropagation();M.preventDefault();return false},yb=function(M){M.preventDefault();M.stopPropagation();ta.active.val("ahex",a(this).attr("title")||null,M.target);return false},Bb=a.isFunction(d[1])&&d[1]||null,ob=a.isFunction(d[2])&&d[2]|| -null,Cb=a.isFunction(d[3])&&d[3]||null,Kb=function(){ta.current.val("ahex",ta.active.val("ahex"));var M=function(){if(!(!l.window.expandable||a.support.boxModel)){var I=z.find("table:first");z.before("