- Linting (ESLint): Finish extensions and most files in editor/; unfinished: editor/svg-editor.js, editor/svgcanvas.js

- Linting (ESLint): Fix ignore file paths
- History `elem` fix
This commit is contained in:
Brett Zamir
2018-05-16 08:53:27 +08:00
parent 5bcbb948eb
commit 340915be4e
51 changed files with 12031 additions and 12108 deletions

View File

@@ -1,13 +1,14 @@
node_modules node_modules
editor/jquery.js
editor/jspdf/jspdf.min.js editor/jspdf/jspdf.min.js
editor/jspdf/underscore-min.js editor/jspdf/underscore-min.js
jgraduate/jpicker.min.js editor/jgraduate/jpicker.min.js
jgraduate/jquery.jgraduate.js editor/jgraduate/jquery.jgraduate.min.js
jquery-ui editor/jquery-ui
jquerybbq editor/jquerybbq
js-hotkeys editor/js-hotkeys
spinbtn/JQuerySpinBtn.min.js editor/spinbtn/JQuerySpinBtn.min.js
test/qunit test/qunit
test/sinon test/sinon
wave/json2.js wave/json2.js

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true*/ /* globals $, svgedit */
/** /**
* Package: svgedit.browser * Package: svgedit.browser
* *
@@ -12,7 +12,8 @@
// Dependencies: // Dependencies:
// 1) jQuery (for $.alert()) // 1) jQuery (for $.alert())
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.browser) { if (!svgedit.browser) {
svgedit.browser = {}; svgedit.browser = {};
@@ -21,12 +22,12 @@ if (!svgedit.browser) {
// alias // alias
var NS = svgedit.NS; var NS = svgedit.NS;
var supportsSvg_ = (function() { var supportsSvg_ = (function () {
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect; return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
}()); }());
svgedit.browser.supportsSvg = function() { return supportsSvg_; }; svgedit.browser.supportsSvg = function () { return supportsSvg_; };
if(!svgedit.browser.supportsSvg()) { if (!svgedit.browser.supportsSvg()) {
window.location = 'browser-not-supported.html'; window.location = 'browser-not-supported.html';
return; return;
} }
@@ -44,41 +45,41 @@ var isWindows_ = userAgent.indexOf('Windows') >= 0;
var isMac_ = userAgent.indexOf('Macintosh') >= 0; var isMac_ = userAgent.indexOf('Macintosh') >= 0;
var isTouch_ = 'ontouchstart' in window; var isTouch_ = 'ontouchstart' in window;
var supportsSelectors_ = (function() { var supportsSelectors_ = (function () {
return !!svg.querySelector; return !!svg.querySelector;
}()); }());
var supportsXpath_ = (function() { var supportsXpath_ = (function () {
return !!document.evaluate; return !!document.evaluate;
}()); }());
// segList functions (for FF1.5 and 2.0) // segList functions (for FF1.5 and 2.0)
var supportsPathReplaceItem_ = (function() { var supportsPathReplaceItem_ = (function () {
var path = document.createElementNS(NS.SVG, 'path'); var path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,10'); path.setAttribute('d', 'M0,0 10,10');
var seglist = path.pathSegList; var seglist = path.pathSegList;
var seg = path.createSVGPathSegLinetoAbs(5,5); var seg = path.createSVGPathSegLinetoAbs(5, 5);
try { try {
seglist.replaceItem(seg, 1); seglist.replaceItem(seg, 1);
return true; return true;
} catch(err) {} } catch (err) {}
return false; return false;
}()); }());
var supportsPathInsertItemBefore_ = (function() { var supportsPathInsertItemBefore_ = (function () {
var path = document.createElementNS(NS.SVG, 'path'); var path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,10'); path.setAttribute('d', 'M0,0 10,10');
var seglist = path.pathSegList; var seglist = path.pathSegList;
var seg = path.createSVGPathSegLinetoAbs(5,5); var seg = path.createSVGPathSegLinetoAbs(5, 5);
try { try {
seglist.insertItemBefore(seg, 1); seglist.insertItemBefore(seg, 1);
return true; return true;
} catch(err) {} } catch (err) {}
return false; return false;
}()); }());
// text character positioning (for IE9) // text character positioning (for IE9)
var supportsGoodTextCharPos_ = (function() { var supportsGoodTextCharPos_ = (function () {
var svgroot = document.createElementNS(NS.SVG, 'svg'); var svgroot = document.createElementNS(NS.SVG, 'svg');
var svgcontent = document.createElementNS(NS.SVG, 'svg'); var svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgroot); document.documentElement.appendChild(svgroot);
@@ -92,7 +93,7 @@ var supportsGoodTextCharPos_ = (function() {
return (pos === 0); return (pos === 0);
}()); }());
var supportsPathBBox_ = (function() { var supportsPathBBox_ = (function () {
var svgcontent = document.createElementNS(NS.SVG, 'svg'); var svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgcontent); document.documentElement.appendChild(svgcontent);
var path = document.createElementNS(NS.SVG, 'path'); var path = document.createElementNS(NS.SVG, 'path');
@@ -104,7 +105,7 @@ var supportsPathBBox_ = (function() {
}()); }());
// Support for correct bbox sizing on groups with horizontal/vertical lines // Support for correct bbox sizing on groups with horizontal/vertical lines
var supportsHVLineContainerBBox_ = (function() { var supportsHVLineContainerBBox_ = (function () {
var svgcontent = document.createElementNS(NS.SVG, 'svg'); var svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgcontent); document.documentElement.appendChild(svgcontent);
var path = document.createElementNS(NS.SVG, 'path'); var path = document.createElementNS(NS.SVG, 'path');
@@ -121,31 +122,31 @@ var supportsHVLineContainerBBox_ = (function() {
return (bbox.width == 15); return (bbox.width == 15);
}()); }());
var supportsEditableText_ = (function() { var supportsEditableText_ = (function () {
// TODO: Find better way to check support for this // TODO: Find better way to check support for this
return isOpera_; return isOpera_;
}()); }());
var supportsGoodDecimals_ = (function() { var supportsGoodDecimals_ = (function () {
// Correct decimals on clone attributes (Opera < 10.5/win/non-en) // Correct decimals on clone attributes (Opera < 10.5/win/non-en)
var rect = document.createElementNS(NS.SVG, 'rect'); var rect = document.createElementNS(NS.SVG, 'rect');
rect.setAttribute('x', 0.1); rect.setAttribute('x', 0.1);
var crect = rect.cloneNode(false); var crect = rect.cloneNode(false);
var retValue = (crect.getAttribute('x').indexOf(',') == -1); var retValue = (crect.getAttribute('x').indexOf(',') === -1);
if(!retValue) { if (!retValue) {
$.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n'+ $.alert('NOTE: This version of Opera is known to contain bugs in SVG-edit.\n' +
'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.'); 'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.');
} }
return retValue; return retValue;
}()); }());
var supportsNonScalingStroke_ = (function() { var supportsNonScalingStroke_ = (function () {
var rect = document.createElementNS(NS.SVG, 'rect'); var rect = document.createElementNS(NS.SVG, 'rect');
rect.setAttribute('style', 'vector-effect:non-scaling-stroke'); rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
return rect.style.vectorEffect === 'non-scaling-stroke'; return rect.style.vectorEffect === 'non-scaling-stroke';
}()); }());
var supportsNativeSVGTransformLists_ = (function() { var supportsNativeSVGTransformLists_ = (function () {
var rect = document.createElementNS(NS.SVG, 'rect'); var rect = document.createElementNS(NS.SVG, 'rect');
var rxform = rect.transform.baseVal; var rxform = rect.transform.baseVal;
var t1 = svg.createSVGTransform(); var t1 = svg.createSVGTransform();
@@ -163,26 +164,25 @@ var supportsNativeSVGTransformLists_ = (function() {
// Public API // Public API
svgedit.browser.isOpera = function() { return isOpera_; }; svgedit.browser.isOpera = function () { return isOpera_; };
svgedit.browser.isWebkit = function() { return isWebkit_; }; svgedit.browser.isWebkit = function () { return isWebkit_; };
svgedit.browser.isGecko = function() { return isGecko_; }; svgedit.browser.isGecko = function () { return isGecko_; };
svgedit.browser.isIE = function() { return isIE_; }; svgedit.browser.isIE = function () { return isIE_; };
svgedit.browser.isChrome = function() { return isChrome_; }; svgedit.browser.isChrome = function () { return isChrome_; };
svgedit.browser.isWindows = function() { return isWindows_; }; svgedit.browser.isWindows = function () { return isWindows_; };
svgedit.browser.isMac = function() { return isMac_; }; svgedit.browser.isMac = function () { return isMac_; };
svgedit.browser.isTouch = function() { return isTouch_; }; svgedit.browser.isTouch = function () { return isTouch_; };
svgedit.browser.supportsSelectors = function() { return supportsSelectors_; }; svgedit.browser.supportsSelectors = function () { return supportsSelectors_; };
svgedit.browser.supportsXpath = function() { return supportsXpath_; }; 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_; };
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_; };
}()); }());

View File

@@ -3,7 +3,7 @@
// CREATE A NEW FILE config.js AND ADD CONTENTS // CREATE A NEW FILE config.js AND ADD CONTENTS
// SUCH AS SHOWN BELOW INTO THAT FILE. // SUCH AS SHOWN BELOW INTO THAT FILE.
/*globals svgEditor*/ /* globals svgEditor */
/* /*
The config.js file is intended for the setting of configuration or The config.js file is intended for the setting of configuration or
preferences which must run early on; if this is not needed, it is preferences which must run early on; if this is not needed, it is
@@ -56,17 +56,17 @@ svgEditor.setConfig({
}); });
// OTHER CONFIG // OTHER CONFIG
svgEditor.setConfig({ svgEditor.setConfig({
// canvasName: 'default', // canvasName: 'default',
// canvas_expansion: 3, // canvas_expansion: 3,
// initFill: { // initFill: {
// color: 'FF0000', // solid red // color: 'FF0000', // solid red
// opacity: 1 // opacity: 1
// }, // },
// initStroke: { // initStroke: {
// width: 5, // width: 5,
// color: '000000', // solid black // color: '000000', // solid black
// opacity: 1 // opacity: 1
// }, // },
// initOpacity: 1, // initOpacity: 1,
// colorPickerCSS: null, // colorPickerCSS: null,

View File

@@ -1,66 +1,66 @@
/*globals $, svgEditor*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true*/ /* globals $, svgEditor */
/** /**
* Package: svgedit.contextmenu * Package: svgedit.contextmenu
* *
* Licensed under the Apache License, Version 2 * Licensed under the Apache License, Version 2
* *
* Author: Adam Bender * Author: Adam Bender
*/ */
// Dependencies: // Dependencies:
// 1) jQuery (for dom injection of context menus) // 1) jQuery (for dom injection of context menus)
var svgedit = svgedit || {}; var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
(function() { (function () {
var self = this; var self = this;
if (!svgedit.contextmenu) { if (!svgedit.contextmenu) {
svgedit.contextmenu = {}; svgedit.contextmenu = {};
}
self.contextMenuExtensions = {};
var menuItemIsValid = function (menuItem) {
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function';
};
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;
} }
self.contextMenuExtensions = {}; if (menuItem.id in self.contextMenuExtensions) {
var menuItemIsValid = function(menuItem) { console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"');
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action == 'function'; return;
}; }
var addContextMenuItem = function(menuItem) { // Register menuItem action, see below for deferred menu dom injection
// menuItem: {id, label, shortcut, action} console.log('Registed contextmenu item: {id:' + menuItem.id + ', label:' + menuItem.label + '}');
if (!menuItemIsValid(menuItem)) { self.contextMenuExtensions[menuItem.id] = menuItem;
console.error("Menu items must be defined and have at least properties: id, label, action, where action must be a function"); // TODO: Need to consider how to handle custom enable/disable behavior
return; };
} var hasCustomHandler = function (handlerKey) {
if (menuItem.id in self.contextMenuExtensions) { return self.contextMenuExtensions[handlerKey] && true;
console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"'); };
return; var getCustomHandler = function (handlerKey) {
} return self.contextMenuExtensions[handlerKey].action;
// Register menuItem action, see below for deferred menu dom injection };
console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}"); var injectExtendedContextMenuItemIntoDom = function (menuItem) {
self.contextMenuExtensions[menuItem.id] = menuItem; if (Object.keys(self.contextMenuExtensions).length === 0) {
//TODO: Need to consider how to handle custom enable/disable behavior // 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.
var hasCustomHandler = function(handlerKey) { $('#cmenu_canvas').append("<li class='separator'>");
return self.contextMenuExtensions[handlerKey] && true; }
}; var shortcut = menuItem.shortcut || '';
var getCustomHandler = function(handlerKey) { $('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" +
return self.contextMenuExtensions[handlerKey].action; menuItem.label + "<span class='shortcut'>" +
}; shortcut + '</span></a></li>');
var injectExtendedContextMenuItemIntoDom = function(menuItem) { };
if (Object.keys(self.contextMenuExtensions).length === 0) { // Defer injection to wait out initial menu processing. This probably goes away once all context
// all menuItems appear at the bottom of the menu in their own container. // menu behavior is brought here.
// if this is the first extension menu we need to add the separator. svgEditor.ready(function () {
$("#cmenu_canvas").append("<li class='separator'>"); var menuItem;
} for (menuItem in self.contextMenuExtensions) {
var shortcut = menuItem.shortcut || ""; injectExtendedContextMenuItemIntoDom(self.contextMenuExtensions[menuItem]);
$("#cmenu_canvas").append("<li class='disabled'><a href='#" + menuItem.id + "'>" }
+ menuItem.label + "<span class='shortcut'>" });
+ shortcut + "</span></a></li>"); svgedit.contextmenu.resetCustomMenus = function () { self.contextMenuExtensions = {}; };
}; svgedit.contextmenu.add = addContextMenuItem;
// Defer injection to wait out initial menu processing. This probably goes away once all context svgedit.contextmenu.hasCustomHandler = hasCustomHandler;
// menu behavior is brought here. svgedit.contextmenu.getCustomHandler = getCustomHandler;
svgEditor.ready(function() {
var menuItem;
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;
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals $, svgroot */ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true, forin: true*/ /* globals $, svgroot */
/** /**
* Coords. * Coords.
* *
@@ -16,17 +16,18 @@
// 6) units.js // 6) units.js
// 7) svgtransformlist.js // 7) svgtransformlist.js
var svgedit = svgedit || {}; var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.coords) { if (!svgedit.coords) {
svgedit.coords = {}; svgedit.coords = {};
} }
// this is how we map paths to our preferred relative segment types // 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', var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; 'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
/** /**
* @typedef editorContext * @typedef editorContext
@@ -39,8 +40,8 @@ var editorContext_ = null;
/** /**
* @param {editorContext} editorContext * @param {editorContext} editorContext
*/ */
svgedit.coords.init = function(editorContext) { svgedit.coords.init = function (editorContext) {
editorContext_ = editorContext; editorContext_ = editorContext;
}; };
/** /**
@@ -49,269 +50,267 @@ svgedit.coords.init = function(editorContext) {
* @param {object} changes - Object with changes to be remapped * @param {object} changes - Object with changes to be remapped
* @param {SVGMatrix} m - Matrix object to use for remapping coordinates * @param {SVGMatrix} m - Matrix object to use for remapping coordinates
*/ */
svgedit.coords.remapElement = function(selected, changes, m) { svgedit.coords.remapElement = function (selected, changes, m) {
var i, type, var i, type,
remap = function(x, y) { return svgedit.math.transformPoint(x, y, m); }, remap = function (x, y) { return svgedit.math.transformPoint(x, y, m); },
scalew = function(w) { return m.a * w; }, scalew = function (w) { return m.a * w; },
scaleh = function(h) { return m.d * h; }, scaleh = function (h) { return m.d * h; },
doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg', doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg',
finishUp = function() { finishUp = function () {
var o; var o;
if (doSnapping) { if (doSnapping) {
for (o in changes) { for (o in changes) {
changes[o] = svgedit.utilities.snapToGrid(changes[o]); changes[o] = svgedit.utilities.snapToGrid(changes[o]);
} }
} }
svgedit.utilities.assignAttributes(selected, changes, 1000, true); svgedit.utilities.assignAttributes(selected, changes, 1000, true);
}, },
box = svgedit.utilities.getBBox(selected); box = svgedit.utilities.getBBox(selected);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
type = i === 0 ? 'fill' : 'stroke'; type = i === 0 ? 'fill' : 'stroke';
var attrVal = selected.getAttribute(type); var attrVal = selected.getAttribute(type);
if (attrVal && attrVal.indexOf('url(') === 0) { if (attrVal && attrVal.indexOf('url(') === 0) {
if (m.a < 0 || m.d < 0) { if (m.a < 0 || m.d < 0) {
var grad = svgedit.utilities.getRefElem(attrVal); var grad = svgedit.utilities.getRefElem(attrVal);
var newgrad = grad.cloneNode(true); var newgrad = grad.cloneNode(true);
if (m.a < 0) { if (m.a < 0) {
// flip x // flip x
var x1 = newgrad.getAttribute('x1'); var x1 = newgrad.getAttribute('x1');
var x2 = newgrad.getAttribute('x2'); var x2 = newgrad.getAttribute('x2');
newgrad.setAttribute('x1', -(x1 - 1)); newgrad.setAttribute('x1', -(x1 - 1));
newgrad.setAttribute('x2', -(x2 - 1)); newgrad.setAttribute('x2', -(x2 - 1));
} }
if (m.d < 0) { if (m.d < 0) {
// flip y // flip y
var y1 = newgrad.getAttribute('y1'); var y1 = newgrad.getAttribute('y1');
var y2 = newgrad.getAttribute('y2'); var y2 = newgrad.getAttribute('y2');
newgrad.setAttribute('y1', -(y1 - 1)); newgrad.setAttribute('y1', -(y1 - 1));
newgrad.setAttribute('y2', -(y2 - 1)); newgrad.setAttribute('y2', -(y2 - 1));
} }
newgrad.id = editorContext_.getDrawing().getNextId(); newgrad.id = editorContext_.getDrawing().getNextId();
svgedit.utilities.findDefs().appendChild(newgrad); svgedit.utilities.findDefs().appendChild(newgrad);
selected.setAttribute(type, 'url(#' + newgrad.id + ')'); selected.setAttribute(type, 'url(#' + newgrad.id + ')');
} }
// Not really working :( // Not really working :(
// if (selected.tagName === 'path') { // if (selected.tagName === 'path') {
// reorientGrads(selected, m); // reorientGrads(selected, m);
// } // }
} }
} }
var elName = selected.tagName; var elName = selected.tagName;
var chlist, mt; var chlist, mt;
if (elName === 'g' || elName === 'text' || elName == 'tspan' || elName === 'use') { if (elName === 'g' || elName === 'text' || elName == 'tspan' || elName === 'use') {
// if it was a translate, then just update x,y // 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) ) { if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && (m.e != 0 || m.f != 0)) {
// [T][M] = [M][T'] // [T][M] = [M][T']
// therefore [T'] = [M_inv][T][M] // therefore [T'] = [M_inv][T][M]
var existing = svgedit.math.transformListToTransform(selected).matrix, var existing = svgedit.math.transformListToTransform(selected).matrix,
t_new = svgedit.math.matrixMultiply(existing.inverse(), m, existing); tNew = svgedit.math.matrixMultiply(existing.inverse(), m, existing);
changes.x = parseFloat(changes.x) + t_new.e; changes.x = parseFloat(changes.x) + tNew.e;
changes.y = parseFloat(changes.y) + t_new.f; changes.y = parseFloat(changes.y) + tNew.f;
} else { } else {
// we just absorb all matrices into the element and don't do any remapping // we just absorb all matrices into the element and don't do any remapping
chlist = svgedit.transformlist.getTransformList(selected); chlist = svgedit.transformlist.getTransformList(selected);
mt = svgroot.createSVGTransform(); mt = svgroot.createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m)); mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
chlist.clear(); chlist.clear();
chlist.appendItem(mt); chlist.appendItem(mt);
} }
} }
var c, pt, pt1, pt2, len; var c, pt, pt1, pt2, len;
// now we have a set of changes and an applied reduced transform list // now we have a set of changes and an applied reduced transform list
// we apply the changes directly to the DOM // we apply the changes directly to the DOM
switch (elName) { switch (elName) {
case 'foreignObject': case 'foreignObject':
case 'rect': case 'rect':
case 'image': case 'image':
// Allow images to be inverted (give them matrix when flipped) // Allow images to be inverted (give them matrix when flipped)
if (elName === 'image' && (m.a < 0 || m.d < 0)) { if (elName === 'image' && (m.a < 0 || m.d < 0)) {
// Convert to matrix // Convert to matrix
chlist = svgedit.transformlist.getTransformList(selected); chlist = svgedit.transformlist.getTransformList(selected);
mt = svgroot.createSVGTransform(); mt = svgroot.createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m)); mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
chlist.clear(); chlist.clear();
chlist.appendItem(mt); chlist.appendItem(mt);
} else { } else {
pt1 = remap(changes.x, changes.y); pt1 = remap(changes.x, changes.y);
changes.width = scalew(changes.width); changes.width = scalew(changes.width);
changes.height = scaleh(changes.height); changes.height = scaleh(changes.height);
changes.x = pt1.x + Math.min(0, changes.width); changes.x = pt1.x + Math.min(0, changes.width);
changes.y = pt1.y + Math.min(0, changes.height); changes.y = pt1.y + Math.min(0, changes.height);
changes.width = Math.abs(changes.width); changes.width = Math.abs(changes.width);
changes.height = Math.abs(changes.height); changes.height = Math.abs(changes.height);
} }
finishUp(); finishUp();
break; break;
case 'ellipse': case 'ellipse':
c = remap(changes.cx, changes.cy); c = remap(changes.cx, changes.cy);
changes.cx = c.x; changes.cx = c.x;
changes.cy = c.y; changes.cy = c.y;
changes.rx = scalew(changes.rx); changes.rx = scalew(changes.rx);
changes.ry = scaleh(changes.ry); changes.ry = scaleh(changes.ry);
changes.rx = Math.abs(changes.rx); changes.rx = Math.abs(changes.rx);
changes.ry = Math.abs(changes.ry); changes.ry = Math.abs(changes.ry);
finishUp(); finishUp();
break; break;
case 'circle': case 'circle':
c = remap(changes.cx,changes.cy); c = remap(changes.cx, changes.cy);
changes.cx = c.x; changes.cx = c.x;
changes.cy = c.y; changes.cy = c.y;
// take the minimum of the new selected box's dimensions for the new circle radius // 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 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; var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
changes.r = Math.min(w/2, h/2); changes.r = Math.min(w / 2, h / 2);
if (changes.r) {changes.r = Math.abs(changes.r);} if (changes.r) { changes.r = Math.abs(changes.r); }
finishUp(); finishUp();
break; break;
case 'line': case 'line':
pt1 = remap(changes.x1, changes.y1); pt1 = remap(changes.x1, changes.y1);
pt2 = remap(changes.x2, changes.y2); pt2 = remap(changes.x2, changes.y2);
changes.x1 = pt1.x; changes.x1 = pt1.x;
changes.y1 = pt1.y; changes.y1 = pt1.y;
changes.x2 = pt2.x; changes.x2 = pt2.x;
changes.y2 = pt2.y; changes.y2 = pt2.y;
// deliberately fall through here // deliberately fall through here
case 'text': case 'text':
case 'tspan': case 'tspan':
case 'use': case 'use':
finishUp(); finishUp();
break; break;
case 'g': case 'g':
var gsvg = $(selected).data('gsvg'); var gsvg = $(selected).data('gsvg');
if (gsvg) { if (gsvg) {
svgedit.utilities.assignAttributes(gsvg, changes, 1000, true); svgedit.utilities.assignAttributes(gsvg, changes, 1000, true);
} }
break; break;
case 'polyline': case 'polyline':
case 'polygon': case 'polygon':
len = changes.points.length; len = changes.points.length;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
pt = changes.points[i]; pt = changes.points[i];
pt = remap(pt.x, pt.y); pt = remap(pt.x, pt.y);
changes.points[i].x = pt.x; changes.points[i].x = pt.x;
changes.points[i].y = pt.y; changes.points[i].y = pt.y;
} }
len = changes.points.length; len = changes.points.length;
var pstr = ''; var pstr = '';
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
pt = changes.points[i]; pt = changes.points[i];
pstr += pt.x + ',' + pt.y + ' '; pstr += pt.x + ',' + pt.y + ' ';
} }
selected.setAttribute('points', pstr); selected.setAttribute('points', pstr);
break; break;
case 'path': case 'path':
var seg; var seg;
var segList = selected.pathSegList; var segList = selected.pathSegList;
len = segList.numberOfItems; len = segList.numberOfItems;
changes.d = []; changes.d = [];
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
seg = segList.getItem(i); seg = segList.getItem(i);
changes.d[i] = { changes.d[i] = {
type: seg.pathSegType, type: seg.pathSegType,
x: seg.x, x: seg.x,
y: seg.y, y: seg.y,
x1: seg.x1, x1: seg.x1,
y1: seg.y1, y1: seg.y1,
x2: seg.x2, x2: seg.x2,
y2: seg.y2, y2: seg.y2,
r1: seg.r1, r1: seg.r1,
r2: seg.r2, r2: seg.r2,
angle: seg.angle, angle: seg.angle,
largeArcFlag: seg.largeArcFlag, largeArcFlag: seg.largeArcFlag,
sweepFlag: seg.sweepFlag sweepFlag: seg.sweepFlag
}; };
} }
len = changes.d.length; len = changes.d.length;
var firstseg = changes.d[0], var firstseg = changes.d[0],
currentpt = remap(firstseg.x, firstseg.y); currentpt = remap(firstseg.x, firstseg.y);
changes.d[0].x = currentpt.x; changes.d[0].x = currentpt.x;
changes.d[0].y = currentpt.y; changes.d[0].y = currentpt.y;
for (i = 1; i < len; ++i) { for (i = 1; i < len; ++i) {
seg = changes.d[i]; seg = changes.d[i];
type = seg.type; type = seg.type;
// if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2
// if relative, we want to scalew, scaleh // if relative, we want to scalew, scaleh
if (type % 2 == 0) { // absolute if (type % 2 == 0) { // absolute
var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands
thisy = (seg.y != undefined) ? seg.y : currentpt.y; // for H commands thisy = (seg.y != undefined) ? seg.y : currentpt.y; // for H commands
pt = remap(thisx,thisy); pt = remap(thisx, thisy);
pt1 = remap(seg.x1, seg.y1); pt1 = remap(seg.x1, seg.y1);
pt2 = remap(seg.x2, seg.y2); pt2 = remap(seg.x2, seg.y2);
seg.x = pt.x; seg.x = pt.x;
seg.y = pt.y; seg.y = pt.y;
seg.x1 = pt1.x; seg.x1 = pt1.x;
seg.y1 = pt1.y; seg.y1 = pt1.y;
seg.x2 = pt2.x; seg.x2 = pt2.x;
seg.y2 = pt2.y; seg.y2 = pt2.y;
seg.r1 = scalew(seg.r1); seg.r1 = scalew(seg.r1);
seg.r2 = scaleh(seg.r2); seg.r2 = scaleh(seg.r2);
} } else { // relative
else { // relative seg.x = scalew(seg.x);
seg.x = scalew(seg.x); seg.y = scaleh(seg.y);
seg.y = scaleh(seg.y); seg.x1 = scalew(seg.x1);
seg.x1 = scalew(seg.x1); seg.y1 = scaleh(seg.y1);
seg.y1 = scaleh(seg.y1); seg.x2 = scalew(seg.x2);
seg.x2 = scalew(seg.x2); seg.y2 = scaleh(seg.y2);
seg.y2 = scaleh(seg.y2); seg.r1 = scalew(seg.r1);
seg.r1 = scalew(seg.r1); seg.r2 = scaleh(seg.r2);
seg.r2 = scaleh(seg.r2); }
} } // for each segment
} // for each segment
var dstr = ''; var dstr = '';
len = changes.d.length; len = changes.d.length;
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
seg = changes.d[i]; seg = changes.d[i];
type = seg.type; type = seg.type;
dstr += pathMap[type]; dstr += pathMap[type];
switch (type) { switch (type) {
case 13: // relative horizontal line (h) case 13: // relative horizontal line (h)
case 12: // absolute horizontal line (H) case 12: // absolute horizontal line (H)
dstr += seg.x + ' '; dstr += seg.x + ' ';
break; break;
case 15: // relative vertical line (v) case 15: // relative vertical line (v)
case 14: // absolute vertical line (V) case 14: // absolute vertical line (V)
dstr += seg.y + ' '; dstr += seg.y + ' ';
break; break;
case 3: // relative move (m) case 3: // relative move (m)
case 5: // relative line (l) case 5: // relative line (l)
case 19: // relative smooth quad (t) case 19: // relative smooth quad (t)
case 2: // absolute move (M) case 2: // absolute move (M)
case 4: // absolute line (L) case 4: // absolute line (L)
case 18: // absolute smooth quad (T) case 18: // absolute smooth quad (T)
dstr += seg.x + ',' + seg.y + ' '; dstr += seg.x + ',' + seg.y + ' ';
break; break;
case 7: // relative cubic (c) case 7: // relative cubic (c)
case 6: // absolute cubic (C) case 6: // absolute cubic (C)
dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' + dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' +
seg.x + ',' + seg.y + ' '; seg.x + ',' + seg.y + ' ';
break; break;
case 9: // relative quad (q) case 9: // relative quad (q)
case 8: // absolute quad (Q) case 8: // absolute quad (Q)
dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' '; dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' ';
break; break;
case 11: // relative elliptical arc (a) case 11: // relative elliptical arc (a)
case 10: // absolute elliptical arc (A) case 10: // absolute elliptical arc (A)
dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + (+seg.largeArcFlag) + dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + (+seg.largeArcFlag) +
' ' + (+seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' '; ' ' + (+seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' ';
break; break;
case 17: // relative smooth cubic (s) case 17: // relative smooth cubic (s)
case 16: // absolute smooth cubic (S) case 16: // absolute smooth cubic (S)
dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' '; dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' ';
break; break;
} }
} }
selected.setAttribute('d', dstr); selected.setAttribute('d', dstr);
break; break;
} }
}; };
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true, todo: true*/ /* globals $, svgedit */
/** /**
* Package: svgedit.draw * Package: svgedit.draw
* *
@@ -13,7 +13,8 @@
// 2) browser.js // 2) browser.js
// 3) svgutils.js // 3) svgutils.js
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.draw) { if (!svgedit.draw) {
svgedit.draw = {}; svgedit.draw = {};
@@ -28,25 +29,22 @@ var RandomizeModes = {
ALWAYS_RANDOMIZE: 1, ALWAYS_RANDOMIZE: 1,
NEVER_RANDOMIZE: 2 NEVER_RANDOMIZE: 2
}; };
var randomize_ids = RandomizeModes.LET_DOCUMENT_DECIDE; var randomizeIds = RandomizeModes.LET_DOCUMENT_DECIDE;
/**
/**
* Called to ensure that drawings will or will not have randomized ids. * Called to ensure that drawings will or will not have randomized ids.
* The currentDrawing will have its nonce set if it doesn't already. * The currentDrawing will have its nonce set if it doesn't already.
* @param {boolean} enableRandomization - flag indicating if documents should have randomized ids * @param {boolean} enableRandomization - flag indicating if documents should have randomized ids
* @param {svgedit.draw.Drawing} currentDrawing * @param {svgedit.draw.Drawing} currentDrawing
*/ */
svgedit.draw.randomizeIds = function(enableRandomization, currentDrawing) { svgedit.draw.randomizeIds = function (enableRandomization, currentDrawing) {
randomize_ids = enableRandomization === false ? randomizeIds = enableRandomization === false
RandomizeModes.NEVER_RANDOMIZE : ? RandomizeModes.NEVER_RANDOMIZE
RandomizeModes.ALWAYS_RANDOMIZE; : RandomizeModes.ALWAYS_RANDOMIZE;
if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) { if (randomizeIds == RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) {
currentDrawing.setNonce(Math.floor(Math.random() * 100001)); currentDrawing.setNonce(Math.floor(Math.random() * 100001));
} else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) { } else if (randomizeIds == RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) {
currentDrawing.clearNonce(); currentDrawing.clearNonce();
} }
}; };
@@ -56,12 +54,12 @@ svgedit.draw.randomizeIds = function(enableRandomization, currentDrawing) {
* @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object * @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object
* encapsulates. If the svgElem has a se:nonce attribute on it, then * encapsulates. If the svgElem has a se:nonce attribute on it, then
* IDs will use the nonce as they are generated. * IDs will use the nonce as they are generated.
* @param {String=svg_} [opt_idPrefix] - The ID prefix to use. * @param {String=svg_} [optIdPrefix] - The ID prefix to use.
*/ */
svgedit.draw.Drawing = function(svgElem, opt_idPrefix) { svgedit.draw.Drawing = function (svgElem, optIdPrefix) {
if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI || if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI ||
svgElem.tagName != 'svg' || svgElem.namespaceURI != NS.SVG) { svgElem.tagName != 'svg' || svgElem.namespaceURI != NS.SVG) {
throw "Error: svgedit.draw.Drawing instance initialized without a <svg> element"; throw new Error('Error: svgedit.draw.Drawing instance initialized without a <svg> element');
} }
/** /**
@@ -69,19 +67,19 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
* @type {SVGSVGElement} * @type {SVGSVGElement}
*/ */
this.svgElem_ = svgElem; this.svgElem_ = svgElem;
/** /**
* The latest object number used in this drawing. * The latest object number used in this drawing.
* @type {number} * @type {number}
*/ */
this.obj_num = 0; this.obj_num = 0;
/** /**
* The prefix to prepend to each element id in the drawing. * The prefix to prepend to each element id in the drawing.
* @type {String} * @type {String}
*/ */
this.idPrefix = opt_idPrefix || "svg_"; this.idPrefix = optIdPrefix || 'svg_';
/** /**
* An array of released element ids to immediately reuse. * An array of released element ids to immediately reuse.
* @type {Array.<number>} * @type {Array.<number>}
@@ -120,9 +118,9 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
var n = this.svgElem_.getAttributeNS(NS.SE, 'nonce'); var n = this.svgElem_.getAttributeNS(NS.SE, 'nonce');
// If already set in the DOM, use the nonce throughout the document // If already set in the DOM, use the nonce throughout the document
// else, if randomizeIds(true) has been called, create and set the nonce. // else, if randomizeIds(true) has been called, create and set the nonce.
if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) { if (!!n && randomizeIds != RandomizeModes.NEVER_RANDOMIZE) {
this.nonce_ = n; this.nonce_ = n;
} else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) { } else if (randomizeIds == RandomizeModes.ALWAYS_RANDOMIZE) {
this.setNonce(Math.floor(Math.random() * 100001)); this.setNonce(Math.floor(Math.random() * 100001));
} }
}; };
@@ -150,14 +148,14 @@ svgedit.draw.Drawing.prototype.getSvgElem = function () {
/** /**
* @returns {!string|number} The previously set nonce * @returns {!string|number} The previously set nonce
*/ */
svgedit.draw.Drawing.prototype.getNonce = function() { svgedit.draw.Drawing.prototype.getNonce = function () {
return this.nonce_; return this.nonce_;
}; };
/** /**
* @param {!string|number} n The nonce to set * @param {!string|number} n The nonce to set
*/ */
svgedit.draw.Drawing.prototype.setNonce = function(n) { svgedit.draw.Drawing.prototype.setNonce = function (n) {
this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE); this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n); this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n);
this.nonce_ = n; this.nonce_ = n;
@@ -177,9 +175,9 @@ svgedit.draw.Drawing.prototype.clearNonce = function () {
* @return {String} The latest object Id. * @return {String} The latest object Id.
*/ */
svgedit.draw.Drawing.prototype.getId = function () { svgedit.draw.Drawing.prototype.getId = function () {
return this.nonce_ ? return this.nonce_
this.idPrefix + this.nonce_ + '_' + this.obj_num : ? this.idPrefix + this.nonce_ + '_' + this.obj_num
this.idPrefix + this.obj_num; : this.idPrefix + this.obj_num;
}; };
/** /**
@@ -190,7 +188,7 @@ svgedit.draw.Drawing.prototype.getNextId = function () {
var oldObjNum = this.obj_num; var oldObjNum = this.obj_num;
var restoreOldObjNum = false; var restoreOldObjNum = false;
// If there are any released numbers in the release stack, // If there are any released numbers in the release stack,
// use the last one instead of the next obj_num. // use the last one instead of the next obj_num.
// We need to temporarily use obj_num as that is what getId() depends on. // We need to temporarily use obj_num as that is what getId() depends on.
if (this.releasedNums.length > 0) { if (this.releasedNums.length > 0) {
@@ -239,7 +237,7 @@ svgedit.draw.Drawing.prototype.releaseId = function (id) {
if (typeof num !== 'number' || num <= 0 || this.releasedNums.indexOf(num) != -1) { if (typeof num !== 'number' || num <= 0 || this.releasedNums.indexOf(num) != -1) {
return false; return false;
} }
// push the released number into the released queue // push the released number into the released queue
this.releasedNums.push(num); this.releasedNums.push(num);
@@ -250,7 +248,7 @@ svgedit.draw.Drawing.prototype.releaseId = function (id) {
* Returns the number of layers in the current drawing. * Returns the number of layers in the current drawing.
* @returns {integer} The number of layers in the current drawing. * @returns {integer} The number of layers in the current drawing.
*/ */
svgedit.draw.Drawing.prototype.getNumLayers = function() { svgedit.draw.Drawing.prototype.getNumLayers = function () {
return this.all_layers.length; return this.all_layers.length;
}; };
@@ -262,7 +260,6 @@ svgedit.draw.Drawing.prototype.hasLayer = function (name) {
return this.layer_map[name] !== undefined; return this.layer_map[name] !== undefined;
}; };
/** /**
* Returns the name of the ith layer. If the index is out of range, an empty string is returned. * Returns the name of the ith layer. If the index is out of range, an empty string is returned.
* @param {integer} i - The zero-based index of the layer you are querying. * @param {integer} i - The zero-based index of the layer you are querying.
@@ -275,7 +272,7 @@ svgedit.draw.Drawing.prototype.getLayerName = function (i) {
/** /**
* @returns {SVGGElement} The SVGGElement representing the current layer. * @returns {SVGGElement} The SVGGElement representing the current layer.
*/ */
svgedit.draw.Drawing.prototype.getCurrentLayer = function() { svgedit.draw.Drawing.prototype.getCurrentLayer = function () {
return this.current_layer ? this.current_layer.getGroup() : null; return this.current_layer ? this.current_layer.getGroup() : null;
}; };
@@ -283,13 +280,13 @@ svgedit.draw.Drawing.prototype.getCurrentLayer = function() {
* Get a layer by name. * Get a layer by name.
* @returns {SVGGElement} The SVGGElement representing the named layer or null. * @returns {SVGGElement} The SVGGElement representing the named layer or null.
*/ */
svgedit.draw.Drawing.prototype.getLayerByName = function(name) { svgedit.draw.Drawing.prototype.getLayerByName = function (name) {
var layer = this.layer_map[name]; var layer = this.layer_map[name];
return layer ? layer.getGroup() : null; return layer ? layer.getGroup() : null;
}; };
/** /**
* Returns the name of the currently selected layer. If an error occurs, an empty string * Returns the name of the currently selected layer. If an error occurs, an empty string
* is returned. * is returned.
* @returns {string} The name of the currently active layer (or the empty string if none found). * @returns {string} The name of the currently active layer (or the empty string if none found).
*/ */
@@ -322,39 +319,38 @@ svgedit.draw.Drawing.prototype.setCurrentLayerName = function (name, hrService)
* @returns {Object} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null. * @returns {Object} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null.
*/ */
svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) { svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) {
var layer_count = this.getNumLayers(); var layerCount = this.getNumLayers();
if (!this.current_layer || newpos < 0 || newpos >= layer_count) { if (!this.current_layer || newpos < 0 || newpos >= layerCount) {
return null; return null;
} }
var oldpos; var oldpos;
for (oldpos = 0; oldpos < layer_count; ++oldpos) { for (oldpos = 0; oldpos < layerCount; ++oldpos) {
if (this.all_layers[oldpos] == this.current_layer) {break;} if (this.all_layers[oldpos] == this.current_layer) { break; }
} }
// some unknown error condition (current_layer not in all_layers) // some unknown error condition (current_layer not in all_layers)
if (oldpos == layer_count) { return null; } if (oldpos == layerCount) { return null; }
if (oldpos != newpos) { if (oldpos != newpos) {
// if our new position is below us, we need to insert before the node after newpos // if our new position is below us, we need to insert before the node after newpos
var refGroup = null; var refGroup = null;
var current_group = this.current_layer.getGroup(); var currentGroup = this.current_layer.getGroup();
var oldNextSibling = current_group.nextSibling; var oldNextSibling = currentGroup.nextSibling;
if (newpos > oldpos ) { if (newpos > oldpos) {
if (newpos < layer_count-1) { if (newpos < layerCount - 1) {
refGroup = this.all_layers[newpos+1].getGroup(); refGroup = this.all_layers[newpos + 1].getGroup();
} }
}
// if our new position is above us, we need to insert before the node at newpos // if our new position is above us, we need to insert before the node at newpos
else { } else {
refGroup = this.all_layers[newpos].getGroup(); refGroup = this.all_layers[newpos].getGroup();
} }
this.svgElem_.insertBefore(current_group, refGroup); this.svgElem_.insertBefore(currentGroup, refGroup);
this.identifyLayers(); this.identifyLayers();
this.setCurrentLayer(this.getLayerName(newpos)); this.setCurrentLayer(this.getLayerName(newpos));
return { return {
currentGroup: current_group, currentGroup: currentGroup,
oldNextSibling: oldNextSibling oldNextSibling: oldNextSibling
}; };
} }
@@ -362,25 +358,25 @@ svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) {
}; };
svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) { svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
var current_group = this.current_layer.getGroup(); var currentGroup = this.current_layer.getGroup();
var prevGroup = $(current_group).prev()[0]; var prevGroup = $(currentGroup).prev()[0];
if (!prevGroup) {return;} if (!prevGroup) { return; }
hrService.startBatchCommand('Merge Layer'); hrService.startBatchCommand('Merge Layer');
var layerNextSibling = current_group.nextSibling; var layerNextSibling = currentGroup.nextSibling;
hrService.removeElement(current_group, layerNextSibling, this.svgElem_); hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_);
while (current_group.firstChild) { while (currentGroup.firstChild) {
var child = current_group.firstChild; var child = currentGroup.firstChild;
if (child.localName == 'title') { if (child.localName == 'title') {
hrService.removeElement(child, child.nextSibling, current_group); hrService.removeElement(child, child.nextSibling, currentGroup);
current_group.removeChild(child); currentGroup.removeChild(child);
continue; continue;
} }
var oldNextSibling = child.nextSibling; var oldNextSibling = child.nextSibling;
prevGroup.appendChild(child); prevGroup.appendChild(child);
hrService.moveElement(child, oldNextSibling, current_group); hrService.moveElement(child, oldNextSibling, currentGroup);
} }
// Remove current layer's group // Remove current layer's group
@@ -389,7 +385,7 @@ svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
var index = this.all_layers.indexOf(this.current_layer); var index = this.all_layers.indexOf(this.current_layer);
if (index > 0) { if (index > 0) {
var name = this.current_layer.getName(); var name = this.current_layer.getName();
this.current_layer = this.all_layers[index-1] this.current_layer = this.all_layers[index - 1];
this.all_layers.splice(index, 1); this.all_layers.splice(index, 1);
delete this.layer_map[name]; delete this.layer_map[name];
} }
@@ -399,7 +395,7 @@ svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
svgedit.draw.Drawing.prototype.mergeAllLayers = function (hrService) { svgedit.draw.Drawing.prototype.mergeAllLayers = function (hrService) {
// Set the current layer to the last layer. // Set the current layer to the last layer.
this.current_layer = this.all_layers[this.all_layers.length-1]; this.current_layer = this.all_layers[this.all_layers.length - 1];
hrService.startBatchCommand('Merge all Layers'); hrService.startBatchCommand('Merge all Layers');
while (this.all_layers.length > 1) { while (this.all_layers.length > 1) {
@@ -415,7 +411,7 @@ svgedit.draw.Drawing.prototype.mergeAllLayers = function (hrService) {
* @param {string} name - The name of the layer you want to switch to. * @param {string} name - The name of the layer you want to switch to.
* @returns {boolean} true if the current layer was switched, otherwise false * @returns {boolean} true if the current layer was switched, otherwise false
*/ */
svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) { svgedit.draw.Drawing.prototype.setCurrentLayer = function (name) {
var layer = this.layer_map[name]; var layer = this.layer_map[name];
if (layer) { if (layer) {
if (this.current_layer) { if (this.current_layer) {
@@ -428,13 +424,12 @@ svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) {
return false; return false;
}; };
/** /**
* Deletes the current layer from the drawing and then clears the selection. * 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 function then calls the 'changed' handler. This is an undoable action.
* @returns {SVGGElement} The SVGGElement of the layer removed or null. * @returns {SVGGElement} The SVGGElement of the layer removed or null.
*/ */
svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() { svgedit.draw.Drawing.prototype.deleteCurrentLayer = function () {
if (this.current_layer && this.getNumLayers() > 1) { if (this.current_layer && this.getNumLayers() > 1) {
var oldLayerGroup = this.current_layer.removeGroup(); var oldLayerGroup = this.current_layer.removeGroup();
this.identifyLayers(); this.identifyLayers();
@@ -448,8 +443,8 @@ svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() {
* @param group The group element to search in. * @param group The group element to search in.
* @returns {string} The layer name or empty string. * @returns {string} The layer name or empty string.
*/ */
function findLayerNameInGroup(group) { function findLayerNameInGroup (group) {
var name = $("title", group).text(); var name = $('title', group).text();
// Hack for Opera 10.60 // Hack for Opera 10.60
if (!name && svgedit.browser.isOpera() && group.querySelectorAll) { if (!name && svgedit.browser.isOpera() && group.querySelectorAll) {
@@ -463,18 +458,18 @@ function findLayerNameInGroup(group) {
* @param {Array.<string>} existingLayerNames - Existing layer names. * @param {Array.<string>} existingLayerNames - Existing layer names.
* @returns {string} - The new name. * @returns {string} - The new name.
*/ */
function getNewLayerName(existingLayerNames) { function getNewLayerName (existingLayerNames) {
var i = 1; var i = 1;
// TODO(codedread): What about internationalization of "Layer"? // TODO(codedread): What about internationalization of "Layer"?
while (existingLayerNames.indexOf(("Layer " + i)) >= 0) { i++; } while (existingLayerNames.indexOf(('Layer ' + i)) >= 0) { i++; }
return "Layer " + i; return 'Layer ' + i;
} }
/** /**
* Updates layer system and sets the current layer to the * Updates layer system and sets the current layer to the
* top-most layer (last <g> child of this drawing). * top-most layer (last <g> child of this drawing).
*/ */
svgedit.draw.Drawing.prototype.identifyLayers = function() { svgedit.draw.Drawing.prototype.identifyLayers = function () {
this.all_layers = []; this.all_layers = [];
this.layer_map = {}; this.layer_map = {};
var numchildren = this.svgElem_.childNodes.length; var numchildren = this.svgElem_.childNodes.length;
@@ -486,7 +481,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
var child = this.svgElem_.childNodes.item(i); var child = this.svgElem_.childNodes.item(i);
// for each g, find its layer name // for each g, find its layer name
if (child && child.nodeType == 1) { if (child && child.nodeType == 1) {
if (child.tagName == "g") { if (child.tagName === 'g') {
childgroups = true; childgroups = true;
var name = findLayerNameInGroup(child); var name = findLayerNameInGroup(child);
if (name) { if (name) {
@@ -504,7 +499,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
} }
} }
} }
// If orphans or no layers found, create a new layer and add all the orphans to it // If orphans or no layers found, create a new layer and add all the orphans to it
if (orphans.length > 0 || !childgroups) { if (orphans.length > 0 || !childgroups) {
layer = new svgedit.draw.Layer(getNewLayerName(layernames), null, this.svgElem_); layer = new svgedit.draw.Layer(getNewLayerName(layernames), null, this.svgElem_);
@@ -525,7 +520,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
* @returns {SVGGElement} The SVGGElement of the new layer, which is * @returns {SVGGElement} The SVGGElement of the new layer, which is
* also the current layer of this drawing. * also the current layer of this drawing.
*/ */
svgedit.draw.Drawing.prototype.createLayer = function(name, hrService) { svgedit.draw.Drawing.prototype.createLayer = function (name, hrService) {
if (this.current_layer) { if (this.current_layer) {
this.current_layer.deactivate(); this.current_layer.deactivate();
} }
@@ -556,8 +551,8 @@ svgedit.draw.Drawing.prototype.createLayer = function(name, hrService) {
* @returns {SVGGElement} The SVGGElement of the new layer, which is * @returns {SVGGElement} The SVGGElement of the new layer, which is
* also the current layer of this drawing. * also the current layer of this drawing.
*/ */
svgedit.draw.Drawing.prototype.cloneLayer = function(name, hrService) { svgedit.draw.Drawing.prototype.cloneLayer = function (name, hrService) {
if (!this.current_layer) {return null;} if (!this.current_layer) { return null; }
this.current_layer.deactivate(); this.current_layer.deactivate();
// Check for duplicate name. // Check for duplicate name.
if (name === undefined || name === null || name === '' || this.layer_map[name]) { if (name === undefined || name === null || name === '' || this.layer_map[name]) {
@@ -567,14 +562,14 @@ svgedit.draw.Drawing.prototype.cloneLayer = function(name, hrService) {
// Create new group and add to DOM just after current_layer // Create new group and add to DOM just after current_layer
var currentGroup = this.current_layer.getGroup(); var currentGroup = this.current_layer.getGroup();
var layer = new svgedit.draw.Layer(name, currentGroup, this.svgElem_); var layer = new svgedit.draw.Layer(name, currentGroup, this.svgElem_);
var group = layer.getGroup(); var group = layer.getGroup();
// Clone children // Clone children
var children = currentGroup.childNodes; var children = currentGroup.childNodes;
var index; var index;
for (index = 0; index < children.length; index++) { for (index = 0; index < children.length; index++) {
var ch = children[index]; var ch = children[index];
if (ch.localName == 'title') {continue;} if (ch.localName == 'title') { continue; }
group.appendChild(this.copyElem(ch)); group.appendChild(this.copyElem(ch));
} }
@@ -602,7 +597,7 @@ svgedit.draw.Drawing.prototype.cloneLayer = function(name, hrService) {
* @param {string} layername - The name of the layer which you want to query. * @param {string} layername - The name of the layer which you want to query.
* @returns {boolean} The visibility state of the layer, or false if the layer name was invalid. * @returns {boolean} The visibility state of the layer, or false if the layer name was invalid.
*/ */
svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) { svgedit.draw.Drawing.prototype.getLayerVisibility = function (layername) {
var layer = this.layer_map[layername]; var layer = this.layer_map[layername];
return layer ? layer.isVisible() : false; return layer ? layer.isVisible() : false;
}; };
@@ -616,26 +611,25 @@ svgedit.draw.Drawing.prototype.getLayerVisibility = function(layername) {
* @returns {?SVGGElement} The SVGGElement representing the layer if the * @returns {?SVGGElement} The SVGGElement representing the layer if the
* layername was valid, otherwise null. * layername was valid, otherwise null.
*/ */
svgedit.draw.Drawing.prototype.setLayerVisibility = function(layername, bVisible) { svgedit.draw.Drawing.prototype.setLayerVisibility = function (layername, bVisible) {
if (typeof bVisible !== 'boolean') { if (typeof bVisible !== 'boolean') {
return null; return null;
} }
var layer = this.layer_map[layername]; var layer = this.layer_map[layername];
if (!layer) {return null;} if (!layer) { return null; }
layer.setVisible(bVisible); layer.setVisible(bVisible);
return layer.getGroup(); return layer.getGroup();
}; };
/** /**
* Returns the opacity of the given layer. If the input name is not a layer, null is returned. * Returns the opacity of the given layer. If the input name is not a layer, null is returned.
* @param {string} layername - name of the layer on which to get the opacity * @param {string} layername - name of the layer on which to get the opacity
* @returns {?number} The opacity value of the given layer. This will be a value between 0.0 and 1.0, or null * @returns {?number} 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 * if layername is not a valid layer
*/ */
svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) { svgedit.draw.Drawing.prototype.getLayerOpacity = function (layername) {
var layer = this.layer_map[layername]; var layer = this.layer_map[layername];
if (!layer) {return null;} if (!layer) { return null; }
return layer.getOpacity(); return layer.getOpacity();
}; };
@@ -646,7 +640,7 @@ svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) {
* @param {string} layername - Name of the layer on which to set the opacity * @param {string} layername - Name of the layer on which to set the opacity
* @param {number} opacity - A float value in the range 0.0-1.0 * @param {number} opacity - A float value in the range 0.0-1.0
*/ */
svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) { svgedit.draw.Drawing.prototype.setLayerOpacity = function (layername, opacity) {
if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) { if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) {
return; return;
} }
@@ -661,11 +655,9 @@ svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) {
* @param {Element} el - DOM element to clone * @param {Element} el - DOM element to clone
* @returns {Element} * @returns {Element}
*/ */
svgedit.draw.Drawing.prototype.copyElem = function(el) { svgedit.draw.Drawing.prototype.copyElem = function (el) {
var self = this; var self = this;
var getNextIdClosure = function() { return self.getNextId();} var getNextIdClosure = function () { return self.getNextId(); };
return svgedit.utilities.copyElem(el, getNextIdClosure) return svgedit.utilities.copyElem(el, getNextIdClosure);
} };
}()); }());

View File

@@ -1,79 +1,80 @@
/*globals $, EmbeddedSVGEdit*/ /* eslint-disable no-var */
/*jslint vars: true */ /* globals $, EmbeddedSVGEdit */
var initEmbed; var initEmbed; // eslint-disable-line no-unused-vars
// Todo: Get rid of frame.contentWindow dependencies so can be more easily adjusted to work cross-domain // Todo: Get rid of frame.contentWindow dependencies so can be more easily adjusted to work cross-domain
$(function () {'use strict'; $(function () {
'use strict';
var svgCanvas = null;
var frame;
initEmbed = function () { var svgCanvas = null;
var doc, mainButton; var frame;
svgCanvas = new EmbeddedSVGEdit(frame);
// Hide main button, as we will be controlling new, load, save, etc. from the host document
doc = frame.contentDocument || frame.contentWindow.document;
mainButton = doc.getElementById('main_button');
mainButton.style.display = 'none';
};
function handleSvgData(data, error) { initEmbed = function () {
if (error) { var doc, mainButton;
alert('error ' + error); svgCanvas = new EmbeddedSVGEdit(frame);
} else { // Hide main button, as we will be controlling new, load, save, etc. from the host document
alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data); doc = frame.contentDocument || frame.contentWindow.document;
} mainButton = doc.getElementById('main_button');
} mainButton.style.display = 'none';
};
function loadSvg() { function handleSvgData (data, error) {
var svgexample = '<svg width="640" height="480" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1</title><rect stroke-width="5" stroke="#000000" fill="#FF0000" id="svg_1" height="35" width="51" y="35" x="32"/><ellipse ry="15" rx="24" stroke-width="5" stroke="#000000" fill="#0000ff" id="svg_2" cy="60" cx="66"/></g></svg>'; if (error) {
svgCanvas.setSvgString(svgexample); alert('error ' + error);
} } else {
alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data);
}
}
function saveSvg() { function loadSvg () {
svgCanvas.getSvgString()(handleSvgData); var svgexample = '<svg width="640" height="480" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg"><g><title>Layer 1</title><rect stroke-width="5" stroke="#000000" fill="#FF0000" id="svg_1" height="35" width="51" y="35" x="32"/><ellipse ry="15" rx="24" stroke-width="5" stroke="#000000" fill="#0000ff" id="svg_2" cy="60" cx="66"/></g></svg>';
} svgCanvas.setSvgString(svgexample);
}
function exportPNG() {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage; function saveSvg () {
svgCanvas.getSvgString()(handleSvgData);
}
function exportPNG () {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
var exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow'
);
svgCanvas.rasterExport('PNG', null, exportWindow.name);
}
function exportPDF () {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
var exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow'
);
svgCanvas.rasterExport('PNG', null, exportWindow.name);
}
function exportPDF() {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
/** /**
// If you want to handle the PDF blob yourself, do as follows // If you want to handle the PDF blob yourself, do as follows
svgCanvas.bind('exportedPDF', function (win, data) { svgCanvas.bind('exportedPDF', function (win, data) {
alert(data.dataurlstring); alert(data.dataurlstring);
}); });
svgCanvas.exportPDF(); // Accepts two args: optionalWindowName supplied back to bound exportPDF handler and optionalOutputType (defaults to dataurlstring) svgCanvas.exportPDF(); // Accepts two args: optionalWindowName supplied back to bound exportPDF handler and optionalOutputType (defaults to dataurlstring)
return; return;
*/ */
var exportWindow = window.open( var exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'), 'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow' 'svg-edit-exportWindow'
); );
svgCanvas.exportPDF(exportWindow.name); svgCanvas.exportPDF(exportWindow.name);
} }
// Add event handlers // Add event handlers
$('#load').click(loadSvg); $('#load').click(loadSvg);
$('#save').click(saveSvg); $('#save').click(saveSvg);
$('#exportPNG').click(exportPNG); $('#exportPNG').click(exportPNG);
$('#exportPDF').click(exportPDF); $('#exportPDF').click(exportPDF);
$('body').append( $('body').append(
$('<iframe src="svg-editor.html?extensions=ext-xdomain-messaging.js' + $('<iframe src="svg-editor.html?extensions=ext-xdomain-messaging.js' +
window.location.href.replace(/\?(.*)$/, '&$1') + // Append arguments to this file onto the iframe window.location.href.replace(/\?(.*)$/, '&$1') + // Append arguments to this file onto the iframe
'" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>' '" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>'
) )
); );
frame = document.getElementById('svgedit'); frame = document.getElementById('svgedit');
}); });

View File

@@ -1,4 +1,5 @@
/* /* eslint-disable no-var */
/*
Embedded SVG-edit API Embedded SVG-edit API
General usage: General usage:
@@ -9,11 +10,11 @@ var svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
svgCanvas.setSvgString('string') svgCanvas.setSvgString('string')
- Or if a callback is needed: - Or if a callback is needed:
svgCanvas.setSvgString('string')(function(data, error){ svgCanvas.setSvgString('string')(function(data, error){
if (error){ if (error){
// There was an error // There was an error
} else{ } else{
// Handle data // Handle data
} }
}) })
Everything is done with the same API as the real svg-edit, Everything is done with the same API as the real svg-edit,
@@ -35,20 +36,21 @@ var blah = new EmbeddedSVGEdit(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)}) 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 () {'use strict'; (function () {
'use strict';
var cbid = 0; var cbid = 0;
function getCallbackSetter (d) { function getCallbackSetter (d) {
return function () { return function () {
var t = this, // New callback var t = this, // New callback
args = [].slice.call(arguments), args = [].slice.call(arguments),
cbid = t.send(d, args, function(){}); // The callback (currently it's nothing, but will be set later) cbid = t.send(d, args, function () {}); // The callback (currently it's nothing, but will be set later)
return function(newcallback){ return function (newcallback) {
t.callbacks[cbid] = newcallback; // Set callback t.callbacks[cbid] = newcallback; // Set callback
};
}; };
};
} }
/* /*
@@ -57,32 +59,32 @@ function getCallbackSetter (d) {
* of same domain control * of same domain control
*/ */
function addCallback (t, data) { function addCallback (t, data) {
var result = data.result || data.error, var result = data.result || data.error,
cbid = data.id; cbid = data.id;
if (t.callbacks[cbid]) { if (t.callbacks[cbid]) {
if (data.result) { if (data.result) {
t.callbacks[cbid](result); t.callbacks[cbid](result);
} else { } else {
t.callbacks[cbid](result, 'error'); t.callbacks[cbid](result, 'error');
}
} }
}
} }
function messageListener (e) { function messageListener (e) {
// We accept and post strings as opposed to objects for the sake of IE9 support; this // We accept and post strings as opposed to objects for the sake of IE9 support; this
// will most likely be changed in the future // will most likely be changed in the future
if (typeof e.data !== 'string') { if (typeof e.data !== 'string') {
return; return;
} }
var allowedOrigins = this.allowedOrigins, var allowedOrigins = this.allowedOrigins,
data = e.data && JSON.parse(e.data); data = e.data && JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' || if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
e.source !== this.frame.contentWindow || e.source !== this.frame.contentWindow ||
(allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1) (allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1)
) { ) {
return; return;
} }
addCallback(this, data); addCallback(this, data);
} }
function getMessageListener (t) { function getMessageListener (t) {
@@ -98,82 +100,79 @@ function getMessageListener (t) {
* If supplied, it should probably be the same as svgEditor's allowedOrigins * If supplied, it should probably be the same as svgEditor's allowedOrigins
*/ */
function EmbeddedSVGEdit (frame, allowedOrigins) { function EmbeddedSVGEdit (frame, allowedOrigins) {
if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without 'new' keyword if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without 'new' keyword
return new EmbeddedSVGEdit(frame); return new EmbeddedSVGEdit(frame);
} }
this.allowedOrigins = allowedOrigins || []; this.allowedOrigins = allowedOrigins || [];
// Initialize communication // Initialize communication
this.frame = frame; this.frame = frame;
this.callbacks = {}; this.callbacks = {};
// List of functions extracted with this: // List of functions extracted with this:
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html // 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 < f.length; i++) { q.push(f[i].name); }; q // for (var i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
// var functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString', // var functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility', // 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
// 'moveSelectedToLayer', 'clear']; // 'moveSelectedToLayer', 'clear'];
// Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API // Newer, well, it extracts things that aren't documented as well. All functions accessible through the normal thingy can now be accessed though the API
// var svgCanvas = frame.contentWindow.svgCanvas; // var svgCanvas = frame.contentWindow.svgCanvas;
// var l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} }; // var l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} };
// alert("['" + l.join("', '") + "']"); // alert("['" + l.join("', '") + "']");
// Run in svgedit itself // Run in svgedit itself
var i, var i,
functions = [ functions = [
'clearSvgContentElement', 'setIdPrefix', 'getCurrentDrawing', 'addSvgElementFromJson', 'getTransformList', 'matrixMultiply', 'hasMatrixTransform', 'transformListToTransform', 'convertToNum', 'findDefs', 'getUrlFromAttr', 'getHref', 'setHref', 'getBBox', 'getRotationAngle', 'getElem', 'getRefElem', 'assignAttributes', 'cleanupElement', 'remapElement', 'recalculateDimensions', 'sanitizeSvg', 'runExtensions', 'addExtension', 'round', 'getIntersectionList', 'getStrokedBBox', 'getVisibleElements', 'getVisibleElementsAndBBoxes', 'groupSvgElem', 'getId', 'getNextId', 'call', 'bind', 'prepareSvg', 'setRotationAngle', 'recalculateAllSelectedDimensions', 'clearSelection', 'addToSelection', 'selectOnly', 'removeFromSelection', 'selectAllInCurrentLayer', 'getMouseTarget', 'removeUnusedDefElems', 'svgCanvasToString', 'svgToString', 'embedImage', 'setGoodImage', 'open', 'save', 'rasterExport', 'exportPDF', 'getSvgString', 'randomizeIds', 'uniquifyElems', 'setUseData', 'convertGradients', 'convertToGroup', 'setSvgString', 'importSvgString', 'identifyLayers', 'createLayer', 'cloneLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility', 'moveSelectedToLayer', 'mergeLayer', 'mergeAllLayers', 'leaveContext', 'setContext', 'clear', 'linkControlPoints', 'getContentElem', 'getRootElem', 'getSelectedElems', 'getResolution', 'getZoom', 'getVersion', 'setUiStrings', 'setConfig', 'getTitle', 'setGroupTitle', 'getDocumentTitle', 'setDocumentTitle', 'getEditorNS', 'setResolution', 'getOffset', 'setBBoxZoom', 'setZoom', 'getMode', 'setMode', 'getColor', 'setColor', 'setGradient', 'setPaint', 'setStrokePaint', 'setFillPaint', 'getStrokeWidth', 'setStrokeWidth', 'setStrokeAttr', 'getStyle', 'getOpacity', 'setOpacity', 'getFillOpacity', 'getStrokeOpacity', 'setPaintOpacity', 'getPaintOpacity', 'getBlur', 'setBlurNoUndo', 'setBlurOffsets', 'setBlur', 'getBold', 'setBold', 'getItalic', 'setItalic', 'getFontFamily', 'setFontFamily', 'setFontColor', 'getFontColor', 'getFontSize', 'setFontSize', 'getText', 'setTextContent', 'setImageURL', 'setLinkURL', 'setRectRadius', 'makeHyperlink', 'removeHyperlink', 'setSegType', 'convertToPath', 'changeSelectedAttribute', 'deleteSelectedElements', 'cutSelectedElements', 'copySelectedElements', 'pasteElements', 'groupSelectedElements', 'pushGroupProperties', 'ungroupSelectedElement', 'moveToTopSelectedElement', 'moveToBottomSelectedElement', 'moveUpDownSelected', 'moveSelectedElements', 'cloneSelectedElements', 'alignSelectedElements', 'updateCanvas', 'setBackground', 'cycleElement', 'getPrivateMethods', 'zoomChanged', 'ready' 'clearSvgContentElement', 'setIdPrefix', 'getCurrentDrawing', 'addSvgElementFromJson', 'getTransformList', 'matrixMultiply', 'hasMatrixTransform', 'transformListToTransform', 'convertToNum', 'findDefs', 'getUrlFromAttr', 'getHref', 'setHref', 'getBBox', 'getRotationAngle', 'getElem', 'getRefElem', 'assignAttributes', 'cleanupElement', 'remapElement', 'recalculateDimensions', 'sanitizeSvg', 'runExtensions', 'addExtension', 'round', 'getIntersectionList', 'getStrokedBBox', 'getVisibleElements', 'getVisibleElementsAndBBoxes', 'groupSvgElem', 'getId', 'getNextId', 'call', 'bind', 'prepareSvg', 'setRotationAngle', 'recalculateAllSelectedDimensions', 'clearSelection', 'addToSelection', 'selectOnly', 'removeFromSelection', 'selectAllInCurrentLayer', 'getMouseTarget', 'removeUnusedDefElems', 'svgCanvasToString', 'svgToString', 'embedImage', 'setGoodImage', 'open', 'save', 'rasterExport', 'exportPDF', 'getSvgString', 'randomizeIds', 'uniquifyElems', 'setUseData', 'convertGradients', 'convertToGroup', 'setSvgString', 'importSvgString', 'identifyLayers', 'createLayer', 'cloneLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility', 'moveSelectedToLayer', 'mergeLayer', 'mergeAllLayers', 'leaveContext', 'setContext', 'clear', 'linkControlPoints', 'getContentElem', 'getRootElem', 'getSelectedElems', 'getResolution', 'getZoom', 'getVersion', 'setUiStrings', 'setConfig', 'getTitle', 'setGroupTitle', 'getDocumentTitle', 'setDocumentTitle', 'getEditorNS', 'setResolution', 'getOffset', 'setBBoxZoom', 'setZoom', 'getMode', 'setMode', 'getColor', 'setColor', 'setGradient', 'setPaint', 'setStrokePaint', 'setFillPaint', 'getStrokeWidth', 'setStrokeWidth', 'setStrokeAttr', 'getStyle', 'getOpacity', 'setOpacity', 'getFillOpacity', 'getStrokeOpacity', 'setPaintOpacity', 'getPaintOpacity', 'getBlur', 'setBlurNoUndo', 'setBlurOffsets', 'setBlur', 'getBold', 'setBold', 'getItalic', 'setItalic', 'getFontFamily', 'setFontFamily', 'setFontColor', 'getFontColor', 'getFontSize', 'setFontSize', 'getText', 'setTextContent', 'setImageURL', 'setLinkURL', 'setRectRadius', 'makeHyperlink', 'removeHyperlink', 'setSegType', 'convertToPath', 'changeSelectedAttribute', 'deleteSelectedElements', 'cutSelectedElements', 'copySelectedElements', 'pasteElements', 'groupSelectedElements', 'pushGroupProperties', 'ungroupSelectedElement', 'moveToTopSelectedElement', 'moveToBottomSelectedElement', 'moveUpDownSelected', 'moveSelectedElements', 'cloneSelectedElements', 'alignSelectedElements', 'updateCanvas', 'setBackground', 'cycleElement', 'getPrivateMethods', 'zoomChanged', 'ready'
]; ];
// TODO: rewrite the following, it's pretty scary. // TODO: rewrite the following, it's pretty scary.
for (i = 0; i < functions.length; i++) { for (i = 0; i < functions.length; i++) {
this[functions[i]] = getCallbackSetter(functions[i]); this[functions[i]] = getCallbackSetter(functions[i]);
} }
// Older IE may need a polyfill for addEventListener, but so it would for SVG // Older IE may need a polyfill for addEventListener, but so it would for SVG
window.addEventListener('message', getMessageListener(this), false); window.addEventListener('message', getMessageListener(this), false);
} }
EmbeddedSVGEdit.prototype.send = function (name, args, callback){ EmbeddedSVGEdit.prototype.send = function (name, args, callback) {
var t = this; var t = this;
cbid++; cbid++;
this.callbacks[cbid] = callback; this.callbacks[cbid] = callback;
setTimeout((function (cbid) { setTimeout((function (cbid) {
return function () { // Delay for the callback to be set in case its synchronous return function () { // Delay for the callback to be set in case its synchronous
/* /*
* Todo: Handle non-JSON arguments and return values (undefined, * Todo: Handle non-JSON arguments and return values (undefined,
* nonfinite numbers, functions, and built-in objects like Date, * nonfinite numbers, functions, and built-in objects like Date,
* RegExp), etc.? Allow promises instead of callbacks? Review * RegExp), etc.? Allow promises instead of callbacks? Review
* SVG-Edit functions for whether JSON-able parameters can be * SVG-Edit functions for whether JSON-able parameters can be
* made compatile with all API functionality * made compatile with all API functionality
*/ */
// We accept and post strings for the sake of IE9 support // We accept and post strings for the sake of IE9 support
if (window.location.origin === t.frame.contentWindow.location.origin) { if (window.location.origin === t.frame.contentWindow.location.origin) {
// Although we do not really need this API if we are working same // Although we do not really need this API if we are working same
// domain, it could allow us to write in a way that would work // domain, it could allow us to write in a way that would work
// cross-domain as well, assuming we stick to the argument limitations // cross-domain as well, assuming we stick to the argument limitations
// of the current JSON-based communication API (e.g., not passing // of the current JSON-based communication API (e.g., not passing
// callbacks). We might be able to address these shortcomings; see // callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file. // the todo elsewhere in this file.
var message = {id: cbid}, var message = {id: cbid},
svgCanvas = t.frame.contentWindow.svgCanvas; svgCanvas = t.frame.contentWindow.svgCanvas;
try { try {
message.result = svgCanvas[name].apply(svgCanvas, args); message.result = svgCanvas[name].apply(svgCanvas, args);
} } catch (err) {
catch (err) { message.error = err.message;
message.error = err.message; }
} addCallback(t, message);
addCallback(t, message); } else { // Requires the ext-xdomain-messaging.js extension
} t.frame.contentWindow.postMessage(JSON.stringify({namespace: 'svgCanvas', id: cbid, name: name, args: args}), '*');
else { // Requires the ext-xdomain-messaging.js extension }
t.frame.contentWindow.postMessage(JSON.stringify({namespace: 'svgCanvas', id: cbid, name: name, args: args}), '*'); };
} }(cbid)), 0);
};
}(cbid)), 0);
return cbid; return cbid;
}; };
window.embedded_svg_edit = EmbeddedSVGEdit; // Export old, deprecated API window.embedded_svg_edit = EmbeddedSVGEdit; // Export old, deprecated API
window.EmbeddedSVGEdit = EmbeddedSVGEdit; // Follows common JS convention of CamelCase and, as enforced in JSLint, of initial caps for constructors window.EmbeddedSVGEdit = EmbeddedSVGEdit; // Follows common JS convention of CamelCase and, as enforced in JSLint, of initial caps for constructors
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true*/ /* globals svgEditor, svgCanvas, $ */
/* /*
* ext-arrows.js * ext-arrows.js
* *
@@ -9,65 +9,64 @@
* *
*/ */
svgEditor.addExtension('Arrows', function(S) { svgEditor.addExtension('Arrows', function (S) {
var svgcontent = S.svgcontent, var // svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson, addElem = S.addSvgElementFromJson,
nonce = S.nonce, nonce = S.nonce,
randomize_ids = S.randomize_ids, randomizeIds = S.randomize_ids,
selElems, pathdata, selElems, pathdata,
lang_list = { langList = {
'en':[ 'en': [
{'id': 'arrow_none', 'textContent': 'No arrow' } {'id': 'arrow_none', 'textContent': 'No arrow'}
], ],
'fr':[ 'fr': [
{'id': 'arrow_none', 'textContent': 'Sans flèche' } {'id': 'arrow_none', 'textContent': 'Sans flèche'}
] ]
}, },
arrowprefix, arrowprefix,
prefix = 'se_arrow_'; prefix = 'se_arrow_';
function setArrowNonce(window, n) { function setArrowNonce (window, n) {
randomize_ids = true; randomizeIds = true;
arrowprefix = prefix + n + '_'; arrowprefix = prefix + n + '_';
pathdata.fw.id = arrowprefix + 'fw'; pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk'; pathdata.bk.id = arrowprefix + 'bk';
} }
function unsetArrowNonce(window) { function unsetArrowNonce (window) {
randomize_ids = false; randomizeIds = false;
arrowprefix = prefix; arrowprefix = prefix;
pathdata.fw.id = arrowprefix + 'fw'; pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk'; pathdata.bk.id = arrowprefix + 'bk';
} }
svgCanvas.bind('setnonce', setArrowNonce); svgCanvas.bind('setnonce', setArrowNonce);
svgCanvas.bind('unsetnonce', unsetArrowNonce); svgCanvas.bind('unsetnonce', unsetArrowNonce);
if (randomize_ids) { if (randomizeIds) {
arrowprefix = prefix + nonce + '_'; arrowprefix = prefix + nonce + '_';
} else { } else {
arrowprefix = prefix; arrowprefix = prefix;
} }
pathdata = { pathdata = {
fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'}, 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'} bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'}
}; };
function getLinked(elem, attr) { function getLinked (elem, attr) {
var str = elem.getAttribute(attr); var str = elem.getAttribute(attr);
if(!str) {return null;} if (!str) { return null; }
var m = str.match(/\(\#(.*)\)/); var m = str.match(/\(#(.*)\)/);
if(!m || m.length !== 2) { if (!m || m.length !== 2) {
return null; return null;
} }
return S.getElem(m[1]); return S.getElem(m[1]);
} }
function showPanel(on) { function showPanel (on) {
$('#arrow_panel').toggle(on); $('#arrow_panel').toggle(on);
if(on) { if (on) {
var el = selElems[0]; var el = selElems[0];
var end = el.getAttribute('marker-end'); var end = el.getAttribute('marker-end');
var start = el.getAttribute('marker-start'); var start = el.getAttribute('marker-start');
@@ -95,21 +94,21 @@ svgEditor.addExtension('Arrows', function(S) {
} }
} }
function resetMarker() { function resetMarker () {
var el = selElems[0]; var el = selElems[0];
el.removeAttribute('marker-start'); el.removeAttribute('marker-start');
el.removeAttribute('marker-mid'); el.removeAttribute('marker-mid');
el.removeAttribute('marker-end'); el.removeAttribute('marker-end');
} }
function addMarker(dir, type, id) { function addMarker (dir, type, id) {
// TODO: Make marker (or use?) per arrow type, since refX can be different // TODO: Make marker (or use?) per arrow type, since refX can be different
id = id || arrowprefix + dir; id = id || arrowprefix + dir;
var marker = S.getElem(id); var marker = S.getElem(id);
var data = pathdata[dir]; var data = pathdata[dir];
if (type == 'mid') { if (type === 'mid') {
data.refx = 5; data.refx = 5;
} }
@@ -143,25 +142,25 @@ svgEditor.addExtension('Arrows', function(S) {
return marker; return marker;
} }
function setArrow() { function setArrow () {
var type = this.value; var type = this.value;
resetMarker(); resetMarker();
if (type == 'none') { if (type === 'none') {
return; return;
} }
// Set marker on element // Set marker on element
var dir = 'fw'; var dir = 'fw';
if (type == 'mid_bk') { if (type === 'mid_bk') {
type = 'mid'; type = 'mid';
dir = 'bk'; dir = 'bk';
} else if (type == 'both') { } else if (type === 'both') {
addMarker('bk', type); addMarker('bk', type);
svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')');
type = 'end'; type = 'end';
dir = 'fw'; dir = 'fw';
} else if (type == 'start') { } else if (type === 'start') {
dir = 'bk'; dir = 'bk';
} }
@@ -170,57 +169,57 @@ svgEditor.addExtension('Arrows', function(S) {
S.call('changed', selElems); S.call('changed', selElems);
} }
function colorChanged(elem) { function colorChanged (elem) {
var color = elem.getAttribute('stroke'); var color = elem.getAttribute('stroke');
var mtypes = ['start', 'mid', 'end']; var mtypes = ['start', 'mid', 'end'];
var defs = S.findDefs(); var defs = S.findDefs();
$.each(mtypes, function(i, type) { $.each(mtypes, function (i, type) {
var marker = getLinked(elem, 'marker-'+type); var marker = getLinked(elem, 'marker-' + type);
if(!marker) {return;} if (!marker) { return; }
var cur_color = $(marker).children().attr('fill'); var curColor = $(marker).children().attr('fill');
var cur_d = $(marker).children().attr('d'); var curD = $(marker).children().attr('d');
var new_marker = null; var newMarker = null;
if(cur_color === color) {return;} if (curColor === color) { return; }
var all_markers = $(defs).find('marker'); var allMarkers = $(defs).find('marker');
// Different color, check if already made // Different color, check if already made
all_markers.each(function() { allMarkers.each(function () {
var attrs = $(this).children().attr(['fill', 'd']); var attrs = $(this).children().attr(['fill', 'd']);
if(attrs.fill === color && attrs.d === cur_d) { if (attrs.fill === color && attrs.d === curD) {
// Found another marker with this color and this path // Found another marker with this color and this path
new_marker = this; newMarker = this;
} }
}); });
if(!new_marker) { if (!newMarker) {
// Create a new marker with this color // Create a new marker with this color
var last_id = marker.id; var lastId = marker.id;
var dir = last_id.indexOf('_fw') !== -1?'fw':'bk'; var dir = lastId.indexOf('_fw') !== -1 ? 'fw' : 'bk';
new_marker = addMarker(dir, type, arrowprefix + dir + all_markers.length); newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
$(new_marker).children().attr('fill', color); $(newMarker).children().attr('fill', color);
} }
$(elem).attr('marker-'+type, 'url(#' + new_marker.id + ')'); $(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
// Check if last marker can be removed // Check if last marker can be removed
var remove = true; var remove = true;
$(S.svgcontent).find('line, polyline, path, polygon').each(function() { $(S.svgcontent).find('line, polyline, path, polygon').each(function () {
var elem = this; var elem = this;
$.each(mtypes, function(j, mtype) { $.each(mtypes, function (j, mtype) {
if($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
remove = false; remove = false;
return remove; return remove;
} }
}); });
if(!remove) {return false;} if (!remove) { return false; }
}); });
// Not found, so can safely remove // Not found, so can safely remove
if(remove) { if (remove) {
$(marker).remove(); $(marker).remove();
} }
}); });
@@ -246,26 +245,26 @@ svgEditor.addExtension('Arrows', function(S) {
change: setArrow change: setArrow
} }
}], }],
callback: function() { callback: function () {
$('#arrow_panel').hide(); $('#arrow_panel').hide();
// Set ID so it can be translated in locale file // Set ID so it can be translated in locale file
$('#arrow_list option')[0].id = 'connector_no_arrow'; $('#arrow_list option')[0].id = 'connector_no_arrow';
}, },
addLangData: function(lang) { addLangData: function (lang) {
return { return {
data: lang_list[lang] data: langList[lang]
}; };
}, },
selectedChanged: function(opts) { selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
var marker_elems = ['line', 'path', 'polyline', 'polygon']; var markerElems = ['line', 'path', 'polyline', 'polygon'];
while(i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if(elem && $.inArray(elem.tagName, marker_elems) !== -1) { if (elem && $.inArray(elem.tagName, markerElems) !== -1) {
if(opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
@@ -275,16 +274,16 @@ svgEditor.addExtension('Arrows', function(S) {
} }
} }
}, },
elementChanged: function(opts) { elementChanged: function (opts) {
var elem = opts.elems[0]; var elem = opts.elems[0];
if(elem && ( if (elem && (
elem.getAttribute('marker-start') || elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') || elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end') elem.getAttribute('marker-end')
)) { )) {
// var start = elem.getAttribute('marker-start'); // var start = elem.getAttribute('marker-start');
// var mid = elem.getAttribute('marker-mid'); // var mid = elem.getAttribute('marker-mid');
// var end = elem.getAttribute('marker-end'); // var end = elem.getAttribute('marker-end');
// Has marker, so see if it should match color // Has marker, so see if it should match color
colorChanged(elem); colorChanged(elem);
} }

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true*/ /* globals svgEditor, $ */
/* /*
* ext-closepath.js * ext-closepath.js
* *
@@ -11,30 +11,31 @@
// This extension adds a simple button to the contextual panel for paths // This extension adds a simple button to the contextual panel for paths
// The button toggles whether the path is open or closed // The button toggles whether the path is open or closed
svgEditor.addExtension('ClosePath', function() {'use strict'; svgEditor.addExtension('ClosePath', function () {
'use strict';
var selElems, var selElems,
updateButton = function(path) { updateButton = function (path) {
var seglist = path.pathSegList, var seglist = path.pathSegList,
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType == 1, closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
showbutton = closed ? '#tool_openpath' : '#tool_closepath', showbutton = closed ? '#tool_openpath' : '#tool_closepath',
hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
$(hidebutton).hide(); $(hidebutton).hide();
$(showbutton).show(); $(showbutton).show();
}, },
showPanel = function(on) { showPanel = function (on) {
$('#closepath_panel').toggle(on); $('#closepath_panel').toggle(on);
if (on) { if (on) {
var path = selElems[0]; var path = selElems[0];
if (path) {updateButton(path);} if (path) { updateButton(path); }
} }
}, },
toggleClosed = function() { toggleClosed = function () {
var path = selElems[0]; var path = selElems[0];
if (path) { if (path) {
var seglist = path.pathSegList, var seglist = path.pathSegList,
last = seglist.numberOfItems - 1; last = seglist.numberOfItems - 1;
// is closed // is closed
if (seglist.getItem(last).pathSegType == 1) { if (seglist.getItem(last).pathSegType === 1) {
seglist.removeItem(last); seglist.removeItem(last);
} else { } else {
seglist.appendItem(path.createSVGPathSegClosePath()); seglist.appendItem(path.createSVGPathSegClosePath());
@@ -52,7 +53,7 @@ svgEditor.addExtension('ClosePath', function() {'use strict';
panel: 'closepath_panel', panel: 'closepath_panel',
title: 'Open path', title: 'Open path',
events: { events: {
click: function() { click: function () {
toggleClosed(); toggleClosed();
} }
} }
@@ -63,20 +64,20 @@ svgEditor.addExtension('ClosePath', function() {'use strict';
panel: 'closepath_panel', panel: 'closepath_panel',
title: 'Close path', title: 'Close path',
events: { events: {
click: function() { click: function () {
toggleClosed(); toggleClosed();
} }
} }
}], }],
callback: function() { callback: function () {
$('#closepath_panel').hide(); $('#closepath_panel').hide();
}, },
selectedChanged: function(opts) { selectedChanged: function (opts) {
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while (i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if (elem && elem.tagName == 'path') { if (elem && elem.tagName === 'path') {
if (opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
showPanel(true); showPanel(true);
} else { } else {

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true, continue: true, eqeq: true, todo: true*/ /* globals svgEditor, svgCanvas, $ */
/* /*
* ext-connector.js * ext-connector.js
* *
@@ -8,8 +8,8 @@
* Copyright(c) 2010 Alexis Deveria * Copyright(c) 2010 Alexis Deveria
* *
*/ */
svgEditor.addExtension("Connector", function(S) { svgEditor.addExtension('Connector', function (S) {
var svgcontent = S.svgcontent, var svgcontent = S.svgcontent,
svgroot = S.svgroot, svgroot = S.svgroot,
getNextId = S.getNextId, getNextId = S.getNextId,
@@ -18,153 +18,151 @@ svgEditor.addExtension("Connector", function(S) {
selManager = S.selectorManager, selManager = S.selectorManager,
curConfig = svgEditor.curConfig, curConfig = svgEditor.curConfig,
started = false, started = false,
start_x, startX,
start_y, startY,
cur_line, curLine,
start_elem, startElem,
end_elem, endElem,
connections = [], connections = [],
conn_sel = ".se_connector", connSel = '.se_connector',
se_ns, seNs,
// connect_str = "-SE_CONNECT-", // connect_str = '-SE_CONNECT-',
selElems = [], selElems = [],
elData = $.data; elData = $.data;
var lang_list = { var langList = {
"en":[ 'en': [
{"id": "mode_connect", "title": "Connect two objects" } {'id': 'mode_connect', 'title': 'Connect two objects'}
], ],
"fr":[ 'fr': [
{"id": "mode_connect", "title": "Connecter deux objets"} {'id': 'mode_connect', 'title': 'Connecter deux objets'}
] ]
}; };
function getBBintersect(x, y, bb, offset) { function getBBintersect (x, y, bb, offset) {
if(offset) { if (offset) {
offset -= 0; offset -= 0;
bb = $.extend({}, bb); bb = $.extend({}, bb);
bb.width += offset; bb.width += offset;
bb.height += offset; bb.height += offset;
bb.x -= offset/2; bb.x -= offset / 2;
bb.y -= offset/2; bb.y -= offset / 2;
} }
var mid_x = bb.x + bb.width/2; var midX = bb.x + bb.width / 2;
var mid_y = bb.y + bb.height/2; var midY = bb.y + bb.height / 2;
var len_x = x - mid_x; var lenX = x - midX;
var len_y = y - mid_y; var lenY = y - midY;
var slope = Math.abs(len_y/len_x); var slope = Math.abs(lenY / lenX);
var ratio; var ratio;
if(slope < bb.height/bb.width) { if (slope < bb.height / bb.width) {
ratio = (bb.width/2) / Math.abs(len_x); ratio = (bb.width / 2) / Math.abs(lenX);
} else { } else {
ratio = (bb.height/2) / Math.abs(len_y); ratio = (bb.height / 2) / Math.abs(lenY);
} }
return { return {
x: mid_x + len_x * ratio, x: midX + lenX * ratio,
y: mid_y + len_y * ratio y: midY + lenY * ratio
}; };
} }
function getOffset(side, line) { function getOffset (side, line) {
var give_offset = !!line.getAttribute('marker-' + side); var giveOffset = !!line.getAttribute('marker-' + side);
// var give_offset = $(line).data(side+'_off'); // var giveOffset = $(line).data(side+'_off');
// TODO: Make this number (5) be based on marker width/height // TODO: Make this number (5) be based on marker width/height
var size = line.getAttribute('stroke-width') * 5; var size = line.getAttribute('stroke-width') * 5;
return give_offset ? size : 0; return giveOffset ? size : 0;
} }
function showPanel(on) { function showPanel (on) {
var conn_rules = $('#connector_rules'); var connRules = $('#connector_rules');
if(!conn_rules.length) { if (!connRules.length) {
conn_rules = $('<style id="connector_rules"></style>').appendTo('head'); connRules = $('<style id="connector_rules"></style>').appendTo('head');
} }
conn_rules.text(!on?"":"#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }"); connRules.text(!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }');
$('#connector_panel').toggle(on); $('#connector_panel').toggle(on);
} }
function setPoint(elem, pos, x, y, setMid) { function setPoint (elem, pos, x, y, setMid) {
var i, pts = elem.points; var i, pts = elem.points;
var pt = svgroot.createSVGPoint(); var pt = svgroot.createSVGPoint();
pt.x = x; pt.x = x;
pt.y = y; pt.y = y;
if (pos === 'end') {pos = pts.numberOfItems - 1;} if (pos === 'end') { pos = pts.numberOfItems - 1; }
// TODO: Test for this on init, then use alt only if needed // TODO: Test for this on init, then use alt only if needed
try { try {
pts.replaceItem(pt, pos); pts.replaceItem(pt, pos);
} catch(err) { } catch (err) {
// Should only occur in FF which formats points attr as "n,n n,n", so just split // Should only occur in FF which formats points attr as "n,n n,n", so just split
var pt_arr = elem.getAttribute("points").split(" "); var ptArr = elem.getAttribute('points').split(' ');
for (i = 0; i < pt_arr.length; i++) { for (i = 0; i < ptArr.length; i++) {
if (i === pos) { if (i === pos) {
pt_arr[i] = x + ',' + y; ptArr[i] = x + ',' + y;
} }
} }
elem.setAttribute("points",pt_arr.join(" ")); elem.setAttribute('points', ptArr.join(' '));
} }
if(setMid) { if (setMid) {
// Add center point // Add center point
var pt_start = pts.getItem(0); var ptStart = pts.getItem(0);
var pt_end = pts.getItem(pts.numberOfItems-1); var ptEnd = pts.getItem(pts.numberOfItems - 1);
setPoint(elem, 1, (pt_end.x + pt_start.x)/2, (pt_end.y + pt_start.y)/2); setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2);
} }
} }
function updateLine(diff_x, diff_y) { function updateLine (diffX, diffY) {
// Update line with element // Update line with element
var i = connections.length; var i = connections.length;
while(i--) { while (i--) {
var conn = connections[i]; var conn = connections[i];
var line = conn.connector; var line = conn.connector;
var elem = conn.elem; // var elem = conn.elem;
var pre = conn.is_start?'start':'end';
// var sw = line.getAttribute('stroke-width') * 5;
// Update bbox for this element
var bb = elData(line, pre+'_bb');
bb.x = conn.start_x + diff_x;
bb.y = conn.start_y + diff_y;
elData(line, pre+'_bb', bb);
var alt_pre = conn.is_start?'end':'start';
// Get center pt of connected element
var bb2 = elData(line, alt_pre+'_bb');
var src_x = bb2.x + bb2.width/2;
var src_y = bb2.y + bb2.height/2;
// Set point of element being moved
var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0
setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
// Set point of connected element
var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line));
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
var pre = conn.is_start ? 'start' : 'end';
// var sw = line.getAttribute('stroke-width') * 5;
// Update bbox for this element
var bb = elData(line, pre + '_bb');
bb.x = conn.start_x + diffX;
bb.y = conn.start_y + diffY;
elData(line, pre + '_bb', bb);
var altPre = conn.is_start ? 'end' : 'start';
// Get center pt of connected element
var bb2 = elData(line, altPre + '_bb');
var srcX = bb2.x + bb2.width / 2;
var srcY = bb2.y + bb2.height / 2;
// Set point of element being moved
var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0
setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
// Set point of connected element
var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line));
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
} }
} }
function findConnectors(elems) { function findConnectors (elems) {
var i; var i;
if (!elems) {elems = selElems;} if (!elems) { elems = selElems; }
var connectors = $(svgcontent).find(conn_sel); var connectors = $(svgcontent).find(connSel);
connections = []; connections = [];
// Loop through connectors to see if one is connected to the element // Loop through connectors to see if one is connected to the element
connectors.each(function() { connectors.each(function () {
var add_this; var addThis;
function add () { function add () {
if ($.inArray(this, elems) !== -1) { if ($.inArray(this, elems) !== -1) {
// Pretend this element is selected // Pretend this element is selected
add_this = true; addThis = true;
} }
} }
@@ -173,42 +171,42 @@ svgEditor.addExtension("Connector", function(S) {
['start', 'end'].forEach(function (pos, i) { ['start', 'end'].forEach(function (pos, i) {
var key = 'c_' + pos; var key = 'c_' + pos;
var part = elData(this, key); var part = elData(this, key);
if(part == null) { if (part == null) {
part = document.getElementById( part = document.getElementById(
this.attributes['se:connector'].value.split(' ')[i] this.attributes['se:connector'].value.split(' ')[i]
); );
elData(this, 'c_'+pos, part.id); elData(this, 'c_' + pos, part.id);
elData(this, pos+'_bb', svgCanvas.getStrokedBBox([part])); elData(this, pos + '_bb', svgCanvas.getStrokedBBox([part]));
} else part = document.getElementById(part); } else part = document.getElementById(part);
parts.push(part); parts.push(part);
}.bind(this)); }.bind(this));
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
var c_elem = parts[i]; var cElem = parts[i];
add_this = false; addThis = false;
// The connected element might be part of a selected group // The connected element might be part of a selected group
$(c_elem).parents().each(add); $(cElem).parents().each(add);
if(!c_elem || !c_elem.parentNode) { if (!cElem || !cElem.parentNode) {
$(this).remove(); $(this).remove();
continue; continue;
} }
if($.inArray(c_elem, elems) !== -1 || add_this) { if ($.inArray(cElem, elems) !== -1 || addThis) {
var bb = svgCanvas.getStrokedBBox([c_elem]); var bb = svgCanvas.getStrokedBBox([cElem]);
connections.push({ connections.push({
elem: c_elem, elem: cElem,
connector: this, connector: this,
is_start: (i === 0), is_start: (i === 0),
start_x: bb.x, start_x: bb.x,
start_y: bb.y start_y: bb.y
}); });
} }
} }
}); });
} }
function updateConnectors(elems) { function updateConnectors (elems) {
// Updates connector lines based on selected elements // Updates connector lines based on selected elements
// Is not used on mousemove, as it runs getStrokedBBox every time, // Is not used on mousemove, as it runs getStrokedBBox every time,
// which isn't necessary there. // which isn't necessary there.
@@ -222,227 +220,222 @@ svgEditor.addExtension("Connector", function(S) {
var line = conn.connector; var line = conn.connector;
var elem = conn.elem; var elem = conn.elem;
var sw = line.getAttribute('stroke-width') * 5; // var sw = line.getAttribute('stroke-width') * 5;
var pre = conn.is_start?'start':'end'; var pre = conn.is_start ? 'start' : 'end';
// Update bbox for this element // Update bbox for this element
var bb = svgCanvas.getStrokedBBox([elem]); var bb = svgCanvas.getStrokedBBox([elem]);
bb.x = conn.start_x; bb.x = conn.start_x;
bb.y = conn.start_y; bb.y = conn.start_y;
elData(line, pre+'_bb', bb); elData(line, pre + '_bb', bb);
var add_offset = elData(line, pre+'_off'); /* var addOffset = */ elData(line, pre + '_off');
var alt_pre = conn.is_start?'end':'start'; var altPre = conn.is_start ? 'end' : 'start';
// Get center pt of connected element // Get center pt of connected element
var bb2 = elData(line, alt_pre+'_bb'); var bb2 = elData(line, altPre + '_bb');
var src_x = bb2.x + bb2.width/2; var srcX = bb2.x + bb2.width / 2;
var src_y = bb2.y + bb2.height/2; var srcY = bb2.y + bb2.height / 2;
// Set point of element being moved // Set point of element being moved
var pt = getBBintersect(src_x, src_y, bb, getOffset(pre, line)); var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line));
setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true);
// Set point of connected element // Set point of connected element
var pt2 = getBBintersect(pt.x, pt.y, elData(line, alt_pre + '_bb'), getOffset(alt_pre, line)); var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line));
setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true);
// Update points attribute manually for webkit // Update points attribute manually for webkit
if (navigator.userAgent.indexOf('AppleWebKit') !== -1) { if (navigator.userAgent.indexOf('AppleWebKit') !== -1) {
var pts = line.points; var pts = line.points;
var len = pts.numberOfItems; var len = pts.numberOfItems;
var pt_arr = []; var ptArr = [];
for (j = 0; j < len; j++) { for (j = 0; j < len; j++) {
pt = pts.getItem(j); pt = pts.getItem(j);
pt_arr[j] = pt.x + ',' + pt.y; ptArr[j] = pt.x + ',' + pt.y;
} }
line.setAttribute('points', pt_arr.join(' ')); line.setAttribute('points', ptArr.join(' '));
} }
} }
} }
} }
// Do once // Do once
(function() { (function () {
var gse = svgCanvas.groupSelectedElements; var gse = svgCanvas.groupSelectedElements;
svgCanvas.groupSelectedElements = function() { svgCanvas.groupSelectedElements = function () {
svgCanvas.removeFromSelection($(conn_sel).toArray()); svgCanvas.removeFromSelection($(connSel).toArray());
return gse.apply(this, arguments); return gse.apply(this, arguments);
}; };
var mse = svgCanvas.moveSelectedElements; var mse = svgCanvas.moveSelectedElements;
svgCanvas.moveSelectedElements = function() { svgCanvas.moveSelectedElements = function () {
var cmd = mse.apply(this, arguments); var cmd = mse.apply(this, arguments);
updateConnectors(); updateConnectors();
return cmd; return cmd;
}; };
se_ns = svgCanvas.getEditorNS(); seNs = svgCanvas.getEditorNS();
}()); }());
// Do on reset // Do on reset
function init() { function init () {
// Make sure all connectors have data set // Make sure all connectors have data set
$(svgcontent).find('*').each(function() { $(svgcontent).find('*').each(function () {
var conn = this.getAttributeNS(se_ns, "connector"); var conn = this.getAttributeNS(seNs, 'connector');
if(conn) { if (conn) {
this.setAttribute('class', conn_sel.substr(1)); this.setAttribute('class', connSel.substr(1));
var conn_data = conn.split(' '); var connData = conn.split(' ');
var sbb = svgCanvas.getStrokedBBox([getElem(conn_data[0])]); var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]);
var ebb = svgCanvas.getStrokedBBox([getElem(conn_data[1])]); var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]);
$(this).data('c_start',conn_data[0]) $(this).data('c_start', connData[0])
.data('c_end',conn_data[1]) .data('c_end', connData[1])
.data('start_bb', sbb) .data('start_bb', sbb)
.data('end_bb', ebb); .data('end_bb', ebb);
svgCanvas.getEditorNS(true); svgCanvas.getEditorNS(true);
} }
}); });
// updateConnectors(); // updateConnectors();
} }
// $(svgroot).parent().mousemove(function(e) { // $(svgroot).parent().mousemove(function (e) {
// // if(started // // if (started
// // || svgCanvas.getMode() != "connector" // // || svgCanvas.getMode() !== 'connector'
// // || e.target.parentNode.parentNode != svgcontent) return; // // || e.target.parentNode.parentNode !== svgcontent) return;
// //
// console.log('y') // console.log('y')
// // if(e.target.parentNode.parentNode === svgcontent) { // // if (e.target.parentNode.parentNode === svgcontent) {
// // // //
// // } // // }
// }); // });
return { return {
name: "Connector", name: 'Connector',
svgicons: svgEditor.curConfig.imgPath + "conn.svg", svgicons: svgEditor.curConfig.imgPath + 'conn.svg',
buttons: [{ buttons: [{
id: "mode_connect", id: 'mode_connect',
type: "mode", type: 'mode',
icon: svgEditor.curConfig.imgPath + "cut.png", icon: svgEditor.curConfig.imgPath + 'cut.png',
title: "Connect two objects", title: 'Connect two objects',
includeWith: { includeWith: {
button: '#tool_line', button: '#tool_line',
isDefault: false, isDefault: false,
position: 1 position: 1
}, },
events: { events: {
'click': function() { 'click': function () {
svgCanvas.setMode("connector"); svgCanvas.setMode('connector');
} }
} }
}], }],
addLangData: function(lang) { addLangData: function (lang) {
return { return {
data: lang_list[lang] data: langList[lang]
}; };
}, },
mouseDown: function(opts) { mouseDown: function (opts) {
var e = opts.event; var e = opts.event;
start_x = opts.start_x; startX = opts.start_x;
start_y = opts.start_y; startY = opts.start_y;
var mode = svgCanvas.getMode(); var mode = svgCanvas.getMode();
if (mode == "connector") {
if (started) {return;}
var mouse_target = e.target; if (mode === 'connector') {
if (started) { return; }
var parents = $(mouse_target).parents();
var mouseTarget = e.target;
if($.inArray(svgcontent, parents) !== -1) {
var parents = $(mouseTarget).parents();
if ($.inArray(svgcontent, parents) !== -1) {
// Connectable element // Connectable element
// If child of foreignObject, use parent // If child of foreignObject, use parent
var fo = $(mouse_target).closest("foreignObject"); var fo = $(mouseTarget).closest('foreignObject');
start_elem = fo.length ? fo[0] : mouse_target; startElem = fo.length ? fo[0] : mouseTarget;
// Get center of source element // Get center of source element
var bb = svgCanvas.getStrokedBBox([start_elem]); var bb = svgCanvas.getStrokedBBox([startElem]);
var x = bb.x + bb.width/2; var x = bb.x + bb.width / 2;
var y = bb.y + bb.height/2; var y = bb.y + bb.height / 2;
started = true; started = true;
cur_line = addElem({ curLine = addElem({
"element": "polyline", 'element': 'polyline',
"attr": { 'attr': {
"id": getNextId(), 'id': getNextId(),
"points": (x+','+y+' '+x+','+y+' '+start_x+','+start_y), 'points': (x + ',' + y + ' ' + x + ',' + y + ' ' + startX + ',' + startY),
"stroke": '#' + curConfig.initStroke.color, 'stroke': '#' + curConfig.initStroke.color,
"stroke-width": (!start_elem.stroke_width || start_elem.stroke_width == 0) ? curConfig.initStroke.width : start_elem.stroke_width, 'stroke-width': (!startElem.stroke_width || startElem.stroke_width === 0) ? curConfig.initStroke.width : startElem.stroke_width,
"fill": "none", 'fill': 'none',
"opacity": curConfig.initStroke.opacity, 'opacity': curConfig.initStroke.opacity,
"style": "pointer-events:none" 'style': 'pointer-events:none'
} }
}); });
elData(cur_line, 'start_bb', bb); elData(curLine, 'start_bb', bb);
} }
return { return {
started: true started: true
}; };
} }
if (mode == "select") { if (mode === 'select') {
findConnectors(); findConnectors();
} }
}, },
mouseMove: function(opts) { mouseMove: function (opts) {
var zoom = svgCanvas.getZoom(); var zoom = svgCanvas.getZoom();
var e = opts.event; // var e = opts.event;
var x = opts.mouse_x/zoom; var x = opts.mouse_x / zoom;
var y = opts.mouse_y/zoom; var y = opts.mouse_y / zoom;
var diff_x = x - start_x, var diffX = x - startX,
diff_y = y - start_y; diffY = y - startY;
var mode = svgCanvas.getMode(); var mode = svgCanvas.getMode();
if (mode == "connector" && started) { if (mode === 'connector' && started) {
// var sw = curLine.getAttribute('stroke-width') * 3;
var sw = cur_line.getAttribute('stroke-width') * 3;
// Set start point (adjusts based on bb) // Set start point (adjusts based on bb)
var pt = getBBintersect(x, y, elData(cur_line, 'start_bb'), getOffset('start', cur_line)); var pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine));
start_x = pt.x; startX = pt.x;
start_y = pt.y; startY = pt.y;
setPoint(cur_line, 0, pt.x, pt.y, true); setPoint(curLine, 0, pt.x, pt.y, true);
// Set end point // Set end point
setPoint(cur_line, 'end', x, y, true); setPoint(curLine, 'end', x, y, true);
} else if (mode == "select") { } else if (mode === 'select') {
var slen = selElems.length; var slen = selElems.length;
while(slen--) { while (slen--) {
var elem = selElems[slen]; var elem = selElems[slen];
// Look for selected connector elements // Look for selected connector elements
if(elem && elData(elem, 'c_start')) { if (elem && elData(elem, 'c_start')) {
// Remove the "translate" transform given to move // Remove the "translate" transform given to move
svgCanvas.removeFromSelection([elem]); svgCanvas.removeFromSelection([elem]);
svgCanvas.getTransformList(elem).clear(); svgCanvas.getTransformList(elem).clear();
} }
} }
if(connections.length) { if (connections.length) {
updateLine(diff_x, diff_y); updateLine(diffX, diffY);
} }
} }
}, },
mouseUp: function(opts) { mouseUp: function (opts) {
var zoom = svgCanvas.getZoom(); // var zoom = svgCanvas.getZoom();
var e = opts.event, var e = opts.event,
x = opts.mouse_x/zoom, // x = opts.mouse_x / zoom,
y = opts.mouse_y/zoom, // y = opts.mouse_y / zoom,
mouse_target = e.target; mouseTarget = e.target;
if(svgCanvas.getMode() == "connector") {
var fo = $(mouse_target).closest("foreignObject");
if (fo.length) {mouse_target = fo[0];}
var parents = $(mouse_target).parents();
if (mouse_target == start_elem) { if (svgCanvas.getMode() === 'connector') {
var fo = $(mouseTarget).closest('foreignObject');
if (fo.length) { mouseTarget = fo[0]; }
var parents = $(mouseTarget).parents();
if (mouseTarget === startElem) {
// Start line through click // Start line through click
started = true; started = true;
return { return {
@@ -453,7 +446,7 @@ svgEditor.addExtension("Connector", function(S) {
} }
if ($.inArray(svgcontent, parents) === -1) { if ($.inArray(svgcontent, parents) === -1) {
// Not a valid target element, so remove line // Not a valid target element, so remove line
$(cur_line).remove(); $(curLine).remove();
started = false; started = false;
return { return {
keep: false, keep: false,
@@ -462,66 +455,66 @@ svgEditor.addExtension("Connector", function(S) {
}; };
} }
// Valid end element // Valid end element
end_elem = mouse_target; endElem = mouseTarget;
var start_id = start_elem.id, end_id = end_elem.id; var startId = startElem.id, endId = endElem.id;
var conn_str = start_id + " " + end_id; var connStr = startId + ' ' + endId;
var alt_str = end_id + " " + start_id; var altStr = endId + ' ' + startId;
// Don't create connector if one already exists // Don't create connector if one already exists
var dupe = $(svgcontent).find(conn_sel).filter(function() { var dupe = $(svgcontent).find(connSel).filter(function () {
var conn = this.getAttributeNS(se_ns, "connector"); var conn = this.getAttributeNS(seNs, 'connector');
if (conn == conn_str || conn == alt_str) {return true;} if (conn === connStr || conn === altStr) { return true; }
}); });
if(dupe.length) { if (dupe.length) {
$(cur_line).remove(); $(curLine).remove();
return { return {
keep: false, keep: false,
element: null, element: null,
started: false started: false
}; };
} }
var bb = svgCanvas.getStrokedBBox([end_elem]); var bb = svgCanvas.getStrokedBBox([endElem]);
var pt = getBBintersect(start_x, start_y, bb, getOffset('start', cur_line)); var pt = getBBintersect(startX, startY, bb, getOffset('start', curLine));
setPoint(cur_line, 'end', pt.x, pt.y, true); setPoint(curLine, 'end', pt.x, pt.y, true);
$(cur_line) $(curLine)
.data("c_start", start_id) .data('c_start', startId)
.data("c_end", end_id) .data('c_end', endId)
.data("end_bb", bb); .data('end_bb', bb);
se_ns = svgCanvas.getEditorNS(true); seNs = svgCanvas.getEditorNS(true);
cur_line.setAttributeNS(se_ns, "se:connector", conn_str); curLine.setAttributeNS(seNs, 'se:connector', connStr);
cur_line.setAttribute('class', conn_sel.substr(1)); curLine.setAttribute('class', connSel.substr(1));
cur_line.setAttribute('opacity', 1); curLine.setAttribute('opacity', 1);
svgCanvas.addToSelection([cur_line]); svgCanvas.addToSelection([curLine]);
svgCanvas.moveToBottomSelectedElement(); svgCanvas.moveToBottomSelectedElement();
selManager.requestSelector(cur_line).showGrips(false); selManager.requestSelector(curLine).showGrips(false);
started = false; started = false;
return { return {
keep: true, keep: true,
element: cur_line, element: curLine,
started: started started: started
}; };
} }
}, },
selectedChanged: function(opts) { selectedChanged: function (opts) {
// TODO: Find better way to skip operations if no connectors are in use // TODO: Find better way to skip operations if no connectors are in use
if(!$(svgcontent).find(conn_sel).length) {return;} if (!$(svgcontent).find(connSel).length) { return; }
if(svgCanvas.getMode() == 'connector') { if (svgCanvas.getMode() === 'connector') {
svgCanvas.setMode('select'); svgCanvas.setMode('select');
} }
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while(i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if(elem && elData(elem, 'c_start')) { if (elem && elData(elem, 'c_start')) {
selManager.requestSelector(elem).showGrips(false); selManager.requestSelector(elem).showGrips(false);
if(opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
// TODO: Set up context tools and hide most regular line tools // TODO: Set up context tools and hide most regular line tools
showPanel(true); showPanel(true);
} else { } else {
@@ -533,48 +526,48 @@ svgEditor.addExtension("Connector", function(S) {
} }
updateConnectors(); updateConnectors();
}, },
elementChanged: function(opts) { elementChanged: function (opts) {
var elem = opts.elems[0]; var elem = opts.elems[0];
if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') { if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') {
// Update svgcontent (can change on import) // Update svgcontent (can change on import)
svgcontent = elem; svgcontent = elem;
init(); init();
} }
// Has marker, so change offset // Has marker, so change offset
var start; var start;
if (elem && ( if (elem && (
elem.getAttribute("marker-start") || elem.getAttribute('marker-start') ||
elem.getAttribute("marker-mid") || elem.getAttribute('marker-mid') ||
elem.getAttribute("marker-end") elem.getAttribute('marker-end')
)) { )) {
start = elem.getAttribute("marker-start"); start = elem.getAttribute('marker-start');
var mid = elem.getAttribute("marker-mid"); var mid = elem.getAttribute('marker-mid');
var end = elem.getAttribute("marker-end"); var end = elem.getAttribute('marker-end');
cur_line = elem; curLine = elem;
$(elem) $(elem)
.data("start_off", !!start) .data('start_off', !!start)
.data("end_off", !!end); .data('end_off', !!end);
if (elem.tagName === 'line' && mid) { if (elem.tagName === 'line' && mid) {
// Convert to polyline to accept mid-arrow // Convert to polyline to accept mid-arrow
var x1 = Number(elem.getAttribute('x1')); var x1 = Number(elem.getAttribute('x1'));
var x2 = Number(elem.getAttribute('x2')); var x2 = Number(elem.getAttribute('x2'));
var y1 = Number(elem.getAttribute('y1')); var y1 = Number(elem.getAttribute('y1'));
var y2 = Number(elem.getAttribute('y2')); var y2 = Number(elem.getAttribute('y2'));
var id = elem.id; var id = elem.id;
var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' '); var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
var pline = addElem({ var pline = addElem({
"element": "polyline", 'element': 'polyline',
"attr": { 'attr': {
"points": (x1+','+y1+ mid_pt +x2+','+y2), 'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2),
"stroke": elem.getAttribute('stroke'), 'stroke': elem.getAttribute('stroke'),
"stroke-width": elem.getAttribute('stroke-width'), 'stroke-width': elem.getAttribute('stroke-width'),
"marker-mid": mid, 'marker-mid': mid,
"fill": "none", 'fill': 'none',
"opacity": elem.getAttribute('opacity') || 1 'opacity': elem.getAttribute('opacity') || 1
} }
}); });
$(elem).after(pline).remove(); $(elem).after(pline).remove();
@@ -585,36 +578,37 @@ svgEditor.addExtension("Connector", function(S) {
} }
} }
// Update line if it's a connector // Update line if it's a connector
if (elem.getAttribute('class') == conn_sel.substr(1)) { if (elem.getAttribute('class') === connSel.substr(1)) {
start = getElem(elData(elem, 'c_start')); start = getElem(elData(elem, 'c_start'));
updateConnectors([start]); updateConnectors([start]);
} else { } else {
updateConnectors(); updateConnectors();
} }
}, },
IDsUpdated: function(input) { IDsUpdated: function (input) {
var remove = []; var remove = [];
input.elems.forEach(function(elem){ input.elems.forEach(function (elem) {
if('se:connector' in elem.attr) { if ('se:connector' in elem.attr) {
elem.attr['se:connector'] = elem.attr['se:connector'].split(' ') elem.attr['se:connector'] = elem.attr['se:connector'].split(' ')
.map(function(oldID){ return input.changes[oldID] }).join(' '); .map(function (oldID) { return input.changes[oldID]; }).join(' ');
// Check validity - the field would be something like 'svg_21 svg_22', but // Check validity - the field would be something like 'svg_21 svg_22', but
// if one end is missing, it would be 'svg_21' and therefore fail this test // if one end is missing, it would be 'svg_21' and therefore fail this test
if(!/. ./.test(elem.attr['se:connector'])) if (!/. ./.test(elem.attr['se:connector'])) {
remove.push(elem.attr.id); remove.push(elem.attr.id);
}
} }
}); });
return {remove: remove}; return {remove: remove};
}, },
toolButtonStateUpdate: function(opts) { toolButtonStateUpdate: function (opts) {
if (opts.nostroke) { if (opts.nostroke) {
if ($('#mode_connect').hasClass('tool_button_current')) { if ($('#mode_connect').hasClass('tool_button_current')) {
svgEditor.clickSelect(); svgEditor.clickSelect();
} }
} }
$('#mode_connect') $('#mode_connect')
.toggleClass('disabled',opts.nostroke); .toggleClass('disabled', opts.nostroke);
} }
}; };
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true*/ /* globals svgEditor, svgedit, $ */
/* /*
* ext-eyedropper.js * ext-eyedropper.js
* *
@@ -15,26 +15,27 @@
// 3) svg_editor.js // 3) svg_editor.js
// 4) svgcanvas.js // 4) svgcanvas.js
svgEditor.addExtension("eyedropper", function(S) {'use strict'; svgEditor.addExtension('eyedropper', function (S) {
'use strict';
var // NS = svgedit.NS, var // NS = svgedit.NS,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
svgCanvas = svgEditor.canvas, svgCanvas = svgEditor.canvas,
ChangeElementCommand = svgedit.history.ChangeElementCommand, ChangeElementCommand = svgedit.history.ChangeElementCommand,
addToHistory = function(cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); }, addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
currentStyle = { currentStyle = {
fillPaint: "red", fillOpacity: 1.0, fillPaint: 'red', fillOpacity: 1.0,
strokePaint: "black", strokeOpacity: 1.0, strokePaint: 'black', strokeOpacity: 1.0,
strokeWidth: 5, strokeDashArray: null, strokeWidth: 5, strokeDashArray: null,
opacity: 1.0, opacity: 1.0,
strokeLinecap: 'butt', strokeLinecap: 'butt',
strokeLinejoin: 'miter' strokeLinejoin: 'miter'
}; };
function getStyle(opts) { function getStyle (opts) {
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool // if we are in eyedropper mode, we don't want to disable the eye-dropper tool
var mode = svgCanvas.getMode(); var mode = svgCanvas.getMode();
if (mode == "eyedropper") {return;} if (mode === 'eyedropper') { return; }
var elem = null; var elem = null;
var tool = $('#tool_eyedropper'); var tool = $('#tool_eyedropper');
@@ -45,65 +46,63 @@ svgEditor.addExtension("eyedropper", function(S) {'use strict';
elem = opts.elems[0]; elem = opts.elems[0];
tool.removeClass('disabled'); tool.removeClass('disabled');
// grab the current style // grab the current style
currentStyle.fillPaint = elem.getAttribute("fill") || "black"; currentStyle.fillPaint = elem.getAttribute('fill') || 'black';
currentStyle.fillOpacity = elem.getAttribute("fill-opacity") || 1.0; currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0;
currentStyle.strokePaint = elem.getAttribute("stroke"); currentStyle.strokePaint = elem.getAttribute('stroke');
currentStyle.strokeOpacity = elem.getAttribute("stroke-opacity") || 1.0; currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0;
currentStyle.strokeWidth = elem.getAttribute("stroke-width"); currentStyle.strokeWidth = elem.getAttribute('stroke-width');
currentStyle.strokeDashArray = elem.getAttribute("stroke-dasharray"); currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray');
currentStyle.strokeLinecap = elem.getAttribute("stroke-linecap"); currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap');
currentStyle.strokeLinejoin = elem.getAttribute("stroke-linejoin"); currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin');
currentStyle.opacity = elem.getAttribute("opacity") || 1.0; currentStyle.opacity = elem.getAttribute('opacity') || 1.0;
}
// disable eye-dropper tool // disable eye-dropper tool
else { } else {
tool.addClass('disabled'); tool.addClass('disabled');
} }
} }
return { return {
name: "eyedropper", name: 'eyedropper',
svgicons: svgEditor.curConfig.extPath + "eyedropper-icon.xml", svgicons: svgEditor.curConfig.extPath + 'eyedropper-icon.xml',
buttons: [{ buttons: [{
id: "tool_eyedropper", id: 'tool_eyedropper',
type: "mode", type: 'mode',
title: "Eye Dropper Tool", title: 'Eye Dropper Tool',
key: "I", key: 'I',
events: { events: {
"click": function() { click: function () {
svgCanvas.setMode("eyedropper"); svgCanvas.setMode('eyedropper');
} }
} }
}], }],
// if we have selected an element, grab its paint and enable the eye dropper button // if we have selected an element, grab its paint and enable the eye dropper button
selectedChanged: getStyle, selectedChanged: getStyle,
elementChanged: getStyle, elementChanged: getStyle,
mouseDown: function(opts) { mouseDown: function (opts) {
var mode = svgCanvas.getMode(); var mode = svgCanvas.getMode();
if (mode == "eyedropper") { if (mode === 'eyedropper') {
var e = opts.event; var e = opts.event;
var target = e.target; var target = e.target;
if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) { if ($.inArray(target.nodeName, ['svg', 'g', 'use']) === -1) {
var changes = {}; var changes = {};
var change = function(elem, attrname, newvalue) { var change = function (elem, attrname, newvalue) {
changes[attrname] = elem.getAttribute(attrname); changes[attrname] = elem.getAttribute(attrname);
elem.setAttribute(attrname, newvalue); elem.setAttribute(attrname, newvalue);
}; };
if (currentStyle.fillPaint) {change(target, "fill", currentStyle.fillPaint);} if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); }
if (currentStyle.fillOpacity) {change(target, "fill-opacity", currentStyle.fillOpacity);} if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); }
if (currentStyle.strokePaint) {change(target, "stroke", currentStyle.strokePaint);} if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); }
if (currentStyle.strokeOpacity) {change(target, "stroke-opacity", currentStyle.strokeOpacity);} if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); }
if (currentStyle.strokeWidth) {change(target, "stroke-width", currentStyle.strokeWidth);} if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); }
if (currentStyle.strokeDashArray) {change(target, "stroke-dasharray", currentStyle.strokeDashArray);} if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); }
if (currentStyle.opacity) {change(target, "opacity", currentStyle.opacity);} if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); }
if (currentStyle.strokeLinecap) {change(target, "stroke-linecap", currentStyle.strokeLinecap);} if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); }
if (currentStyle.strokeLinejoin) {change(target, "stroke-linejoin", currentStyle.strokeLinejoin);} if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); }
addToHistory(new ChangeElementCommand(target, changes)); addToHistory(new ChangeElementCommand(target, changes));
} }
} }

View File

@@ -1,20 +1,20 @@
/*globals svgEditor, svgedit, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true, todo: true*/ /* globals svgEditor, svgedit, svgCanvas, $ */
/* /*
* ext-foreignobject.js * ext-foreignobject.js
* *
* Licensed under the Apache License, Version 2 * Licensed under the Apache License, Version 2
* *
* Copyright(c) 2010 Jacques Distler * Copyright(c) 2010 Jacques Distler
* Copyright(c) 2010 Alexis Deveria * Copyright(c) 2010 Alexis Deveria
* *
*/ */
svgEditor.addExtension("foreignObject", function(S) { svgEditor.addExtension('foreignObject', function (S) {
var NS = svgedit.NS, var NS = svgedit.NS,
Utils = svgedit.utilities, Utils = svgedit.utilities,
svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson, // addElem = S.addSvgElementFromJson,
selElems, selElems,
editingforeign = false, editingforeign = false,
svgdoc = S.svgroot.parentNode.ownerDocument, svgdoc = S.svgroot.parentNode.ownerDocument,
@@ -27,16 +27,16 @@ svgEditor.addExtension("foreignObject", function(S) {
$('#svg_source_textarea').css('height', height); $('#svg_source_textarea').css('height', height);
}; };
function showPanel(on) { function showPanel (on) {
var fc_rules = $('#fc_rules'); var fcRules = $('#fc_rules');
if(!fc_rules.length) { if (!fcRules.length) {
fc_rules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
fc_rules.text(!on?"":" #tool_topath { display: none !important; }"); fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#foreignObject_panel').toggle(on); $('#foreignObject_panel').toggle(on);
} }
function toggleSourceButtons(on) { function toggleSourceButtons (on) {
$('#tool_source_save, #tool_source_cancel').toggle(!on); $('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#foreign_save, #foreign_cancel').toggle(on); $('#foreign_save, #foreign_cancel').toggle(on);
} }
@@ -50,7 +50,7 @@ svgEditor.addExtension("foreignObject", function(S) {
// //
// Returns: // Returns:
// This function returns false if the set was unsuccessful, true otherwise. // This function returns false if the set was unsuccessful, true otherwise.
function setForeignString(xmlString) { function setForeignString (xmlString) {
var elt = selElems[0]; var elt = selElems[0];
try { try {
// convert string into XML document // convert string into XML document
@@ -58,9 +58,9 @@ svgEditor.addExtension("foreignObject", function(S) {
// run it through our sanitizer to remove anything we do not support // run it through our sanitizer to remove anything we do not support
S.sanitizeSvg(newDoc.documentElement); S.sanitizeSvg(newDoc.documentElement);
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt); elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
S.call("changed", [elt]); S.call('changed', [elt]);
svgCanvas.clearSelection(); svgCanvas.clearSelection();
} catch(e) { } catch (e) {
console.log(e); console.log(e);
return false; return false;
} }
@@ -68,9 +68,9 @@ svgEditor.addExtension("foreignObject", function(S) {
return true; return true;
} }
function showForeignEditor() { function showForeignEditor () {
var elt = selElems[0]; var elt = selElems[0];
if (!elt || editingforeign) {return;} if (!elt || editingforeign) { return; }
editingforeign = true; editingforeign = true;
toggleSourceButtons(true); toggleSourceButtons(true);
elt.removeAttribute('fill'); elt.removeAttribute('fill');
@@ -82,78 +82,78 @@ svgEditor.addExtension("foreignObject", function(S) {
$('#svg_source_textarea').focus(); $('#svg_source_textarea').focus();
} }
function setAttr(attr, val) { function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val); svgCanvas.changeSelectedAttribute(attr, val);
S.call("changed", selElems); S.call('changed', selElems);
} }
return { return {
name: "foreignObject", name: 'foreignObject',
svgicons: svgEditor.curConfig.extPath + "foreignobject-icons.xml", svgicons: svgEditor.curConfig.extPath + 'foreignobject-icons.xml',
buttons: [{ buttons: [{
id: "tool_foreign", id: 'tool_foreign',
type: "mode", type: 'mode',
title: "Foreign Object Tool", title: 'Foreign Object Tool',
events: { events: {
'click': function() { 'click': function () {
svgCanvas.setMode('foreign'); svgCanvas.setMode('foreign');
} }
} }
},{ }, {
id: "edit_foreign", id: 'edit_foreign',
type: "context", type: 'context',
panel: "foreignObject_panel", panel: 'foreignObject_panel',
title: "Edit ForeignObject Content", title: 'Edit ForeignObject Content',
events: { events: {
'click': function() { 'click': function () {
showForeignEditor(); showForeignEditor();
} }
} }
}], }],
context_tools: [{ context_tools: [{
type: "input", type: 'input',
panel: "foreignObject_panel", panel: 'foreignObject_panel',
title: "Change foreignObject's width", title: "Change foreignObject's width",
id: "foreign_width", id: 'foreign_width',
label: "w", label: 'w',
size: 3, size: 3,
events: { events: {
change: function() { change: function () {
setAttr('width', this.value); setAttr('width', this.value);
} }
} }
},{ }, {
type: "input", type: 'input',
panel: "foreignObject_panel", panel: 'foreignObject_panel',
title: "Change foreignObject's height", title: "Change foreignObject's height",
id: "foreign_height", id: 'foreign_height',
label: "h", label: 'h',
events: { events: {
change: function() { change: function () {
setAttr('height', this.value); setAttr('height', this.value);
} }
} }
}, { }, {
type: "input", type: 'input',
panel: "foreignObject_panel", panel: 'foreignObject_panel',
title: "Change foreignObject's font size", title: "Change foreignObject's font size",
id: "foreign_font_size", id: 'foreign_font_size',
label: "font-size", label: 'font-size',
size: 2, size: 2,
defval: 16, defval: 16,
events: { events: {
change: function() { change: function () {
setAttr('font-size', this.value); setAttr('font-size', this.value);
} }
} }
} }
], ],
callback: function() { callback: function () {
$('#foreignObject_panel').hide(); $('#foreignObject_panel').hide();
var endChanges = function() { var endChanges = function () {
$('#svg_source_editor').hide(); $('#svg_source_editor').hide();
editingforeign = false; editingforeign = false;
$('#svg_source_textarea').blur(); $('#svg_source_textarea').blur();
@@ -161,48 +161,46 @@ svgEditor.addExtension("foreignObject", function(S) {
}; };
// TODO: Needs to be done after orig icon loads // TODO: Needs to be done after orig icon loads
setTimeout(function() { setTimeout(function () {
// Create source save/cancel buttons // Create source save/cancel buttons
var save = $('#tool_source_save').clone() /* var save = */ $('#tool_source_save').clone()
.hide().attr('id', 'foreign_save').unbind() .hide().attr('id', 'foreign_save').unbind()
.appendTo("#tool_source_back").click(function() { .appendTo('#tool_source_back').click(function () {
if (!editingforeign) { return; }
if (!editingforeign) {return;}
if (!setForeignString($('#svg_source_textarea').val())) { if (!setForeignString($('#svg_source_textarea').val())) {
$.confirm("Errors found. Revert to original?", function(ok) { $.confirm('Errors found. Revert to original?', function (ok) {
if(!ok) {return false;} if (!ok) { return false; }
endChanges(); endChanges();
}); });
} else { } else {
endChanges(); endChanges();
} }
// setSelectMode(); // setSelectMode();
}); });
var cancel = $('#tool_source_cancel').clone() /* var cancel = */ $('#tool_source_cancel').clone()
.hide().attr('id', 'foreign_cancel').unbind() .hide().attr('id', 'foreign_cancel').unbind()
.appendTo("#tool_source_back").click(function() { .appendTo('#tool_source_back').click(function () {
endChanges(); endChanges();
}); });
}, 3000); }, 3000);
}, },
mouseDown: function(opts) { mouseDown: function (opts) {
var e = opts.event; // var e = opts.event;
if(svgCanvas.getMode() == "foreign") {
if (svgCanvas.getMode() === 'foreign') {
started = true; started = true;
newFO = S.addSvgElementFromJson({ newFO = S.addSvgElementFromJson({
"element": "foreignObject", 'element': 'foreignObject',
"attr": { 'attr': {
"x": opts.start_x, 'x': opts.start_x,
"y": opts.start_y, 'y': opts.start_y,
"id": S.getNextId(), 'id': S.getNextId(),
"font-size": 16, //cur_text.font_size, 'font-size': 16, // cur_text.font_size,
"width": "48", 'width': '48',
"height": "20", 'height': '20',
"style": "pointer-events:inherit" 'style': 'pointer-events:inherit'
} }
}); });
var m = svgdoc.createElementNS(NS.MATH, 'math'); var m = svgdoc.createElementNS(NS.MATH, 'math');
@@ -210,11 +208,11 @@ svgEditor.addExtension("foreignObject", function(S) {
m.setAttribute('display', 'inline'); m.setAttribute('display', 'inline');
var mi = svgdoc.createElementNS(NS.MATH, 'mi'); var mi = svgdoc.createElementNS(NS.MATH, 'mi');
mi.setAttribute('mathvariant', 'normal'); mi.setAttribute('mathvariant', 'normal');
mi.textContent = "\u03A6"; mi.textContent = '\u03A6';
var mo = svgdoc.createElementNS(NS.MATH, 'mo'); var mo = svgdoc.createElementNS(NS.MATH, 'mo');
mo.textContent = "\u222A"; mo.textContent = '\u222A';
var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); var mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
mi2.textContent = "\u2133"; mi2.textContent = '\u2133';
m.appendChild(mi); m.appendChild(mi);
m.appendChild(mo); m.appendChild(mo);
m.appendChild(mi2); m.appendChild(mi2);
@@ -224,34 +222,32 @@ svgEditor.addExtension("foreignObject", function(S) {
}; };
} }
}, },
mouseUp: function(opts) { mouseUp: function (opts) {
var e = opts.event; // var e = opts.event;
if(svgCanvas.getMode() == "foreign" && started) { if (svgCanvas.getMode() === 'foreign' && started) {
var attrs = $(newFO).attr(["width", "height"]); var attrs = $(newFO).attr(['width', 'height']);
var keep = (attrs.width != 0 || attrs.height != 0); var keep = (attrs.width !== '0' || attrs.height !== '0');
svgCanvas.addToSelection([newFO], true); svgCanvas.addToSelection([newFO], true);
return { return {
keep: keep, keep: keep,
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function(opts) { selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
var i = selElems.length; var i = selElems.length;
while(i--) { while (i--) {
var elem = selElems[i]; var elem = selElems[i];
if(elem && elem.tagName === 'foreignObject') { if (elem && elem.tagName === 'foreignObject') {
if(opts.selectedElement && !opts.multiselected) { if (opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute("font-size")); $('#foreign_font_size').val(elem.getAttribute('font-size'));
$('#foreign_width').val(elem.getAttribute("width")); $('#foreign_width').val(elem.getAttribute('width'));
$('#foreign_height').val(elem.getAttribute("height")); $('#foreign_height').val(elem.getAttribute('height'));
showPanel(true); showPanel(true);
} else { } else {
showPanel(false); showPanel(false);
@@ -261,8 +257,8 @@ svgEditor.addExtension("foreignObject", function(S) {
} }
} }
}, },
elementChanged: function(opts) { elementChanged: function (opts) {
var elem = opts.elems[0]; // var elem = opts.elems[0];
} }
}; };
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true*/ /* globals svgEditor, svgedit, svgCanvas, $ */
/* /*
* ext-grid.js * ext-grid.js
* *
@@ -14,7 +14,8 @@
// 1) units.js // 1) units.js
// 2) everything else // 2) everything else
svgEditor.addExtension('view_grid', function() { 'use strict'; svgEditor.addExtension('view_grid', function () {
'use strict';
var NS = svgedit.NS, var NS = svgedit.NS,
svgdoc = document.getElementById('svgcanvas').ownerDocument, svgdoc = document.getElementById('svgcanvas').ownerDocument,
@@ -44,8 +45,8 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
assignAttributes(gridPattern, { assignAttributes(gridPattern, {
'id': 'gridpattern', 'id': 'gridpattern',
'patternUnits': 'userSpaceOnUse', 'patternUnits': 'userSpaceOnUse',
'x': 0, //-(value.strokeWidth / 2), // position for strokewidth 'x': 0, // -(value.strokeWidth / 2), // position for strokewidth
'y': 0, //-(value.strokeWidth / 2), // position for strokewidth 'y': 0, // -(value.strokeWidth / 2), // position for strokewidth
'width': 100, 'width': 100,
'height': 100 'height': 100
}); });
@@ -74,56 +75,56 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
}); });
$('#canvasGrid').append(gridBox); $('#canvasGrid').append(gridBox);
function updateGrid(zoom) { function updateGrid (zoom) {
var i; var i;
// TODO: Try this with <line> elements, then compare performance difference // TODO: Try this with <line> elements, then compare performance difference
var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
var u_multi = unit * zoom; var uMulti = unit * zoom;
// Calculate the main number interval // Calculate the main number interval
var raw_m = 100 / u_multi; var rawM = 100 / uMulti;
var multi = 1; var multi = 1;
for (i = 0; i < intervals.length; i++) { for (i = 0; i < intervals.length; i++) {
var num = intervals[i]; var num = intervals[i];
multi = num; multi = num;
if (raw_m <= num) { if (rawM <= num) {
break; break;
} }
} }
var big_int = multi * u_multi; var bigInt = multi * uMulti;
// Set the canvas size to the width of the container // Set the canvas size to the width of the container
hcanvas.width = big_int; hcanvas.width = bigInt;
hcanvas.height = big_int; hcanvas.height = bigInt;
var ctx = hcanvas.getContext('2d'); var ctx = hcanvas.getContext('2d');
var cur_d = 0.5; var curD = 0.5;
var part = big_int / 10; var part = bigInt / 10;
ctx.globalAlpha = 0.2; ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.curConfig.gridColor; ctx.strokeStyle = svgEditor.curConfig.gridColor;
for (i = 1; i < 10; i++) { for (i = 1; i < 10; i++) {
var sub_d = Math.round(part * i) + 0.5; var subD = Math.round(part * i) + 0.5;
// var line_num = (i % 2)?12:10; // var lineNum = (i % 2)?12:10;
var line_num = 0; var lineNum = 0;
ctx.moveTo(sub_d, big_int); ctx.moveTo(subD, bigInt);
ctx.lineTo(sub_d, line_num); ctx.lineTo(subD, lineNum);
ctx.moveTo(big_int, sub_d); ctx.moveTo(bigInt, subD);
ctx.lineTo(line_num ,sub_d); ctx.lineTo(lineNum, subD);
} }
ctx.stroke(); ctx.stroke();
ctx.beginPath(); ctx.beginPath();
ctx.globalAlpha = 0.5; ctx.globalAlpha = 0.5;
ctx.moveTo(cur_d, big_int); ctx.moveTo(curD, bigInt);
ctx.lineTo(cur_d, 0); ctx.lineTo(curD, 0);
ctx.moveTo(big_int, cur_d); ctx.moveTo(bigInt, curD);
ctx.lineTo(0, cur_d); ctx.lineTo(0, curD);
ctx.stroke(); ctx.stroke();
var datauri = hcanvas.toDataURL('image/png'); var datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', big_int); gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', big_int); gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', big_int); gridimg.parentNode.setAttribute('width', bigInt);
gridimg.parentNode.setAttribute('height', big_int); gridimg.parentNode.setAttribute('height', bigInt);
svgCanvas.setHref(gridimg, datauri); svgCanvas.setHref(gridimg, datauri);
} }
@@ -138,8 +139,8 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
name: 'view_grid', name: 'view_grid',
svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml', svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml',
zoomChanged: function(zoom) { zoomChanged: function (zoom) {
if (showGrid) {updateGrid(zoom);} if (showGrid) { updateGrid(zoom); }
}, },
callback: function () { callback: function () {
if (showGrid) { if (showGrid) {
@@ -152,7 +153,7 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
panel: 'editor_panel', panel: 'editor_panel',
title: 'Show/Hide Grid', title: 'Show/Hide Grid',
events: { events: {
click: function() { click: function () {
svgEditor.curConfig.showGrid = showGrid = !showGrid; svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate(); gridUpdate();
} }

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true*/ /* globals svgEditor, svgCanvas, $ */
/* /*
* ext-helloworld.js * ext-helloworld.js
* *
@@ -8,73 +8,72 @@
* Copyright(c) 2010 Alexis Deveria * Copyright(c) 2010 Alexis Deveria
* *
*/ */
/* /*
This is a very basic SVG-Edit extension. It adds a "Hello World" button in This is a very basic SVG-Edit extension. It adds a "Hello World" button in
the left panel. Clicking on the button, and then the canvas will show the the left panel. Clicking on the button, and then the canvas will show the
user the point on the canvas that was clicked on. user the point on the canvas that was clicked on.
*/ */
svgEditor.addExtension("Hello World", function() {'use strict';
return { svgEditor.addExtension('Hello World', function () {
name: "Hello World", 'use strict';
// For more notes on how to make an icon file, see the source of
// the helloworld-icon.xml return {
svgicons: svgEditor.curConfig.extPath + "helloworld-icon.xml", name: 'Hello World',
// For more notes on how to make an icon file, see the source of
// Multiple buttons can be added in this array // the helloworld-icon.xml
buttons: [{ svgicons: svgEditor.curConfig.extPath + 'helloworld-icon.xml',
// Must match the icon ID in helloworld-icon.xml
id: "hello_world", // Multiple buttons can be added in this array
buttons: [{
// This indicates that the button will be added to the "mode" // Must match the icon ID in helloworld-icon.xml
// button panel on the left side id: 'hello_world',
type: "mode",
// This indicates that the button will be added to the "mode"
// Tooltip text // button panel on the left side
title: "Say 'Hello World'", type: 'mode',
// Events // Tooltip text
events: { title: "Say 'Hello World'",
'click': function() {
// The action taken when the button is clicked on. // Events
// For "mode" buttons, any other button will events: {
// automatically be de-pressed. 'click': function () {
svgCanvas.setMode("hello_world"); // The action taken when the button is clicked on.
} // For "mode" buttons, any other button will
} // automatically be de-pressed.
}], svgCanvas.setMode('hello_world');
// This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels)
mouseDown: function() {
// Check the mode on mousedown
if(svgCanvas.getMode() == "hello_world") {
// The returned object must include "started" with
// a value of true in order for mouseUp to be triggered
return {started: true};
}
},
// This is triggered from anywhere, but "started" must have been set
// to true (see above). Note that "opts" is an object with event info
mouseUp: function(opts) {
// Check the mode on mouseup
if(svgCanvas.getMode() == "hello_world") {
var zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value
var x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom;
var text = "Hello World!\n\nYou clicked here: "
+ x + ", " + y;
// Show the text using the custom alert function
$.alert(text);
} }
} }
}; }],
}); // This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels)
mouseDown: function () {
// Check the mode on mousedown
if (svgCanvas.getMode() === 'hello_world') {
// The returned object must include "started" with
// a value of true in order for mouseUp to be triggered
return {started: true};
}
},
// This is triggered from anywhere, but "started" must have been set
// to true (see above). Note that "opts" is an object with event info
mouseUp: function (opts) {
// Check the mode on mouseup
if (svgCanvas.getMode() === 'hello_world') {
var zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value
var x = opts.mouse_x / zoom;
var y = opts.mouse_y / zoom;
var text = 'Hello World!\n\nYou clicked here: ' +
x + ', ' + y;
// Show the text using the custom alert function
$.alert(text);
}
}
};
});

View File

@@ -1,5 +1,5 @@
/*globals $, svgEditor, svgedit, svgCanvas, DOMParser*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true, es5: true, todo: true */ /* globals $, svgEditor, svgedit, svgCanvas, DOMParser */
/* /*
* ext-imagelib.js * ext-imagelib.js
* *
@@ -9,7 +9,8 @@
* *
*/ */
svgEditor.addExtension("imagelib", function() {'use strict'; svgEditor.addExtension('imagelib', function () {
'use strict';
var uiStrings = svgEditor.uiStrings; var uiStrings = svgEditor.uiStrings;
@@ -23,7 +24,8 @@ svgEditor.addExtension("imagelib", function() {'use strict';
} }
}); });
var img_libs = [{ var imgLibs = [
{
name: 'Demo library (local)', name: 'Demo library (local)',
url: svgEditor.curConfig.extPath + 'imagelib/index.html', url: svgEditor.curConfig.extPath + 'imagelib/index.html',
description: 'Demonstration library for SVG-edit on this server' description: 'Demonstration library for SVG-edit on this server'
@@ -40,20 +42,20 @@ svgEditor.addExtension("imagelib", function() {'use strict';
} }
]; ];
function closeBrowser() { function closeBrowser () {
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
} }
function importImage(url) { function importImage (url) {
var newImage = svgCanvas.addSvgElementFromJson({ var newImage = svgCanvas.addSvgElementFromJson({
"element": "image", 'element': 'image',
"attr": { 'attr': {
"x": 0, 'x': 0,
"y": 0, 'y': 0,
"width": 0, 'width': 0,
"height": 0, 'height': 0,
"id": svgCanvas.getNextId(), 'id': svgCanvas.getNextId(),
"style": "pointer-events:inherit" 'style': 'pointer-events:inherit'
} }
}); });
svgCanvas.clearSelection(); svgCanvas.clearSelection();
@@ -62,16 +64,16 @@ svgEditor.addExtension("imagelib", function() {'use strict';
} }
var mode = 's'; var mode = 's';
var multi_arr = []; var multiArr = [];
var tranfer_stopped = false; var transferStopped = false;
var pending = {}; var pending = {};
var preview, submit; var preview, submit;
window.addEventListener("message", function(evt) { window.addEventListener('message', function (evt) {
// Receive postMessage data // Receive postMessage data
var response = evt.data; var response = evt.data;
if (!response || typeof response !== "string") { // Todo: Should namespace postMessage API for this extension and filter out here if (!response || typeof response !== 'string') { // Todo: Should namespace postMessage API for this extension and filter out here
// Do nothing // Do nothing
return; return;
} }
@@ -80,172 +82,168 @@ svgEditor.addExtension("imagelib", function() {'use strict';
if (res.namespace) { // Part of embedAPI communications if (res.namespace) { // Part of embedAPI communications
return; return;
} }
} } catch (e) {}
catch (e) {}
var char1 = response.charAt(0); var char1 = response.charAt(0);
var id; var id;
var svg_str; var svgStr;
var img_str; var imgStr;
if (char1 != "{" && tranfer_stopped) { if (char1 !== '{' && transferStopped) {
tranfer_stopped = false; transferStopped = false;
return; return;
} }
if (char1 == '|') { if (char1 === '|') {
var secondpos = response.indexOf('|', 1); var secondpos = response.indexOf('|', 1);
id = response.substr(1, secondpos-1); id = response.substr(1, secondpos - 1);
response = response.substr(secondpos+1); response = response.substr(secondpos + 1);
char1 = response.charAt(0); char1 = response.charAt(0);
} }
// Hide possible transfer dialog box // Hide possible transfer dialog box
$('#dialog_box').hide(); $('#dialog_box').hide();
var entry, cur_meta; var entry, curMeta;
switch (char1) { switch (char1) {
case '{': case '{':
// Metadata // Metadata
tranfer_stopped = false; transferStopped = false;
cur_meta = JSON.parse(response); curMeta = JSON.parse(response);
pending[cur_meta.id] = cur_meta; pending[curMeta.id] = curMeta;
var name = (cur_meta.name || 'file'); var name = (curMeta.name || 'file');
var message = uiStrings.notification.retrieving.replace('%s', name); var message = uiStrings.notification.retrieving.replace('%s', name);
if (mode != 'm') { if (mode !== 'm') {
$.process_cancel(message, function() { $.process_cancel(message, function () {
tranfer_stopped = true; transferStopped = true;
// Should a message be sent back to the frame? // Should a message be sent back to the frame?
$('#dialog_box').hide(); $('#dialog_box').hide();
});
} else {
entry = $('<div>' + message + '</div>').data('id', curMeta.id);
preview.append(entry);
curMeta.entry = entry;
}
return;
case '<':
svgStr = true;
break;
case 'd':
if (response.indexOf('data:image/svg+xml') === 0) {
var pre = 'data:image/svg+xml;base64,';
var src = response.substring(pre.length);
response = svgedit.utilities.decode64(src);
svgStr = true;
break;
} else if (response.indexOf('data:image/') === 0) {
imgStr = true;
break;
}
// Else fall through
default:
// TODO: See if there's a way to base64 encode the binary data stream
// var str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
// Assume it's raw image data
// importImage(str);
// Don't give warning as postMessage may have been used by something else
if (mode !== 'm') {
closeBrowser();
} else {
pending[id].entry.remove();
}
// $.alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') {
// closeBrowser();
// } else {
// pending[id].entry.remove();
// }
// });
return;
}
switch (mode) {
case 's':
// Import one
if (svgStr) {
svgCanvas.importSvgString(response);
} else if (imgStr) {
importImage(response);
}
closeBrowser();
break;
case 'm':
// Import multiple
multiArr.push([(svgStr ? 'svg' : 'img'), response]);
var title;
curMeta = pending[id];
if (svgStr) {
if (curMeta && curMeta.name) {
title = curMeta.name;
} else {
// Try to find a title
var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
}
if (curMeta) {
preview.children().each(function () {
if ($(this).data('id') === id) {
if (curMeta.preview_url) {
$(this).html('<img src="' + curMeta.preview_url + '">' + title);
} else {
$(this).text(title);
}
submit.removeAttr('disabled');
}
}); });
} else { } else {
entry = $('<div>' + message + '</div>').data('id', cur_meta.id); preview.append('<div>' + title + '</div>');
preview.append(entry); submit.removeAttr('disabled');
cur_meta.entry = entry;
} }
} else {
return; if (curMeta && curMeta.preview_url) {
case '<': title = curMeta.name || '';
svg_str = true;
break;
case 'd':
if (response.indexOf('data:image/svg+xml') === 0) {
var pre = 'data:image/svg+xml;base64,';
var src = response.substring(pre.length);
response = svgedit.utilities.decode64(src);
svg_str = true;
break;
} else if (response.indexOf('data:image/') === 0) {
img_str = true;
break;
} }
// Else fall through if (curMeta && curMeta.preview_url) {
default: entry = '<img src="' + curMeta.preview_url + '">' + title;
// TODO: See if there's a way to base64 encode the binary data stream
// var str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
// Assume it's raw image data
// importImage(str);
// Don't give warning as postMessage may have been used by something else
if (mode !== 'm') {
closeBrowser();
} else { } else {
pending[id].entry.remove(); entry = '<img src="' + response + '">';
} }
// $.alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') {
// closeBrowser();
// } else {
// pending[id].entry.remove();
// }
// });
return;
}
switch (mode) {
case 's':
// Import one
if (svg_str) {
svgCanvas.importSvgString(response);
} else if (img_str) {
importImage(response);
}
closeBrowser();
break;
case 'm':
// Import multiple
multi_arr.push([(svg_str ? 'svg' : 'img'), response]);
var title;
cur_meta = pending[id];
if (svg_str) {
if (cur_meta && cur_meta.name) {
title = cur_meta.name;
} else {
// Try to find a title
var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
}
if (cur_meta) {
preview.children().each(function() {
if ($(this).data('id') == id) {
if (cur_meta.preview_url) {
$(this).html('<img src="' + cur_meta.preview_url + '">' + title);
} else {
$(this).text(title);
}
submit.removeAttr('disabled');
}
});
} else {
preview.append('<div>'+title+'</div>');
submit.removeAttr('disabled');
}
} else {
if (cur_meta && cur_meta.preview_url) {
title = cur_meta.name || '';
}
if (cur_meta && cur_meta.preview_url) {
entry = '<img src="' + cur_meta.preview_url + '">' + title;
} else {
entry = '<img src="' + response + '">';
}
if (cur_meta) {
preview.children().each(function() {
if ($(this).data('id') == id) {
$(this).html(entry);
submit.removeAttr('disabled');
}
});
} else {
preview.append($('<div>').append(entry));
submit.removeAttr('disabled');
}
if (curMeta) {
preview.children().each(function () {
if ($(this).data('id') === id) {
$(this).html(entry);
submit.removeAttr('disabled');
}
});
} else {
preview.append($('<div>').append(entry));
submit.removeAttr('disabled');
} }
break; }
case 'o': break;
// Open case 'o':
if (!svg_str) {break;} // Open
svgEditor.openPrep(function(ok) { if (!svgStr) { break; }
if (!ok) {return;} svgEditor.openPrep(function (ok) {
svgCanvas.clear(); if (!ok) { return; }
svgCanvas.setSvgString(response); svgCanvas.clear();
// updateCanvas(); svgCanvas.setSvgString(response);
}); // updateCanvas();
closeBrowser(); });
break; closeBrowser();
break;
} }
}, true); }, true);
function toggleMulti(show) { function toggleMulti (show) {
$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)}); $('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
if (!preview) { if (!preview) {
preview = $('<div id=imglib_preview>').css({ preview = $('<div id=imglib_preview>').css({
@@ -257,208 +255,202 @@ svgEditor.addExtension("imagelib", function() {'use strict';
background: '#fff', background: '#fff',
overflow: 'auto' overflow: 'auto'
}).insertAfter('#lib_framewrap'); }).insertAfter('#lib_framewrap');
submit = $('<button disabled>Import selected</button>') submit = $('<button disabled>Import selected</button>')
.appendTo('#imgbrowse') .appendTo('#imgbrowse')
.on("click touchend", function() { .on('click touchend', function () {
$.each(multi_arr, function(i) { $.each(multiArr, function (i) {
var type = this[0]; var type = this[0];
var data = this[1]; var data = this[1];
if (type == 'svg') { if (type === 'svg') {
svgCanvas.importSvgString(data); svgCanvas.importSvgString(data);
} else { } else {
importImage(data); importImage(data);
} }
svgCanvas.moveSelectedElements(i*20, i*20, false); svgCanvas.moveSelectedElements(i * 20, i * 20, false);
});
preview.empty();
multiArr = [];
$('#imgbrowse_holder').hide();
}).css({
position: 'absolute',
bottom: 10,
right: -10
}); });
preview.empty();
multi_arr = [];
$('#imgbrowse_holder').hide();
}).css({
position: 'absolute',
bottom: 10,
right: -10
});
} }
preview.toggle(show); preview.toggle(show);
submit.toggle(show); submit.toggle(show);
} }
function showBrowser() { function showBrowser () {
var browser = $('#imgbrowse'); var browser = $('#imgbrowse');
if (!browser.length) { if (!browser.length) {
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>\ $('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
</div></div>').insertAfter('#svg_docprops'); '</div></div>').insertAfter('#svg_docprops');
browser = $('#imgbrowse'); browser = $('#imgbrowse');
var all_libs = uiStrings.imagelib.select_lib; var allLibs = uiStrings.imagelib.select_lib;
var lib_opts = $('<ul id=imglib_opts>').appendTo(browser); var libOpts = $('<ul id=imglib_opts>').appendTo(browser);
var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>'); var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
var header = $('<h1>').prependTo(browser).text(all_libs).css({ var header = $('<h1>').prependTo(browser).text(allLibs).css({
position: 'absolute', position: 'absolute',
top: 0, top: 0,
left: 0, left: 0,
width: '100%' width: '100%'
}); });
var cancel = $('<button>' + uiStrings.common.cancel + '</button>') var cancel = $('<button>' + uiStrings.common.cancel + '</button>')
.appendTo(browser) .appendTo(browser)
.on("click touchend", function() { .on('click touchend', function () {
$('#imgbrowse_holder').hide(); $('#imgbrowse_holder').hide();
}).css({ }).css({
position: 'absolute', position: 'absolute',
top: 5, top: 5,
right: -10 right: -10
}); });
var leftBlock = $('<span>').css({position:'absolute',top:5,left:10}).appendTo(browser); var leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>') var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>')
.appendTo(leftBlock) .appendTo(leftBlock)
.on("click touchend", function() { .on('click touchend', function () {
frame.attr('src', 'about:blank').hide(); frame.attr('src', 'about:blank').hide();
lib_opts.show(); libOpts.show();
header.text(all_libs); header.text(allLibs);
back.hide(); back.hide();
}).css({ }).css({
'margin-right': 5 'margin-right': 5
}).hide(); }).hide();
var type = $('<select><option value=s>' + /* var type = */ $('<select><option value=s>' +
uiStrings.imagelib.import_single + '</option><option value=m>' + uiStrings.imagelib.import_single + '</option><option value=m>' +
uiStrings.imagelib.import_multi + '</option><option value=o>' + uiStrings.imagelib.import_multi + '</option><option value=o>' +
uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function() { uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () {
mode = $(this).val(); mode = $(this).val();
switch (mode) { switch (mode) {
case 's': case 's':
case 'o': case 'o':
toggleMulti(false); toggleMulti(false);
break; break;
case 'm': case 'm':
// Import multiple // Import multiple
toggleMulti(true); toggleMulti(true);
break; break;
} }
}).css({ }).css({
'margin-top': 10 'margin-top': 10
}); });
cancel.prepend($.getSvgIcon('cancel', true)); cancel.prepend($.getSvgIcon('cancel', true));
back.prepend($.getSvgIcon('tool_imagelib', true)); back.prepend($.getSvgIcon('tool_imagelib', true));
$.each(img_libs, function(i, opts) { $.each(imgLibs, function (i, opts) {
$('<li>') $('<li>')
.appendTo(lib_opts) .appendTo(libOpts)
.text(opts.name) .text(opts.name)
.on("click touchend", function() { .on('click touchend', function () {
frame.attr('src', opts.url).show(); frame.attr('src', opts.url).show();
header.text(opts.name); header.text(opts.name);
lib_opts.hide(); libOpts.hide();
back.show(); back.show();
}).append('<span>' + opts.description + '</span>'); }).append('<span>' + opts.description + '</span>');
}); });
} else { } else {
$('#imgbrowse_holder').show(); $('#imgbrowse_holder').show();
} }
} }
return { return {
svgicons: svgEditor.curConfig.extPath + "ext-imagelib.xml", svgicons: svgEditor.curConfig.extPath + 'ext-imagelib.xml',
buttons: [{ buttons: [{
id: "tool_imagelib", id: 'tool_imagelib',
type: "app_menu", // _flyout type: 'app_menu', // _flyout
position: 4, position: 4,
title: "Image library", title: 'Image library',
events: { events: {
"mouseup": showBrowser 'mouseup': showBrowser
} }
}], }],
callback: function() { callback: function () {
$('<style>').text(
$('<style>').text('\ '#imgbrowse_holder {' +
#imgbrowse_holder {\ 'position: absolute;' +
position: absolute;\ 'top: 0;' +
top: 0;\ 'left: 0;' +
left: 0;\ 'width: 100%;' +
width: 100%;\ 'height: 100%;' +
height: 100%;\ 'background-color: rgba(0, 0, 0, .5);' +
background-color: rgba(0, 0, 0, .5);\ 'z-index: 5;' +
z-index: 5;\ '}' +
}\ '#imgbrowse {' +
\ 'position: absolute;' +
#imgbrowse {\ 'top: 25px;' +
position: absolute;\ 'left: 25px;' +
top: 25px;\ 'right: 25px;' +
left: 25px;\ 'bottom: 25px;' +
right: 25px;\ 'min-width: 300px;' +
bottom: 25px;\ 'min-height: 200px;' +
min-width: 300px;\ 'background: #B0B0B0;' +
min-height: 200px;\ 'border: 1px outset #777;' +
background: #B0B0B0;\ '}' +
border: 1px outset #777;\ '#imgbrowse h1 {' +
}\ 'font-size: 20px;' +
#imgbrowse h1 {\ 'margin: .4em;' +
font-size: 20px;\ 'text-align: center;' +
margin: .4em;\ '}' +
text-align: center;\ '#lib_framewrap,' +
}\ '#imgbrowse > ul {' +
#lib_framewrap,\ 'position: absolute;' +
#imgbrowse > ul {\ 'top: 45px;' +
position: absolute;\ 'left: 10px;' +
top: 45px;\ 'right: 10px;' +
left: 10px;\ 'bottom: 10px;' +
right: 10px;\ 'background: white;' +
bottom: 10px;\ 'margin: 0;' +
background: white;\ 'padding: 0;' +
margin: 0;\ '}' +
padding: 0;\ '#imgbrowse > ul {' +
}\ 'overflow: auto;' +
#imgbrowse > ul {\ '}' +
overflow: auto;\ '#imgbrowse > div {' +
}\ 'border: 1px solid #666;' +
#imgbrowse > div {\ '}' +
border: 1px solid #666;\ '#imglib_preview > div {' +
}\ 'padding: 5px;' +
#imglib_preview > div {\ 'font-size: 12px;' +
padding: 5px;\ '}' +
font-size: 12px;\ '#imglib_preview img {' +
}\ 'display: block;' +
#imglib_preview img {\ 'margin: 0 auto;' +
display: block;\ 'max-height: 100px;' +
margin: 0 auto;\ '}' +
max-height: 100px;\ '#imgbrowse li {' +
}\ 'list-style: none;' +
#imgbrowse li {\ 'padding: .5em;' +
list-style: none;\ 'background: #E8E8E8;' +
padding: .5em;\ 'border-bottom: 1px solid #B0B0B0;' +
background: #E8E8E8;\ 'line-height: 1.2em;' +
border-bottom: 1px solid #B0B0B0;\ 'font-style: sans-serif;' +
line-height: 1.2em;\ '}' +
font-style: sans-serif;\ '#imgbrowse li > span {' +
}\ 'color: #666;' +
#imgbrowse li > span {\ 'font-size: 15px;' +
color: #666;\ 'display: block;' +
font-size: 15px;\ '}' +
display: block;\ '#imgbrowse li:hover {' +
}\ 'background: #FFC;' +
#imgbrowse li:hover {\ 'cursor: pointer;' +
background: #FFC;\ '}' +
cursor: pointer;\ '#imgbrowse iframe {' +
}\ 'width: 100%;' +
#imgbrowse iframe {\ 'height: 100%;' +
width: 100%;\ 'border: 0;' +
height: 100%;\ '}'
border: 0;\ ).appendTo('head');
}\
').appendTo('head');
} }
}; };
}); });

View File

@@ -1,23 +1,23 @@
/*globals svgEditor, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true, todo: true */ /* globals svgEditor, svgCanvas, $ */
/* /*
* ext-markers.js * ext-markers.js
* *
* Licensed under the Apache License, Version 2 * Licensed under the Apache License, Version 2
* *
* Copyright(c) 2010 Will Schleter * Copyright(c) 2010 Will Schleter
* based on ext-arrows.js by Copyright(c) 2010 Alexis Deveria * based on ext-arrows.js by Copyright(c) 2010 Alexis Deveria
* *
* This extension provides for the addition of markers to the either end * This extension provides for the addition of markers to the either end
* or the middle of a line, polyline, path, polygon. * or the middle of a line, polyline, path, polygon.
* *
* Markers may be either a graphic or arbitary text * Markers may be either a graphic or arbitary text
* *
* to simplify the coding and make the implementation as robust as possible, * to simplify the coding and make the implementation as robust as possible,
* markers are not shared - every object has its own set of markers. * markers are not shared - every object has its own set of markers.
* this relationship is maintained by a naming convention between the * this relationship is maintained by a naming convention between the
* ids of the markers and the ids of the object * ids of the markers and the ids of the object
* *
* The following restrictions exist for simplicty of use and programming * The following restrictions exist for simplicty of use and programming
* objects and their markers to have the same color * objects and their markers to have the same color
* marker size is fixed * marker size is fixed
@@ -32,236 +32,235 @@
* *
*/ */
svgEditor.addExtension("Markers", function(S) { svgEditor.addExtension('Markers', function (S) {
var // svgcontent = S.svgcontent, var // svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson, addElem = S.addSvgElementFromJson,
selElems; selElems;
var mtypes = ['start','mid','end']; var mtypes = ['start', 'mid', 'end'];
var markerPrefix = 'se_marker_';
var idPrefix = 'mkr_';
var marker_prefix = 'se_marker_';
var id_prefix = 'mkr_';
// note - to add additional marker types add them below with a unique id // note - to add additional marker types add them below with a unique id
// and add the associated icon(s) to marker-icons.svg // and add the associated icon(s) to marker-icons.svg
// the geometry is normallized to a 100x100 box with the origin at lower left // the geometry is normallized to a 100x100 box with the origin at lower left
// Safari did not like negative values for low left of viewBox // Safari did not like negative values for low left of viewBox
// remember that the coordinate system has +y downward // remember that the coordinate system has +y downward
var marker_types = { var markerTypes = {
nomarker: {}, nomarker: {},
leftarrow: leftarrow:
{element:'path', attr:{d:'M0,50 L100,90 L70,50 L100,10 Z'}}, {element: 'path', attr: {d: 'M0,50 L100,90 L70,50 L100,10 Z'}},
rightarrow: rightarrow:
{element:'path', attr:{d:'M100,50 L0,90 L30,50 L0,10 Z'}}, {element: 'path', attr: {d: 'M100,50 L0,90 L30,50 L0,10 Z'}},
textmarker: textmarker:
{element:'text', attr: {x:0, y:0,'stroke-width':0,'stroke':'none','font-size':75,'font-family':'serif','text-anchor':'left', {element: 'text', attr: {x: 0, y: 0, 'stroke-width': 0, 'stroke': 'none', 'font-size': 75, 'font-family': 'serif', 'text-anchor': 'left',
'xml:space': 'preserve'}}, 'xml:space': 'preserve'}},
forwardslash: forwardslash:
{element:'path', attr:{d:'M30,100 L70,0'}}, {element: 'path', attr: {d: 'M30,100 L70,0'}},
reverseslash: reverseslash:
{element:'path', attr:{d:'M30,0 L70,100'}}, {element: 'path', attr: {d: 'M30,0 L70,100'}},
verticalslash: verticalslash:
{element:'path', attr:{d:'M50,0 L50,100'}}, {element: 'path', attr: {d: 'M50,0 L50,100'}},
box: box:
{element:'path', attr:{d:'M20,20 L20,80 L80,80 L80,20 Z'}}, {element: 'path', attr: {d: 'M20,20 L20,80 L80,80 L80,20 Z'}},
star: star:
{element:'path', attr:{d:'M10,30 L90,30 L20,90 L50,10 L80,90 Z'}}, {element: 'path', attr: {d: 'M10,30 L90,30 L20,90 L50,10 L80,90 Z'}},
xmark: xmark:
{element:'path', attr:{d:'M20,80 L80,20 M80,80 L20,20'}}, {element: 'path', attr: {d: 'M20,80 L80,20 M80,80 L20,20'}},
triangle: triangle:
{element:'path', attr:{d:'M10,80 L50,20 L80,80 Z'}}, {element: 'path', attr: {d: 'M10,80 L50,20 L80,80 Z'}},
mcircle: mcircle:
{element:'circle', attr:{r:30, cx:50, cy:50}} {element: 'circle', attr: {r: 30, cx: 50, cy: 50}}
}; };
var langList = {
var lang_list = { 'en': [
"en":[ {id: 'start_marker_list', title: 'Select start marker type'},
{id: "start_marker_list", title: "Select start marker type" }, {id: 'mid_marker_list', title: 'Select mid marker type'},
{id: "mid_marker_list", title: "Select mid marker type" }, {id: 'end_marker_list', title: 'Select end marker type'},
{id: "end_marker_list", title: "Select end marker type" }, {id: 'nomarker', title: 'No Marker'},
{id: "nomarker", title: "No Marker" }, {id: 'leftarrow', title: 'Left Arrow'},
{id: "leftarrow", title: "Left Arrow" }, {id: 'rightarrow', title: 'Right Arrow'},
{id: "rightarrow", title: "Right Arrow" }, {id: 'textmarker', title: 'Text Marker'},
{id: "textmarker", title: "Text Marker" }, {id: 'forwardslash', title: 'Forward Slash'},
{id: "forwardslash", title: "Forward Slash" }, {id: 'reverseslash', title: 'Reverse Slash'},
{id: "reverseslash", title: "Reverse Slash" }, {id: 'verticalslash', title: 'Vertical Slash'},
{id: "verticalslash", title: "Vertical Slash" }, {id: 'box', title: 'Box'},
{id: "box", title: "Box" }, {id: 'star', title: 'Star'},
{id: "star", title: "Star" }, {id: 'xmark', title: 'X'},
{id: "xmark", title: "X" }, {id: 'triangle', title: 'Triangle'},
{id: "triangle", title: "Triangle" }, {id: 'mcircle', title: 'Circle'},
{id: "mcircle", title: "Circle" }, {id: 'leftarrow_o', title: 'Open Left Arrow'},
{id: "leftarrow_o", title: "Open Left Arrow" }, {id: 'rightarrow_o', title: 'Open Right Arrow'},
{id: "rightarrow_o", title: "Open Right Arrow" }, {id: 'box_o', title: 'Open Box'},
{id: "box_o", title: "Open Box" }, {id: 'star_o', title: 'Open Star'},
{id: "star_o", title: "Open Star" }, {id: 'triangle_o', title: 'Open Triangle'},
{id: "triangle_o", title: "Open Triangle" }, {id: 'mcircle_o', title: 'Open Circle'}
{id: "mcircle_o", title: "Open Circle" }
] ]
}; };
// duplicate shapes to support unfilled (open) marker types with an _o suffix // duplicate shapes to support unfilled (open) marker types with an _o suffix
$.each(['leftarrow','rightarrow','box','star','mcircle','triangle'],function(i,v) { $.each(['leftarrow', 'rightarrow', 'box', 'star', 'mcircle', 'triangle'], function (i, v) {
marker_types[v+'_o'] = marker_types[v]; markerTypes[v + '_o'] = markerTypes[v];
}); });
// elem = a graphic element will have an attribute like marker-start // elem = a graphic element will have an attribute like marker-start
// attr - marker-start, marker-mid, or marker-end // attr - marker-start, marker-mid, or marker-end
// returns the marker element that is linked to the graphic element // returns the marker element that is linked to the graphic element
function getLinked(elem, attr) { function getLinked (elem, attr) {
var str = elem.getAttribute(attr); var str = elem.getAttribute(attr);
if(!str) {return null;} if (!str) { return null; }
var m = str.match(/\(\#(.*)\)/); var m = str.match(/\(#(.*)\)/);
if(!m || m.length !== 2) { if (!m || m.length !== 2) {
return null; return null;
} }
return S.getElem(m[1]); return S.getElem(m[1]);
} }
function setIcon(pos,id) { function setIcon (pos, id) {
if (id.substr(0,1) !== '\\') {id = '\\textmarker';} if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; }
var ci = '#'+id_prefix+pos+'_'+id.substr(1); var ci = '#' + idPrefix + pos + '_' + id.substr(1);
svgEditor.setIcon('#cur_' + pos +'_marker_list', $(ci).children()); svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children());
$(ci).addClass('current').siblings().removeClass('current'); $(ci).addClass('current').siblings().removeClass('current');
} }
// toggles context tool panel off/on // toggles context tool panel off/on
//sets the controls with the selected element's settings // sets the controls with the selected element's settings
function showPanel(on) { function showPanel (on) {
$('#marker_panel').toggle(on); $('#marker_panel').toggle(on);
if(on) { if (on) {
var el = selElems[0]; var el = selElems[0];
var val; var val;
var ci; var ci;
$.each(mtypes, function(i, pos) { $.each(mtypes, function (i, pos) {
var m = getLinked(el, "marker-" + pos); var m = getLinked(el, 'marker-' + pos);
var txtbox = $('#' + pos + '_marker'); var txtbox = $('#' + pos + '_marker');
if (!m) { if (!m) {
val = '\\nomarker'; val = '\\nomarker';
ci = val; ci = val;
txtbox.hide(); // hide text box txtbox.hide(); // hide text box
} else { } else {
if (!m.attributes.se_type) {return;} // not created by this extension if (!m.attributes.se_type) { return; } // not created by this extension
val = '\\' + m.attributes.se_type.textContent; val = '\\' + m.attributes.se_type.textContent;
ci = val; ci = val;
if (val === '\\textmarker') { if (val === '\\textmarker') {
val = m.lastChild.textContent; val = m.lastChild.textContent;
//txtbox.show(); // show text box // txtbox.show(); // show text box
} else { } else {
txtbox.hide(); // hide text box txtbox.hide(); // hide text box
} }
} }
txtbox.val(val); txtbox.val(val);
setIcon(pos,ci); setIcon(pos, ci);
}); });
} }
} }
function addMarker (id, val) {
var txtBoxBg = '#ffffff';
var txtBoxBorder = 'none';
var txtBoxStrokeWidth = 0;
function addMarker(id, val) {
var txt_box_bg = '#ffffff';
var txt_box_border = 'none';
var txt_box_stroke_width = 0;
var marker = S.getElem(id); var marker = S.getElem(id);
if (marker) {return;} if (marker) { return; }
if (val == '' || val == '\\nomarker') {return;} if (val === '' || val === '\\nomarker') { return; }
var el = selElems[0]; var el = selElems[0];
var color = el.getAttribute('stroke'); var color = el.getAttribute('stroke');
//NOTE: Safari didn't like a negative value in viewBox // NOTE: Safari didn't like a negative value in viewBox
//so we use a standardized 0 0 100 100 // so we use a standardized 0 0 100 100
//with 50 50 being mapped to the marker position // with 50 50 being mapped to the marker position
var refX = 50; var refX = 50;
var refY = 50; var refY = 50;
var viewBox = "0 0 100 100"; var viewBox = '0 0 100 100';
var markerWidth = 5; var markerWidth = 5;
var markerHeight = 5; var markerHeight = 5;
var strokeWidth = 10; var strokeWidth = 10;
var se_type; var seType;
if (val.substr(0,1) === '\\') {se_type = val.substr(1);} if (val.substr(0, 1) === '\\') {
else {se_type = 'textmarker';} seType = val.substr(1);
} else { seType = 'textmarker'; }
if (!markerTypes[seType]) { return; } // an unknown type!
if (!marker_types[se_type]) {return;} // an unknown type!
// create a generic marker // create a generic marker
marker = addElem({ marker = addElem({
"element": "marker", 'element': 'marker',
"attr": { 'attr': {
"id": id, 'id': id,
"markerUnits": "strokeWidth", 'markerUnits': 'strokeWidth',
"orient": "auto", 'orient': 'auto',
"style": "pointer-events:none", 'style': 'pointer-events:none',
"se_type": se_type 'se_type': seType
} }
}); });
if (se_type != 'textmarker') { if (seType !== 'textmarker') {
var mel = addElem(marker_types[se_type]); var mel = addElem(markerTypes[seType]);
var fillcolor = color; var fillcolor = color;
if (se_type.substr(-2) === '_o') {fillcolor = 'none';} if (seType.substr(-2) === '_o') { fillcolor = 'none'; }
mel.setAttribute('fill', fillcolor); mel.setAttribute('fill', fillcolor);
mel.setAttribute('stroke', color); mel.setAttribute('stroke', color);
mel.setAttribute('stroke-width', strokeWidth); mel.setAttribute('stroke-width', strokeWidth);
marker.appendChild(mel); marker.appendChild(mel);
} else { } else {
var text = addElem(marker_types[se_type]); var text = addElem(markerTypes[seType]);
// have to add text to get bounding box // have to add text to get bounding box
text.textContent = val; text.textContent = val;
var tb = text.getBBox(); var tb = text.getBBox();
//alert( tb.x + " " + tb.y + " " + tb.width + " " + tb.height); // alert(tb.x + ' ' + tb.y + ' ' + tb.width + ' ' + tb.height);
var pad = 1; var pad = 1;
var bb = tb; var bb = tb;
bb.x = 0; bb.x = 0;
bb.y = 0; bb.y = 0;
bb.width += pad*2; bb.width += pad * 2;
bb.height += pad*2; bb.height += pad * 2;
// shift text according to its size // shift text according to its size
text.setAttribute('x', pad); text.setAttribute('x', pad);
text.setAttribute('y', bb.height - pad - tb.height/4); // kludge? text.setAttribute('y', bb.height - pad - tb.height / 4); // kludge?
text.setAttribute('fill',color); text.setAttribute('fill', color);
refX = bb.width/2 + pad; refX = bb.width / 2 + pad;
refY = bb.height/2 + pad; refY = bb.height / 2 + pad;
viewBox = bb.x + " " + bb.y + " " + bb.width + " " + bb.height; viewBox = bb.x + ' ' + bb.y + ' ' + bb.width + ' ' + bb.height;
markerWidth = bb.width/10; markerWidth = bb.width / 10;
markerHeight = bb.height/10; markerHeight = bb.height / 10;
var box = addElem({ var box = addElem({
"element": "rect", 'element': 'rect',
"attr": { 'attr': {
"x": bb.x, 'x': bb.x,
"y": bb.y, 'y': bb.y,
"width": bb.width, 'width': bb.width,
"height": bb.height, 'height': bb.height,
"fill": txt_box_bg, 'fill': txtBoxBg,
"stroke": txt_box_border, 'stroke': txtBoxBorder,
"stroke-width": txt_box_stroke_width 'stroke-width': txtBoxStrokeWidth
} }
}); });
marker.setAttribute("orient",0); marker.setAttribute('orient', 0);
marker.appendChild(box); marker.appendChild(box);
marker.appendChild(text); marker.appendChild(text);
} }
marker.setAttribute("viewBox",viewBox); marker.setAttribute('viewBox', viewBox);
marker.setAttribute("markerWidth", markerWidth); marker.setAttribute('markerWidth', markerWidth);
marker.setAttribute("markerHeight", markerHeight); marker.setAttribute('markerHeight', markerHeight);
marker.setAttribute("refX", refX); marker.setAttribute('refX', refX);
marker.setAttribute("refY", refY); marker.setAttribute('refY', refY);
S.findDefs().appendChild(marker); S.findDefs().appendChild(marker);
return marker; return marker;
} }
function convertline(elem) { function convertline (elem) {
// this routine came from the connectors extension // this routine came from the connectors extension
// it is needed because midpoint markers don't work with line elements // it is needed because midpoint markers don't work with line elements
if (!(elem.tagName === 'line')) {return elem;} if (!(elem.tagName === 'line')) { return elem; }
// Convert to polyline to accept mid-arrow // Convert to polyline to accept mid-arrow
@@ -271,27 +270,27 @@ svgEditor.addExtension("Markers", function(S) {
var y2 = Number(elem.getAttribute('y2')); var y2 = Number(elem.getAttribute('y2'));
var id = elem.id; var id = elem.id;
var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' '); var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
var pline = addElem({ var pline = addElem({
"element": "polyline", 'element': 'polyline',
"attr": { 'attr': {
"points": (x1+','+y1+ mid_pt +x2+','+y2), 'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2),
"stroke": elem.getAttribute('stroke'), 'stroke': elem.getAttribute('stroke'),
"stroke-width": elem.getAttribute('stroke-width'), 'stroke-width': elem.getAttribute('stroke-width'),
"fill": "none", 'fill': 'none',
"opacity": elem.getAttribute('opacity') || 1 'opacity': elem.getAttribute('opacity') || 1
} }
}); });
$.each(mtypes, function(i, pos) { // get any existing marker definitions $.each(mtypes, function (i, pos) { // get any existing marker definitions
var nam = 'marker-'+pos; var nam = 'marker-' + pos;
var m = elem.getAttribute(nam); var m = elem.getAttribute(nam);
if (m) {pline.setAttribute(nam,elem.getAttribute(nam));} if (m) { pline.setAttribute(nam, elem.getAttribute(nam)); }
}); });
var batchCmd = new S.BatchCommand(); var batchCmd = new S.BatchCommand();
batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode)); batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode));
batchCmd.addSubCommand(new S.InsertElementCommand(pline)); batchCmd.addSubCommand(new S.InsertElementCommand(pline));
$(elem).after(pline).remove(); $(elem).after(pline).remove();
svgCanvas.clearSelection(); svgCanvas.clearSelection();
pline.id = id; pline.id = id;
@@ -300,85 +299,85 @@ svgEditor.addExtension("Markers", function(S) {
return pline; return pline;
} }
function setMarker() { function setMarker () {
var poslist={'start_marker':'start','mid_marker':'mid','end_marker':'end'}; var poslist = {'start_marker': 'start', 'mid_marker': 'mid', 'end_marker': 'end'};
var pos = poslist[this.id]; var pos = poslist[this.id];
var marker_name = 'marker-'+pos; var markerName = 'marker-' + pos;
var val = this.value; var val = this.value;
var el = selElems[0]; var el = selElems[0];
var marker = getLinked(el, marker_name); var marker = getLinked(el, markerName);
if (marker) {$(marker).remove();} if (marker) { $(marker).remove(); }
el.removeAttribute(marker_name); el.removeAttribute(markerName);
if (val == '') {val = '\\nomarker';} if (val === '') { val = '\\nomarker'; }
if (val == '\\nomarker') { if (val === '\\nomarker') {
setIcon(pos,val); setIcon(pos, val);
S.call("changed", selElems); S.call('changed', selElems);
return; return;
} }
// Set marker on element // Set marker on element
var id = marker_prefix + pos + '_' + el.id; var id = markerPrefix + pos + '_' + el.id;
addMarker(id, val); addMarker(id, val);
svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")"); svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
if (el.tagName === 'line' && pos == 'mid') {el = convertline(el);} if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
S.call("changed", selElems); S.call('changed', selElems);
setIcon(pos,val); setIcon(pos, val);
} }
// called when the main system modifies an object // called when the main system modifies an object
// this routine changes the associated markers to be the same color // this routine changes the associated markers to be the same color
function colorChanged(elem) { function colorChanged (elem) {
var color = elem.getAttribute('stroke'); var color = elem.getAttribute('stroke');
$.each(mtypes, function(i, pos) { $.each(mtypes, function (i, pos) {
var marker = getLinked(elem, 'marker-'+pos); var marker = getLinked(elem, 'marker-' + pos);
if (!marker) {return;} if (!marker) { return; }
if (!marker.attributes.se_type) {return;} // not created by this extension if (!marker.attributes.se_type) { return; } // not created by this extension
var ch = marker.lastElementChild; var ch = marker.lastElementChild;
if (!ch) {return;} if (!ch) { return; }
var curfill = ch.getAttribute('fill'); var curfill = ch.getAttribute('fill');
var curstroke = ch.getAttribute('stroke'); var curstroke = ch.getAttribute('stroke');
if (curfill && curfill != 'none') {ch.setAttribute('fill', color);} if (curfill && curfill !== 'none') { ch.setAttribute('fill', color); }
if (curstroke && curstroke != 'none') {ch.setAttribute('stroke', color);} if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color); }
}); });
} }
// called when the main system creates or modifies an object // called when the main system creates or modifies an object
// primary purpose is create new markers for cloned objects // primary purpose is create new markers for cloned objects
function updateReferences(el) { function updateReferences (el) {
$.each(mtypes, function (i, pos) { $.each(mtypes, function (i, pos) {
var id = marker_prefix + pos + '_' + el.id; var id = markerPrefix + pos + '_' + el.id;
var marker_name = 'marker-'+pos; var markerName = 'marker-' + pos;
var marker = getLinked(el, marker_name); var marker = getLinked(el, markerName);
if (!marker || !marker.attributes.se_type) {return;} // not created by this extension if (!marker || !marker.attributes.se_type) { return; } // not created by this extension
var url = el.getAttribute(marker_name); var url = el.getAttribute(markerName);
if (url) { if (url) {
var len = el.id.length; var len = el.id.length;
var linkid = url.substr(-len-1, len); var linkid = url.substr(-len - 1, len);
if (el.id != linkid) { if (el.id !== linkid) {
var val = $('#'+pos + '_marker').attr('value'); var val = $('#' + pos + '_marker').attr('value');
addMarker(id, val); addMarker(id, val);
svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")"); svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
if (el.tagName === 'line' && pos == 'mid') {el = convertline(el);} if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
S.call("changed", selElems); S.call('changed', selElems);
} }
} }
}); });
} }
// simulate a change event a text box that stores the current element's marker type // simulate a change event a text box that stores the current element's marker type
function triggerTextEntry(pos, val) { function triggerTextEntry (pos, val) {
$('#'+pos+'_marker').val(val); $('#' + pos + '_marker').val(val);
$('#'+pos+'_marker').change(); $('#' + pos + '_marker').change();
// var txtbox = $('#'+pos+'_marker'); // var txtbox = $('#'+pos+'_marker');
// if (val.substr(0,1)=='\\') {txtbox.hide();} // if (val.substr(0,1)=='\\') {txtbox.hide();}
// else {txtbox.show();} // else {txtbox.show();}
} }
function showTextPrompt(pos) { function showTextPrompt (pos) {
var def = $('#'+pos+'_marker').val(); var def = $('#' + pos + '_marker').val();
if (def.substr(0,1) === '\\') {def = '';} if (def.substr(0, 1) === '\\') { def = ''; }
$.prompt('Enter text for ' + pos + ' marker', def , function(txt) { $.prompt('Enter text for ' + pos + ' marker', def, function (txt) {
if (txt) {triggerTextEntry(pos, txt);} if (txt) { triggerTextEntry(pos, txt); }
}); });
} }
@@ -406,66 +405,64 @@ svgEditor.addExtension("Markers", function(S) {
} }
*/ */
// callback function for a toolbar button click // callback function for a toolbar button click
function setArrowFromButton(obj) { function setArrowFromButton (obj) {
var parts = this.id.split('_'); var parts = this.id.split('_');
var pos = parts[1]; var pos = parts[1];
var val = parts[2]; var val = parts[2];
if (parts[3]) { val += '_' + parts[3];} if (parts[3]) { val += '_' + parts[3]; }
if (val != 'textmarker') { if (val !== 'textmarker') {
triggerTextEntry(pos, '\\'+val); triggerTextEntry(pos, '\\' + val);
} else { } else {
showTextPrompt(pos); showTextPrompt(pos);
} }
} }
function getTitle(lang, id) { function getTitle (lang, id) {
var i, list = lang_list[lang]; var i, list = langList[lang];
for (i in list) { for (i in list) {
if (list.hasOwnProperty(i) && list[i].id == id) { if (list.hasOwnProperty(i) && list[i].id === id) {
return list[i].title; return list[i].title;
} }
} }
return id; return id;
} }
// build the toolbar button array from the marker definitions // build the toolbar button array from the marker definitions
// TODO: need to incorporate language specific titles // TODO: need to incorporate language specific titles
function buildButtonList() { function buildButtonList () {
var buttons=[]; var buttons = [];
// var i = 0; // var i = 0;
/* /*
buttons.push({ buttons.push({
id:id_prefix + 'markers_off', id: idPrefix + 'markers_off',
title:'Turn off all markers', title: 'Turn off all markers',
type:'context', type: 'context',
events: { 'click': setMarkerSet }, events: { 'click': setMarkerSet },
panel: 'marker_panel' panel: 'marker_panel'
}); });
buttons.push({ buttons.push({
id:id_prefix + 'markers_dimension', id: idPrefix + 'markers_dimension',
title:'Dimension', title: 'Dimension',
type:'context', type: 'context',
events: { 'click': setMarkerSet }, events: { 'click': setMarkerSet },
panel: 'marker_panel' panel: 'marker_panel'
}); });
buttons.push({ buttons.push({
id:id_prefix + 'markers_label', id: idPrefix + 'markers_label',
title:'Label', title: 'Label',
type:'context', type: 'context',
events: { 'click': setMarkerSet }, events: { 'click': setMarkerSet },
panel: 'marker_panel' panel: 'marker_panel'
}); });
*/ */
$.each(mtypes, function (k, pos) { $.each(mtypes, function (k, pos) {
var listname = pos + "_marker_list"; var listname = pos + '_marker_list';
var def = true; var def = true;
$.each(marker_types, function (id, v) { $.each(markerTypes, function (id, v) {
var title = getTitle('en', id); var title = getTitle('en', String(id));
buttons.push({ buttons.push({
id: id_prefix + pos + '_' + id, id: idPrefix + pos + '_' + id,
svgicon: id, svgicon: id,
title: title, title: title,
type: 'context', type: 'context',
@@ -481,99 +478,98 @@ svgEditor.addExtension("Markers", function(S) {
} }
return { return {
name: "Markers", name: 'Markers',
svgicons: svgEditor.curConfig.extPath + "markers-icons.xml", svgicons: svgEditor.curConfig.extPath + 'markers-icons.xml',
buttons: buildButtonList(), buttons: buildButtonList(),
context_tools: [ context_tools: [
{ {
type: "input", type: 'input',
panel: "marker_panel", panel: 'marker_panel',
title: "Start marker", title: 'Start marker',
id: "start_marker", id: 'start_marker',
label: "s", label: 's',
size: 3, size: 3,
events: { change: setMarker } events: { change: setMarker }
},{ }, {
type: "button-select", type: 'button-select',
panel: "marker_panel", panel: 'marker_panel',
title: getTitle('en', 'start_marker_list'), title: getTitle('en', 'start_marker_list'),
id: "start_marker_list", id: 'start_marker_list',
colnum: 3, colnum: 3,
events: { change: setArrowFromButton } events: { change: setArrowFromButton }
},{ }, {
type: "input", type: 'input',
panel: "marker_panel", panel: 'marker_panel',
title: "Middle marker", title: 'Middle marker',
id: "mid_marker", id: 'mid_marker',
label: "m", label: 'm',
defval: "", defval: '',
size: 3, size: 3,
events: { change: setMarker } events: { change: setMarker }
},{ }, {
type: "button-select", type: 'button-select',
panel: "marker_panel", panel: 'marker_panel',
title: getTitle('en', 'mid_marker_list'), title: getTitle('en', 'mid_marker_list'),
id: "mid_marker_list", id: 'mid_marker_list',
colnum: 3, colnum: 3,
events: { change: setArrowFromButton } events: { change: setArrowFromButton }
},{ }, {
type: "input", type: 'input',
panel: "marker_panel", panel: 'marker_panel',
title: "End marker", title: 'End marker',
id: "end_marker", id: 'end_marker',
label: "e", label: 'e',
size: 3, size: 3,
events: { change: setMarker } events: { change: setMarker }
},{ }, {
type: "button-select", type: 'button-select',
panel: "marker_panel", panel: 'marker_panel',
title: getTitle('en', 'end_marker_list'), title: getTitle('en', 'end_marker_list'),
id: "end_marker_list", id: 'end_marker_list',
colnum: 3, colnum: 3,
events: { change: setArrowFromButton } events: { change: setArrowFromButton }
} ], }
callback: function() { ],
callback: function () {
$('#marker_panel').addClass('toolset').hide(); $('#marker_panel').addClass('toolset').hide();
}, },
addLangData: function(lang) { addLangData: function (lang) {
return { data: lang_list[lang] }; return { data: langList[lang] };
}, },
selectedChanged: function (opts) {
// Use this to update the current selected elements
// console.log('selectChanged',opts);
selElems = opts.elems;
selectedChanged: function(opts) { var i = selElems.length;
// Use this to update the current selected elements var markerElems = ['line', 'path', 'polyline', 'polygon'];
//console.log('selectChanged',opts);
selElems = opts.elems;
var i = selElems.length; while (i--) {
var marker_elems = ['line','path','polyline','polygon']; var elem = selElems[i];
if (elem && $.inArray(elem.tagName, markerElems) !== -1) {
while(i--) { if (opts.selectedElement && !opts.multiselected) {
var elem = selElems[i]; showPanel(true);
if(elem && $.inArray(elem.tagName, marker_elems) !== -1) { } else {
if (opts.selectedElement && !opts.multiselected) { showPanel(false);
showPanel(true); }
} else { } else {
showPanel(false); showPanel(false);
} }
} else {
showPanel(false);
} }
} },
},
elementChanged: function(opts) { elementChanged: function (opts) {
//console.log('elementChanged',opts); // console.log('elementChanged',opts);
var elem = opts.elems[0]; var elem = opts.elems[0];
if (elem && ( if (elem && (
elem.getAttribute("marker-start") || elem.getAttribute('marker-start') ||
elem.getAttribute("marker-mid") || elem.getAttribute('marker-mid') ||
elem.getAttribute("marker-end") elem.getAttribute('marker-end')
)) { )) {
colorChanged(elem); colorChanged(elem);
updateReferences(elem); updateReferences(elem);
}
// changing_flag = false; // Not apparently in use
} }
// changing_flag = false; // Not apparently in use
}
}; };
}); });

View File

@@ -1,5 +1,5 @@
/*globals MathJax, svgEditor, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint es5: true, todo: true, vars: true*/ /* globals MathJax, svgEditor, svgCanvas, $ */
/* /*
* ext-mathjax.js * ext-mathjax.js
* *
@@ -9,265 +9,256 @@
* *
*/ */
svgEditor.addExtension("mathjax", function() {'use strict'; svgEditor.addExtension('mathjax', function () {
// Configuration of the MathJax extention. 'use strict';
// Configuration of the MathJax extention.
// This will be added to the head tag before MathJax is loaded. // This will be added to the head tag before MathJax is loaded.
var /*mathjaxConfiguration = '<script type="text/x-mathjax-config">\ var /* mathjaxConfiguration = '<script type="text/x-mathjax-config">\
MathJax.Hub.Config({\ MathJax.Hub.Config({\
extensions: ["tex2jax.js"],\ extensions: ["tex2jax.js"],\
jax: ["input/TeX","output/SVG"],\ jax: ["input/TeX","output/SVG"],\
showProcessingMessages: true,\ showProcessingMessages: true,\
showMathMenu: false,\ showMathMenu: false,\
showMathMenuMSIE: false,\ showMathMenuMSIE: false,\
errorSettings: {\ errorSettings: {\
message: ["[Math Processing Error]"],\ message: ["[Math Processing Error]"],\
style: {color: "#CC0000", "font-style":"italic"}\ style: {color: "#CC0000", "font-style":"italic"}\
},\ },\
elements: [],\ elements: [],\
tex2jax: {\ tex2jax: {\
ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\ ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\
},\ },\
TeX: {\ TeX: {\
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\ extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\
},\ },\
"SVG": {\ "SVG": {\
}\ }\
});\ });\
</script>',*/ </script>', */
// mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js', // mathjaxSrc = 'http://cdn.mathjax.org/mathjax/latest/MathJax.js',
mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js', mathjaxSrcSecure = 'https://c328740.ssl.cf1.rackcdn.com/mathjax/latest/MathJax.js?config=TeX-AMS-MML_SVG.js',
math, math,
locationX, locationX,
locationY, locationY,
mathjaxLoaded = false, mathjaxLoaded = false,
uiStrings = svgEditor.uiStrings; uiStrings = svgEditor.uiStrings;
// TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback. // TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
$.extend(uiStrings, { $.extend(uiStrings, {
mathjax: { mathjax: {
embed_svg: 'Save as mathematics', embed_svg: 'Save as mathematics',
embed_mathml: 'Save as figure', embed_mathml: 'Save as figure',
svg_save_warning: 'The math will be transformed into a figure is manipulatable like everything else. You will not be able to manipulate the TeX-code anymore. ', svg_save_warning: 'The math will be transformed into a figure is manipulatable like everything else. You will not be able to manipulate the TeX-code anymore. ',
mathml_save_warning: 'Advised. The math will be saved as a figure.', mathml_save_warning: 'Advised. The math will be saved as a figure.',
title: 'Mathematics code editor' title: 'Mathematics code editor'
} }
}); });
function saveMath () {
var code = $('#mathjax_code_textarea').val();
// displaystyle to force MathJax NOT to use the inline style. Because it is
// less fancy!
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
function saveMath() { /*
var code = $('#mathjax_code_textarea').val(); * The MathJax library doesn't want to bloat your webpage so it creates
// displaystyle to force MathJax NOT to use the inline style. Because it is * every symbol (glymph) you need only once. These are saved in a <svg> on
// less fancy! * the top of your html document, just under the body tag. Each glymph has
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']); * its unique id and is saved as a <path> in the <defs> tag of the <svg>
*
* Then when the symbols are needed in the rest of your html document they
* are refferd to by a <use> tag.
* Because of bug 1076 we can't just grab the defs tag on the top and add it
* to your formula's <svg> and copy the lot. So we have to replace each
* <use> tag by it's <path>.
*/
MathJax.Hub.queue.Push(
function () {
var mathjaxMath = $('.MathJax_SVG');
var svg = $(mathjaxMath.html());
svg.find('use').each(function () {
var x, y, id, transform;
/* // TODO: find a less pragmatic and more elegant solution to this.
* The MathJax library doesn't want to bloat your webpage so it creates if ($(this).attr('href')) {
* every symbol (glymph) you need only once. These are saved in a <svg> on id = $(this).attr('href').slice(1); // Works in Chrome.
* the top of your html document, just under the body tag. Each glymph has } else {
* its unique id and is saved as a <path> in the <defs> tag of the <svg> id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
* }
* Then when the symbols are needed in the rest of your html document they
* are refferd to by a <use> tag.
* Because of bug 1076 we can't just grab the defs tag on the top and add it
* to your formula's <svg> and copy the lot. So we have to replace each
* <use> tag by it's <path>.
*/
MathJax.Hub.queue.Push(
function() {
var mathjaxMath = $('.MathJax_SVG');
var svg = $(mathjaxMath.html());
svg.find('use').each(function() {
var x, y, id, transform;
// TODO: find a less pragmatic and more elegant solution to this. var glymph = $('#' + id).clone().removeAttr('id');
if ($(this).attr('href')) { x = $(this).attr('x');
id = $(this).attr('href').slice(1); // Works in Chrome. y = $(this).attr('y');
} else { transform = $(this).attr('transform');
id = $(this).attr('xlink:href').slice(1); // Works in Firefox. if (transform && (x || y)) {
} glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')');
} else if (transform) {
glymph.attr('transform', transform);
} else if (x || y) {
glymph.attr('transform', 'translate(' + x + ',' + y + ')');
}
$(this).replaceWith(glymph);
});
// Remove the style tag because it interferes with SVG-Edit.
svg.removeAttr('style');
svg.attr('xmlns', 'http://www.w3.org/2000/svg');
svgCanvas.importSvgString($('<div>').append(svg.clone()).html(), true);
svgCanvas.ungroupSelectedElement();
// TODO: To undo the adding of the Formula you now have to undo twice.
// This should only be once!
svgCanvas.moveSelectedElements(locationX, locationY, true);
}
);
}
var glymph = $('#' + id).clone().removeAttr('id'); return {
x = $(this).attr('x'); name: 'MathJax',
y = $(this).attr('y'); svgicons: svgEditor.curConfig.extPath + 'mathjax-icons.xml',
transform = $(this).attr('transform'); buttons: [{
if (transform && ( x || y )) { id: 'tool_mathjax',
glymph.attr('transform', transform + ' translate(' + x + ',' + y + ')'); type: 'mode',
} title: 'Add Mathematics',
else if (transform) { events: {
glymph.attr('transform', transform); click: function () {
} // Only load Mathjax when needed, we don't want to strain Svg-Edit any more.
else if (x || y) { // From this point on it is very probable that it will be needed, so load it.
glymph.attr('transform', 'translate(' + x + ',' + y + ')'); if (mathjaxLoaded === false) {
} $('<div id="mathjax">' +
$(this).replaceWith(glymph); '<!-- Here is where MathJax creates the math -->' +
}); '<div id="mathjax_creator" class="tex2jax_process" style="display:none">' +
// Remove the style tag because it interferes with SVG-Edit. '$${}$$' +
svg.removeAttr('style'); '</div>' +
svg.attr('xmlns', 'http://www.w3.org/2000/svg'); '<div id="mathjax_overlay"></div>' +
svgCanvas.importSvgString($('<div>').append(svg.clone()).html(), true); '<div id="mathjax_container">' +
svgCanvas.ungroupSelectedElement(); '<div id="tool_mathjax_back" class="toolbar_button">' +
// TODO: To undo the adding of the Formula you now have to undo twice. '<button id="tool_mathjax_save">OK</button>' +
// This should only be once! '<button id="tool_mathjax_cancel">Cancel</button>' +
svgCanvas.moveSelectedElements(locationX, locationY, true); '</div>' +
} '<fieldset>' +
); '<legend id="mathjax_legend">Mathematics Editor</legend>' +
} '<label>' +
'<span id="mathjax_explication">Please type your mathematics in ' +
'<a href="http://en.wikipedia.org/wiki/Help:Displaying_a_formula" target="_blank">TeX</a> code.</span></label>' +
'<textarea id="mathjax_code_textarea" spellcheck="false"></textarea>' +
'</fieldset>' +
'</div>' +
'</div>'
).insertAfter('#svg_prefs').hide();
return { // Make the MathEditor draggable.
name: "MathJax", $('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'});
svgicons: svgEditor.curConfig.extPath + "mathjax-icons.xml",
buttons: [{
id: "tool_mathjax",
type: "mode",
title: "Add Mathematics",
events: {
click: function() {
// Only load Mathjax when needed, we don't want to strain Svg-Edit any more.
// From this point on it is very probable that it will be needed, so load it.
if (mathjaxLoaded === false) {
$('<div id="mathjax">\ // Add functionality and picture to cancel button.
<!-- Here is where MathJax creates the math -->\ $('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
<div id="mathjax_creator" class="tex2jax_process" style="display:none">\ .on('click touched', function () {
$${}$$\ $('#mathjax').hide();
</div>\ });
<div id="mathjax_overlay"></div>\
<div id="mathjax_container">\
<div id="tool_mathjax_back" class="toolbar_button">\
<button id="tool_mathjax_save">OK</button>\
<button id="tool_mathjax_cancel">Cancel</button>\
</div>\
<fieldset>\
<legend id="mathjax_legend">Mathematics Editor</legend>\
<label>\
<span id="mathjax_explication">Please type your mathematics in \
<a href="http://en.wikipedia.org/wiki/Help:Displaying_a_formula" target="_blank">TeX</a> code.</span></label>\
<textarea id="mathjax_code_textarea" spellcheck="false"></textarea>\
</fieldset>\
</div>\
</div>'
).insertAfter('#svg_prefs').hide();
// Make the MathEditor draggable. // Add functionality and picture to the save button.
$('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'}); $('#tool_mathjax_save').prepend($.getSvgIcon('ok', true))
.on('click touched', function () {
saveMath();
$('#mathjax').hide();
});
// Add functionality and picture to cancel button. // MathJax preprocessing has to ignore most of the page.
$('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true)) $('body').addClass('tex2jax_ignore');
.on("click touched", function() {
$('#mathjax').hide();
});
// Add functionality and picture to the save button. // Now get (and run) the MathJax Library.
$('#tool_mathjax_save').prepend($.getSvgIcon('ok', true)) $.getScript(mathjaxSrcSecure)
.on("click touched", function() { .done(function (script, textStatus) {
saveMath(); // When MathJax is loaded get the div where the math will be rendered.
$('#mathjax').hide(); MathJax.Hub.queue.Push(function () {
}); math = MathJax.Hub.getAllJax('#mathjax_creator')[0];
console.log(math);
mathjaxLoaded = true;
console.log('MathJax Loaded');
});
})
// If it fails.
.fail(function () {
console.log('Failed loadeing MathJax.');
$.alert('Failed loading MathJax. You will not be able to change the mathematics.');
});
}
// Set the mode.
svgCanvas.setMode('mathjax');
}
}
}],
// MathJax preprocessing has to ignore most of the page. mouseDown: function () {
$('body').addClass('tex2jax_ignore'); if (svgCanvas.getMode() === 'mathjax') {
return {started: true};
}
},
mouseUp: function (opts) {
if (svgCanvas.getMode() === 'mathjax') {
// Get the coordinates from your mouse.
var zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value
locationX = opts.mouse_x / zoom;
locationY = opts.mouse_y / zoom;
// Now get (and run) the MathJax Library. $('#mathjax').show();
$.getScript(mathjaxSrcSecure) return {started: false}; // Otherwise the last selected object dissapears.
.done(function(script, textStatus) { }
},
callback: function () {
$('<style>').text(
'#mathjax fieldset{' +
'padding: 5px;' +
'margin: 5px;' +
'border: 1px solid #DDD;' +
'}' +
'#mathjax label{' +
'display: block;' +
'margin: .5em;' +
'}' +
'#mathjax legend {' +
'max-width:195px;' +
'}' +
'#mathjax_overlay {' +
'position: absolute;' +
'top: 0;' +
'left: 0;' +
'right: 0;' +
'bottom: 0;' +
'background-color: black;' +
'opacity: 0.6;' +
'z-index: 20000;' +
'}' +
'#mathjax_container {' +
'position: absolute;' +
'top: 50px;' +
'padding: 10px;' +
'background-color: #B0B0B0;' +
'border: 1px outset #777;' +
'opacity: 1.0;' +
'font-family: Verdana, Helvetica, sans-serif;' +
'font-size: .8em;' +
'z-index: 20001;' +
'}' +
'#tool_mathjax_back {' +
'margin-left: 1em;' +
'overflow: auto;' +
'}' +
'#mathjax_legend{' +
'font-weight: bold;' +
'font-size:1.1em;' +
'}' +
'#mathjax_code_textarea {\\n' +
'margin: 5px .7em;' +
'overflow: hidden;' +
'width: 416px;' +
'display: block;' +
'height: 100px;' +
'}'
).appendTo('head');
// When MathJax is loaded get the div where the math will be rendered. // Add the MathJax configuration.
MathJax.Hub.queue.Push(function() { // $(mathjaxConfiguration).appendTo('head');
math = MathJax.Hub.getAllJax('#mathjax_creator')[0]; }
console.log(math); };
mathjaxLoaded = true;
console.log('MathJax Loaded');
});
})
// If it fails.
.fail(function() {
console.log("Failed loadeing MathJax.");
$.alert("Failed loading MathJax. You will not be able to change the mathematics.");
});
}
// Set the mode.
svgCanvas.setMode("mathjax");
}
}
}],
mouseDown: function() {
if (svgCanvas.getMode() === "mathjax") {
return {started: true};
}
},
mouseUp: function(opts) {
if (svgCanvas.getMode() === "mathjax") {
// Get the coordinates from your mouse.
var zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value
locationX = opts.mouse_x / zoom;
locationY = opts.mouse_y / zoom;
$('#mathjax').show();
return {started: false}; // Otherwise the last selected object dissapears.
}
},
callback: function() {
$('<style>').text('\
#mathjax fieldset{\
padding: 5px;\
margin: 5px;\
border: 1px solid #DDD;\
}\
#mathjax label{\
display: block;\
margin: .5em;\
}\
#mathjax legend {\
max-width:195px;\
}\
#mathjax_overlay {\
position: absolute;\
top: 0;\
left: 0;\
right: 0;\
bottom: 0;\
background-color: black;\
opacity: 0.6;\
z-index: 20000;\
}\
\
#mathjax_container {\
position: absolute;\
top: 50px;\
padding: 10px;\
background-color: #B0B0B0;\
border: 1px outset #777;\
opacity: 1.0;\
font-family: Verdana, Helvetica, sans-serif;\
font-size: .8em;\
z-index: 20001;\
}\
\
#tool_mathjax_back {\
margin-left: 1em;\
overflow: auto;\
}\
\
#mathjax_legend{\
font-weight: bold;\
font-size:1.1em;\
}\
\
#mathjax_code_textarea {\\n\
margin: 5px .7em;\
overflow: hidden;\
width: 416px;\
display: block;\
height: 100px;\
}\
').appendTo('head');
// Add the MathJax configuration.
//$(mathjaxConfiguration).appendTo('head');
}
};
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, $ */ /* eslint-disable no-var */
/*jslint es5: true, vars: true*/ /* globals svgEditor, svgedit, $ */
/* /*
* ext-overview_window.js * ext-overview_window.js
* *
@@ -10,11 +10,12 @@
*/ */
var overviewWindowGlobals = {}; var overviewWindowGlobals = {};
svgEditor.addExtension("overview_window", function() { 'use strict'; svgEditor.addExtension('overview_window', function () {
'use strict';
// Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and // Disabled in Chrome 48-, see https://github.com/SVG-Edit/svgedit/issues/26 and
// https://code.google.com/p/chromium/issues/detail?id=565120. // https://code.google.com/p/chromium/issues/detail?id=565120.
if (svgedit.browser.isChrome()) { if (svgedit.browser.isChrome()) {
var verIndex = navigator.userAgent.indexOf("Chrome/") + 7; var verIndex = navigator.userAgent.indexOf('Chrome/') + 7;
var chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10); var chromeVersion = parseInt(navigator.userAgent.substring(verIndex), 10);
if (chromeVersion < 49) { if (chromeVersion < 49) {
return; return;
@@ -22,130 +23,129 @@ svgEditor.addExtension("overview_window", function() { 'use strict';
} }
// Define and insert the base html element. // Define and insert the base html element.
var propsWindowHtml= "\ var propsWindowHtml =
<div id=\"overview_window_content_pane\" style=\" width:100%; word-wrap:break-word; display:inline-block; margin-top:20px;\">\ '<div id="overview_window_content_pane" style="width:100%; word-wrap:break-word; display:inline-block; margin-top:20px;">' +
<div id=\"overview_window_content\" style=\"position:relative; left:12px; top:0px;\">\ '<div id="overview_window_content" style="position:relative; left:12px; top:0px;">' +
<div style=\"background-color:#A0A0A0; display:inline-block; overflow:visible;\">\ '<div style="background-color:#A0A0A0; display:inline-block; overflow:visible;">' +
<svg id=\"overviewMiniView\" width=\"150\" height=\"100\" x=\"0\" y=\"0\" viewBox=\"0 0 4800 3600\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\ '<svg id="overviewMiniView" width="150" height="100" x="0" y="0" viewBox="0 0 4800 3600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">' +
<use x=\"0\" y=\"0\" xlink:href=\"#svgroot\"> </use>\ '<use x="0" y="0" xlink:href="#svgroot"> </use>' +
</svg>\ '</svg>' +
<div id=\"overview_window_view_box\" style=\"min-width:50px; min-height:50px; position:absolute; top:30px; left:30px; z-index:5; background-color:rgba(255,0,102,0.3);\">\ '<div id="overview_window_view_box" style="min-width:50px; min-height:50px; position:absolute; top:30px; left:30px; z-index:5; background-color:rgba(255,0,102,0.3);">' +
</div>\ '</div>' +
</div>\ '</div>' +
</div>\ '</div>' +
</div>"; '</div>';
$("#sidepanels").append(propsWindowHtml); $('#sidepanels').append(propsWindowHtml);
// Define dynamic animation of the view box. // Define dynamic animation of the view box.
var updateViewBox = function(){ var updateViewBox = function () {
var portHeight=parseFloat($("#workarea").css("height")); var portHeight = parseFloat($('#workarea').css('height'));
var portWidth=parseFloat($("#workarea").css("width")); var portWidth = parseFloat($('#workarea').css('width'));
var portX=$("#workarea").scrollLeft(); var portX = $('#workarea').scrollLeft();
var portY=$("#workarea").scrollTop(); var portY = $('#workarea').scrollTop();
var windowWidth=parseFloat($("#svgcanvas").css("width")); var windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight=parseFloat($("#svgcanvas").css("height")); var windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth=$("#overviewMiniView").attr("width"); var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight=$("#overviewMiniView").attr("height"); var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX=portX/windowWidth*overviewWidth; var viewBoxX = portX / windowWidth * overviewWidth;
var viewBoxY=portY/windowHeight*overviewHeight; var viewBoxY = portY / windowHeight * overviewHeight;
var viewBoxWidth=portWidth/windowWidth*overviewWidth; var viewBoxWidth = portWidth / windowWidth * overviewWidth;
var viewBoxHeight=portHeight/windowHeight*overviewHeight; var viewBoxHeight = portHeight / windowHeight * overviewHeight;
$("#overview_window_view_box").css("min-width",viewBoxWidth+"px"); $('#overview_window_view_box').css('min-width', viewBoxWidth + 'px');
$("#overview_window_view_box").css("min-height",viewBoxHeight+"px"); $('#overview_window_view_box').css('min-height', viewBoxHeight + 'px');
$("#overview_window_view_box").css("top",viewBoxY+"px"); $('#overview_window_view_box').css('top', viewBoxY + 'px');
$("#overview_window_view_box").css("left",viewBoxX+"px"); $('#overview_window_view_box').css('left', viewBoxX + 'px');
}; };
$("#workarea").scroll(function(){ $('#workarea').scroll(function () {
if(!(overviewWindowGlobals.viewBoxDragging)){ if (!(overviewWindowGlobals.viewBoxDragging)) {
updateViewBox(); updateViewBox();
} }
}); });
$("#workarea").resize(updateViewBox); $('#workarea').resize(updateViewBox);
updateViewBox(); updateViewBox();
// Compensate for changes in zoom and canvas size. // Compensate for changes in zoom and canvas size.
var updateViewDimensions= function(){ var updateViewDimensions = function () {
var viewWidth=$("#svgroot").attr("width"); var viewWidth = $('#svgroot').attr('width');
var viewHeight=$("#svgroot").attr("height"); var viewHeight = $('#svgroot').attr('height');
var viewX=640; var viewX = 640;
var viewY=480; var viewY = 480;
if(svgedit.browser.isIE()) if (svgedit.browser.isIE()) {
{
// This has only been tested with Firefox 10 and IE 9 (without chrome frame). // This has only been tested with Firefox 10 and IE 9 (without chrome frame).
// I am not sure if if is Firefox or IE that is being non compliant here. // I am not sure if if is Firefox or IE that is being non compliant here.
// Either way the one that is noncompliant may become more compliant later. // Either way the one that is noncompliant may become more compliant later.
//TAG:HACK // TAG:HACK
//TAG:VERSION_DEPENDENT // TAG:VERSION_DEPENDENT
//TAG:BROWSER_SNIFFING // TAG:BROWSER_SNIFFING
viewX=0; viewX = 0;
viewY=0; viewY = 0;
} }
var svgWidth_old=$("#overviewMiniView").attr("width"); var svgWidthOld = $('#overviewMiniView').attr('width');
var svgHeight_new=viewHeight/viewWidth*svgWidth_old; var svgHeightNew = viewHeight / viewWidth * svgWidthOld;
$("#overviewMiniView").attr("viewBox",viewX+" "+viewY+" "+viewWidth+" "+viewHeight); $('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
$("#overviewMiniView").attr("height",svgHeight_new); $('#overviewMiniView').attr('height', svgHeightNew);
updateViewBox(); updateViewBox();
}; };
updateViewDimensions(); updateViewDimensions();
// Set up the overview window as a controller for the view port.
overviewWindowGlobals.viewBoxDragging=false;
var updateViewPortFromViewBox = function(){
var windowWidth =parseFloat($("#svgcanvas").css("width" ));
var windowHeight=parseFloat($("#svgcanvas").css("height"));
var overviewWidth =$("#overviewMiniView").attr("width" );
var overviewHeight=$("#overviewMiniView").attr("height");
var viewBoxX=parseFloat($("#overview_window_view_box").css("left"));
var viewBoxY=parseFloat($("#overview_window_view_box").css("top" ));
var portX=viewBoxX/overviewWidth *windowWidth;
var portY=viewBoxY/overviewHeight*windowHeight;
$("#workarea").scrollLeft(portX); // Set up the overview window as a controller for the view port.
$("#workarea").scrollTop(portY); overviewWindowGlobals.viewBoxDragging = false;
var updateViewPortFromViewBox = function () {
var windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX = parseFloat($('#overview_window_view_box').css('left'));
var viewBoxY = parseFloat($('#overview_window_view_box').css('top'));
var portX = viewBoxX / overviewWidth * windowWidth;
var portY = viewBoxY / overviewHeight * windowHeight;
$('#workarea').scrollLeft(portX);
$('#workarea').scrollTop(portY);
}; };
$( "#overview_window_view_box" ).draggable({ containment: "parent" $('#overview_window_view_box').draggable({
,drag: updateViewPortFromViewBox containment: 'parent',
,start:function(){overviewWindowGlobals.viewBoxDragging=true; } drag: updateViewPortFromViewBox,
,stop :function(){overviewWindowGlobals.viewBoxDragging=false;} start: function () { overviewWindowGlobals.viewBoxDragging = true; },
}); stop: function () { overviewWindowGlobals.viewBoxDragging = false; }
$("#overviewMiniView").click(function(evt){ });
$('#overviewMiniView').click(function (evt) {
// Firefox doesn't support evt.offsetX and evt.offsetY. // Firefox doesn't support evt.offsetX and evt.offsetY.
var mouseX=(evt.offsetX || evt.originalEvent.layerX); var mouseX = (evt.offsetX || evt.originalEvent.layerX);
var mouseY=(evt.offsetY || evt.originalEvent.layerY); var mouseY = (evt.offsetY || evt.originalEvent.layerY);
var overviewWidth =$("#overviewMiniView").attr("width" ); var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight=$("#overviewMiniView").attr("height"); var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxWidth =parseFloat($("#overview_window_view_box").css("min-width" )); var viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width'));
var viewBoxHeight=parseFloat($("#overview_window_view_box").css("min-height")); var viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height'));
var viewBoxX=mouseX - 0.5 * viewBoxWidth; var viewBoxX = mouseX - 0.5 * viewBoxWidth;
var viewBoxY=mouseY- 0.5 * viewBoxHeight; var viewBoxY = mouseY - 0.5 * viewBoxHeight;
//deal with constraints // deal with constraints
if(viewBoxX<0){ if (viewBoxX < 0) {
viewBoxX=0; viewBoxX = 0;
} }
if(viewBoxY<0){ if (viewBoxY < 0) {
viewBoxY=0; viewBoxY = 0;
} }
if(viewBoxX+viewBoxWidth>overviewWidth){ if (viewBoxX + viewBoxWidth > overviewWidth) {
viewBoxX=overviewWidth-viewBoxWidth; viewBoxX = overviewWidth - viewBoxWidth;
} }
if(viewBoxY+viewBoxHeight>overviewHeight){ if (viewBoxY + viewBoxHeight > overviewHeight) {
viewBoxY=overviewHeight-viewBoxHeight; viewBoxY = overviewHeight - viewBoxHeight;
} }
$("#overview_window_view_box").css("top",viewBoxY+"px"); $('#overview_window_view_box').css('top', viewBoxY + 'px');
$("#overview_window_view_box").css("left",viewBoxX+"px"); $('#overview_window_view_box').css('left', viewBoxX + 'px');
updateViewPortFromViewBox(); updateViewPortFromViewBox();
}); });
return { return {
name: "overview window", name: 'overview window',
canvasUpdated: updateViewDimensions, canvasUpdated: updateViewDimensions,
workareaResized: updateViewBox workareaResized: updateViewBox
}; };

View File

@@ -1,5 +1,4 @@
/*globals svgEditor, svgCanvas*/ /* globals svgEditor, svgCanvas */
/*jslint eqeq: true*/
/* /*
* ext-panning.js * ext-panning.js
* *
@@ -8,12 +7,13 @@
* Copyright(c) 2013 Luis Aguirre * Copyright(c) 2013 Luis Aguirre
* *
*/ */
/* /*
This is a very basic SVG-Edit extension to let tablet/mobile devices panning without problem This is a very basic SVG-Edit extension to let tablet/mobile devices panning without problem
*/ */
svgEditor.addExtension('ext-panning', function() {'use strict'; svgEditor.addExtension('ext-panning', function () {
'use strict';
return { return {
name: 'Extension Panning', name: 'Extension Panning',
svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml', svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml',
@@ -22,19 +22,19 @@ svgEditor.addExtension('ext-panning', function() {'use strict';
type: 'mode', type: 'mode',
title: 'Panning', title: 'Panning',
events: { events: {
click: function() { click: function () {
svgCanvas.setMode('ext-panning'); svgCanvas.setMode('ext-panning');
} }
} }
}], }],
mouseDown: function() { mouseDown: function () {
if (svgCanvas.getMode() == 'ext-panning') { if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true); svgEditor.setPanning(true);
return {started: true}; return {started: true};
} }
}, },
mouseUp: function() { mouseUp: function () {
if (svgCanvas.getMode() == 'ext-panning') { if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false); svgEditor.setPanning(false);
return { return {
keep: false, keep: false,

View File

@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg"> <svg xmlns="http://www.w3.org/2000/svg">
<g id="ext-panning"> <g id="ext-panning">
<svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"> <svg xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
<path fill="#7f0000" stroke="#000000" stroke-width="10" d="m1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z"></path> <path fill="#7f0000" stroke="#000000" stroke-width="10" d="m1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z"></path>
</svg> </svg>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 724 B

View File

@@ -1,22 +1,22 @@
/*globals $, svgCanvas, svgEditor*/ /* eslint-disable no-var */
/*jslint regexp:true*/ /* globals $, svgCanvas, svgEditor */
// TODO: Might add support for "exportImage" custom // TODO: Might add support for "exportImage" custom
// handler as in "ext-server_opensave.js" (and in savefile.php) // handler as in "ext-server_opensave.js" (and in savefile.php)
svgEditor.addExtension("php_savefile", { svgEditor.addExtension('php_savefile', {
callback: function() { callback: function () {
'use strict'; 'use strict';
function getFileNameFromTitle () { function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle(); var title = svgCanvas.getDocumentTitle();
return $.trim(title); return $.trim(title);
} }
var save_svg_action = svgEditor.curConfig.extPath + 'savefile.php'; var saveSvgAction = svgEditor.curConfig.extPath + 'savefile.php';
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function(win, data) { save: function (win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data,
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
$.post(save_svg_action, {output_svg: svg, filename: filename}); $.post(saveSvgAction, {output_svg: svg, filename: filename});
} }
}); });
} }

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, svgedit, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true, todo: true */ /* globals svgEditor, svgCanvas, $ */
/* /*
* ext-polygon.js * ext-polygon.js
* *
@@ -8,9 +8,10 @@
* All rights reserved * All rights reserved
* *
*/ */
svgEditor.addExtension("polygon", function(S) {'use strict'; svgEditor.addExtension('polygon', function (S) {
'use strict';
var // NS = svgedit.NS, var // NS = svgedit.NS,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
// addElem = S.addSvgElementFromJson, // addElem = S.addSvgElementFromJson,
selElems, selElems,
@@ -18,53 +19,51 @@ svgEditor.addExtension("polygon", function(S) {'use strict';
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG, // newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
// edg = 0, // edg = 0,
// undoCommand = "Not image"; // undoCommand = 'Not image';
started, newFO; started, newFO;
// var ccZoom; // var ccZoom;
// var wEl, hEl; // var wEl, hEl;
// var wOffset, hOffset; // var wOffset, hOffset;
// var ccRBG; // var ccRBG;
var ccRgbEl; // var ccOpacity;
// var ccOpacity; // var brushW, brushH;
// var brushW, brushH;
var shape; // var ccDebug = document.getElementById('debugpanel');
// var ccDebug = document.getElementById('debugpanel'); /* var properlySourceSizeTextArea = function(){
// TODO: remove magic numbers here and get values from CSS
/* var properlySourceSizeTextArea = function(){ var height = $('#svg_source_container').height() - 80;
// TODO: remove magic numbers here and get values from CSS $('#svg_source_textarea').css('height', height);
var height = $('#svg_source_container').height() - 80; }; */
$('#svg_source_textarea').css('height', height); function showPanel (on) {
}; */ var fcRules = $('#fc_rules');
function showPanel(on){ if (!fcRules.length) {
var fc_rules = $('#fc_rules'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
if (!fc_rules.length) { }
fc_rules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
} $('#polygon_panel').toggle(on);
fc_rules.text(!on ? "" : " #tool_topath { display: none !important; }"); }
$('#polygon_panel').toggle(on);
}
/* /*
function toggleSourceButtons(on){ function toggleSourceButtons(on){
$('#tool_source_save, #tool_source_cancel').toggle(!on); $('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#polygon_save, #polygon_cancel').toggle(on); $('#polygon_save, #polygon_cancel').toggle(on);
} }
*/ */
function setAttr(attr, val){ function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val); svgCanvas.changeSelectedAttribute(attr, val);
S.call("changed", selElems); S.call('changed', selElems);
} }
function cot(n){ function cot (n) {
return 1 / Math.tan(n); return 1 / Math.tan(n);
} }
function sec(n){ function sec (n) {
return 1 / Math.cos(n); return 1 / Math.cos(n);
} }
/** /**
* Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3 * Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3
@@ -95,13 +94,13 @@ svgEditor.addExtension("polygon", function(S) {'use strict';
$.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){ $.post(ajaxEndpoint, {'tex': tex, 'display': 'inline'}, function(data){
var children = data.documentElement.childNodes; var children = data.documentElement.childNodes;
while (children.length > 0) { while (children.length > 0) {
mrow.appendChild(svgdoc.adoptNode(children[0], true)); mrow.appendChild(svgdoc.adoptNode(children[0], true));
} }
S.sanitizeSvg(math); S.sanitizeSvg(math);
S.call("changed", [elt]); S.call('changed', [elt]);
}); });
elt.replaceChild(math, elt.firstChild); elt.replaceChild(math, elt.firstChild);
S.call("changed", [elt]); S.call('changed', [elt]);
svgCanvas.clearSelection(); svgCanvas.clearSelection();
} catch(e) { } catch(e) {
console.log(e); console.log(e);
@@ -111,184 +110,177 @@ svgEditor.addExtension("polygon", function(S) {'use strict';
return true; return true;
} }
*/ */
return { return {
name: "polygon", name: 'polygon',
svgicons: svgEditor.curConfig.extPath + "polygon-icons.svg", svgicons: svgEditor.curConfig.extPath + 'polygon-icons.svg',
buttons: [{ buttons: [{
id: "tool_polygon", id: 'tool_polygon',
type: "mode", type: 'mode',
title: "Polygon Tool", title: 'Polygon Tool',
position: 11, position: 11,
events: { events: {
'click': function(){ 'click': function () {
svgCanvas.setMode('polygon'); svgCanvas.setMode('polygon');
showPanel(true); showPanel(true);
} }
} }
}], }],
context_tools: [{ context_tools: [{
type: "input", type: 'input',
panel: "polygon_panel", panel: 'polygon_panel',
title: "Number of Sides", title: 'Number of Sides',
id: "polySides", id: 'polySides',
label: "sides", label: 'sides',
size: 3, size: 3,
defval: 5, defval: 5,
events: { events: {
change: function(){ change: function () {
setAttr('sides', this.value); setAttr('sides', this.value);
} }
} }
}], }],
callback: function(){ callback: function () {
$('#polygon_panel').hide();
$('#polygon_panel').hide();
var endChanges = function () {
var endChanges = function(){ };
};
// TODO: Needs to be done after orig icon loads
// TODO: Needs to be done after orig icon loads setTimeout(function () {
setTimeout(function(){ // Create source save/cancel buttons
// Create source save/cancel buttons /* var save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () {
var save = $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo("#tool_source_back").click(function(){ if (!editingitex) {
if (!editingitex) {
return; return;
} }
// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint? // Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
if (!setItexString($('#svg_source_textarea').val())) { /*
$.confirm("Errors found. Revert to original?", function(ok){ if (!setItexString($('#svg_source_textarea').val())) {
if (!ok) { $.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) {
return false; return false;
} }
endChanges(); endChanges();
}); });
} } else { */
else { endChanges();
endChanges(); // }
} // setSelectMode();
// setSelectMode(); });
});
/* var cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () {
var cancel = $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo("#tool_source_back").click(function(){ endChanges();
endChanges(); });
}); }, 3000);
},
}, 3000); mouseDown: function (opts) {
}, // var e = opts.event;
mouseDown: function(opts){ var rgb = svgCanvas.getColor('fill');
// var e = opts.event; // var ccRgbEl = rgb.substring(1, rgb.length);
var rgb = svgCanvas.getColor("fill"); var sRgb = svgCanvas.getColor('stroke');
ccRgbEl = rgb.substring(1, rgb.length); // ccSRgbEl = sRgb.substring(1, rgb.length);
var sRgb = svgCanvas.getColor("stroke"); var sWidth = svgCanvas.getStrokeWidth();
// ccSRgbEl = sRgb.substring(1, rgb.length);
var sWidth = svgCanvas.getStrokeWidth(); if (svgCanvas.getMode() === 'polygon') {
started = true;
if (svgCanvas.getMode() == "polygon") {
started = true; newFO = S.addSvgElementFromJson({
'element': 'polygon',
newFO = S.addSvgElementFromJson({ 'attr': {
"element": "polygon", 'cx': opts.start_x,
"attr": { 'cy': opts.start_y,
"cx": opts.start_x, 'id': S.getNextId(),
"cy": opts.start_y, 'shape': 'regularPoly',
"id": S.getNextId(), 'sides': document.getElementById('polySides').value,
"shape": "regularPoly", 'orient': 'x',
"sides": document.getElementById("polySides").value, 'edge': 0,
"orient": "x", 'fill': rgb,
"edge": 0, 'strokecolor': sRgb,
"fill": rgb, 'strokeWidth': sWidth
"strokecolor": sRgb, }
"strokeWidth": sWidth });
}
}); return {
started: true
return { };
started: true
};
}
},
mouseMove: function(opts){
if (!started) {
return;
} }
if (svgCanvas.getMode() == "polygon") { },
// var e = opts.event; mouseMove: function (opts) {
var x = opts.mouse_x; if (!started) {
var y = opts.mouse_y; return;
var c = $(newFO).attr(["cx", "cy", "sides", "orient", "fill", "strokecolor", "strokeWidth"]); }
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides, if (svgCanvas.getMode() === 'polygon') {
// var e = opts.event;
var x = opts.mouse_x;
var y = opts.mouse_y;
var c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
var cx = c.cx, cy = c.cy, fill = c.fill, strokecolor = c.strokecolor, strokewidth = c.strokeWidth, sides = c.sides,
// orient = c.orient, // orient = c.orient,
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5; edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
newFO.setAttributeNS(null, "edge", edg); newFO.setAttributeNS(null, 'edge', edg);
var inradius = (edg / 2) * cot(Math.PI / sides); var inradius = (edg / 2) * cot(Math.PI / sides);
var circumradius = inradius * sec(Math.PI / sides); var circumradius = inradius * sec(Math.PI / sides);
var points = ''; var points = '';
var s; var s;
for (s = 0; sides >= s; s++) { for (s = 0; sides >= s; s++) {
var angle = 2.0 * Math.PI * s / sides; var angle = 2.0 * Math.PI * s / sides;
x = (circumradius * Math.cos(angle)) + cx; x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy; y = (circumradius * Math.sin(angle)) + cy;
points += x + ',' + y + ' '; points += x + ',' + y + ' ';
} }
//var poly = newFO.createElementNS(NS.SVG, 'polygon'); // var poly = newFO.createElementNS(NS.SVG, 'polygon');
newFO.setAttributeNS(null, 'points', points); newFO.setAttributeNS(null, 'points', points);
newFO.setAttributeNS(null, 'fill', fill); newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor); newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokewidth); newFO.setAttributeNS(null, 'stroke-width', strokewidth);
// newFO.setAttributeNS(null, 'transform', "rotate(-90)"); // newFO.setAttributeNS(null, 'transform', 'rotate(-90)');
shape = newFO.getAttributeNS(null, 'shape'); // var shape = newFO.getAttributeNS(null, 'shape');
//newFO.appendChild(poly); // newFO.appendChild(poly);
//DrawPoly(cx, cy, sides, edg, orient); // DrawPoly(cx, cy, sides, edg, orient);
return { return {
started: true started: true
}; };
} }
},
},
mouseUp: function (opts) {
mouseUp: function(opts){ if (svgCanvas.getMode() === 'polygon') {
if (svgCanvas.getMode() == "polygon") { var attrs = $(newFO).attr('edge');
var attrs = $(newFO).attr("edge"); var keep = (attrs.edge !== '0');
var keep = (attrs.edge != 0); // svgCanvas.addToSelection([newFO], true);
// svgCanvas.addToSelection([newFO], true); return {
return { keep: keep,
keep: keep, element: newFO
element: newFO };
}; }
} },
selectedChanged: function (opts) {
}, // Use this to update the current selected elements
selectedChanged: function(opts){ selElems = opts.elems;
// Use this to update the current selected elements
selElems = opts.elems; var i = selElems.length;
var i = selElems.length; while (i--) {
var elem = selElems[i];
while (i--) { if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
var elem = selElems[i]; if (opts.selectedElement && !opts.multiselected) {
if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') { $('#polySides').val(elem.getAttribute('sides'));
if (opts.selectedElement && !opts.multiselected) {
$('#polySides').val(elem.getAttribute("sides")); showPanel(true);
} else {
showPanel(true); showPanel(false);
} }
else { } else {
showPanel(false); showPanel(false);
} }
} }
else { },
showPanel(false); elementChanged: function (opts) {
} // var elem = opts.elems[0];
} }
}, };
elementChanged: function(opts){
// var elem = opts.elems[0];
}
};
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, svgCanvas, canvg, $, top*/ /* eslint-disable no-var */
/*jslint vars: true*/ /* globals svgEditor, svgedit, svgCanvas, canvg, $, top */
/* /*
* ext-server_moinsave.js * ext-server_moinsave.js
* *
@@ -12,48 +12,47 @@
* *
*/ */
svgEditor.addExtension("server_opensave", { svgEditor.addExtension('server_opensave', {
callback: function() {'use strict'; callback: function () {
'use strict';
var Utils = svgedit.utilities; var Utils = svgedit.utilities;
var save_svg_action = '/+modify'; var saveSvgAction = '/+modify';
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
var target = $('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); /* var target = */ $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function(win, data) { save: function (win, data) {
var svg = "<?xml version=\"1.0\"?>\n" + data; var svg = '<?xml version="1.0"?>\n' + data;
var qstr = $.param.querystring(); var qstr = $.param.querystring();
var name = qstr.substr(9).split('/+get/')[1]; var name = qstr.substr(9).split('/+get/')[1];
var svg_data = Utils.encode64(svg); var svgData = Utils.encode64(svg);
if(!$('#export_canvas').length) { if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
} }
var c = $('#export_canvas')[0]; var c = $('#export_canvas')[0];
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () { Utils.buildCanvgCallback(function () {
canvg(c, svg, {renderCallback: function() { canvg(c, svg, {renderCallback: function () {
var datauri = c.toDataURL('image/png'); var datauri = c.toDataURL('image/png');
// var uiStrings = svgEditor.uiStrings; // var uiStrings = svgEditor.uiStrings;
var png_data = Utils.encode64(datauri); // Brett: This encoding seems unnecessary var pngData = Utils.encode64(datauri); // Brett: This encoding seems unnecessary
var form = $('<form>').attr({ /* var form = */ $('<form>').attr({
method: 'post', method: 'post',
action: save_svg_action + '/' + name, action: saveSvgAction + '/' + name,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="png_data" value="' + png_data + '">') }).append('<input type="hidden" name="png_data" value="' + pngData + '">')
.append('<input type="hidden" name="filepath" value="' + svg_data + '">') .append('<input type="hidden" name="filepath" value="' + svgData + '">')
.append('<input type="hidden" name="filename" value="' + 'drawing.svg">') .append('<input type="hidden" name="filename" value="' + 'drawing.svg">')
.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">') .append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
.appendTo('body') .appendTo('body')
.submit().remove(); .submit().remove();
}}); }});
})(); })();
alert("Saved! Return to Item View!"); alert('Saved! Return to Item View!');
top.window.location = '/'+name; top.window.location = '/' + name;
} }
}); });
} }
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, svgCanvas, canvg, $*/ /* eslint-disable no-var */
/*jslint eqeq: true, browser:true*/ /* globals svgEditor, svgedit, svgCanvas, canvg, $ */
/* /*
* ext-server_opensave.js * ext-server_opensave.js
* *
@@ -9,15 +9,15 @@
* *
*/ */
svgEditor.addExtension("server_opensave", { svgEditor.addExtension('server_opensave', {
callback: function() { callback: function () {
'use strict'; 'use strict';
function getFileNameFromTitle () { function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle(); var title = svgCanvas.getDocumentTitle();
// We convert (to underscore) only those disallowed Win7 file name characters // We convert (to underscore) only those disallowed Win7 file name characters
return $.trim(title).replace(/[\/\\:*?"<>|]/g, '_'); return $.trim(title).replace(/[/\\:*?"<>|]/g, '_');
} }
function xhtmlEscape(str) { function xhtmlEscape (str) {
return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways return str.replace(/&(?!amp;)/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;'); // < is actually disallowed above anyways
} }
function clientDownloadSupport (filename, suffix, uri) { function clientDownloadSupport (filename, suffix, uri) {
@@ -29,17 +29,17 @@ svgEditor.addExtension("server_opensave", {
return true; return true;
} }
} }
var open_svg_action, import_svg_action, import_img_action, var openSvgAction, importSvgAction, importImgAction,
open_svg_form, import_svg_form, import_img_form, openSvgForm, importSvgForm, importImgForm,
save_svg_action = svgEditor.curConfig.extPath + 'filesave.php', saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php',
save_img_action = svgEditor.curConfig.extPath + 'filesave.php', saveImgAction = svgEditor.curConfig.extPath + 'filesave.php',
// Create upload target (hidden iframe) // Create upload target (hidden iframe)
cancelled = false, cancelled = false,
Utils = svgedit.utilities; Utils = svgedit.utilities;
$('<iframe name="output_frame" src="#"/>').hide().appendTo('body'); $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({ svgEditor.setCustomHandlers({
save: function(win, data) { save: function (win, data) {
var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works var svg = '<?xml version="1.0" encoding="UTF-8"?>\n' + data, // Firefox doesn't seem to know it is UTF-8 (no matter whether we use or skip the clientDownload code) despite the Content-Disposition header containing UTF-8, but adding the encoding works
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
@@ -49,7 +49,7 @@ svgEditor.addExtension("server_opensave", {
$('<form>').attr({ $('<form>').attr({
method: 'post', method: 'post',
action: save_svg_action, action: saveSvgAction,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape(svg) + '">') }).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape(svg) + '">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">') .append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
@@ -64,7 +64,7 @@ svgEditor.addExtension("server_opensave", {
} }
$('<form>').attr({ $('<form>').attr({
method: 'post', method: 'post',
action: save_img_action, action: saveImgAction,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">') }).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="application/pdf">') .append('<input type="hidden" name="mime" value="application/pdf">')
@@ -73,46 +73,46 @@ svgEditor.addExtension("server_opensave", {
.submit().remove(); .submit().remove();
}, },
// Todo: Integrate this extension with a new built-in exportWindowType, "download" // Todo: Integrate this extension with a new built-in exportWindowType, "download"
exportImage: function(win, data) { exportImage: function (win, data) {
var c, var c,
issues = data.issues, issues = data.issues,
mimeType = data.mimeType, mimeType = data.mimeType,
quality = data.quality; quality = data.quality;
if(!$('#export_canvas').length) { if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body'); $('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
} }
c = $('#export_canvas')[0]; c = $('#export_canvas')[0];
c.width = svgCanvas.contentW; c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH; c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () { Utils.buildCanvgCallback(function () {
canvg(c, data.svg, {renderCallback: function() { canvg(c, data.svg, {renderCallback: function () {
var pre, filename, suffix, var pre, filename, suffix,
datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType), datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType),
// uiStrings = svgEditor.uiStrings, // uiStrings = svgEditor.uiStrings,
note = ''; note = '';
// Check if there are issues // Check if there are issues
if (issues.length) { if (issues.length) {
pre = "\n \u2022 "; pre = '\n \u2022 ';
note += ("\n\n" + pre + issues.join(pre)); note += ('\n\n' + pre + issues.join(pre));
} }
if(note.length) { if (note.length) {
alert(note); alert(note);
} }
filename = getFileNameFromTitle(); filename = getFileNameFromTitle();
suffix = '.' + data.type.toLowerCase(); suffix = '.' + data.type.toLowerCase();
if (clientDownloadSupport(filename, suffix, datauri)) { if (clientDownloadSupport(filename, suffix, datauri)) {
return; return;
} }
$('<form>').attr({ $('<form>').attr({
method: 'post', method: 'post',
action: save_img_action, action: saveImgAction,
target: 'output_frame' target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">') }).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="' + mimeType + '">') .append('<input type="hidden" name="mime" value="' + mimeType + '">')
@@ -125,81 +125,80 @@ svgEditor.addExtension("server_opensave", {
}); });
// Do nothing if client support is found // Do nothing if client support is found
if (window.FileReader) {return;} if (window.FileReader) { return; }
// Change these to appropriate script file // Change these to appropriate script file
open_svg_action = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg'; openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
import_svg_action = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg'; importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
import_img_action = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img'; importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
// Set up function for PHP uploader to use // Set up function for PHP uploader to use
svgEditor.processFile = function(str64, type) { svgEditor.processFile = function (str64, type) {
var xmlstr; var xmlstr;
if (cancelled) { if (cancelled) {
cancelled = false; cancelled = false;
return; return;
} }
$('#dialog_box').hide(); $('#dialog_box').hide();
if (type !== 'import_img') { if (type !== 'import_img') {
xmlstr = Utils.decode64(str64); xmlstr = Utils.decode64(str64);
} }
switch (type) { switch (type) {
case 'load_svg': case 'load_svg':
svgCanvas.clear(); svgCanvas.clear();
svgCanvas.setSvgString(xmlstr); svgCanvas.setSvgString(xmlstr);
svgEditor.updateCanvas(); svgEditor.updateCanvas();
break; break;
case 'import_svg': case 'import_svg':
svgCanvas.importSvgString(xmlstr); svgCanvas.importSvgString(xmlstr);
svgEditor.updateCanvas(); svgEditor.updateCanvas();
break; break;
case 'import_img': case 'import_img':
svgCanvas.setGoodImage(str64); svgCanvas.setGoodImage(str64);
break; break;
} }
}; };
// Create upload form // Create upload form
open_svg_form = $('<form>'); openSvgForm = $('<form>');
open_svg_form.attr({ openSvgForm.attr({
enctype: 'multipart/form-data', enctype: 'multipart/form-data',
method: 'post', method: 'post',
action: open_svg_action, action: openSvgAction,
target: 'output_frame' target: 'output_frame'
}); });
// Create import form // Create import form
import_svg_form = open_svg_form.clone().attr('action', import_svg_action); importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
// Create image form // Create image form
import_img_form = open_svg_form.clone().attr('action', import_img_action); importImgForm = openSvgForm.clone().attr('action', importImgAction);
// It appears necessary to rebuild this input every time a file is // It appears necessary to rebuild this input every time a file is
// selected so the same file can be picked and the change event can fire. // selected so the same file can be picked and the change event can fire.
function rebuildInput(form) { function rebuildInput (form) {
form.empty(); form.empty();
var inp = $('<input type="file" name="svg_file">').appendTo(form); var inp = $('<input type="file" name="svg_file">').appendTo(form);
function submit () {
function submit() {
// This submits the form, which returns the file data using svgEditor.processFile() // This submits the form, which returns the file data using svgEditor.processFile()
form.submit(); form.submit();
rebuildInput(form); rebuildInput(form);
$.process_cancel("Uploading...", function() { $.process_cancel('Uploading...', function () {
cancelled = true; cancelled = true;
$('#dialog_box').hide(); $('#dialog_box').hide();
}); });
} }
if(form[0] == open_svg_form[0]) { if (form[0] === openSvgForm[0]) {
inp.change(function() { inp.change(function () {
// This takes care of the "are you sure" dialog box // This takes care of the "are you sure" dialog box
svgEditor.openPrep(function(ok) { svgEditor.openPrep(function (ok) {
if(!ok) { if (!ok) {
rebuildInput(form); rebuildInput(form);
return; return;
} }
@@ -207,22 +206,21 @@ svgEditor.addExtension("server_opensave", {
}); });
}); });
} else { } else {
inp.change(function() { inp.change(function () {
// This submits the form, which returns the file data using svgEditor.processFile() // This submits the form, which returns the file data using svgEditor.processFile()
submit(); submit();
}); });
} }
} }
// Create the input elements // Create the input elements
rebuildInput(open_svg_form); rebuildInput(openSvgForm);
rebuildInput(import_svg_form); rebuildInput(importSvgForm);
rebuildInput(import_img_form); rebuildInput(importImgForm);
// Add forms to buttons // Add forms to buttons
$("#tool_open").show().prepend(open_svg_form); $('#tool_open').show().prepend(openSvgForm);
$("#tool_import").show().prepend(import_svg_form); $('#tool_import').show().prepend(importSvgForm);
$("#tool_image").prepend(import_img_form); $('#tool_image').prepend(importImgForm);
} }
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, $, DOMParser*/ /* eslint-disable no-var */
/*jslint es5: true, vars: true, eqeq: true*/ /* globals svgEditor, $, DOMParser */
/* /*
* ext-shapes.js * ext-shapes.js
* *
@@ -10,11 +10,12 @@
* *
*/ */
svgEditor.addExtension('shapes', function() {'use strict'; svgEditor.addExtension('shapes', function () {
var current_d, cur_shape_id; 'use strict';
var currentD, curShapeId;
var canv = svgEditor.canvas; var canv = svgEditor.canvas;
var cur_shape; var curShape;
var start_x, start_y; var startX, startY;
var svgroot = canv.getRootElem(); var svgroot = canv.getRootElem();
var lastBBox = {}; var lastBBox = {};
@@ -73,67 +74,66 @@ svgEditor.addExtension('shapes', function() {'use strict';
} }
}; };
var cur_lib = library.basic; var curLib = library.basic;
var mode_id = 'shapelib'; var modeId = 'shapelib';
var startClientPos = {}; var startClientPos = {};
function loadIcons() { function loadIcons () {
$('#shape_buttons').empty().append(cur_lib.buttons); $('#shape_buttons').empty().append(curLib.buttons);
} }
function makeButtons(cat, shapes) { function makeButtons (cat, shapes) {
var size = cur_lib.size || 300; var size = curLib.size || 300;
var fill = cur_lib.fill || false; var fill = curLib.fill || false;
var off = size * 0.05; var off = size * 0.05;
var vb = [-off, -off, size + off*2, size + off*2].join(' '); var vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
var stroke = fill ? 0: (size/30); var stroke = fill ? 0 : (size / 30);
var shape_icon = new DOMParser().parseFromString( var shapeIcon = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="'+(fill?'#333':'none')+'" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>', '<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>',
'text/xml'); 'text/xml');
var width = 24; var width = 24;
var height = 24; var height = 24;
shape_icon.documentElement.setAttribute('width', width); shapeIcon.documentElement.setAttribute('width', width);
shape_icon.documentElement.setAttribute('height', height); shapeIcon.documentElement.setAttribute('height', height);
var svg_elem = $(document.importNode(shape_icon.documentElement,true)); var svgElem = $(document.importNode(shapeIcon.documentElement, true));
var data = shapes.data; var data = shapes.data;
cur_lib.buttons = []; curLib.buttons = [];
var id; var id;
for (id in data) { for (id in data) {
var path_d = data[id]; var pathD = data[id];
var icon = svg_elem.clone(); var icon = svgElem.clone();
icon.find('path').attr('d', path_d); icon.find('path').attr('d', pathD);
var icon_btn = icon.wrap('<div class="tool_button">').parent().attr({ var iconBtn = icon.wrap('<div class="tool_button">').parent().attr({
id: mode_id + '_' + id, id: modeId + '_' + id,
title: id title: id
}); });
// Store for later use // Store for later use
cur_lib.buttons.push(icon_btn[0]); curLib.buttons.push(iconBtn[0]);
} }
} }
function loadLibrary(cat_id) { function loadLibrary (catId) {
var lib = library[catId];
var lib = library[cat_id];
if (!lib) { if (!lib) {
$('#shape_buttons').html('Loading...'); $('#shape_buttons').html('Loading...');
$.getJSON(svgEditor.curConfig.extPath + 'shapelib/' + cat_id + '.json', function(result) { $.getJSON(svgEditor.curConfig.extPath + 'shapelib/' + catId + '.json', function (result) {
cur_lib = library[cat_id] = { curLib = library[catId] = {
data: result.data, data: result.data,
size: result.size, size: result.size,
fill: result.fill fill: result.fill
}; };
makeButtons(cat_id, result); makeButtons(catId, result);
loadIcons(); loadIcons();
}); });
return; return;
} }
cur_lib = lib; curLib = lib;
if (!lib.buttons.length) {makeButtons(cat_id, lib);} if (!lib.buttons.length) { makeButtons(catId, lib); }
loadIcons(); loadIcons();
} }
@@ -145,53 +145,52 @@ svgEditor.addExtension('shapes', function() {'use strict';
position: 6, position: 6,
title: 'Shape library', title: 'Shape library',
events: { events: {
click: function() { click: function () {
canv.setMode(mode_id); canv.setMode(modeId);
} }
} }
}], }],
callback: function() { callback: function () {
$('<style>').text('\ $('<style>').text(
#shape_buttons {\ '#shape_buttons {' +
overflow: auto;\ 'overflow: auto;' +
width: 180px;\ 'width: 180px;' +
max-height: 300px;\ 'max-height: 300px;' +
display: table-cell;\ 'display: table-cell;' +
vertical-align: middle;\ 'vertical-align: middle;' +
}\ '}' +
\ '#shape_cats {' +
#shape_cats {\ 'min-width: 110px;' +
min-width: 110px;\ 'display: table-cell;' +
display: table-cell;\ 'vertical-align: middle;' +
vertical-align: middle;\ 'height: 300px;' +
height: 300px;\ '}' +
}\ '#shape_cats > div {' +
#shape_cats > div {\ 'line-height: 1em;' +
line-height: 1em;\ 'padding: .5em;' +
padding: .5em;\ 'border:1px solid #B0B0B0;' +
border:1px solid #B0B0B0;\ 'background: #E8E8E8;' +
background: #E8E8E8;\ 'margin-bottom: -1px;' +
margin-bottom: -1px;\ '}' +
}\ '#shape_cats div:hover {' +
#shape_cats div:hover {\ 'background: #FFFFCC;' +
background: #FFFFCC;\ '}' +
}\ '#shape_cats div.current {' +
#shape_cats div.current {\ 'font-weight: bold;' +
font-weight: bold;\ '}').appendTo('head');
}').appendTo('head');
var btn_div = $('<div id="shape_buttons">'); var btnDiv = $('<div id="shape_buttons">');
$('#tools_shapelib > *').wrapAll(btn_div); $('#tools_shapelib > *').wrapAll(btnDiv);
var shower = $('#tools_shapelib_show'); var shower = $('#tools_shapelib_show');
loadLibrary('basic'); loadLibrary('basic');
// Do mouseup on parent element rather than each button // Do mouseup on parent element rather than each button
$('#shape_buttons').mouseup(function(evt) { $('#shape_buttons').mouseup(function (evt) {
var btn = $(evt.target).closest('div.tool_button'); var btn = $(evt.target).closest('div.tool_button');
if (!btn.length) {return;} if (!btn.length) { return; }
var copy = btn.children().clone(); var copy = btn.children().clone();
shower.children(':not(.flyout_arrow_horiz)').remove(); shower.children(':not(.flyout_arrow_horiz)').remove();
@@ -199,22 +198,22 @@ svgEditor.addExtension('shapes', function() {'use strict';
.append(copy) .append(copy)
.attr('data-curopt', '#' + btn[0].id) // This sets the current mode .attr('data-curopt', '#' + btn[0].id) // This sets the current mode
.mouseup(); .mouseup();
canv.setMode(mode_id); canv.setMode(modeId);
cur_shape_id = btn[0].id.substr((mode_id+'_').length); curShapeId = btn[0].id.substr((modeId + '_').length);
current_d = cur_lib.data[cur_shape_id]; currentD = curLib.data[curShapeId];
$('.tools_flyout').fadeOut(); $('.tools_flyout').fadeOut();
}); });
var shape_cats = $('<div id="shape_cats">'); var shapeCats = $('<div id="shape_cats">');
var cat_str = ''; var catStr = '';
$.each(categories, function(id, label) { $.each(categories, function (id, label) {
cat_str += '<div data-cat=' + id + '>' + label + '</div>'; catStr += '<div data-cat=' + id + '>' + label + '</div>';
}); });
shape_cats.html(cat_str).children().bind('mouseup', function() { shapeCats.html(catStr).children().bind('mouseup', function () {
var catlink = $(this); var catlink = $(this);
catlink.siblings().removeClass('current'); catlink.siblings().removeClass('current');
catlink.addClass('current'); catlink.addClass('current');
@@ -224,134 +223,133 @@ svgEditor.addExtension('shapes', function() {'use strict';
return false; return false;
}); });
shape_cats.children().eq(0).addClass('current'); shapeCats.children().eq(0).addClass('current');
$('#tools_shapelib').append(shape_cats); $('#tools_shapelib').append(shapeCats);
shower.mouseup(function() { shower.mouseup(function () {
canv.setMode(current_d ? mode_id : 'select'); canv.setMode(currentD ? modeId : 'select');
}); });
$('#tool_shapelib').remove(); $('#tool_shapelib').remove();
var h = $('#tools_shapelib').height(); var h = $('#tools_shapelib').height();
$('#tools_shapelib').css({ $('#tools_shapelib').css({
'margin-top': -(h/2 - 15), 'margin-top': -(h / 2 - 15),
'margin-left': 3 'margin-left': 3
}); });
}, },
mouseDown: function(opts) { mouseDown: function (opts) {
var mode = canv.getMode(); var mode = canv.getMode();
if (mode !== mode_id) {return;} if (mode !== modeId) { return; }
startX = opts.start_x;
var x = startX;
startY = opts.start_y;
var y = startY;
var curStyle = canv.getStyle();
start_x = opts.start_x;
var x = start_x;
start_y = opts.start_y;
var y = start_y;
var cur_style = canv.getStyle();
startClientPos.x = opts.event.clientX; startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY; startClientPos.y = opts.event.clientY;
cur_shape = canv.addSvgElementFromJson({ curShape = canv.addSvgElementFromJson({
'element': 'path', 'element': 'path',
'curStyles': true, 'curStyles': true,
'attr': { 'attr': {
'd': current_d, 'd': currentD,
'id': canv.getNextId(), 'id': canv.getNextId(),
'opacity': cur_style.opacity / 2, 'opacity': curStyle.opacity / 2,
'style': 'pointer-events:none' 'style': 'pointer-events:none'
} }
}); });
// Make sure shape uses absolute values // Make sure shape uses absolute values
if (/[a-z]/.test(current_d)) { if (/[a-z]/.test(currentD)) {
current_d = cur_lib.data[cur_shape_id] = canv.pathActions.convertPath(cur_shape); currentD = curLib.data[curShapeId] = canv.pathActions.convertPath(curShape);
cur_shape.setAttribute('d', current_d); curShape.setAttribute('d', currentD);
canv.pathActions.fixEnd(cur_shape); canv.pathActions.fixEnd(curShape);
} }
cur_shape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')'); curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
canv.recalculateDimensions(cur_shape); canv.recalculateDimensions(curShape);
var tlist = canv.getTransformList(cur_shape); /* var tlist = */ canv.getTransformList(curShape);
lastBBox = cur_shape.getBBox(); lastBBox = curShape.getBBox();
return { return {
started: true started: true
}; };
}, },
mouseMove: function(opts) { mouseMove: function (opts) {
var mode = canv.getMode(); var mode = canv.getMode();
if (mode !== mode_id) {return;} if (mode !== modeId) { return; }
var zoom = canv.getZoom(); var zoom = canv.getZoom();
var evt = opts.event; var evt = opts.event;
var x = opts.mouse_x/zoom; var x = opts.mouse_x / zoom;
var y = opts.mouse_y/zoom; var y = opts.mouse_y / zoom;
var tlist = canv.getTransformList(cur_shape), var tlist = canv.getTransformList(curShape),
box = cur_shape.getBBox(), box = curShape.getBBox(),
left = box.x, top = box.y, width = box.width, left = box.x, top = box.y, width = box.width,
height = box.height; height = box.height;
var dx = (x-start_x), dy = (y-start_y); var dx = (x - startX), dy = (y - startY);
var newbox = { var newbox = {
'x': Math.min(start_x,x), 'x': Math.min(startX, x),
'y': Math.min(start_y,y), 'y': Math.min(startY, y),
'width': Math.abs(x-start_x), 'width': Math.abs(x - startX),
'height': Math.abs(y-start_y) 'height': Math.abs(y - startY)
}; };
var tx = 0, ty = 0, var tx = 0, ty = 0,
sy = height ? (height+dy)/height : 1, sy = height ? (height + dy) / height : 1,
sx = width ? (width+dx)/width : 1; sx = width ? (width + dx) / width : 1;
sx = (newbox.width / lastBBox.width) || 1; sx = (newbox.width / lastBBox.width) || 1;
sy = (newbox.height / lastBBox.height) || 1; sy = (newbox.height / lastBBox.height) || 1;
// Not perfect, but mostly works... // Not perfect, but mostly works...
if (x < start_x) { if (x < startX) {
tx = lastBBox.width; tx = lastBBox.width;
} }
if (y < start_y) {ty = lastBBox.height;} if (y < startY) { ty = lastBBox.height; }
// update the transform list with translate,scale,translate // update the transform list with translate,scale,translate
var translateOrigin = svgroot.createSVGTransform(), var translateOrigin = svgroot.createSVGTransform(),
scale = svgroot.createSVGTransform(), scale = svgroot.createSVGTransform(),
translateBack = svgroot.createSVGTransform(); translateBack = svgroot.createSVGTransform();
translateOrigin.setTranslate(-(left+tx), -(top+ty)); translateOrigin.setTranslate(-(left + tx), -(top + ty));
if (!evt.shiftKey) { if (!evt.shiftKey) {
var max = Math.min(Math.abs(sx), Math.abs(sy)); var max = Math.min(Math.abs(sx), Math.abs(sy));
sx = max * (sx < 0 ? -1 : 1); sx = max * (sx < 0 ? -1 : 1);
sy = max * (sy < 0 ? -1 : 1); sy = max * (sy < 0 ? -1 : 1);
} }
scale.setScale(sx,sy); scale.setScale(sx, sy);
translateBack.setTranslate(left+tx, top+ty); translateBack.setTranslate(left + tx, top + ty);
tlist.appendItem(translateBack); tlist.appendItem(translateBack);
tlist.appendItem(scale); tlist.appendItem(scale);
tlist.appendItem(translateOrigin); tlist.appendItem(translateOrigin);
canv.recalculateDimensions(cur_shape); canv.recalculateDimensions(curShape);
lastBBox = cur_shape.getBBox(); lastBBox = curShape.getBBox();
}, },
mouseUp: function(opts) { mouseUp: function (opts) {
var mode = canv.getMode(); var mode = canv.getMode();
if (mode !== mode_id) {return;} if (mode !== modeId) { return; }
var keepObject = (opts.event.clientX != startClientPos.x && opts.event.clientY != startClientPos.y); var keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y);
return { return {
keep: keepObject, keep: keepObject,
element: cur_shape, element: curShape,
started: false started: false
}; };
} }
}; };
}); });

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, svgCanvas, $*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true*/ /* globals svgEditor, svgCanvas, $ */
/* /*
* ext-star.js * ext-star.js
* *
@@ -9,7 +9,8 @@
* *
*/ */
svgEditor.addExtension('star', function(S){'use strict'; svgEditor.addExtension('star', function (S) {
'use strict';
var // NS = svgedit.NS, var // NS = svgedit.NS,
// svgcontent = S.svgcontent, // svgcontent = S.svgcontent,
@@ -17,19 +18,18 @@ svgEditor.addExtension('star', function(S){'use strict';
// editingitex = false, // editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument, // svgdoc = S.svgroot.parentNode.ownerDocument,
started, started,
newFO, newFO;
// edg = 0, // edg = 0,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, // newFOG, newFOGParent, newDef, newImageName, newMaskID,
// undoCommand = 'Not image', // undoCommand = 'Not image',
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH, // modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
shape;
function showPanel(on){ function showPanel (on) {
var fc_rules = $('#fc_rules'); var fcRules = $('#fc_rules');
if (!fc_rules.length) { if (!fcRules.length) {
fc_rules = $('<style id="fc_rules"></style>').appendTo('head'); fcRules = $('<style id="fc_rules"></style>').appendTo('head');
} }
fc_rules.text(!on ? '' : ' #tool_topath { display: none !important; }'); fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#star_panel').toggle(on); $('#star_panel').toggle(on);
} }
@@ -39,7 +39,7 @@ svgEditor.addExtension('star', function(S){'use strict';
} }
*/ */
function setAttr(attr, val){ function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val); svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems); S.call('changed', selElems);
} }
@@ -63,7 +63,7 @@ svgEditor.addExtension('star', function(S){'use strict';
title: 'Star Tool', title: 'Star Tool',
position: 12, position: 12,
events: { events: {
click: function(){ click: function () {
showPanel(true); showPanel(true);
svgCanvas.setMode('star'); svgCanvas.setMode('star');
} }
@@ -79,7 +79,7 @@ svgEditor.addExtension('star', function(S){'use strict';
size: 3, size: 3,
defval: 5, defval: 5,
events: { events: {
change: function(){ change: function () {
setAttr('point', this.value); setAttr('point', this.value);
} }
} }
@@ -100,23 +100,23 @@ svgEditor.addExtension('star', function(S){'use strict';
size: 3, size: 3,
defval: 0, defval: 0,
events: { events: {
change: function(){ change: function () {
setAttr('radialshift', this.value); setAttr('radialshift', this.value);
} }
} }
}], }],
callback: function(){ callback: function () {
$('#star_panel').hide(); $('#star_panel').hide();
// var endChanges = function(){}; // var endChanges = function(){};
}, },
mouseDown: function(opts){ mouseDown: function (opts) {
var rgb = svgCanvas.getColor('fill'); var rgb = svgCanvas.getColor('fill');
// var ccRgbEl = rgb.substring(1, rgb.length); // var ccRgbEl = rgb.substring(1, rgb.length);
var sRgb = svgCanvas.getColor('stroke'); var sRgb = svgCanvas.getColor('stroke');
// var ccSRgbEl = sRgb.substring(1, rgb.length); // var ccSRgbEl = sRgb.substring(1, rgb.length);
var sWidth = svgCanvas.getStrokeWidth(); var sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() == 'star') { if (svgCanvas.getMode() === 'star') {
started = true; started = true;
newFO = S.addSvgElementFromJson({ newFO = S.addSvgElementFromJson({
@@ -141,11 +141,11 @@ svgEditor.addExtension('star', function(S){'use strict';
}; };
} }
}, },
mouseMove: function(opts){ mouseMove: function (opts) {
if (!started) { if (!started) {
return; return;
} }
if (svgCanvas.getMode() == 'star') { if (svgCanvas.getMode() === 'star') {
var x = opts.mouse_x; var x = opts.mouse_x;
var y = opts.mouse_y; var y = opts.mouse_y;
var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']); var c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
@@ -158,9 +158,9 @@ svgEditor.addExtension('star', function(S){'use strict';
var s; var s;
for (s = 0; point >= s; s++) { for (s = 0; point >= s; s++) {
var angle = 2.0 * Math.PI * (s / point); var angle = 2.0 * Math.PI * (s / point);
if ('point' == orient) { if (orient === 'point') {
angle -= (Math.PI / 2); angle -= (Math.PI / 2);
} else if ('edge' == orient) { } else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2); angle = (angle + (Math.PI / point)) - (Math.PI / 2);
} }
@@ -169,11 +169,11 @@ svgEditor.addExtension('star', function(S){'use strict';
polyPoints += x + ',' + y + ' '; polyPoints += x + ',' + y + ' ';
if (null != inradius) { if (inradius != null) {
angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point); angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point);
if ('point' == orient) { if (orient === 'point') {
angle -= (Math.PI / 2); angle -= (Math.PI / 2);
} else if ('edge' == orient) { } else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2); angle = (angle + (Math.PI / point)) - (Math.PI / 2);
} }
angle += radialShift; angle += radialShift;
@@ -188,25 +188,24 @@ svgEditor.addExtension('star', function(S){'use strict';
newFO.setAttributeNS(null, 'fill', fill); newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor); newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokewidth); newFO.setAttributeNS(null, 'stroke-width', strokewidth);
shape = newFO.getAttributeNS(null, 'shape'); /* var shape = */ newFO.getAttributeNS(null, 'shape');
return { return {
started: true started: true
}; };
} }
}, },
mouseUp: function(){ mouseUp: function () {
if (svgCanvas.getMode() == 'star') { if (svgCanvas.getMode() === 'star') {
var attrs = $(newFO).attr(['r']); var attrs = $(newFO).attr(['r']);
// svgCanvas.addToSelection([newFO], true); // svgCanvas.addToSelection([newFO], true);
return { return {
keep: (attrs.r != 0), keep: (attrs.r !== '0'),
element: newFO element: newFO
}; };
} }
}, },
selectedChanged: function(opts){ selectedChanged: function (opts) {
// Use this to update the current selected elements // Use this to update the current selected elements
selElems = opts.elems; selElems = opts.elems;
@@ -220,8 +219,7 @@ svgEditor.addExtension('star', function(S){'use strict';
$('#starNumPoints').val(elem.getAttribute('point')); $('#starNumPoints').val(elem.getAttribute('point'));
$('#radialShift').val(elem.getAttribute('radialshift')); $('#radialShift').val(elem.getAttribute('radialshift'));
showPanel(true); showPanel(true);
} } else {
else {
showPanel(false); showPanel(false);
} }
} else { } else {
@@ -229,7 +227,7 @@ svgEditor.addExtension('star', function(S){'use strict';
} }
} }
}, },
elementChanged: function(opts){ elementChanged: function (opts) {
// var elem = opts.elems[0]; // var elem = opts.elems[0];
} }
}; };

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, $, widget*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true, regexp: true, continue: true*/ /* globals svgEditor, svgCanvas, $, widget */
/* /*
* ext-storage.js * ext-storage.js
* *
@@ -26,7 +26,7 @@ TODOS
2. We might provide control of storage settings through the UI besides the 2. We might provide control of storage settings through the UI besides the
initial (or URL-forced) dialog. initial (or URL-forced) dialog.
*/ */
svgEditor.addExtension('storage', function() { svgEditor.addExtension('storage', function () {
// We could empty any already-set data for users when they decline storage, // We could empty any already-set data for users when they decline storage,
// but it would be a risk for users who wanted to store but accidentally // but it would be a risk for users who wanted to store but accidentally
// said "no"; instead, we'll let those who already set it, delete it themselves; // said "no"; instead, we'll let those who already set it, delete it themselves;
@@ -53,8 +53,7 @@ svgEditor.addExtension('storage', function() {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) { loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || '')); return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
}); });
} } else {
else {
loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val; loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val;
} }
} }
@@ -63,22 +62,21 @@ svgEditor.addExtension('storage', function() {
var name = 'svgedit-' + svgEditor.curConfig.canvasName; var name = 'svgedit-' + svgEditor.curConfig.canvasName;
if (!val) { if (!val) {
storage.removeItem(name); storage.removeItem(name);
} } else {
else {
storage.setItem(name, val); storage.setItem(name, val);
} }
} }
} }
function expireCookie (cookie) { function expireCookie (cookie) {
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT'; document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
} }
function removeStoragePrefCookie () { function removeStoragePrefCookie () {
expireCookie('store'); expireCookie('store');
} }
function emptyStorage() { function emptyStorage () {
setSVGContentStorage(''); setSVGContentStorage('');
var name; var name;
for (name in svgEditor.curPrefs) { for (name in svgEditor.curPrefs) {
@@ -91,8 +89,8 @@ svgEditor.addExtension('storage', function() {
} }
} }
} }
// emptyStorage(); // emptyStorage();
/** /**
* Listen for unloading: If and only if opted in by the user, set the content * Listen for unloading: If and only if opted in by the user, set the content
@@ -103,14 +101,14 @@ svgEditor.addExtension('storage', function() {
* 3. Use localStorage (where available) or cookies to set preferences. * 3. Use localStorage (where available) or cookies to set preferences.
*/ */
function setupBeforeUnloadListener () { function setupBeforeUnloadListener () {
window.addEventListener('beforeunload', function(e) { window.addEventListener('beforeunload', function (e) {
// Don't save anything unless the user opted in to storage // Don't save anything unless the user opted in to storage
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) { if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
return; return;
} }
var key; var key;
if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) { if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
setSVGContentStorage(svgCanvas.getSvgString()); setSVGContentStorage(svgCanvas.getSvgString());
} }
svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
@@ -121,18 +119,16 @@ svgEditor.addExtension('storage', function() {
for (key in curPrefs) { for (key in curPrefs) {
if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
var val = curPrefs[key], var val = curPrefs[key],
store = (val != undefined); store = (val !== undefined);
key = 'svg-edit-' + key; key = 'svg-edit-' + key;
if (!store) { if (!store) {
continue; continue;
} }
if (storage) { if (storage) {
storage.setItem(key, val); storage.setItem(key, val);
} } else if (window.widget) {
else if (window.widget) {
widget.setPreferenceForKey(val, key); widget.setPreferenceForKey(val, key);
} } else {
else {
val = encodeURIComponent(val); val = encodeURIComponent(val);
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
} }
@@ -195,7 +191,6 @@ svgEditor.addExtension('storage', function() {
) )
// ...then show the storage prompt. // ...then show the storage prompt.
)) { )) {
var options = []; var options = [];
if (storage) { if (storage) {
options.unshift( options.unshift(
@@ -203,8 +198,7 @@ svgEditor.addExtension('storage', function() {
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly}, {value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent} {value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
); );
} } else {
else {
options.unshift( options.unshift(
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs}, {value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs} {value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
@@ -242,8 +236,7 @@ svgEditor.addExtension('storage', function() {
replaceStoragePrompt(); replaceStoragePrompt();
return; return;
} }
} } else { // The user does not wish storage (or cancelled, which we treat equivalently)
else { // The user does not wish storage (or cancelled, which we treat equivalently)
removeStoragePrefCookie(); removeStoragePrefCookie();
if (pref && // If the user explicitly expresses wish for no storage if (pref && // If the user explicitly expresses wish for no storage
emptyStorageOnDecline emptyStorageOnDecline
@@ -259,21 +252,21 @@ svgEditor.addExtension('storage', function() {
// Reset width/height of dialog (e.g., for use by Export) // Reset width/height of dialog (e.g., for use by Export)
$('#dialog_container')[0].style.width = oldContainerWidth; $('#dialog_container')[0].style.width = oldContainerWidth;
$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft; $('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;
$('#dialog_content')[0].style.height = oldContentHeight; $('#dialog_content')[0].style.height = oldContentHeight;
$('#dialog_container')[0].style.height = oldContainerHeight; $('#dialog_container')[0].style.height = oldContainerHeight;
// It should be enough to (conditionally) add to storage on // It should be enough to (conditionally) add to storage on
// beforeunload, but if we wished to update immediately, // beforeunload, but if we wished to update immediately,
// we might wish to try setting: // we might wish to try setting:
// svgEditor.setConfig({noStorageOnLoad: true}); // svgEditor.setConfig({noStorageOnLoad: true});
// and then call: // and then call:
// svgEditor.loadContentAndPrefs(); // svgEditor.loadContentAndPrefs();
// We don't check for noStorageOnLoad here because // We don't check for noStorageOnLoad here because
// the prompt gives the user the option to store data // the prompt gives the user the option to store data
setupBeforeUnloadListener(); setupBeforeUnloadListener();
svgEditor.storagePromptClosed = true; svgEditor.storagePromptClosed = true;
}, },
null, null,
@@ -284,8 +277,7 @@ svgEditor.addExtension('storage', function() {
tooltip: uiStrings.confirmSetStorage.rememberTooltip tooltip: uiStrings.confirmSetStorage.rememberTooltip
} }
); );
} } else if (!noStorageOnLoad || forceStorage) {
else if (!noStorageOnLoad || forceStorage) {
setupBeforeUnloadListener(); setupBeforeUnloadListener();
} }
} }

View File

@@ -1,67 +1,67 @@
/*globals svgEditor*/ /* eslint-disable no-var */
/* globals svgEditor */
/* /*
Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind
Todos: Todos:
1. See WebAppFind Readme for SVG-related todos 1. See WebAppFind Readme for SVG-related todos
*/ */
(function () {'use strict'; (function () {
'use strict';
var pathID, var pathID,
saveMessage = 'webapp-save', saveMessage = 'webapp-save',
readMessage = 'webapp-read', readMessage = 'webapp-read',
excludedMessages = [readMessage, saveMessage]; excludedMessages = [readMessage, saveMessage];
window.addEventListener('message', function(e) { window.addEventListener('message', function (e) {
if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively) if (e.origin !== window.location.origin || // PRIVACY AND SECURITY! (for viewing and saving, respectively)
(!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below (!Array.isArray(e.data) || excludedMessages.indexOf(e.data[0]) > -1) // Validate format and avoid our post below
) { ) {
return; return;
} }
var svgString, var svgString,
messageType = e.data[0]; messageType = e.data[0];
switch (messageType) { switch (messageType) {
case 'webapp-view': case 'webapp-view':
// Populate the contents // Populate the contents
pathID = e.data[1]; pathID = e.data[1];
svgString = e.data[2]; svgString = e.data[2];
svgEditor.loadFromString(svgString); svgEditor.loadFromString(svgString);
/*if ($('#tool_save_file')) { /* if ($('#tool_save_file')) {
$('#tool_save_file').disabled = false; $('#tool_save_file').disabled = false;
}*/ } */
break; break;
case 'webapp-save-end': case 'webapp-save-end':
alert('save complete for pathID ' + e.data[1] + '!'); alert('save complete for pathID ' + e.data[1] + '!');
break; break;
default: default:
throw 'Unexpected mode'; throw new Error('Unexpected mode');
} }
}, false); }, false);
window.postMessage([readMessage], window.location.origin !== 'null' ? window.location.origin : '*'); // Avoid "null" string error for file: protocol (even though file protocol not currently supported by add-on) window.postMessage([readMessage], window.location.origin !== 'null' ? window.location.origin : '*'); // Avoid "null" string error for file: protocol (even though file protocol not currently supported by add-on)
svgEditor.addExtension('WebAppFind', function() { svgEditor.addExtension('WebAppFind', function () {
return {
return { name: 'WebAppFind',
name: 'WebAppFind', svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg',
svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg', buttons: [{
buttons: [{ id: 'webappfind_save', //
id: 'webappfind_save', // type: 'app_menu',
type: 'app_menu', title: 'Save Image back to Disk',
title: 'Save Image back to Disk', position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)") events: {
events: { click: function () {
click: function () { if (!pathID) { // Not ready yet as haven't received first payload
if (!pathID) { // Not ready yet as haven't received first payload return;
return; }
} window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin);
window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin); }
} }
} }]
}] };
};
}); });
}()); }());

View File

@@ -1,12 +1,14 @@
/* eslint-disable no-var */
/* globals svgEditor, svgCanvas */
/** /**
* Should not be needed for same domain control (just call via child frame), * Should not be needed for same domain control (just call via child frame),
* but an API common for cross-domain and same domain use can be found * but an API common for cross-domain and same domain use can be found
* in embedapi.js with a demo at embedapi.html * in embedapi.js with a demo at embedapi.html
*/ */
/*globals svgEditor, svgCanvas*/ svgEditor.addExtension('xdomain-messaging', function () {
svgEditor.addExtension('xdomain-messaging', function() {'use strict'; 'use strict';
try { try {
window.addEventListener('message', function(e) { window.addEventListener('message', function (e) {
// We accept and post strings for the sake of IE9 support // We accept and post strings for the sake of IE9 support
if (typeof e.data !== 'string' || e.data.charAt() === '|') { if (typeof e.data !== 'string' || e.data.charAt() === '|') {
return; return;
@@ -35,8 +37,7 @@ svgEditor.addExtension('xdomain-messaging', function() {'use strict';
} }
e.source.postMessage(JSON.stringify(message), '*'); e.source.postMessage(JSON.stringify(message), '*');
}, false); }, false);
} } catch (err) {
catch (err) {
console.log('Error with xdomain message listener: ' + err); console.log('Error with xdomain message listener: ' + err);
} }
}); });

View File

@@ -11,30 +11,30 @@
*/ */
// Very minimal PHP file, all we do is Base64 encode the uploaded file and // Very minimal PHP file, all we do is Base64 encode the uploaded file and
// return it to the editor // return it to the editor
if (!isset($_REQUEST['type'])) { if (!isset($_REQUEST['type'])) {
echo "No type given"; echo 'No type given';
exit; exit;
} }
$type = $_REQUEST['type']; $type = $_REQUEST['type'];
if (!in_array($type, array('load_svg', 'import_svg', 'import_img'))) { if (!in_array($type, array('load_svg', 'import_svg', 'import_img'))) {
echo "Not a recognized type"; echo 'Not a recognized type';
exit; exit;
} }
require('allowedMimeTypes.php'); require('allowedMimeTypes.php');
$file = $_FILES['svg_file']['tmp_name']; $file = $_FILES['svg_file']['tmp_name'];
$output = file_get_contents($file); $output = file_get_contents($file);
$prefix = ''; $prefix = '';
// Make Data URL prefix for import image // Make Data URL prefix for import image
if ($type == 'import_img') { if ($type == 'import_img') {
$info = getimagesize($file); $info = getimagesize($file);
if (!in_array($info['mime'], $allowedMimeTypesBySuffix)) { if (!in_array($info['mime'], $allowedMimeTypesBySuffix)) {
echo "Disallowed MIME for supplied file"; echo 'Disallowed MIME for supplied file';
exit; exit;
} }
$prefix = 'data:' . $info['mime'] . ';base64,'; $prefix = 'data:' . $info['mime'] . ';base64,';
@@ -45,7 +45,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<script> <script>
top.svgEditor.processFile("<?php top.svgEditor.processFile("<?php
// This should be safe since SVG edit does its own filtering (e.g., if an SVG file contains scripts) // This should be safe since SVG edit does its own filtering (e.g., if an SVG file contains scripts)
echo $prefix . base64_encode($output); echo $prefix . base64_encode($output);

View File

@@ -44,17 +44,17 @@ if ($suffix == '.svg') {
$contents = base64_decode(substr($contents, $pos)); $contents = base64_decode(substr($contents, $pos));
} }
header("Cache-Control: public"); header('Cache-Control: public');
header("Content-Description: File Transfer"); header('Content-Description: File Transfer');
// See http://tools.ietf.org/html/rfc6266#section-4.1 // See http://tools.ietf.org/html/rfc6266#section-4.1
header("Content-Disposition: attachment; filename*=UTF-8''" . encodeRFC5987ValueChars( header("Content-Disposition: attachment; filename*=UTF-8''" . encodeRFC5987ValueChars(
// preg_replace('@[\\\\/:*?"<>|]@', '', $file) // If we wanted to strip Windows-disallowed characters server-side (but not a security issue, so we can strip client-side instead) // preg_replace('@[\\\\/:*?"<>|]@', '', $file) // If we wanted to strip Windows-disallowed characters server-side (but not a security issue, so we can strip client-side instead)
$file $file
)); ));
header("Content-Type: " . $mime); header('Content-Type: ' . $mime);
header("Content-Transfer-Encoding: binary"); header('Content-Transfer-Encoding: binary');
echo $contents; echo $contents;
?> ?>

View File

@@ -2,6 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>-</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
</head> </head>
<body> <body>
@@ -11,59 +12,6 @@
<br> <br>
<a href="../../images/logo.png">logo.png</a> <a href="../../images/logo.png">logo.png</a>
<script> <script src="index.js"></script>
/* eslint-disable no-var */
/* globals $ */
$('a').click(function() {'use strict';
var metaStr;
var href = this.href;
var target = window.parent;
// Convert Non-SVG images to data URL first
// (this could also have been done server-side by the library)
if (this.href.indexOf('.svg') === -1) {
metaStr = JSON.stringify({
name: $(this).text(),
id: href
});
target.postMessage(metaStr, '*');
var img = new Image();
img.onload = function() {
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
var dataurl;
try {
dataurl = canvas.toDataURL();
} catch(err) {
// This fails in Firefox with file:// URLs :(
alert('Data URL conversion failed: ' + err);
dataurl = '';
}
target.postMessage('|' + href + '|' + dataurl, '*');
};
img.src = href;
} else {
// Send metadata (also indicates file is about to be sent)
metaStr = JSON.stringify({
name: $(this).text(),
id: href
});
target.postMessage(metaStr, '*');
// Do ajax request for image's href value
$.get(href, function (data) {
data = '|' + href + '|' + data;
// This is where the magic happens!
target.postMessage(data, '*');
}, 'html'); // 'html' is necessary to keep returned data as a string
}
return false;
});
</script>
</body> </body>
</html> </html>

View File

@@ -0,0 +1,51 @@
/* eslint-disable no-var */
/* globals $ */
$('a').click(function () {
'use strict';
var metaStr;
var href = this.href;
var target = window.parent;
// Convert Non-SVG images to data URL first
// (this could also have been done server-side by the library)
if (this.href.indexOf('.svg') === -1) {
metaStr = JSON.stringify({
name: $(this).text(),
id: href
});
target.postMessage(metaStr, '*');
var img = new Image();
img.onload = function () {
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
var dataurl;
try {
dataurl = canvas.toDataURL();
} catch (err) {
// This fails in Firefox with file:// URLs :(
alert('Data URL conversion failed: ' + err);
dataurl = '';
}
target.postMessage('|' + href + '|' + dataurl, '*');
};
img.src = href;
} else {
// Send metadata (also indicates file is about to be sent)
metaStr = JSON.stringify({
name: $(this).text(),
id: href
});
target.postMessage(metaStr, '*');
// Do ajax request for image's href value
$.get(href, function (data) {
data = '|' + href + '|' + data;
// This is where the magic happens!
target.postMessage(data, '*');
}, 'html'); // 'html' is necessary to keep returned data as a string
}
return false;
});

View File

@@ -1,5 +1,5 @@
/*globals svgedit*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true, continue: true, forin: true*/ /* globals svgedit */
/** /**
* Package: svedit.history * Package: svedit.history
* *
@@ -13,7 +13,8 @@
// 2) svgtransformlist.js // 2) svgtransformlist.js
// 3) svgutils.js // 3) svgutils.js
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.history) { if (!svgedit.history) {
svgedit.history = {}; svgedit.history = {};
@@ -27,7 +28,7 @@ svgedit.history.HistoryEventTypes = {
AFTER_UNAPPLY: 'after_unapply' AFTER_UNAPPLY: 'after_unapply'
}; };
var removedElements = {}; // var removedElements = {};
/** /**
* An interface that all command objects must implement. * An interface that all command objects must implement.
@@ -61,18 +62,18 @@ var removedElements = {};
* @param {Element} oldParent - The element's parent before it was moved * @param {Element} oldParent - The element's parent before it was moved
* @param {string} [text] - An optional string visible to user related to this change * @param {string} [text] - An optional string visible to user related to this change
*/ */
svgedit.history.MoveElementCommand = function(elem, oldNextSibling, oldParent, text) { svgedit.history.MoveElementCommand = function (elem, oldNextSibling, oldParent, text) {
this.elem = elem; this.elem = elem;
this.text = text ? ("Move " + elem.tagName + " to " + text) : ("Move " + elem.tagName); this.text = text ? ('Move ' + elem.tagName + ' to ' + text) : ('Move ' + elem.tagName);
this.oldNextSibling = oldNextSibling; this.oldNextSibling = oldNextSibling;
this.oldParent = oldParent; this.oldParent = oldParent;
this.newNextSibling = elem.nextSibling; this.newNextSibling = elem.nextSibling;
this.newParent = elem.parentNode; this.newParent = elem.parentNode;
}; };
svgedit.history.MoveElementCommand.type = function() { return 'svgedit.history.MoveElementCommand'; }; svgedit.history.MoveElementCommand.type = function () { return 'svgedit.history.MoveElementCommand'; };
svgedit.history.MoveElementCommand.prototype.type = svgedit.history.MoveElementCommand.type; svgedit.history.MoveElementCommand.prototype.type = svgedit.history.MoveElementCommand.type;
svgedit.history.MoveElementCommand.prototype.getText = function() { svgedit.history.MoveElementCommand.prototype.getText = function () {
return this.text; return this.text;
}; };
@@ -80,7 +81,7 @@ svgedit.history.MoveElementCommand.prototype.getText = function() {
* Re-positions the element * Re-positions the element
* @param {handleHistoryEvent: function} * @param {handleHistoryEvent: function}
*/ */
svgedit.history.MoveElementCommand.prototype.apply = function(handler) { svgedit.history.MoveElementCommand.prototype.apply = function (handler) {
// TODO(codedread): Refactor this common event code into a base HistoryCommand class. // TODO(codedread): Refactor this common event code into a base HistoryCommand class.
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
@@ -97,7 +98,7 @@ svgedit.history.MoveElementCommand.prototype.apply = function(handler) {
* Positions the element back to its original location * Positions the element back to its original location
* @param {handleHistoryEvent: function} * @param {handleHistoryEvent: function}
*/ */
svgedit.history.MoveElementCommand.prototype.unapply = function(handler) { svgedit.history.MoveElementCommand.prototype.unapply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
} }
@@ -111,11 +112,10 @@ svgedit.history.MoveElementCommand.prototype.unapply = function(handler) {
// Function: svgedit.history.MoveElementCommand.elements // Function: svgedit.history.MoveElementCommand.elements
// Returns array with element associated with this command // Returns array with element associated with this command
svgedit.history.MoveElementCommand.prototype.elements = function() { svgedit.history.MoveElementCommand.prototype.elements = function () {
return [this.elem]; return [this.elem];
}; };
// Class: svgedit.history.InsertElementCommand // Class: svgedit.history.InsertElementCommand
// implements svgedit.history.HistoryCommand // implements svgedit.history.HistoryCommand
// History command for an element that was added to the DOM // History command for an element that was added to the DOM
@@ -123,23 +123,23 @@ svgedit.history.MoveElementCommand.prototype.elements = function() {
// Parameters: // Parameters:
// elem - The newly added DOM element // elem - The newly added DOM element
// text - An optional string visible to user related to this change // text - An optional string visible to user related to this change
svgedit.history.InsertElementCommand = function(elem, text) { svgedit.history.InsertElementCommand = function (elem, text) {
this.elem = elem; this.elem = elem;
this.text = text || ("Create " + elem.tagName); this.text = text || ('Create ' + elem.tagName);
this.parent = elem.parentNode; this.parent = elem.parentNode;
this.nextSibling = this.elem.nextSibling; this.nextSibling = this.elem.nextSibling;
}; };
svgedit.history.InsertElementCommand.type = function() { return 'svgedit.history.InsertElementCommand'; }; svgedit.history.InsertElementCommand.type = function () { return 'svgedit.history.InsertElementCommand'; };
svgedit.history.InsertElementCommand.prototype.type = svgedit.history.InsertElementCommand.type; svgedit.history.InsertElementCommand.prototype.type = svgedit.history.InsertElementCommand.type;
// Function: svgedit.history.InsertElementCommand.getText // Function: svgedit.history.InsertElementCommand.getText
svgedit.history.InsertElementCommand.prototype.getText = function() { svgedit.history.InsertElementCommand.prototype.getText = function () {
return this.text; return this.text;
}; };
// Function: svgedit.history.InsertElementCommand.apply // Function: svgedit.history.InsertElementCommand.apply
// Re-Inserts the new element // Re-Inserts the new element
svgedit.history.InsertElementCommand.prototype.apply = function(handler) { svgedit.history.InsertElementCommand.prototype.apply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
} }
@@ -153,7 +153,7 @@ svgedit.history.InsertElementCommand.prototype.apply = function(handler) {
// Function: svgedit.history.InsertElementCommand.unapply // Function: svgedit.history.InsertElementCommand.unapply
// Removes the element // Removes the element
svgedit.history.InsertElementCommand.prototype.unapply = function(handler) { svgedit.history.InsertElementCommand.prototype.unapply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
} }
@@ -168,11 +168,10 @@ svgedit.history.InsertElementCommand.prototype.unapply = function(handler) {
// Function: svgedit.history.InsertElementCommand.elements // Function: svgedit.history.InsertElementCommand.elements
// Returns array with element associated with this command // Returns array with element associated with this command
svgedit.history.InsertElementCommand.prototype.elements = function() { svgedit.history.InsertElementCommand.prototype.elements = function () {
return [this.elem]; return [this.elem];
}; };
// Class: svgedit.history.RemoveElementCommand // Class: svgedit.history.RemoveElementCommand
// implements svgedit.history.HistoryCommand // implements svgedit.history.HistoryCommand
// History command for an element removed from the DOM // History command for an element removed from the DOM
@@ -182,26 +181,26 @@ svgedit.history.InsertElementCommand.prototype.elements = function() {
// oldNextSibling - the DOM element's nextSibling when it was in the DOM // oldNextSibling - the DOM element's nextSibling when it was in the DOM
// oldParent - The DOM element's parent // oldParent - The DOM element's parent
// text - An optional string visible to user related to this change // text - An optional string visible to user related to this change
svgedit.history.RemoveElementCommand = function(elem, oldNextSibling, oldParent, text) { svgedit.history.RemoveElementCommand = function (elem, oldNextSibling, oldParent, text) {
this.elem = elem; this.elem = elem;
this.text = text || ("Delete " + elem.tagName); this.text = text || ('Delete ' + elem.tagName);
this.nextSibling = oldNextSibling; this.nextSibling = oldNextSibling;
this.parent = oldParent; this.parent = oldParent;
// special hack for webkit: remove this element's entry in the svgTransformLists map // special hack for webkit: remove this element's entry in the svgTransformLists map
svgedit.transformlist.removeElementFromListMap(elem); svgedit.transformlist.removeElementFromListMap(elem);
}; };
svgedit.history.RemoveElementCommand.type = function() { return 'svgedit.history.RemoveElementCommand'; }; svgedit.history.RemoveElementCommand.type = function () { return 'svgedit.history.RemoveElementCommand'; };
svgedit.history.RemoveElementCommand.prototype.type = svgedit.history.RemoveElementCommand.type; svgedit.history.RemoveElementCommand.prototype.type = svgedit.history.RemoveElementCommand.type;
// Function: svgedit.history.RemoveElementCommand.getText // Function: svgedit.history.RemoveElementCommand.getText
svgedit.history.RemoveElementCommand.prototype.getText = function() { svgedit.history.RemoveElementCommand.prototype.getText = function () {
return this.text; return this.text;
}; };
// Function: RemoveElementCommand.apply // Function: RemoveElementCommand.apply
// Re-removes the new element // Re-removes the new element
svgedit.history.RemoveElementCommand.prototype.apply = function(handler) { svgedit.history.RemoveElementCommand.prototype.apply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
} }
@@ -217,7 +216,7 @@ svgedit.history.RemoveElementCommand.prototype.apply = function(handler) {
// Function: RemoveElementCommand.unapply // Function: RemoveElementCommand.unapply
// Re-adds the new element // Re-adds the new element
svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) { svgedit.history.RemoveElementCommand.prototype.unapply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
} }
@@ -225,12 +224,11 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
svgedit.transformlist.removeElementFromListMap(this.elem); svgedit.transformlist.removeElementFromListMap(this.elem);
if (this.nextSibling == null) { if (this.nextSibling == null) {
if (window.console) { if (window.console) {
console.log('Error: reference element was lost'); console.log('Error: reference element was lost');
} }
} }
this.parent.insertBefore(this.elem, this.nextSibling); this.parent.insertBefore(this.elem, this.nextSibling);
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
} }
@@ -238,11 +236,10 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
// Function: RemoveElementCommand.elements // Function: RemoveElementCommand.elements
// Returns array with element associated with this command // Returns array with element associated with this command
svgedit.history.RemoveElementCommand.prototype.elements = function() { svgedit.history.RemoveElementCommand.prototype.elements = function () {
return [this.elem]; return [this.elem];
}; };
// Class: svgedit.history.ChangeElementCommand // Class: svgedit.history.ChangeElementCommand
// implements svgedit.history.HistoryCommand // implements svgedit.history.HistoryCommand
// History command to make a change to an element. // History command to make a change to an element.
@@ -252,66 +249,70 @@ svgedit.history.RemoveElementCommand.prototype.elements = function() {
// elem - The DOM element that was changed // elem - The DOM element that was changed
// attrs - An object with the attributes to be changed and the values they had *before* the change // attrs - An object with the attributes to be changed and the values they had *before* the change
// text - An optional string visible to user related to this change // text - An optional string visible to user related to this change
svgedit.history.ChangeElementCommand = function(elem, attrs, text) { svgedit.history.ChangeElementCommand = function (elem, attrs, text) {
this.elem = elem; this.elem = elem;
this.text = text ? ("Change " + elem.tagName + " " + text) : ("Change " + elem.tagName); this.text = text ? ('Change ' + elem.tagName + ' ' + text) : ('Change ' + elem.tagName);
this.newValues = {}; this.newValues = {};
this.oldValues = attrs; this.oldValues = attrs;
var attr; var attr;
for (attr in attrs) { for (attr in attrs) {
if (attr == "#text") {this.newValues[attr] = elem.textContent;} if (attr === '#text') {
else if (attr == "#href") {this.newValues[attr] = svgedit.utilities.getHref(elem);} this.newValues[attr] = elem.textContent;
else {this.newValues[attr] = elem.getAttribute(attr);} } else if (attr === '#href') {
this.newValues[attr] = svgedit.utilities.getHref(elem);
} else {
this.newValues[attr] = elem.getAttribute(attr);
}
} }
}; };
svgedit.history.ChangeElementCommand.type = function() { return 'svgedit.history.ChangeElementCommand'; }; svgedit.history.ChangeElementCommand.type = function () { return 'svgedit.history.ChangeElementCommand'; };
svgedit.history.ChangeElementCommand.prototype.type = svgedit.history.ChangeElementCommand.type; svgedit.history.ChangeElementCommand.prototype.type = svgedit.history.ChangeElementCommand.type;
// Function: svgedit.history.ChangeElementCommand.getText // Function: svgedit.history.ChangeElementCommand.getText
svgedit.history.ChangeElementCommand.prototype.getText = function() { svgedit.history.ChangeElementCommand.prototype.getText = function () {
return this.text; return this.text;
}; };
// Function: svgedit.history.ChangeElementCommand.apply // Function: svgedit.history.ChangeElementCommand.apply
// Performs the stored change action // Performs the stored change action
svgedit.history.ChangeElementCommand.prototype.apply = function(handler) { svgedit.history.ChangeElementCommand.prototype.apply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
} }
var bChangedTransform = false; var bChangedTransform = false;
var attr; var attr;
for (attr in this.newValues ) { for (attr in this.newValues) {
if (this.newValues[attr]) { if (this.newValues[attr]) {
if (attr == "#text") {this.elem.textContent = this.newValues[attr];} if (attr === '#text') {
else if (attr == "#href") {svgedit.utilities.setHref(this.elem, this.newValues[attr]);} this.elem.textContent = this.newValues[attr];
else {this.elem.setAttribute(attr, this.newValues[attr]);} } else if (attr === '#href') {
} svgedit.utilities.setHref(this.elem, this.newValues[attr]);
else { } else {
if (attr == "#text") { this.elem.setAttribute(attr, this.newValues[attr]);
this.elem.textContent = "";
} }
else { } else {
this.elem.setAttribute(attr, ""); if (attr === '#text') {
this.elem.textContent = '';
} else {
this.elem.setAttribute(attr, '');
this.elem.removeAttribute(attr); this.elem.removeAttribute(attr);
} }
} }
if (attr == "transform") { bChangedTransform = true; } if (attr === 'transform') { bChangedTransform = true; }
} }
// relocate rotational transform, if necessary // relocate rotational transform, if necessary
if (!bChangedTransform) { if (!bChangedTransform) {
var angle = svgedit.utilities.getRotationAngle(this.elem); var angle = svgedit.utilities.getRotationAngle(this.elem);
if (angle) { if (angle) {
// TODO: These instances of elem either need to be declared as global var bbox = this.elem.getBBox();
// (which would not be good for conflicts) or declare/use this.elem var cx = bbox.x + bbox.width / 2,
var bbox = elem.getBBox(); cy = bbox.y + bbox.height / 2;
var cx = bbox.x + bbox.width/2, var rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join('');
cy = bbox.y + bbox.height/2; if (rotate !== this.elem.getAttribute('transform')) {
var rotate = ["rotate(", angle, " ", cx, ",", cy, ")"].join(''); this.elem.setAttribute('transform', rotate);
if (rotate != elem.getAttribute("transform")) {
elem.setAttribute("transform", rotate);
} }
} }
} }
@@ -325,39 +326,41 @@ svgedit.history.ChangeElementCommand.prototype.apply = function(handler) {
// Function: svgedit.history.ChangeElementCommand.unapply // Function: svgedit.history.ChangeElementCommand.unapply
// Reverses the stored change action // Reverses the stored change action
svgedit.history.ChangeElementCommand.prototype.unapply = function(handler) { svgedit.history.ChangeElementCommand.prototype.unapply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
} }
var bChangedTransform = false; var bChangedTransform = false;
var attr; var attr;
for (attr in this.oldValues ) { for (attr in this.oldValues) {
if (this.oldValues[attr]) { if (this.oldValues[attr]) {
if (attr == "#text") {this.elem.textContent = this.oldValues[attr];} if (attr === '#text') {
else if (attr == "#href") {svgedit.utilities.setHref(this.elem, this.oldValues[attr]);} this.elem.textContent = this.oldValues[attr];
else { } else if (attr === '#href') {
svgedit.utilities.setHref(this.elem, this.oldValues[attr]);
} else {
this.elem.setAttribute(attr, this.oldValues[attr]); this.elem.setAttribute(attr, this.oldValues[attr]);
} }
} } else {
else { if (attr === '#text') {
if (attr == "#text") { this.elem.textContent = '';
this.elem.textContent = ""; } else {
this.elem.removeAttribute(attr);
} }
else {this.elem.removeAttribute(attr);}
} }
if (attr == "transform") { bChangedTransform = true; } if (attr === 'transform') { bChangedTransform = true; }
} }
// relocate rotational transform, if necessary // relocate rotational transform, if necessary
if (!bChangedTransform) { if (!bChangedTransform) {
var angle = svgedit.utilities.getRotationAngle(this.elem); var angle = svgedit.utilities.getRotationAngle(this.elem);
if (angle) { if (angle) {
var bbox = elem.getBBox(); var bbox = this.elem.getBBox();
var cx = bbox.x + bbox.width/2, var cx = bbox.x + bbox.width / 2,
cy = bbox.y + bbox.height/2; cy = bbox.y + bbox.height / 2;
var rotate = ["rotate(", angle, " ", cx, ",", cy, ")"].join(''); var rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join('');
if (rotate != elem.getAttribute("transform")) { if (rotate !== this.elem.getAttribute('transform')) {
elem.setAttribute("transform", rotate); this.elem.setAttribute('transform', rotate);
} }
} }
} }
@@ -374,37 +377,35 @@ svgedit.history.ChangeElementCommand.prototype.unapply = function(handler) {
// Function: ChangeElementCommand.elements // Function: ChangeElementCommand.elements
// Returns array with element associated with this command // Returns array with element associated with this command
svgedit.history.ChangeElementCommand.prototype.elements = function() { svgedit.history.ChangeElementCommand.prototype.elements = function () {
return [this.elem]; return [this.elem];
}; };
// TODO: create a 'typing' command object that tracks changes in text // TODO: create a 'typing' command object that tracks changes in text
// if a new Typing command is created and the top command on the stack is also a Typing // if a new Typing command is created and the top command on the stack is also a Typing
// and they both affect the same element, then collapse the two commands into one // and they both affect the same element, then collapse the two commands into one
// Class: svgedit.history.BatchCommand // Class: svgedit.history.BatchCommand
// implements svgedit.history.HistoryCommand // implements svgedit.history.HistoryCommand
// History command that can contain/execute multiple other commands // History command that can contain/execute multiple other commands
// //
// Parameters: // Parameters:
// text - An optional string visible to user related to this change // text - An optional string visible to user related to this change
svgedit.history.BatchCommand = function(text) { svgedit.history.BatchCommand = function (text) {
this.text = text || "Batch Command"; this.text = text || 'Batch Command';
this.stack = []; this.stack = [];
}; };
svgedit.history.BatchCommand.type = function() { return 'svgedit.history.BatchCommand'; }; svgedit.history.BatchCommand.type = function () { return 'svgedit.history.BatchCommand'; };
svgedit.history.BatchCommand.prototype.type = svgedit.history.BatchCommand.type; svgedit.history.BatchCommand.prototype.type = svgedit.history.BatchCommand.type;
// Function: svgedit.history.BatchCommand.getText // Function: svgedit.history.BatchCommand.getText
svgedit.history.BatchCommand.prototype.getText = function() { svgedit.history.BatchCommand.prototype.getText = function () {
return this.text; return this.text;
}; };
// Function: svgedit.history.BatchCommand.apply // Function: svgedit.history.BatchCommand.apply
// Runs "apply" on all subcommands // Runs "apply" on all subcommands
svgedit.history.BatchCommand.prototype.apply = function(handler) { svgedit.history.BatchCommand.prototype.apply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
} }
@@ -422,13 +423,13 @@ svgedit.history.BatchCommand.prototype.apply = function(handler) {
// Function: svgedit.history.BatchCommand.unapply // Function: svgedit.history.BatchCommand.unapply
// Runs "unapply" on all subcommands // Runs "unapply" on all subcommands
svgedit.history.BatchCommand.prototype.unapply = function(handler) { svgedit.history.BatchCommand.prototype.unapply = function (handler) {
if (handler) { if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this); handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
} }
var i; var i;
for (i = this.stack.length-1; i >= 0; i--) { for (i = this.stack.length - 1; i >= 0; i--) {
this.stack[i].unapply(handler); this.stack[i].unapply(handler);
} }
@@ -439,14 +440,14 @@ svgedit.history.BatchCommand.prototype.unapply = function(handler) {
// Function: svgedit.history.BatchCommand.elements // Function: svgedit.history.BatchCommand.elements
// Iterate through all our subcommands and returns all the elements we are changing // Iterate through all our subcommands and returns all the elements we are changing
svgedit.history.BatchCommand.prototype.elements = function() { svgedit.history.BatchCommand.prototype.elements = function () {
var elems = []; var elems = [];
var cmd = this.stack.length; var cmd = this.stack.length;
while (cmd--) { while (cmd--) {
var thisElems = this.stack[cmd].elements(); var thisElems = this.stack[cmd].elements();
var elem = thisElems.length; var elem = thisElems.length;
while (elem--) { while (elem--) {
if (elems.indexOf(thisElems[elem]) == -1) {elems.push(thisElems[elem]);} if (elems.indexOf(thisElems[elem]) === -1) { elems.push(thisElems[elem]); }
} }
} }
return elems; return elems;
@@ -457,22 +458,21 @@ svgedit.history.BatchCommand.prototype.elements = function() {
// //
// Parameters: // Parameters:
// cmd - The undo command object to add // cmd - The undo command object to add
svgedit.history.BatchCommand.prototype.addSubCommand = function(cmd) { svgedit.history.BatchCommand.prototype.addSubCommand = function (cmd) {
this.stack.push(cmd); this.stack.push(cmd);
}; };
// Function: svgedit.history.BatchCommand.isEmpty // Function: svgedit.history.BatchCommand.isEmpty
// Returns a boolean indicating whether or not the batch command is empty // Returns a boolean indicating whether or not the batch command is empty
svgedit.history.BatchCommand.prototype.isEmpty = function() { svgedit.history.BatchCommand.prototype.isEmpty = function () {
return this.stack.length === 0; return this.stack.length === 0;
}; };
// Class: svgedit.history.UndoManager // Class: svgedit.history.UndoManager
// Parameters: // Parameters:
// historyEventHandler - an object that conforms to the HistoryEventHandler interface // historyEventHandler - an object that conforms to the HistoryEventHandler interface
// (see above) // (see above)
svgedit.history.UndoManager = function(historyEventHandler) { svgedit.history.UndoManager = function (historyEventHandler) {
this.handler_ = historyEventHandler || null; this.handler_ = historyEventHandler || null;
this.undoStackPointer = 0; this.undoStackPointer = 0;
this.undoStack = []; this.undoStack = [];
@@ -485,7 +485,7 @@ svgedit.history.UndoManager = function(historyEventHandler) {
// Function: svgedit.history.UndoManager.resetUndoStack // Function: svgedit.history.UndoManager.resetUndoStack
// Resets the undo stack, effectively clearing the undo/redo history // Resets the undo stack, effectively clearing the undo/redo history
svgedit.history.UndoManager.prototype.resetUndoStack = function() { svgedit.history.UndoManager.prototype.resetUndoStack = function () {
this.undoStack = []; this.undoStack = [];
this.undoStackPointer = 0; this.undoStackPointer = 0;
}; };
@@ -493,34 +493,34 @@ svgedit.history.UndoManager.prototype.resetUndoStack = function() {
// Function: svgedit.history.UndoManager.getUndoStackSize // Function: svgedit.history.UndoManager.getUndoStackSize
// Returns: // Returns:
// Integer with the current size of the undo history stack // Integer with the current size of the undo history stack
svgedit.history.UndoManager.prototype.getUndoStackSize = function() { svgedit.history.UndoManager.prototype.getUndoStackSize = function () {
return this.undoStackPointer; return this.undoStackPointer;
}; };
// Function: svgedit.history.UndoManager.getRedoStackSize // Function: svgedit.history.UndoManager.getRedoStackSize
// Returns: // Returns:
// Integer with the current size of the redo history stack // Integer with the current size of the redo history stack
svgedit.history.UndoManager.prototype.getRedoStackSize = function() { svgedit.history.UndoManager.prototype.getRedoStackSize = function () {
return this.undoStack.length - this.undoStackPointer; return this.undoStack.length - this.undoStackPointer;
}; };
// Function: svgedit.history.UndoManager.getNextUndoCommandText // Function: svgedit.history.UndoManager.getNextUndoCommandText
// Returns: // Returns:
// String associated with the next undo command // String associated with the next undo command
svgedit.history.UndoManager.prototype.getNextUndoCommandText = function() { svgedit.history.UndoManager.prototype.getNextUndoCommandText = function () {
return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer-1].getText() : ""; return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer - 1].getText() : '';
}; };
// Function: svgedit.history.UndoManager.getNextRedoCommandText // Function: svgedit.history.UndoManager.getNextRedoCommandText
// Returns: // Returns:
// String associated with the next redo command // String associated with the next redo command
svgedit.history.UndoManager.prototype.getNextRedoCommandText = function() { svgedit.history.UndoManager.prototype.getNextRedoCommandText = function () {
return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : ""; return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : '';
}; };
// Function: svgedit.history.UndoManager.undo // Function: svgedit.history.UndoManager.undo
// Performs an undo step // Performs an undo step
svgedit.history.UndoManager.prototype.undo = function() { svgedit.history.UndoManager.prototype.undo = function () {
if (this.undoStackPointer > 0) { if (this.undoStackPointer > 0) {
var cmd = this.undoStack[--this.undoStackPointer]; var cmd = this.undoStack[--this.undoStackPointer];
cmd.unapply(this.handler_); cmd.unapply(this.handler_);
@@ -529,7 +529,7 @@ svgedit.history.UndoManager.prototype.undo = function() {
// Function: svgedit.history.UndoManager.redo // Function: svgedit.history.UndoManager.redo
// Performs a redo step // Performs a redo step
svgedit.history.UndoManager.prototype.redo = function() { svgedit.history.UndoManager.prototype.redo = function () {
if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) { if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
var cmd = this.undoStack[this.undoStackPointer++]; var cmd = this.undoStack[this.undoStackPointer++];
cmd.apply(this.handler_); cmd.apply(this.handler_);
@@ -541,7 +541,7 @@ svgedit.history.UndoManager.prototype.redo = function() {
// //
// Parameters: // Parameters:
// cmd - The command object to add // cmd - The command object to add
svgedit.history.UndoManager.prototype.addCommandToHistory = function(cmd) { svgedit.history.UndoManager.prototype.addCommandToHistory = function (cmd) {
// FIXME: we MUST compress consecutive text changes to the same element // FIXME: we MUST compress consecutive text changes to the same element
// (right now each keystroke is saved as a separate command that includes the // (right now each keystroke is saved as a separate command that includes the
// entire text contents of the text element) // entire text contents of the text element)
@@ -556,24 +556,23 @@ svgedit.history.UndoManager.prototype.addCommandToHistory = function(cmd) {
this.undoStackPointer = this.undoStack.length; this.undoStackPointer = this.undoStack.length;
}; };
// Function: svgedit.history.UndoManager.beginUndoableChange // Function: svgedit.history.UndoManager.beginUndoableChange
// This function tells the canvas to remember the old values of the // This function tells the canvas to remember the old values of the
// attrName attribute for each element sent in. The elements and values // attrName attribute for each element sent in. The elements and values
// are stored on a stack, so the next call to finishUndoableChange() will // 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 // 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. // from the DOM and uses all of these to construct the undo-able command.
// //
// Parameters: // Parameters:
// attrName - The name of the attribute being changed // attrName - The name of the attribute being changed
// elems - Array of DOM elements being changed // elems - Array of DOM elements being changed
svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, elems) { svgedit.history.UndoManager.prototype.beginUndoableChange = function (attrName, elems) {
var p = ++this.undoChangeStackPointer; var p = ++this.undoChangeStackPointer;
var i = elems.length; var i = elems.length;
var oldValues = new Array(i), elements = new Array(i); var oldValues = new Array(i), elements = new Array(i);
while (i--) { while (i--) {
var elem = elems[i]; var elem = elems[i];
if (elem == null) {continue;} if (elem == null) { continue; }
elements[i] = elem; elements[i] = elem;
oldValues[i] = elem.getAttribute(attrName); oldValues[i] = elem.getAttribute(attrName);
} }
@@ -591,23 +590,22 @@ svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, e
// //
// Returns: // Returns:
// Batch command object with resulting changes // Batch command object with resulting changes
svgedit.history.UndoManager.prototype.finishUndoableChange = function() { svgedit.history.UndoManager.prototype.finishUndoableChange = function () {
var p = this.undoChangeStackPointer--; var p = this.undoChangeStackPointer--;
var changeset = this.undoableChangeStack[p]; var changeset = this.undoableChangeStack[p];
var i = changeset.elements.length; var i = changeset.elements.length;
var attrName = changeset.attrName; var attrName = changeset.attrName;
var batchCmd = new svgedit.history.BatchCommand("Change " + attrName); var batchCmd = new svgedit.history.BatchCommand('Change ' + attrName);
while (i--) { while (i--) {
var elem = changeset.elements[i]; var elem = changeset.elements[i];
if (elem == null) {continue;} if (elem == null) { continue; }
var changes = {}; var changes = {};
changes[attrName] = changeset.oldValues[i]; changes[attrName] = changeset.oldValues[i];
if (changes[attrName] != elem.getAttribute(attrName)) { if (changes[attrName] !== elem.getAttribute(attrName)) {
batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(elem, changes, attrName)); batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(elem, changes, attrName));
} }
} }
this.undoableChangeStack[p] = null; this.undoableChangeStack[p] = null;
return batchCmd; return batchCmd;
}; };
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals svgedit*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true */ /* globals svgedit */
/** /**
* Package: svgedit.history * Package: svgedit.history
* *
@@ -11,8 +11,8 @@
// Dependencies: // Dependencies:
// 1) history.js // 1) history.js
(function() { (function () {
'use strict'; 'use strict';
if (!svgedit.history) { if (!svgedit.history) {
svgedit.history = {}; svgedit.history = {};
@@ -57,7 +57,7 @@ var history = svgedit.history;
* A value of null is valid for cases where no history recording is required. * A value of null is valid for cases where no history recording is required.
* See singleton: HistoryRecordingService.NO_HISTORY * See singleton: HistoryRecordingService.NO_HISTORY
*/ */
var HistoryRecordingService = history.HistoryRecordingService = function(undoManager) { var HistoryRecordingService = history.HistoryRecordingService = function (undoManager) {
this.undoManager_ = undoManager; this.undoManager_ = undoManager;
this.currentBatchCommand_ = null; this.currentBatchCommand_ = null;
this.batchCommandStack_ = []; this.batchCommandStack_ = [];
@@ -76,8 +76,8 @@ HistoryRecordingService.NO_HISTORY = new HistoryRecordingService();
* @param {string} text - Optional string describing the batch command. * @param {string} text - Optional string describing the batch command.
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
*/ */
HistoryRecordingService.prototype.startBatchCommand = function(text) { HistoryRecordingService.prototype.startBatchCommand = function (text) {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
this.currentBatchCommand_ = new history.BatchCommand(text); this.currentBatchCommand_ = new history.BatchCommand(text);
this.batchCommandStack_.push(this.currentBatchCommand_); this.batchCommandStack_.push(this.currentBatchCommand_);
return this; return this;
@@ -87,13 +87,13 @@ HistoryRecordingService.prototype.startBatchCommand = function(text) {
* End a batch command and add it to the history or a parent batch command. * End a batch command and add it to the history or a parent batch command.
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
*/ */
HistoryRecordingService.prototype.endBatchCommand = function() { HistoryRecordingService.prototype.endBatchCommand = function () {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) { if (this.currentBatchCommand_) {
var batchCommand = this.currentBatchCommand_; var batchCommand = this.currentBatchCommand_;
this.batchCommandStack_.pop(); this.batchCommandStack_.pop();
var length = this.batchCommandStack_.length; var length = this.batchCommandStack_.length;
this.currentBatchCommand_ = length ? this.batchCommandStack_[length-1] : null; this.currentBatchCommand_ = length ? this.batchCommandStack_[length - 1] : null;
this.addCommand_(batchCommand); this.addCommand_(batchCommand);
} }
return this; return this;
@@ -107,8 +107,8 @@ HistoryRecordingService.prototype.endBatchCommand = function() {
* @param {string} [text] - An optional string visible to user related to this change * @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
*/ */
HistoryRecordingService.prototype.moveElement = function(elem, oldNextSibling, oldParent, text) { HistoryRecordingService.prototype.moveElement = function (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
this.addCommand_(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text)); this.addCommand_(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text));
return this; return this;
}; };
@@ -119,13 +119,12 @@ HistoryRecordingService.prototype.moveElement = function(elem, oldNextSibling, o
* @param {string} [text] - An optional string visible to user related to this change * @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
*/ */
HistoryRecordingService.prototype.insertElement = function(elem, text) { HistoryRecordingService.prototype.insertElement = function (elem, text) {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
this.addCommand_(new history.InsertElementCommand(elem, text)); this.addCommand_(new history.InsertElementCommand(elem, text));
return this; return this;
}; };
/** /**
* Add a RemoveElementCommand to the history or current batch command * Add a RemoveElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was removed * @param {Element} elem - The DOM element that was removed
@@ -134,13 +133,12 @@ HistoryRecordingService.prototype.insertElement = function(elem, text) {
* @param {string} [text] - An optional string visible to user related to this change * @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
*/ */
HistoryRecordingService.prototype.removeElement = function(elem, oldNextSibling, oldParent, text) { HistoryRecordingService.prototype.removeElement = function (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
this.addCommand_(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text)); this.addCommand_(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text));
return this; return this;
}; };
/** /**
* Add a ChangeElementCommand to the history or current batch command * Add a ChangeElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was changed * @param {Element} elem - The DOM element that was changed
@@ -148,8 +146,8 @@ HistoryRecordingService.prototype.removeElement = function(elem, oldNextSibling,
* @param {string} [text] - An optional string visible to user related to this change * @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
*/ */
HistoryRecordingService.prototype.changeElement = function(elem, attrs, text) { HistoryRecordingService.prototype.changeElement = function (elem, attrs, text) {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
this.addCommand_(new history.ChangeElementCommand(elem, attrs, text)); this.addCommand_(new history.ChangeElementCommand(elem, attrs, text));
return this; return this;
}; };
@@ -160,14 +158,12 @@ HistoryRecordingService.prototype.changeElement = function(elem, attrs, text) {
* @returns {svgedit.history.HistoryRecordingService} * @returns {svgedit.history.HistoryRecordingService}
* @private * @private
*/ */
HistoryRecordingService.prototype.addCommand_ = function(cmd) { HistoryRecordingService.prototype.addCommand_ = function (cmd) {
if (!this.undoManager_) {return this;} if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) { if (this.currentBatchCommand_) {
this.currentBatchCommand_.addSubCommand(cmd); this.currentBatchCommand_.addSubCommand(cmd);
} else { } else {
this.undoManager_.addCommandToHistory(cmd); this.undoManager_.addCommandToHistory(cmd);
} }
}; };
}()); }());

115
editor/jquery-svg.js vendored
View File

@@ -1,5 +1,5 @@
/*globals $, jQuery */ /* eslint-disable no-var */
/*jslint vars: true */ /* globals $, jQuery */
/** /**
* jQuery module to work with SVG. * jQuery module to work with SVG.
* *
@@ -10,65 +10,66 @@
// Dependencies: // Dependencies:
// 1) jquery // 1) jquery
(function() {'use strict'; (function () {
'use strict';
// This fixes $(...).attr() to work as expected with SVG elements. // This fixes $(...).attr() to work as expected with SVG elements.
// Does not currently use *AttributeNS() since we rarely need that. // Does not currently use *AttributeNS() since we rarely need that.
// See http://api.jquery.com/attr/ for basic documentation of .attr() // See http://api.jquery.com/attr/ for basic documentation of .attr()
// Additional functionality: // Additional functionality:
// - When getting attributes, a string that's a number is return as type number. // - 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 // - If an array is supplied as first parameter, multiple values are returned
// as an object with values for each given attributes // as an object with values for each given attributes
var proxied = jQuery.fn.attr, var proxied = jQuery.fn.attr,
// TODO use NS.SVG instead // TODO use NS.SVG instead
svgns = "http://www.w3.org/2000/svg"; svgns = 'http://www.w3.org/2000/svg';
jQuery.fn.attr = function(key, value) { jQuery.fn.attr = function (key, value) {
var i, attr; var i, attr;
var len = this.length; var len = this.length;
if (!len) {return proxied.apply(this, arguments);} if (!len) { return proxied.apply(this, arguments); }
for (i = 0; i < len; ++i) { for (i = 0; i < len; ++i) {
var elem = this[i]; var elem = this[i];
// set/get SVG attribute // set/get SVG attribute
if (elem.namespaceURI === svgns) { if (elem.namespaceURI === svgns) {
// Setting attribute // Setting attribute
if (value !== undefined) { if (value !== undefined) {
elem.setAttribute(key, value); elem.setAttribute(key, value);
} else if ($.isArray(key)) { } else if ($.isArray(key)) {
// Getting attributes from array // Getting attributes from array
var j = key.length, obj = {}; var j = key.length, obj = {};
while (j--) { while (j--) {
var aname = key[j]; var aname = key[j];
attr = elem.getAttribute(aname); attr = elem.getAttribute(aname);
// This returns a number when appropriate // This returns a number when appropriate
if (attr || attr === "0") { if (attr || attr === '0') {
attr = isNaN(attr) ? attr : (attr - 0); attr = isNaN(attr) ? attr : (attr - 0);
} }
obj[aname] = attr; obj[aname] = attr;
} }
return obj; return obj;
} }
if (typeof key === "object") { if (typeof key === 'object') {
// Setting attributes form object // Setting attributes form object
var v; var v;
for (v in key) { for (v in key) {
elem.setAttribute(v, key[v]); elem.setAttribute(v, key[v]);
} }
// Getting attribute // Getting attribute
} else { } else {
attr = elem.getAttribute(key); attr = elem.getAttribute(key);
if (attr || attr === "0") { if (attr || attr === '0') {
attr = isNaN(attr) ? attr : (attr - 0); attr = isNaN(attr) ? attr : (attr - 0);
} }
return attr; return attr;
} }
} else { } else {
return proxied.apply(this, arguments); return proxied.apply(this, arguments);
} }
} }
return this; return this;
}; };
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals $ svgedit*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true */ /* globals $ svgedit */
/** /**
* Package: svgedit.history * Package: svgedit.history
* *
@@ -13,15 +13,14 @@
// 1) svgedit.js // 1) svgedit.js
// 2) draw.js // 2) draw.js
(function() { (function () {
'use strict'; 'use strict';
if (!svgedit.draw) { if (!svgedit.draw) {
svgedit.draw = {}; svgedit.draw = {};
} }
var NS = svgedit.NS; var NS = svgedit.NS;
/** /**
* This class encapsulates the concept of a layer in the drawing. It can be constructed with * This class encapsulates the concept of a layer in the drawing. It can be constructed with
* an existing group element or, with three parameters, will create a new layer group element. * an existing group element or, with three parameters, will create a new layer group element.
@@ -39,17 +38,17 @@ var NS = svgedit.NS;
* @param {SVGGElement=} svgElem - The SVG DOM element. If defined, use this to add * @param {SVGGElement=} svgElem - The SVG DOM element. If defined, use this to add
* a new layer to the document. * a new layer to the document.
*/ */
var Layer = svgedit.draw.Layer = function(name, group, svgElem) { var Layer = svgedit.draw.Layer = function (name, group, svgElem) {
this.name_ = name; this.name_ = name;
this.group_ = svgElem ? null : group; this.group_ = svgElem ? null : group;
if (svgElem) { if (svgElem) {
// Create a group element with title and add it to the DOM. // Create a group element with title and add it to the DOM.
var svgdoc = svgElem.ownerDocument; var svgdoc = svgElem.ownerDocument;
this.group_ = svgdoc.createElementNS(NS.SVG, "g"); this.group_ = svgdoc.createElementNS(NS.SVG, 'g');
var layer_title = svgdoc.createElementNS(NS.SVG, "title"); var layerTitle = svgdoc.createElementNS(NS.SVG, 'title');
layer_title.textContent = name; layerTitle.textContent = name;
this.group_.appendChild(layer_title); this.group_.appendChild(layerTitle);
if (group) { if (group) {
$(group).after(this.group_); $(group).after(this.group_);
} else { } else {
@@ -58,9 +57,11 @@ var Layer = svgedit.draw.Layer = function(name, group, svgElem) {
} }
addLayerClass(this.group_); addLayerClass(this.group_);
svgedit.utilities.walkTree(this.group_, function(e){e.setAttribute("style", "pointer-events:inherit");}); svgedit.utilities.walkTree(this.group_, function (e) {
e.setAttribute('style', 'pointer-events:inherit');
});
this.group_.setAttribute("style", svgElem ? "pointer-events:all" : "pointer-events:none"); this.group_.setAttribute('style', svgElem ? 'pointer-events:all' : 'pointer-events:none');
}; };
/** /**
@@ -73,12 +74,11 @@ Layer.CLASS_NAME = 'layer';
*/ */
Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)'); Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)');
/** /**
* Get the layer's name. * Get the layer's name.
* @returns {string} The layer name * @returns {string} The layer name
*/ */
Layer.prototype.getName = function() { Layer.prototype.getName = function () {
return this.name_; return this.name_;
}; };
@@ -86,33 +86,33 @@ Layer.prototype.getName = function() {
* Get the group element for this layer. * Get the group element for this layer.
* @returns {SVGGElement} The layer SVG group * @returns {SVGGElement} The layer SVG group
*/ */
Layer.prototype.getGroup = function() { Layer.prototype.getGroup = function () {
return this.group_; return this.group_;
}; };
/** /**
* Active this layer so it takes pointer events. * Active this layer so it takes pointer events.
*/ */
Layer.prototype.activate = function() { Layer.prototype.activate = function () {
this.group_.setAttribute("style", "pointer-events:all"); this.group_.setAttribute('style', 'pointer-events:all');
}; };
/** /**
* Deactive this layer so it does NOT take pointer events. * Deactive this layer so it does NOT take pointer events.
*/ */
Layer.prototype.deactivate = function() { Layer.prototype.deactivate = function () {
this.group_.setAttribute("style", "pointer-events:none"); this.group_.setAttribute('style', 'pointer-events:none');
}; };
/** /**
* Set this layer visible or hidden based on 'visible' parameter. * Set this layer visible or hidden based on 'visible' parameter.
* @param {boolean} visible - If true, make visible; otherwise, hide it. * @param {boolean} visible - If true, make visible; otherwise, hide it.
*/ */
Layer.prototype.setVisible = function(visible) { Layer.prototype.setVisible = function (visible) {
var expected = visible === undefined || visible ? "inline" : "none"; var expected = visible === undefined || visible ? 'inline' : 'none';
var oldDisplay = this.group_.getAttribute("display"); var oldDisplay = this.group_.getAttribute('display');
if (oldDisplay !== expected) { if (oldDisplay !== expected) {
this.group_.setAttribute("display", expected); this.group_.setAttribute('display', expected);
} }
}; };
@@ -120,7 +120,7 @@ Layer.prototype.setVisible = function(visible) {
* Is this layer visible? * Is this layer visible?
* @returns {boolean} True if visible. * @returns {boolean} True if visible.
*/ */
Layer.prototype.isVisible = function() { Layer.prototype.isVisible = function () {
return this.group_.getAttribute('display') !== 'none'; return this.group_.getAttribute('display') !== 'none';
}; };
@@ -128,7 +128,7 @@ Layer.prototype.isVisible = function() {
* Get layer opacity. * Get layer opacity.
* @returns {number} Opacity value. * @returns {number} Opacity value.
*/ */
Layer.prototype.getOpacity = function() { Layer.prototype.getOpacity = function () {
var opacity = this.group_.getAttribute('opacity'); var opacity = this.group_.getAttribute('opacity');
if (opacity === null || opacity === undefined) { if (opacity === null || opacity === undefined) {
return 1; return 1;
@@ -141,7 +141,7 @@ Layer.prototype.getOpacity = function() {
* nothing happens. * nothing happens.
* @param {number} opacity - A float value in the range 0.0-1.0 * @param {number} opacity - A float value in the range 0.0-1.0
*/ */
Layer.prototype.setOpacity = function(opacity) { Layer.prototype.setOpacity = function (opacity) {
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) { if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
this.group_.setAttribute('opacity', opacity); this.group_.setAttribute('opacity', opacity);
} }
@@ -151,13 +151,13 @@ Layer.prototype.setOpacity = function(opacity) {
* Append children to this layer. * Append children to this layer.
* @param {SVGGElement} children - The children to append to this layer. * @param {SVGGElement} children - The children to append to this layer.
*/ */
Layer.prototype.appendChildren = function(children) { Layer.prototype.appendChildren = function (children) {
for (var i = 0; i < children.length; ++i) { for (var i = 0; i < children.length; ++i) {
this.group_.appendChild(children[i]); this.group_.appendChild(children[i]);
} }
}; };
Layer.prototype.getTitleElement = function() { Layer.prototype.getTitleElement = function () {
var len = this.group_.childNodes.length; var len = this.group_.childNodes.length;
for (var i = 0; i < len; ++i) { for (var i = 0; i < len; ++i) {
var child = this.group_.childNodes.item(i); var child = this.group_.childNodes.item(i);
@@ -174,7 +174,7 @@ Layer.prototype.getTitleElement = function() {
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service * @param {svgedit.history.HistoryRecordingService} hrService - History recording service
* @returns {string|null} The new name if changed; otherwise, null. * @returns {string|null} The new name if changed; otherwise, null.
*/ */
Layer.prototype.setName = function(name, hrService) { Layer.prototype.setName = function (name, hrService) {
var previousName = this.name_; var previousName = this.name_;
name = svgedit.utilities.toXml(name); name = svgedit.utilities.toXml(name);
// now change the underlying title element contents // now change the underlying title element contents
@@ -184,7 +184,7 @@ Layer.prototype.setName = function(name, hrService) {
title.textContent = name; title.textContent = name;
this.name_ = name; this.name_ = name;
if (hrService) { if (hrService) {
hrService.changeElement(title, {'#text':previousName}); hrService.changeElement(title, {'#text': previousName});
} }
return this.name_; return this.name_;
} }
@@ -196,27 +196,25 @@ Layer.prototype.setName = function(name, hrService) {
* @param {SVGGElement} children - The children to append to this layer. * @param {SVGGElement} children - The children to append to this layer.
* @returns {SVGGElement} The layer SVG group that was just removed. * @returns {SVGGElement} The layer SVG group that was just removed.
*/ */
Layer.prototype.removeGroup = function() { Layer.prototype.removeGroup = function () {
var parent = this.group_.parentNode; var parent = this.group_.parentNode;
var group = parent.removeChild(this.group_); var group = parent.removeChild(this.group_);
this.group_ = undefined; this.group_ = undefined;
return group; return group;
}; };
/** /**
* Add class Layer.CLASS_NAME to the element (usually class='layer'). * Add class Layer.CLASS_NAME to the element (usually class='layer').
* *
* Parameters: * Parameters:
* @param {SVGGElement} elem - The SVG element to update * @param {SVGGElement} elem - The SVG element to update
*/ */
function addLayerClass(elem) { function addLayerClass (elem) {
var classes = elem.getAttribute('class'); var classes = elem.getAttribute('class');
if (classes === null || classes === undefined || classes.length === 0) { if (classes === null || classes === undefined || classes.length === 0) {
elem.setAttribute('class', Layer.CLASS_NAME); elem.setAttribute('class', Layer.CLASS_NAME);
} else if (! Layer.CLASS_REGEX.test(classes)) { } else if (!Layer.CLASS_REGEX.test(classes)) {
elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME); elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME);
} }
} }
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals svgedit*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true */ /* globals svgedit */
/** /**
* Package: svedit.math * Package: svedit.math
* *
@@ -11,7 +11,7 @@
// Dependencies: // Dependencies:
// None. // None.
/** /**
* @typedef AngleCoord45 * @typedef AngleCoord45
* @type {object} * @type {object}
@@ -20,7 +20,8 @@
* @property {number} a - The angle at which to snap * @property {number} a - The angle at which to snap
*/ */
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.math) { if (!svgedit.math) {
svgedit.math = {}; svgedit.math = {};
@@ -41,12 +42,11 @@ var svg = document.createElementNS(svgedit.NS.SVG, 'svg');
* @returns {object} An x, y object representing the transformed point * @returns {object} An x, y object representing the transformed point
*/ */
svgedit.math.transformPoint = function (x, y, m) { svgedit.math.transformPoint = function (x, y, m) {
return { x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f}; return {x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f};
}; };
/** /**
* Helper function to check if the matrix performs no actual transform * Helper function to check if the matrix performs no actual transform
* (i.e. exists for identity purposes) * (i.e. exists for identity purposes)
* @param {SVGMatrix} m - The matrix object to check * @param {SVGMatrix} m - The matrix object to check
* @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0 * @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0
@@ -55,7 +55,6 @@ svgedit.math.isIdentity = function (m) {
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0); return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
}; };
/** /**
* This function tries to return a SVGMatrix that is the multiplication m1*m2. * This function tries to return a SVGMatrix that is the multiplication m1*m2.
* We also round to zero when it's near zero * We also round to zero when it's near zero
@@ -63,18 +62,18 @@ svgedit.math.isIdentity = function (m) {
* @returns {SVGMatrix} The matrix object resulting from the calculation * @returns {SVGMatrix} The matrix object resulting from the calculation
*/ */
svgedit.math.matrixMultiply = function (matr) { svgedit.math.matrixMultiply = function (matr) {
var args = arguments, i = args.length, m = args[i-1]; var args = arguments, i = args.length, m = args[i - 1];
while (i-- > 1) { while (i-- > 1) {
var m1 = args[i-1]; var m1 = args[i - 1];
m = m1.multiply(m); m = m1.multiply(m);
} }
if (Math.abs(m.a) < NEAR_ZERO) {m.a = 0;} if (Math.abs(m.a) < NEAR_ZERO) { m.a = 0; }
if (Math.abs(m.b) < NEAR_ZERO) {m.b = 0;} if (Math.abs(m.b) < NEAR_ZERO) { m.b = 0; }
if (Math.abs(m.c) < NEAR_ZERO) {m.c = 0;} if (Math.abs(m.c) < NEAR_ZERO) { m.c = 0; }
if (Math.abs(m.d) < NEAR_ZERO) {m.d = 0;} if (Math.abs(m.d) < NEAR_ZERO) { m.d = 0; }
if (Math.abs(m.e) < NEAR_ZERO) {m.e = 0;} if (Math.abs(m.e) < NEAR_ZERO) { m.e = 0; }
if (Math.abs(m.f) < NEAR_ZERO) {m.f = 0;} if (Math.abs(m.f) < NEAR_ZERO) { m.f = 0; }
return m; return m;
}; };
@@ -85,11 +84,11 @@ svgedit.math.matrixMultiply = function (matr) {
* @returns {boolean} Whether or not a matrix transform was found * @returns {boolean} Whether or not a matrix transform was found
*/ */
svgedit.math.hasMatrixTransform = function (tlist) { svgedit.math.hasMatrixTransform = function (tlist) {
if (!tlist) {return false;} if (!tlist) { return false; }
var num = tlist.numberOfItems; var num = tlist.numberOfItems;
while (num--) { while (num--) {
var xform = tlist.getItem(num); var xform = tlist.getItem(num);
if (xform.type == 1 && !svgedit.math.isIdentity(xform.matrix)) {return true;} if (xform.type == 1 && !svgedit.math.isIdentity(xform.matrix)) { return true; }
} }
return false; return false;
}; };
@@ -164,15 +163,14 @@ svgedit.math.transformListToTransform = function (tlist, min, max) {
var i; var i;
for (i = min; i <= max; ++i) { for (i = min; i <= max; ++i) {
// if our indices are out of range, just use a harmless identity matrix // if our indices are out of range, just use a harmless identity matrix
var mtom = (i >= 0 && i < tlist.numberOfItems ? var mtom = (i >= 0 && i < tlist.numberOfItems
tlist.getItem(i).matrix : ? tlist.getItem(i).matrix
svg.createSVGMatrix()); : svg.createSVGMatrix());
m = svgedit.math.matrixMultiply(m, mtom); m = svgedit.math.matrixMultiply(m, mtom);
} }
return svg.createSVGTransformFromMatrix(m); return svg.createSVGTransformFromMatrix(m);
}; };
/** /**
* Get the matrix object for a given element * Get the matrix object for a given element
* @param {Element} elem - The DOM element to check * @param {Element} elem - The DOM element to check
@@ -183,7 +181,6 @@ svgedit.math.getMatrix = function (elem) {
return svgedit.math.transformListToTransform(tlist).matrix; return svgedit.math.transformListToTransform(tlist).matrix;
}; };
/** /**
* Returns a 45 degree angle coordinate associated with the two given * Returns a 45 degree angle coordinate associated with the two given
* coordinates * coordinates
@@ -208,7 +205,6 @@ svgedit.math.snapToAngle = function (x1, y1, x2, y2) {
}; };
}; };
/** /**
* Check if two rectangles (BBoxes objects) intersect each other * Check if two rectangles (BBoxes objects) intersect each other
* @param {SVGRect} r1 - The first BBox-like object * @param {SVGRect} r1 - The first BBox-like object
@@ -221,5 +217,4 @@ svgedit.math.rectsIntersect = function (r1, r2) {
r2.y < (r1.y + r1.height) && r2.y < (r1.y + r1.height) &&
(r2.y + r2.height) > r1.y; (r2.y + r2.height) > r1.y;
}; };
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit, svgroot*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true, continue: true*/ /* globals $, svgedit, svgroot */
/** /**
* Package: svgedit.path * Package: svgedit.path
* *
@@ -15,7 +15,8 @@
// 3) math.js // 3) math.js
// 4) svgutils.js // 4) svgutils.js
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.path) { if (!svgedit.path) {
svgedit.path = {}; svgedit.path = {};
@@ -41,33 +42,33 @@ var segData = {
var pathFuncs = []; var pathFuncs = [];
var link_control_pts = true; var linkControlPts = true;
// Stores references to paths via IDs. // Stores references to paths via IDs.
// TODO: Make this cross-document happy. // TODO: Make this cross-document happy.
var pathData = {}; var pathData = {};
svgedit.path.setLinkControlPoints = function(lcp) { svgedit.path.setLinkControlPoints = function (lcp) {
link_control_pts = lcp; linkControlPts = lcp;
}; };
svgedit.path.path = null; svgedit.path.path = null;
var editorContext_ = null; var editorContext_ = null;
svgedit.path.init = function(editorContext) { svgedit.path.init = function (editorContext) {
editorContext_ = editorContext; editorContext_ = editorContext;
pathFuncs = [0, 'ClosePath']; pathFuncs = [0, 'ClosePath'];
var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc',
'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth']; 'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth'];
$.each(pathFuncsStrs, function(i, s) { $.each(pathFuncsStrs, function (i, s) {
pathFuncs.push(s+'Abs'); pathFuncs.push(s + 'Abs');
pathFuncs.push(s+'Rel'); pathFuncs.push(s + 'Rel');
}); });
}; };
svgedit.path.insertItemBefore = function(elem, newseg, index) { svgedit.path.insertItemBefore = function (elem, newseg, index) {
// Support insertItemBefore on paths for FF2 // Support insertItemBefore on paths for FF2
var list = elem.pathSegList; var list = elem.pathSegList;
@@ -78,13 +79,13 @@ svgedit.path.insertItemBefore = function(elem, newseg, index) {
var len = list.numberOfItems; var len = list.numberOfItems;
var arr = []; var arr = [];
var i; var i;
for (i=0; i < len; i++) { for (i = 0; i < len; i++) {
var cur_seg = list.getItem(i); var curSeg = list.getItem(i);
arr.push(cur_seg); arr.push(curSeg);
} }
list.clear(); list.clear();
for (i=0; i < len; i++) { for (i = 0; i < len; i++) {
if (i == index) { //index+1 if (i == index) { // index + 1
list.appendItem(newseg); list.appendItem(newseg);
} }
list.appendItem(arr[i]); list.appendItem(arr[i]);
@@ -92,20 +93,20 @@ svgedit.path.insertItemBefore = function(elem, newseg, index) {
}; };
// TODO: See if this should just live in replacePathSeg // TODO: See if this should just live in replacePathSeg
svgedit.path.ptObjToArr = function(type, seg_item) { svgedit.path.ptObjToArr = function (type, segItem) {
var arr = segData[type], len = arr.length; var arr = segData[type], len = arr.length;
var i, out = []; var i, out = [];
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
out[i] = seg_item[arr[i]]; out[i] = segItem[arr[i]];
} }
return out; return out;
}; };
svgedit.path.getGripPt = function(seg, alt_pt) { svgedit.path.getGripPt = function (seg, altPt) {
var out = { var out = {
x: alt_pt? alt_pt.x : seg.item.x, x: altPt ? altPt.x : seg.item.x,
y: alt_pt? alt_pt.y : seg.item.y y: altPt ? altPt.y : seg.item.y
}, path = seg.path; }, path = seg.path;
if (path.matrix) { if (path.matrix) {
var pt = svgedit.math.transformPoint(out.x, out.y, path.matrix); var pt = svgedit.math.transformPoint(out.x, out.y, path.matrix);
@@ -118,7 +119,7 @@ svgedit.path.getGripPt = function(seg, alt_pt) {
return out; return out;
}; };
svgedit.path.getPointFromGrip = function(pt, path) { svgedit.path.getPointFromGrip = function (pt, path) {
var out = { var out = {
x: pt.x, x: pt.x,
y: pt.y y: pt.y
@@ -136,11 +137,11 @@ svgedit.path.getPointFromGrip = function(pt, path) {
return out; return out;
}; };
svgedit.path.addPointGrip = function(index, x, y) { svgedit.path.addPointGrip = function (index, x, y) {
// create the container of all the point grips // create the container of all the point grips
var pointGripContainer = svgedit.path.getGripContainer(); var pointGripContainer = svgedit.path.getGripContainer();
var pointGrip = svgedit.utilities.getElem('pathpointgrip_'+index); var pointGrip = svgedit.utilities.getElem('pathpointgrip_' + index);
// create it // create it
if (!pointGrip) { if (!pointGrip) {
pointGrip = document.createElementNS(NS.SVG, 'circle'); pointGrip = document.createElementNS(NS.SVG, 'circle');
@@ -157,8 +158,8 @@ svgedit.path.addPointGrip = function(index, x, y) {
}); });
pointGrip = pointGripContainer.appendChild(pointGrip); pointGrip = pointGripContainer.appendChild(pointGrip);
var grip = $('#pathpointgrip_'+index); var grip = $('#pathpointgrip_' + index);
grip.dblclick(function() { grip.dblclick(function () {
if (svgedit.path.path) { if (svgedit.path.path) {
svgedit.path.path.setSegType(); svgedit.path.path.setSegType();
} }
@@ -175,7 +176,7 @@ svgedit.path.addPointGrip = function(index, x, y) {
return pointGrip; return pointGrip;
}; };
svgedit.path.getGripContainer = function() { svgedit.path.getGripContainer = function () {
var c = svgedit.utilities.getElem('pathpointgrip_container'); var c = svgedit.utilities.getElem('pathpointgrip_container');
if (!c) { if (!c) {
var parent = svgedit.utilities.getElem('selectorParentGroup'); var parent = svgedit.utilities.getElem('selectorParentGroup');
@@ -185,9 +186,9 @@ svgedit.path.getGripContainer = function() {
return c; return c;
}; };
svgedit.path.addCtrlGrip = function(id) { svgedit.path.addCtrlGrip = function (id) {
var pointGrip = svgedit.utilities.getElem('ctrlpointgrip_'+id); var pointGrip = svgedit.utilities.getElem('ctrlpointgrip_' + id);
if (pointGrip) {return pointGrip;} if (pointGrip) { return pointGrip; }
pointGrip = document.createElementNS(NS.SVG, 'circle'); pointGrip = document.createElementNS(NS.SVG, 'circle');
svgedit.utilities.assignAttributes(pointGrip, { svgedit.utilities.assignAttributes(pointGrip, {
@@ -205,13 +206,13 @@ svgedit.path.addCtrlGrip = function(id) {
return pointGrip; return pointGrip;
}; };
svgedit.path.getCtrlLine = function(id) { svgedit.path.getCtrlLine = function (id) {
var ctrlLine = svgedit.utilities.getElem('ctrlLine_'+id); var ctrlLine = svgedit.utilities.getElem('ctrlLine_' + id);
if (ctrlLine) {return ctrlLine;} if (ctrlLine) { return ctrlLine; }
ctrlLine = document.createElementNS(NS.SVG, 'line'); ctrlLine = document.createElementNS(NS.SVG, 'line');
svgedit.utilities.assignAttributes(ctrlLine, { svgedit.utilities.assignAttributes(ctrlLine, {
'id': 'ctrlLine_'+id, 'id': 'ctrlLine_' + id,
'stroke': '#555', 'stroke': '#555',
'stroke-width': 1, 'stroke-width': 1,
'style': 'pointer-events:none' 'style': 'pointer-events:none'
@@ -220,7 +221,7 @@ svgedit.path.getCtrlLine = function(id) {
return ctrlLine; return ctrlLine;
}; };
svgedit.path.getPointGrip = function(seg, update) { svgedit.path.getPointGrip = function (seg, update) {
var index = seg.index; var index = seg.index;
var pointGrip = svgedit.path.addPointGrip(index); var pointGrip = svgedit.path.addPointGrip(index);
@@ -236,17 +237,17 @@ svgedit.path.getPointGrip = function(seg, update) {
return pointGrip; return pointGrip;
}; };
svgedit.path.getControlPoints = function(seg) { svgedit.path.getControlPoints = function (seg) {
var item = seg.item; var item = seg.item;
var index = seg.index; var index = seg.index;
if (!('x1' in item) || !('x2' in item)) {return null;} if (!('x1' in item) || !('x2' in item)) { return null; }
var cpt = {}; var cpt = {};
var pointGripContainer = svgedit.path.getGripContainer(); /* var pointGripContainer = */ svgedit.path.getGripContainer();
// Note that this is intentionally not seg.prev.item // Note that this is intentionally not seg.prev.item
var prev = svgedit.path.path.segs[index-1].item; var prev = svgedit.path.path.segs[index - 1].item;
var seg_items = [prev, item]; var segItems = [prev, item];
var i; var i;
for (i = 1; i < 3; i++) { for (i = 1; i < 3; i++) {
@@ -254,8 +255,8 @@ svgedit.path.getControlPoints = function(seg) {
var ctrlLine = cpt['c' + i + '_line'] = svgedit.path.getCtrlLine(id); var ctrlLine = cpt['c' + i + '_line'] = svgedit.path.getCtrlLine(id);
var pt = svgedit.path.getGripPt(seg, {x:item['x' + i], y:item['y' + i]}); var pt = svgedit.path.getGripPt(seg, {x: item['x' + i], y: item['y' + i]});
var gpt = svgedit.path.getGripPt(seg, {x:seg_items[i-1].x, y:seg_items[i-1].y}); var gpt = svgedit.path.getGripPt(seg, {x: segItems[i - 1].x, y: segItems[i - 1].y});
svgedit.utilities.assignAttributes(ctrlLine, { svgedit.utilities.assignAttributes(ctrlLine, {
'x1': pt.x, 'x1': pt.x,
@@ -281,7 +282,7 @@ svgedit.path.getControlPoints = function(seg) {
}; };
// This replaces the segment at the given index. Type is given as number. // This replaces the segment at the given index. Type is given as number.
svgedit.path.replacePathSeg = function(type, index, pts, elem) { svgedit.path.replacePathSeg = function (type, index, pts, elem) {
var path = elem || svgedit.path.path.elem; var path = elem || svgedit.path.path.elem;
var func = 'createSVGPathSeg' + pathFuncs[type]; var func = 'createSVGPathSeg' + pathFuncs[type];
@@ -295,8 +296,8 @@ svgedit.path.replacePathSeg = function(type, index, pts, elem) {
var arr = []; var arr = [];
var i; var i;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
var cur_seg = segList.getItem(i); var curSeg = segList.getItem(i);
arr.push(cur_seg); arr.push(curSeg);
} }
segList.clear(); segList.clear();
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
@@ -309,7 +310,7 @@ svgedit.path.replacePathSeg = function(type, index, pts, elem) {
} }
}; };
svgedit.path.getSegSelector = function(seg, update) { svgedit.path.getSegSelector = function (seg, update) {
var index = seg.index; var index = seg.index;
var segLine = svgedit.utilities.getElem('segline_' + index); var segLine = svgedit.utilities.getElem('segline_' + index);
if (!segLine) { if (!segLine) {
@@ -322,7 +323,7 @@ svgedit.path.getSegSelector = function(seg, update) {
'fill': 'none', 'fill': 'none',
'stroke': '#0FF', 'stroke': '#0FF',
'stroke-width': 2, 'stroke-width': 2,
'style':'pointer-events:none', 'style': 'pointer-events:none',
'd': 'M0,0 0,0' 'd': 'M0,0 0,0'
}); });
pointGripContainer.appendChild(segLine); pointGripContainer.appendChild(segLine);
@@ -342,9 +343,9 @@ svgedit.path.getSegSelector = function(seg, update) {
var pts = svgedit.path.ptObjToArr(seg.type, seg.item, true); var pts = svgedit.path.ptObjToArr(seg.type, seg.item, true);
var i; var i;
for (i = 0; i < pts.length; i += 2) { for (i = 0; i < pts.length; i += 2) {
pt = svgedit.path.getGripPt(seg, {x:pts[i], y:pts[i+1]}); pt = svgedit.path.getGripPt(seg, {x: pts[i], y: pts[i + 1]});
pts[i] = pt.x; pts[i] = pt.x;
pts[i+1] = pt.y; pts[i + 1] = pt.y;
} }
svgedit.path.replacePathSeg(seg.type, 1, pts, segLine); svgedit.path.replacePathSeg(seg.type, 1, pts, segLine);
@@ -354,56 +355,55 @@ svgedit.path.getSegSelector = function(seg, update) {
// Function: smoothControlPoints // Function: smoothControlPoints
// Takes three points and creates a smoother line based on them // Takes three points and creates a smoother line based on them
// //
// Parameters: // Parameters:
// ct1 - Object with x and y values (first control point) // ct1 - Object with x and y values (first control point)
// ct2 - Object with x and y values (second control point) // ct2 - Object with x and y values (second control point)
// pt - Object with x and y values (third point) // pt - Object with x and y values (third point)
// //
// Returns: // Returns:
// Array of two "smoothed" point objects // Array of two "smoothed" point objects
svgedit.path.smoothControlPoints = function(ct1, ct2, pt) { svgedit.path.smoothControlPoints = function (ct1, ct2, pt) {
// each point must not be the origin // each point must not be the origin
var x1 = ct1.x - pt.x, var x1 = ct1.x - pt.x,
y1 = ct1.y - pt.y, y1 = ct1.y - pt.y,
x2 = ct2.x - pt.x, x2 = ct2.x - pt.x,
y2 = ct2.y - pt.y; y2 = ct2.y - pt.y;
if ( (x1 != 0 || y1 != 0) && (x2 != 0 || y2 != 0) ) { if ((x1 != 0 || y1 != 0) && (x2 != 0 || y2 != 0)) {
var anglea = Math.atan2(y1, x1), var anglea = Math.atan2(y1, x1),
angleb = Math.atan2(y2, x2), angleb = Math.atan2(y2, x2),
r1 = Math.sqrt(x1*x1+y1*y1), r1 = Math.sqrt(x1 * x1 + y1 * y1),
r2 = Math.sqrt(x2*x2+y2*y2), r2 = Math.sqrt(x2 * x2 + y2 * y2),
nct1 = editorContext_.getSVGRoot().createSVGPoint(), nct1 = editorContext_.getSVGRoot().createSVGPoint(),
nct2 = editorContext_.getSVGRoot().createSVGPoint(); nct2 = editorContext_.getSVGRoot().createSVGPoint();
if (anglea < 0) { anglea += 2*Math.PI; } if (anglea < 0) { anglea += 2 * Math.PI; }
if (angleb < 0) { angleb += 2*Math.PI; } if (angleb < 0) { angleb += 2 * Math.PI; }
var angleBetween = Math.abs(anglea - angleb), var angleBetween = Math.abs(anglea - angleb),
angleDiff = Math.abs(Math.PI - angleBetween)/2; angleDiff = Math.abs(Math.PI - angleBetween) / 2;
var new_anglea, new_angleb; var newAnglea, newAngleb;
if (anglea - angleb > 0) { if (anglea - angleb > 0) {
new_anglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff); newAnglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff);
new_angleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff); newAngleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff);
} } else {
else { newAnglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff);
new_anglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff); newAngleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
new_angleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
} }
// rotate the points // rotate the points
nct1.x = r1 * Math.cos(new_anglea) + pt.x; nct1.x = r1 * Math.cos(newAnglea) + pt.x;
nct1.y = r1 * Math.sin(new_anglea) + pt.y; nct1.y = r1 * Math.sin(newAnglea) + pt.y;
nct2.x = r2 * Math.cos(new_angleb) + pt.x; nct2.x = r2 * Math.cos(newAngleb) + pt.x;
nct2.y = r2 * Math.sin(new_angleb) + pt.y; nct2.y = r2 * Math.sin(newAngleb) + pt.y;
return [nct1, nct2]; return [nct1, nct2];
} }
return undefined; return undefined;
}; };
svgedit.path.Segment = function(index, item) { svgedit.path.Segment = function (index, item) {
this.selected = false; this.selected = false;
this.index = index; this.index = index;
this.item = item; this.item = item;
@@ -414,7 +414,7 @@ svgedit.path.Segment = function(index, item) {
this.segsel = null; this.segsel = null;
}; };
svgedit.path.Segment.prototype.showCtrlPts = function(y) { svgedit.path.Segment.prototype.showCtrlPts = function (y) {
var i; var i;
for (i in this.ctrlpts) { for (i in this.ctrlpts) {
if (this.ctrlpts.hasOwnProperty(i)) { if (this.ctrlpts.hasOwnProperty(i)) {
@@ -423,12 +423,12 @@ svgedit.path.Segment.prototype.showCtrlPts = function(y) {
} }
}; };
svgedit.path.Segment.prototype.selectCtrls = function(y) { svgedit.path.Segment.prototype.selectCtrls = function (y) {
$('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2'). $('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2')
attr('fill', y ? '#0FF' : '#EEE'); .attr('fill', y ? '#0FF' : '#EEE');
}; };
svgedit.path.Segment.prototype.show = function(y) { svgedit.path.Segment.prototype.show = function (y) {
if (this.ptgrip) { if (this.ptgrip) {
this.ptgrip.setAttribute('display', y ? 'inline' : 'none'); this.ptgrip.setAttribute('display', y ? 'inline' : 'none');
this.segsel.setAttribute('display', y ? 'inline' : 'none'); this.segsel.setAttribute('display', y ? 'inline' : 'none');
@@ -437,7 +437,7 @@ svgedit.path.Segment.prototype.show = function(y) {
} }
}; };
svgedit.path.Segment.prototype.select = function(y) { svgedit.path.Segment.prototype.select = function (y) {
if (this.ptgrip) { if (this.ptgrip) {
this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F'); this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F');
this.segsel.setAttribute('display', y ? 'inline' : 'none'); this.segsel.setAttribute('display', y ? 'inline' : 'none');
@@ -448,13 +448,13 @@ svgedit.path.Segment.prototype.select = function(y) {
} }
}; };
svgedit.path.Segment.prototype.addGrip = function() { svgedit.path.Segment.prototype.addGrip = function () {
this.ptgrip = svgedit.path.getPointGrip(this, true); this.ptgrip = svgedit.path.getPointGrip(this, true);
this.ctrlpts = svgedit.path.getControlPoints(this, true); this.ctrlpts = svgedit.path.getControlPoints(this, true);
this.segsel = svgedit.path.getSegSelector(this, true); this.segsel = svgedit.path.getSegSelector(this, true);
}; };
svgedit.path.Segment.prototype.update = function(full) { svgedit.path.Segment.prototype.update = function (full) {
if (this.ptgrip) { if (this.ptgrip) {
var pt = svgedit.path.getGripPt(this); var pt = svgedit.path.getGripPt(this);
svgedit.utilities.assignAttributes(this.ptgrip, { svgedit.utilities.assignAttributes(this.ptgrip, {
@@ -475,23 +475,23 @@ svgedit.path.Segment.prototype.update = function(full) {
} }
}; };
svgedit.path.Segment.prototype.move = function(dx, dy) { svgedit.path.Segment.prototype.move = function (dx, dy) {
var cur_pts, item = this.item; var curPts, item = this.item;
if (this.ctrlpts) { if (this.ctrlpts) {
cur_pts = [item.x += dx, item.y += dy, curPts = [item.x += dx, item.y += dy,
item.x1, item.y1, item.x2 += dx, item.y2 += dy]; item.x1, item.y1, item.x2 += dx, item.y2 += dy];
} else { } else {
cur_pts = [item.x += dx, item.y += dy]; curPts = [item.x += dx, item.y += dy];
} }
svgedit.path.replacePathSeg(this.type, this.index, cur_pts); svgedit.path.replacePathSeg(this.type, this.index, curPts);
if (this.next && this.next.ctrlpts) { if (this.next && this.next.ctrlpts) {
var next = this.next.item; var next = this.next.item;
var next_pts = [next.x, next.y, var nextPts = [next.x, next.y,
next.x1 += dx, next.y1 += dy, next.x2, next.y2]; next.x1 += dx, next.y1 += dy, next.x2, next.y2];
svgedit.path.replacePathSeg(this.next.type, this.next.index, next_pts); svgedit.path.replacePathSeg(this.next.type, this.next.index, nextPts);
} }
if (this.mate) { if (this.mate) {
@@ -504,26 +504,26 @@ svgedit.path.Segment.prototype.move = function(dx, dy) {
} }
this.update(true); this.update(true);
if (this.next) {this.next.update(true);} if (this.next) { this.next.update(true); }
}; };
svgedit.path.Segment.prototype.setLinked = function(num) { svgedit.path.Segment.prototype.setLinked = function (num) {
var seg, anum, pt; var seg, anum, pt;
if (num == 2) { if (num == 2) {
anum = 1; anum = 1;
seg = this.next; seg = this.next;
if (!seg) {return;} if (!seg) { return; }
pt = this.item; pt = this.item;
} else { } else {
anum = 2; anum = 2;
seg = this.prev; seg = this.prev;
if (!seg) {return;} if (!seg) { return; }
pt = seg.item; pt = seg.item;
} }
var item = seg.item; var item = seg.item;
item['x' + anum ] = pt.x + (pt.x - this.item['x' + num]); item['x' + anum] = pt.x + (pt.x - this.item['x' + num]);
item['y' + anum ] = pt.y + (pt.y - this.item['y' + num]); item['y' + anum] = pt.y + (pt.y - this.item['y' + num]);
var pts = [item.x, item.y, var pts = [item.x, item.y,
item.x1, item.y1, item.x1, item.y1,
@@ -533,30 +533,30 @@ svgedit.path.Segment.prototype.setLinked = function(num) {
seg.update(true); seg.update(true);
}; };
svgedit.path.Segment.prototype.moveCtrl = function(num, dx, dy) { svgedit.path.Segment.prototype.moveCtrl = function (num, dx, dy) {
var item = this.item; var item = this.item;
item['x' + num] += dx; item['x' + num] += dx;
item['y' + num] += dy; item['y' + num] += dy;
var pts = [item.x,item.y, var pts = [item.x, item.y,
item.x1,item.y1, item.x2,item.y2]; item.x1, item.y1, item.x2, item.y2];
svgedit.path.replacePathSeg(this.type, this.index, pts); svgedit.path.replacePathSeg(this.type, this.index, pts);
this.update(true); this.update(true);
}; };
svgedit.path.Segment.prototype.setType = function(new_type, pts) { svgedit.path.Segment.prototype.setType = function (newType, pts) {
svgedit.path.replacePathSeg(new_type, this.index, pts); svgedit.path.replacePathSeg(newType, this.index, pts);
this.type = new_type; this.type = newType;
this.item = svgedit.path.path.elem.pathSegList.getItem(this.index); this.item = svgedit.path.path.elem.pathSegList.getItem(this.index);
this.showCtrlPts(new_type === 6); this.showCtrlPts(newType === 6);
this.ctrlpts = svgedit.path.getControlPoints(this); this.ctrlpts = svgedit.path.getControlPoints(this);
this.update(true); this.update(true);
}; };
svgedit.path.Path = function(elem) { svgedit.path.Path = function (elem) {
if (!elem || elem.tagName !== 'path') { if (!elem || elem.tagName !== 'path') {
throw 'svgedit.path.Path constructed without a <path> element'; throw new Error('svgedit.path.Path constructed without a <path> element');
} }
this.elem = elem; this.elem = elem;
@@ -568,11 +568,13 @@ svgedit.path.Path = function(elem) {
}; };
// Reset path data // Reset path data
svgedit.path.Path.prototype.init = function() { svgedit.path.Path.prototype.init = function () {
// Hide all grips, etc // Hide all grips, etc
//fixed, needed to work on all found elements, not just first // fixed, needed to work on all found elements, not just first
$(svgedit.path.getGripContainer()).find('*').each( function() { $(this).attr('display', 'none') }); $(svgedit.path.getGripContainer()).find('*').each(function () {
$(this).attr('display', 'none');
});
var segList = this.elem.pathSegList; var segList = this.elem.pathSegList;
var len = segList.numberOfItems; var len = segList.numberOfItems;
@@ -590,58 +592,58 @@ svgedit.path.Path.prototype.init = function() {
} }
var segs = this.segs; var segs = this.segs;
var start_i = null; var startI = null;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
var seg = segs[i]; var seg = segs[i];
var next_seg = (i+1) >= len ? null : segs[i+1]; var nextSeg = (i + 1) >= len ? null : segs[i + 1];
var prev_seg = (i-1) < 0 ? null : segs[i-1]; var prevSeg = (i - 1) < 0 ? null : segs[i - 1];
var start_seg; var startSeg;
if (seg.type === 2) { if (seg.type === 2) {
if (prev_seg && prev_seg.type !== 1) { if (prevSeg && prevSeg.type !== 1) {
// New sub-path, last one is open, // New sub-path, last one is open,
// so add a grip to last sub-path's first point // so add a grip to last sub-path's first point
start_seg = segs[start_i]; startSeg = segs[startI];
start_seg.next = segs[start_i+1]; startSeg.next = segs[startI + 1];
start_seg.next.prev = start_seg; startSeg.next.prev = startSeg;
start_seg.addGrip(); startSeg.addGrip();
} }
// Remember that this is a starter seg // Remember that this is a starter seg
start_i = i; startI = i;
} else if (next_seg && next_seg.type === 1) { } else if (nextSeg && nextSeg.type === 1) {
// This is the last real segment of a closed sub-path // This is the last real segment of a closed sub-path
// Next is first seg after "M" // Next is first seg after "M"
seg.next = segs[start_i+1]; seg.next = segs[startI + 1];
// First seg after "M"'s prev is this // First seg after "M"'s prev is this
seg.next.prev = seg; seg.next.prev = seg;
seg.mate = segs[start_i]; seg.mate = segs[startI];
seg.addGrip(); seg.addGrip();
if (this.first_seg == null) { if (this.first_seg == null) {
this.first_seg = seg; this.first_seg = seg;
} }
} else if (!next_seg) { } else if (!nextSeg) {
if (seg.type !== 1) { if (seg.type !== 1) {
// Last seg, doesn't close so add a grip // Last seg, doesn't close so add a grip
// to last sub-path's first point // to last sub-path's first point
start_seg = segs[start_i]; startSeg = segs[startI];
start_seg.next = segs[start_i+1]; startSeg.next = segs[startI + 1];
start_seg.next.prev = start_seg; startSeg.next.prev = startSeg;
start_seg.addGrip(); startSeg.addGrip();
seg.addGrip(); seg.addGrip();
if (!this.first_seg) { if (!this.first_seg) {
// Open path, so set first as real first and add grip // Open path, so set first as real first and add grip
this.first_seg = segs[start_i]; this.first_seg = segs[startI];
} }
} }
} else if (seg.type !== 1){ } else if (seg.type !== 1) {
// Regular segment, so add grip and its "next" // Regular segment, so add grip and its "next"
seg.addGrip(); seg.addGrip();
// Don't set its "next" if it's an "M" // Don't set its "next" if it's an "M"
if (next_seg && next_seg.type !== 2) { if (nextSeg && nextSeg.type !== 2) {
seg.next = next_seg; seg.next = nextSeg;
seg.next.prev = seg; seg.next.prev = seg;
} }
} }
@@ -649,44 +651,44 @@ svgedit.path.Path.prototype.init = function() {
return this; return this;
}; };
svgedit.path.Path.prototype.eachSeg = function(fn) { svgedit.path.Path.prototype.eachSeg = function (fn) {
var i; var i;
var len = this.segs.length; var len = this.segs.length;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
var ret = fn.call(this.segs[i], i); var ret = fn.call(this.segs[i], i);
if (ret === false) {break;} if (ret === false) { break; }
} }
}; };
svgedit.path.Path.prototype.addSeg = function(index) { svgedit.path.Path.prototype.addSeg = function (index) {
// Adds a new segment // Adds a new segment
var seg = this.segs[index]; var seg = this.segs[index];
if (!seg.prev) {return;} if (!seg.prev) { return; }
var prev = seg.prev; var prev = seg.prev;
var newseg, new_x, new_y; var newseg, newX, newY;
switch(seg.item.pathSegType) { switch (seg.item.pathSegType) {
case 4: case 4:
new_x = (seg.item.x + prev.item.x) / 2; newX = (seg.item.x + prev.item.x) / 2;
new_y = (seg.item.y + prev.item.y) / 2; newY = (seg.item.y + prev.item.y) / 2;
newseg = this.elem.createSVGPathSegLinetoAbs(new_x, new_y); newseg = this.elem.createSVGPathSegLinetoAbs(newX, newY);
break; break;
case 6: //make it a curved segment to preserve the shape (WRS) case 6: // make it a curved segment to preserve the shape (WRS)
// http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation // http://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation
var p0_x = (prev.item.x + seg.item.x1)/2; var p0x = (prev.item.x + seg.item.x1) / 2;
var p1_x = (seg.item.x1 + seg.item.x2)/2; var p1x = (seg.item.x1 + seg.item.x2) / 2;
var p2_x = (seg.item.x2 + seg.item.x)/2; var p2x = (seg.item.x2 + seg.item.x) / 2;
var p01_x = (p0_x + p1_x)/2; var p01x = (p0x + p1x) / 2;
var p12_x = (p1_x + p2_x)/2; var p12x = (p1x + p2x) / 2;
new_x = (p01_x + p12_x)/2; newX = (p01x + p12x) / 2;
var p0_y = (prev.item.y + seg.item.y1)/2; var p0y = (prev.item.y + seg.item.y1) / 2;
var p1_y = (seg.item.y1 + seg.item.y2)/2; var p1y = (seg.item.y1 + seg.item.y2) / 2;
var p2_y = (seg.item.y2 + seg.item.y)/2; var p2y = (seg.item.y2 + seg.item.y) / 2;
var p01_y = (p0_y + p1_y)/2; var p01y = (p0y + p1y) / 2;
var p12_y = (p1_y + p2_y)/2; var p12y = (p1y + p2y) / 2;
new_y = (p01_y + p12_y)/2; newY = (p01y + p12y) / 2;
newseg = this.elem.createSVGPathSegCurvetoCubicAbs(new_x, new_y, p0_x, p0_y, p01_x, p01_y); newseg = this.elem.createSVGPathSegCurvetoCubicAbs(newX, newY, p0x, p0y, p01x, p01y);
var pts = [seg.item.x, seg.item.y, p12_x, p12_y, p2_x, p2_y]; var pts = [seg.item.x, seg.item.y, p12x, p12y, p2x, p2y];
svgedit.path.replacePathSeg(seg.type, index, pts); svgedit.path.replacePathSeg(seg.type, index, pts);
break; break;
} }
@@ -694,7 +696,7 @@ svgedit.path.Path.prototype.addSeg = function(index) {
svgedit.path.insertItemBefore(this.elem, newseg, index); svgedit.path.insertItemBefore(this.elem, newseg, index);
}; };
svgedit.path.Path.prototype.deleteSeg = function(index) { svgedit.path.Path.prototype.deleteSeg = function (index) {
var seg = this.segs[index]; var seg = this.segs[index];
var list = this.elem.pathSegList; var list = this.elem.pathSegList;
@@ -712,7 +714,7 @@ svgedit.path.Path.prototype.deleteSeg = function(index) {
list.removeItem(seg.mate.index); list.removeItem(seg.mate.index);
} else if (!seg.prev) { } else if (!seg.prev) {
// First node of open path, make next point the M // First node of open path, make next point the M
var item = seg.item; // var item = seg.item;
pt = [next.item.x, next.item.y]; pt = [next.item.x, next.item.y];
svgedit.path.replacePathSeg(2, seg.next.index, pt); svgedit.path.replacePathSeg(2, seg.next.index, pt);
list.removeItem(index); list.removeItem(index);
@@ -721,11 +723,11 @@ svgedit.path.Path.prototype.deleteSeg = function(index) {
} }
}; };
svgedit.path.Path.prototype.subpathIsClosed = function(index) { svgedit.path.Path.prototype.subpathIsClosed = function (index) {
var closed = false; var closed = false;
// Check if subpath is already open // Check if subpath is already open
svgedit.path.path.eachSeg(function(i) { svgedit.path.path.eachSeg(function (i) {
if (i <= index) {return true;} if (i <= index) { return true; }
if (this.type === 2) { if (this.type === 2) {
// Found M first, so open // Found M first, so open
return false; return false;
@@ -740,7 +742,7 @@ svgedit.path.Path.prototype.subpathIsClosed = function(index) {
return closed; return closed;
}; };
svgedit.path.Path.prototype.removePtFromSelection = function(index) { svgedit.path.Path.prototype.removePtFromSelection = function (index) {
var pos = this.selected_pts.indexOf(index); var pos = this.selected_pts.indexOf(index);
if (pos == -1) { if (pos == -1) {
return; return;
@@ -749,21 +751,21 @@ svgedit.path.Path.prototype.removePtFromSelection = function(index) {
this.selected_pts.splice(pos, 1); this.selected_pts.splice(pos, 1);
}; };
svgedit.path.Path.prototype.clearSelection = function() { svgedit.path.Path.prototype.clearSelection = function () {
this.eachSeg(function() { this.eachSeg(function () {
// 'this' is the segment here // 'this' is the segment here
this.select(false); this.select(false);
}); });
this.selected_pts = []; this.selected_pts = [];
}; };
svgedit.path.Path.prototype.storeD = function() { svgedit.path.Path.prototype.storeD = function () {
this.last_d = this.elem.getAttribute('d'); this.last_d = this.elem.getAttribute('d');
}; };
svgedit.path.Path.prototype.show = function(y) { svgedit.path.Path.prototype.show = function (y) {
// Shows this path's segment grips // Shows this path's segment grips
this.eachSeg(function() { this.eachSeg(function () {
// 'this' is the segment here // 'this' is the segment here
this.show(y); this.show(y);
}); });
@@ -774,90 +776,90 @@ svgedit.path.Path.prototype.show = function(y) {
}; };
// Move selected points // Move selected points
svgedit.path.Path.prototype.movePts = function(d_x, d_y) { svgedit.path.Path.prototype.movePts = function (dx, dy) {
var i = this.selected_pts.length; var i = this.selected_pts.length;
while(i--) { while (i--) {
var seg = this.segs[this.selected_pts[i]]; var seg = this.segs[this.selected_pts[i]];
seg.move(d_x, d_y); seg.move(dx, dy);
} }
}; };
svgedit.path.Path.prototype.moveCtrl = function(d_x, d_y) { svgedit.path.Path.prototype.moveCtrl = function (dx, dy) {
var seg = this.segs[this.selected_pts[0]]; var seg = this.segs[this.selected_pts[0]];
seg.moveCtrl(this.dragctrl, d_x, d_y); seg.moveCtrl(this.dragctrl, dx, dy);
if (link_control_pts) { if (linkControlPts) {
seg.setLinked(this.dragctrl); seg.setLinked(this.dragctrl);
} }
}; };
svgedit.path.Path.prototype.setSegType = function(new_type) { svgedit.path.Path.prototype.setSegType = function (newType) {
this.storeD(); this.storeD();
var i = this.selected_pts.length; var i = this.selected_pts.length;
var text; var text;
while(i--) { while (i--) {
var sel_pt = this.selected_pts[i]; var selPt = this.selected_pts[i];
// Selected seg // Selected seg
var cur = this.segs[sel_pt]; var cur = this.segs[selPt];
var prev = cur.prev; var prev = cur.prev;
if (!prev) {continue;} if (!prev) { continue; }
if (!new_type) { // double-click, so just toggle if (!newType) { // double-click, so just toggle
text = 'Toggle Path Segment Type'; text = 'Toggle Path Segment Type';
// Toggle segment to curve/straight line // Toggle segment to curve/straight line
var old_type = cur.type; var oldType = cur.type;
new_type = (old_type == 6) ? 4 : 6; newType = (oldType == 6) ? 4 : 6;
} }
new_type = Number(new_type); newType = Number(newType);
var cur_x = cur.item.x; var curX = cur.item.x;
var cur_y = cur.item.y; var curY = cur.item.y;
var prev_x = prev.item.x; var prevX = prev.item.x;
var prev_y = prev.item.y; var prevY = prev.item.y;
var points; var points;
switch ( new_type ) { switch (newType) {
case 6: case 6:
if (cur.olditem) { if (cur.olditem) {
var old = cur.olditem; var old = cur.olditem;
points = [cur_x, cur_y, old.x1, old.y1, old.x2, old.y2]; points = [curX, curY, old.x1, old.y1, old.x2, old.y2];
} else { } else {
var diff_x = cur_x - prev_x; var diffX = curX - prevX;
var diff_y = cur_y - prev_y; var diffY = curY - prevY;
// get control points from straight line segment // get control points from straight line segment
/* /*
var ct1_x = (prev_x + (diff_y/2)); var ct1x = (prevX + (diffY/2));
var ct1_y = (prev_y - (diff_x/2)); var ct1y = (prevY - (diffX/2));
var ct2_x = (cur_x + (diff_y/2)); var ct2x = (curX + (diffY/2));
var ct2_y = (cur_y - (diff_x/2)); var ct2y = (curY - (diffX/2));
*/ */
//create control points on the line to preserve the shape (WRS) // create control points on the line to preserve the shape (WRS)
var ct1_x = (prev_x + (diff_x/3)); var ct1x = (prevX + (diffX / 3));
var ct1_y = (prev_y + (diff_y/3)); var ct1y = (prevY + (diffY / 3));
var ct2_x = (cur_x - (diff_x/3)); var ct2x = (curX - (diffX / 3));
var ct2_y = (cur_y - (diff_y/3)); var ct2y = (curY - (diffY / 3));
points = [cur_x, cur_y, ct1_x, ct1_y, ct2_x, ct2_y]; points = [curX, curY, ct1x, ct1y, ct2x, ct2y];
} }
break; break;
case 4: case 4:
points = [cur_x, cur_y]; points = [curX, curY];
// Store original prevve segment nums // Store original prevve segment nums
cur.olditem = cur.item; cur.olditem = cur.item;
break; break;
} }
cur.setType(new_type, points); cur.setType(newType, points);
} }
svgedit.path.path.endChanges(text); svgedit.path.path.endChanges(text);
}; };
svgedit.path.Path.prototype.selectPt = function(pt, ctrl_num) { svgedit.path.Path.prototype.selectPt = function (pt, ctrlNum) {
this.clearSelection(); this.clearSelection();
if (pt == null) { if (pt == null) {
this.eachSeg(function(i) { this.eachSeg(function (i) {
// 'this' is the segment here. // 'this' is the segment here.
if (this.prev) { if (this.prev) {
pt = i; pt = i;
@@ -865,17 +867,17 @@ svgedit.path.Path.prototype.selectPt = function(pt, ctrl_num) {
}); });
} }
this.addPtsToSelection(pt); this.addPtsToSelection(pt);
if (ctrl_num) { if (ctrlNum) {
this.dragctrl = ctrl_num; this.dragctrl = ctrlNum;
if (link_control_pts) { if (linkControlPts) {
this.segs[pt].setLinked(ctrl_num); this.segs[pt].setLinked(ctrlNum);
} }
} }
}; };
// Update position of all points // Update position of all points
svgedit.path.Path.prototype.update = function() { svgedit.path.Path.prototype.update = function () {
var elem = this.elem; var elem = this.elem;
if (svgedit.utilities.getRotationAngle(elem)) { if (svgedit.utilities.getRotationAngle(elem)) {
this.matrix = svgedit.math.getMatrix(elem); this.matrix = svgedit.math.getMatrix(elem);
@@ -885,7 +887,7 @@ svgedit.path.Path.prototype.update = function() {
this.imatrix = null; this.imatrix = null;
} }
this.eachSeg(function(i) { this.eachSeg(function (i) {
this.item = elem.pathSegList.getItem(i); this.item = elem.pathSegList.getItem(i);
this.update(); this.update();
}); });
@@ -893,7 +895,7 @@ svgedit.path.Path.prototype.update = function() {
return this; return this;
}; };
svgedit.path.getPath_ = function(elem) { svgedit.path.getPath_ = function (elem) {
var p = pathData[elem.id]; var p = pathData[elem.id];
if (!p) { if (!p) {
p = pathData[elem.id] = new svgedit.path.Path(elem); p = pathData[elem.id] = new svgedit.path.Path(elem);
@@ -901,16 +903,16 @@ svgedit.path.getPath_ = function(elem) {
return p; return p;
}; };
svgedit.path.removePath_ = function(id) { svgedit.path.removePath_ = function (id) {
if (id in pathData) {delete pathData[id];} if (id in pathData) { delete pathData[id]; }
}; };
var newcx, newcy, oldcx, oldcy, angle; var newcx, newcy, oldcx, oldcy, angle;
var getRotVals = function(x, y) { var getRotVals = function (x, y) {
var dx = x - oldcx; var dx = x - oldcx;
var dy = y - oldcy; var dy = y - oldcy;
// rotate the point around the old center // rotate the point around the old center
var r = Math.sqrt(dx*dx + dy*dy); var r = Math.sqrt(dx * dx + dy * dy);
var theta = Math.atan2(dy, dx) + angle; var theta = Math.atan2(dy, dx) + angle;
dx = r * Math.cos(theta) + oldcx; dx = r * Math.cos(theta) + oldcx;
dy = r * Math.sin(theta) + oldcy; dy = r * Math.sin(theta) + oldcy;
@@ -922,7 +924,7 @@ var getRotVals = function(x, y) {
dx -= newcx; dx -= newcx;
dy -= newcy; dy -= newcy;
r = Math.sqrt(dx*dx + dy*dy); r = Math.sqrt(dx * dx + dy * dy);
theta = Math.atan2(dy, dx) - angle; theta = Math.atan2(dy, dx) - angle;
return {'x': r * Math.cos(theta) + newcx, return {'x': r * Math.cos(theta) + newcx,
@@ -930,67 +932,66 @@ var getRotVals = function(x, y) {
}; };
// If the path was rotated, we must now pay the piper: // If the path was rotated, we must now pay the piper:
// Every path point must be rotated into the rotated coordinate system of // Every path point must be rotated into the rotated coordinate system of
// its old center, then determine the new center, then rotate it back // its old center, then determine the new center, then rotate it back
// This is because we want the path to remember its rotation // This is because we want the path to remember its rotation
// TODO: This is still using ye olde transform methods, can probably // TODO: This is still using ye olde transform methods, can probably
// be optimized or even taken care of by recalculateDimensions // be optimized or even taken care of by recalculateDimensions
svgedit.path.recalcRotatedPath = function() { svgedit.path.recalcRotatedPath = function () {
var current_path = svgedit.path.path.elem; var currentPath = svgedit.path.path.elem;
angle = svgedit.utilities.getRotationAngle(current_path, true); angle = svgedit.utilities.getRotationAngle(currentPath, true);
if (!angle) {return;} if (!angle) { return; }
// selectedBBoxes[0] = svgedit.path.path.oldbbox; // selectedBBoxes[0] = svgedit.path.path.oldbbox;
var box = svgedit.utilities.getBBox(current_path), var box = svgedit.utilities.getBBox(currentPath),
oldbox = svgedit.path.path.oldbbox; //selectedBBoxes[0], oldbox = svgedit.path.path.oldbbox; // selectedBBoxes[0],
oldcx = oldbox.x + oldbox.width/2; oldcx = oldbox.x + oldbox.width / 2;
oldcy = oldbox.y + oldbox.height/2; oldcy = oldbox.y + oldbox.height / 2;
newcx = box.x + box.width/2; newcx = box.x + box.width / 2;
newcy = box.y + box.height/2; newcy = box.y + box.height / 2;
// un-rotate the new center to the proper position // un-rotate the new center to the proper position
var dx = newcx - oldcx, var dx = newcx - oldcx,
dy = newcy - oldcy, dy = newcy - oldcy,
r = Math.sqrt(dx*dx + dy*dy), r = Math.sqrt(dx * dx + dy * dy),
theta = Math.atan2(dy, dx) + angle; theta = Math.atan2(dy, dx) + angle;
newcx = r * Math.cos(theta) + oldcx; newcx = r * Math.cos(theta) + oldcx;
newcy = r * Math.sin(theta) + oldcy; newcy = r * Math.sin(theta) + oldcy;
var list = current_path.pathSegList, var list = currentPath.pathSegList,
i = list.numberOfItems; i = list.numberOfItems;
while (i) { while (i) {
i -= 1; i -= 1;
var seg = list.getItem(i), var seg = list.getItem(i),
type = seg.pathSegType; type = seg.pathSegType;
if (type == 1) {continue;} if (type == 1) { continue; }
var rvals = getRotVals(seg.x, seg.y), var rvals = getRotVals(seg.x, seg.y),
points = [rvals.x, rvals.y]; points = [rvals.x, rvals.y];
if (seg.x1 != null && seg.x2 != null) { if (seg.x1 != null && seg.x2 != null) {
var c_vals1 = getRotVals(seg.x1, seg.y1); var cVals1 = getRotVals(seg.x1, seg.y1);
var c_vals2 = getRotVals(seg.x2, seg.y2); var cVals2 = getRotVals(seg.x2, seg.y2);
points.splice(points.length, 0, c_vals1.x , c_vals1.y, c_vals2.x, c_vals2.y); points.splice(points.length, 0, cVals1.x, cVals1.y, cVals2.x, cVals2.y);
} }
svgedit.path.replacePathSeg(type, i, points); svgedit.path.replacePathSeg(type, i, points);
} // loop for each point } // loop for each point
box = svgedit.utilities.getBBox(current_path); box = svgedit.utilities.getBBox(currentPath);
// selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y; // selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y;
// selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height; // selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height;
// now we must set the new transform to be rotated around the new center // now we must set the new transform to be rotated around the new center
var R_nc = svgroot.createSVGTransform(), var Rnc = svgroot.createSVGTransform(),
tlist = svgedit.transformlist.getTransformList(current_path); tlist = svgedit.transformlist.getTransformList(currentPath);
R_nc.setRotate((angle * 180.0 / Math.PI), newcx, newcy); Rnc.setRotate((angle * 180.0 / Math.PI), newcx, newcy);
tlist.replaceItem(R_nc,0); tlist.replaceItem(Rnc, 0);
}; };
// ==================================== // ====================================
// Public API starts here // Public API starts here
svgedit.path.clearData = function() { svgedit.path.clearData = function () {
pathData = {}; pathData = {};
}; };
}()); }());

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true*/ /* globals $, svgedit */
/** /**
* Package: svgedit.sanitize * Package: svgedit.sanitize
* *
@@ -15,98 +15,99 @@
// 3) browser.js // 3) browser.js
// 4) svgutils.js // 4) svgutils.js
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.sanitize) { if (!svgedit.sanitize) {
svgedit.sanitize = {}; svgedit.sanitize = {};
} }
var NS = svgedit.NS, var NS = svgedit.NS,
REVERSE_NS = svgedit.getReverseNS(); REVERSE_NS = svgedit.getReverseNS();
// this defines which elements and attributes that we support // this defines which elements and attributes that we support
var svgWhiteList_ = { var svgWhiteList_ = {
// SVG Elements // SVG Elements
"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"], '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"], '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"], 'clipPath': ['class', 'clipPathUnits', 'id'],
"defs": [], 'defs': [],
"style" : ["type"], 'style': ['type'],
"desc": [], '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"], '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"], 'feGaussianBlur': ['class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation'],
"filter": ["class", "color-interpolation-filters", "filterRes", "filterUnits", "height", "id", "primitiveUnits", "requiredFeatures", "width", "x", "xlink:href", "y"], '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"], '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"], '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"], '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"], '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"], '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"], 'marker': ['id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox'],
"mask": ["class", "height", "id", "maskContentUnits", "maskUnits", "width", "x", "y"], 'mask': ['class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'],
"metadata": ["class", "id"], '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"], '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"], '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"], '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"], '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"], '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"], '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"], '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"], '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"], '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"], '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"], '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"], 'textPath': ['class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href'],
"title": [], '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"], '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"], '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'],
// MathML Elements // MathML Elements
"annotation": ["encoding"], 'annotation': ['encoding'],
"annotation-xml": ["encoding"], 'annotation-xml': ['encoding'],
"maction": ["actiontype", "other", "selection"], 'maction': ['actiontype', 'other', 'selection'],
"math": ["class", "id", "display", "xmlns"], 'math': ['class', 'id', 'display', 'xmlns'],
"menclose": ["notation"], 'menclose': ['notation'],
"merror": [], 'merror': [],
"mfrac": ["linethickness"], 'mfrac': ['linethickness'],
"mi": ["mathvariant"], 'mi': ['mathvariant'],
"mmultiscripts": [], 'mmultiscripts': [],
"mn": [], 'mn': [],
"mo": ["fence", "lspace", "maxsize", "minsize", "rspace", "stretchy"], 'mo': ['fence', 'lspace', 'maxsize', 'minsize', 'rspace', 'stretchy'],
"mover": [], 'mover': [],
"mpadded": ["lspace", "width", "height", "depth", "voffset"], 'mpadded': ['lspace', 'width', 'height', 'depth', 'voffset'],
"mphantom": [], 'mphantom': [],
"mprescripts": [], 'mprescripts': [],
"mroot": [], 'mroot': [],
"mrow": ["xlink:href", "xlink:type", "xmlns:xlink"], 'mrow': ['xlink:href', 'xlink:type', 'xmlns:xlink'],
"mspace": ["depth", "height", "width"], 'mspace': ['depth', 'height', 'width'],
"msqrt": [], 'msqrt': [],
"mstyle": ["displaystyle", "mathbackground", "mathcolor", "mathvariant", "scriptlevel"], 'mstyle': ['displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel'],
"msub": [], 'msub': [],
"msubsup": [], 'msubsup': [],
"msup": [], 'msup': [],
"mtable": ["align", "columnalign", "columnlines", "columnspacing", "displaystyle", "equalcolumns", "equalrows", "frame", "rowalign", "rowlines", "rowspacing", "width"], 'mtable': ['align', 'columnalign', 'columnlines', 'columnspacing', 'displaystyle', 'equalcolumns', 'equalrows', 'frame', 'rowalign', 'rowlines', 'rowspacing', 'width'],
"mtd": ["columnalign", "columnspan", "rowalign", "rowspan"], 'mtd': ['columnalign', 'columnspan', 'rowalign', 'rowspan'],
"mtext": [], 'mtext': [],
"mtr": ["columnalign", "rowalign"], 'mtr': ['columnalign', 'rowalign'],
"munder": [], 'munder': [],
"munderover": [], 'munderover': [],
"none": [], 'none': [],
"semantics": [] 'semantics': []
}; };
// Produce a Namespace-aware version of svgWhitelist // Produce a Namespace-aware version of svgWhitelist
var svgWhiteListNS_ = {}; var svgWhiteListNS_ = {};
$.each(svgWhiteList_, function(elt, atts){ $.each(svgWhiteList_, function (elt, atts) {
var attNS = {}; var attNS = {};
$.each(atts, function(i, att){ $.each(atts, function (i, att) {
if (att.indexOf(':') >= 0) { if (att.indexOf(':') >= 0) {
var v = att.split(':'); var v = att.split(':');
attNS[v[1]] = NS[(v[0]).toUpperCase()]; attNS[v[1]] = NS[(v[0]).toUpperCase()];
} else { } else {
attNS[att] = att == 'xmlns' ? NS.XMLNS : null; attNS[att] = att == 'xmlns' ? NS.XMLNS : null;
} }
}); });
svgWhiteListNS_[elt] = attNS; svgWhiteListNS_[elt] = attNS;
}); });
// Function: svgedit.sanitize.sanitizeSvg // Function: svgedit.sanitize.sanitizeSvg
@@ -115,145 +116,141 @@ $.each(svgWhiteList_, function(elt, atts){
// //
// Parameters: // Parameters:
// node - The DOM element to be checked (we'll also check its children) // node - The DOM element to be checked (we'll also check its children)
svgedit.sanitize.sanitizeSvg = function(node) { svgedit.sanitize.sanitizeSvg = function (node) {
// Cleanup text nodes // Cleanup text nodes
if (node.nodeType == 3) { // 3 == TEXT_NODE if (node.nodeType == 3) { // 3 == TEXT_NODE
// Trim whitespace // Trim whitespace
node.nodeValue = node.nodeValue.replace(/^\s+|\s+$/g, ''); node.nodeValue = node.nodeValue.replace(/^\s+|\s+$/g, '');
// Remove if empty // Remove if empty
if (node.nodeValue.length === 0) { if (node.nodeValue.length === 0) {
node.parentNode.removeChild(node); node.parentNode.removeChild(node);
} }
} }
// We only care about element nodes. // We only care about element nodes.
// Automatically return for all non-element nodes, such as comments, etc. // Automatically return for all non-element nodes, such as comments, etc.
if (node.nodeType != 1) { // 1 == ELEMENT_NODE if (node.nodeType != 1) { // 1 == ELEMENT_NODE
return; return;
} }
var doc = node.ownerDocument; var doc = node.ownerDocument;
var parent = node.parentNode; var parent = node.parentNode;
// can parent ever be null here? I think the root node's parent is the document... // can parent ever be null here? I think the root node's parent is the document...
if (!doc || !parent) { if (!doc || !parent) {
return; return;
} }
var allowedAttrs = svgWhiteList_[node.nodeName]; var allowedAttrs = svgWhiteList_[node.nodeName];
var allowedAttrsNS = svgWhiteListNS_[node.nodeName]; var allowedAttrsNS = svgWhiteListNS_[node.nodeName];
var i; var i;
// if this element is supported, sanitize it // if this element is supported, sanitize it
if (typeof allowedAttrs !== 'undefined') { if (typeof allowedAttrs !== 'undefined') {
var seAttrs = [];
i = node.attributes.length;
while (i--) {
// if the attribute is not in our whitelist, then remove it
// could use jQuery's inArray(), but I don't know if that's any better
var attr = node.attributes.item(i);
var attrName = attr.nodeName;
var attrLocalName = attr.localName;
var attrNsURI = attr.namespaceURI;
// Check that an attribute with the correct localName in the correct namespace is on
// our whitelist or is a namespace declaration for one of our allowed namespaces
if (!(allowedAttrsNS.hasOwnProperty(attrLocalName) && attrNsURI == allowedAttrsNS[attrLocalName] && attrNsURI != NS.XMLNS) &&
!(attrNsURI == NS.XMLNS && REVERSE_NS[attr.value])) {
// TODO(codedread): Programmatically add the se: attributes to the NS-aware whitelist.
// Bypassing the whitelist to allow se: prefixes.
// Is there a more appropriate way to do this?
if (attrName.indexOf('se:') === 0 || attrName.indexOf('data-') === 0) {
seAttrs.push([attrName, attr.value]);
}
node.removeAttributeNS(attrNsURI, attrLocalName);
}
var seAttrs = []; // Add spaces before negative signs where necessary
i = node.attributes.length; if (svgedit.browser.isGecko()) {
while (i--) { switch (attrName) {
// if the attribute is not in our whitelist, then remove it case 'transform':
// could use jQuery's inArray(), but I don't know if that's any better case 'gradientTransform':
var attr = node.attributes.item(i); case 'patternTransform':
var attrName = attr.nodeName; var val = attr.value.replace(/(\d)-/g, '$1 -');
var attrLocalName = attr.localName; node.setAttribute(attrName, val);
var attrNsURI = attr.namespaceURI; break;
// Check that an attribute with the correct localName in the correct namespace is on }
// our whitelist or is a namespace declaration for one of our allowed namespaces }
if (!(allowedAttrsNS.hasOwnProperty(attrLocalName) && attrNsURI == allowedAttrsNS[attrLocalName] && attrNsURI != NS.XMLNS) &&
!(attrNsURI == NS.XMLNS && REVERSE_NS[attr.value]) )
{
// TODO(codedread): Programmatically add the se: attributes to the NS-aware whitelist.
// Bypassing the whitelist to allow se: prefixes.
// Is there a more appropriate way to do this?
if (attrName.indexOf('se:') === 0 || attrName.indexOf('data-') === 0) {
seAttrs.push([attrName, attr.value]);
}
node.removeAttributeNS(attrNsURI, attrLocalName);
}
// Add spaces before negative signs where necessary // For the style attribute, rewrite it in terms of XML presentational attributes
if (svgedit.browser.isGecko()) { if (attrName == 'style') {
switch (attrName) { var props = attr.value.split(';'),
case 'transform': p = props.length;
case 'gradientTransform': while (p--) {
case 'patternTransform': var nv = props[p].split(':');
var val = attr.value.replace(/(\d)-/g, '$1 -'); var styleAttrName = $.trim(nv[0]);
node.setAttribute(attrName, val); var styleAttrVal = $.trim(nv[1]);
break; // Now check that this attribute is supported
} if (allowedAttrs.indexOf(styleAttrName) >= 0) {
} node.setAttribute(styleAttrName, styleAttrVal);
}
}
node.removeAttribute('style');
}
}
// For the style attribute, rewrite it in terms of XML presentational attributes $.each(seAttrs, function (i, attr) {
if (attrName == 'style') { node.setAttributeNS(NS.SE, attr[0], attr[1]);
var props = attr.value.split(';'), });
p = props.length;
while (p--) {
var nv = props[p].split(':');
var styleAttrName = $.trim(nv[0]);
var styleAttrVal = $.trim(nv[1]);
// Now check that this attribute is supported
if (allowedAttrs.indexOf(styleAttrName) >= 0) {
node.setAttribute(styleAttrName, styleAttrVal);
}
}
node.removeAttribute('style');
}
}
$.each(seAttrs, function(i, attr) { // for some elements that have a xlink:href, ensure the URI refers to a local element
node.setAttributeNS(NS.SE, attr[0], attr[1]); // (but not for links)
}); var href = svgedit.utilities.getHref(node);
if (href &&
['filter', 'linearGradient', 'pattern',
'radialGradient', 'textPath', 'use'].indexOf(node.nodeName) >= 0) {
// TODO: we simply check if the first character is a #, is this bullet-proof?
if (href[0] != '#') {
// remove the attribute (but keep the element)
svgedit.utilities.setHref(node, '');
node.removeAttributeNS(NS.XLINK, 'href');
}
}
// for some elements that have a xlink:href, ensure the URI refers to a local element // Safari crashes on a <use> without a xlink:href, so we just remove the node here
// (but not for links) if (node.nodeName == 'use' && !svgedit.utilities.getHref(node)) {
var href = svgedit.utilities.getHref(node); parent.removeChild(node);
if (href && return;
['filter', 'linearGradient', 'pattern', }
'radialGradient', 'textPath', 'use'].indexOf(node.nodeName) >= 0) { // if the element has attributes pointing to a non-local reference,
// TODO: we simply check if the first character is a #, is this bullet-proof? // need to remove the attribute
if (href[0] != '#') { $.each(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], function (i, attr) {
// remove the attribute (but keep the element) var val = node.getAttribute(attr);
svgedit.utilities.setHref(node, ''); if (val) {
node.removeAttributeNS(NS.XLINK, 'href'); val = svgedit.utilities.getUrlFromAttr(val);
} // simply check for first character being a '#'
} if (val && val[0] !== '#') {
node.setAttribute(attr, '');
node.removeAttribute(attr);
}
}
});
// Safari crashes on a <use> without a xlink:href, so we just remove the node here // recurse to children
if (node.nodeName == 'use' && !svgedit.utilities.getHref(node)) { i = node.childNodes.length;
parent.removeChild(node); while (i--) { svgedit.sanitize.sanitizeSvg(node.childNodes.item(i)); }
return; // else (element not supported), remove it
} } else {
// if the element has attributes pointing to a non-local reference, // remove all children from this node and insert them before this node
// need to remove the attribute // FIXME: in the case of animation elements this will hardly ever be correct
$.each(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], function(i, attr) { var children = [];
var val = node.getAttribute(attr); while (node.hasChildNodes()) {
if (val) { children.push(parent.insertBefore(node.firstChild, node));
val = svgedit.utilities.getUrlFromAttr(val); }
// simply check for first character being a '#'
if (val && val[0] !== '#') {
node.setAttribute(attr, '');
node.removeAttribute(attr);
}
}
});
// recurse to children // remove this node from the document altogether
i = node.childNodes.length; parent.removeChild(node);
while (i--) { svgedit.sanitize.sanitizeSvg(node.childNodes.item(i)); }
}
// else (element not supported), remove it
else {
// remove all children from this node and insert them before this node
// FIXME: in the case of animation elements this will hardly ever be correct
var children = [];
while (node.hasChildNodes()) {
children.push(parent.insertBefore(node.firstChild, node));
}
// remove this node from the document altogether // call sanitizeSvg on each of those children
parent.removeChild(node); i = children.length;
while (i--) { svgedit.sanitize.sanitizeSvg(children[i]); }
// call sanitizeSvg on each of those children }
i = children.length;
while (i--) { svgedit.sanitize.sanitizeSvg(children[i]); }
}
}; };
}()); }());

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true, forin: true*/ /* globals $, svgedit */
/** /**
* Package: svedit.select * Package: svedit.select
* *
@@ -16,7 +16,8 @@
// 4) math.js // 4) math.js
// 5) svgutils.js // 5) svgutils.js
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.select) { if (!svgedit.select) {
svgedit.select = {}; svgedit.select = {};
@@ -34,7 +35,7 @@ var gripRadius = svgedit.browser.isTouch() ? 10 : 4;
// id - integer to internally indentify the selector // id - integer to internally indentify the selector
// elem - DOM element associated with this selector // elem - DOM element associated with this selector
// bbox - Optional bbox to use for initialization (prevents duplicate getBBox call). // bbox - Optional bbox to use for initialization (prevents duplicate getBBox call).
svgedit.select.Selector = function(id, elem, bbox) { svgedit.select.Selector = function (id, elem, bbox) {
// this is the selector's unique number // this is the selector's unique number
this.id = id; this.id = id;
@@ -69,53 +70,51 @@ svgedit.select.Selector = function(id, elem, bbox) {
// this holds a reference to the grip coordinates for this selector // this holds a reference to the grip coordinates for this selector
this.gripCoords = { this.gripCoords = {
'nw': null, 'nw': null,
'n' : null, 'n': null,
'ne': null, 'ne': null,
'e' : null, 'e': null,
'se': null, 'se': null,
's' : null, 's': null,
'sw': null, 'sw': null,
'w' : null 'w': null
}; };
this.reset(this.selectedElement, bbox); this.reset(this.selectedElement, bbox);
}; };
// Function: svgedit.select.Selector.reset // Function: svgedit.select.Selector.reset
// Used to reset the id and element that the selector is attached to // Used to reset the id and element that the selector is attached to
// //
// Parameters: // Parameters:
// e - DOM element associated with this selector // e - DOM element associated with this selector
// bbox - Optional bbox to use for reset (prevents duplicate getBBox call). // bbox - Optional bbox to use for reset (prevents duplicate getBBox call).
svgedit.select.Selector.prototype.reset = function(e, bbox) { svgedit.select.Selector.prototype.reset = function (e, bbox) {
this.locked = true; this.locked = true;
this.selectedElement = e; this.selectedElement = e;
this.resize(bbox); this.resize(bbox);
this.selectorGroup.setAttribute('display', 'inline'); this.selectorGroup.setAttribute('display', 'inline');
}; };
// Function: svgedit.select.Selector.updateGripCursors // Function: svgedit.select.Selector.updateGripCursors
// Updates cursors for corner grips on rotation so arrows point the right way // Updates cursors for corner grips on rotation so arrows point the right way
// //
// Parameters: // Parameters:
// angle - Float indicating current rotation angle in degrees // angle - Float indicating current rotation angle in degrees
svgedit.select.Selector.prototype.updateGripCursors = function(angle) { svgedit.select.Selector.prototype.updateGripCursors = function (angle) {
var dir, var dir,
dir_arr = [], dirArr = [],
steps = Math.round(angle / 45); steps = Math.round(angle / 45);
if (steps < 0) {steps += 8;} if (steps < 0) { steps += 8; }
for (dir in selectorManager_.selectorGrips) { for (dir in selectorManager_.selectorGrips) {
dir_arr.push(dir); dirArr.push(dir);
} }
while (steps > 0) { while (steps > 0) {
dir_arr.push(dir_arr.shift()); dirArr.push(dirArr.shift());
steps--; steps--;
} }
var i = 0; var i = 0;
for (dir in selectorManager_.selectorGrips) { for (dir in selectorManager_.selectorGrips) {
selectorManager_.selectorGrips[dir].setAttribute('style', ('cursor:' + dir_arr[i] + '-resize')); selectorManager_.selectorGrips[dir].setAttribute('style', ('cursor:' + dirArr[i] + '-resize'));
i++; i++;
} }
}; };
@@ -125,7 +124,7 @@ svgedit.select.Selector.prototype.updateGripCursors = function(angle) {
// //
// Parameters: // Parameters:
// show - boolean indicating whether grips should be shown or not // show - boolean indicating whether grips should be shown or not
svgedit.select.Selector.prototype.showGrips = function(show) { svgedit.select.Selector.prototype.showGrips = function (show) {
var bShow = show ? 'inline' : 'none'; var bShow = show ? 'inline' : 'none';
selectorManager_.selectorGripsGroup.setAttribute('display', bShow); selectorManager_.selectorGripsGroup.setAttribute('display', bShow);
var elem = this.selectedElement; var elem = this.selectedElement;
@@ -139,21 +138,21 @@ svgedit.select.Selector.prototype.showGrips = function(show) {
// Function: svgedit.select.Selector.resize // Function: svgedit.select.Selector.resize
// Updates the selector to match the element's size // Updates the selector to match the element's size
// bbox - Optional bbox to use for resize (prevents duplicate getBBox call). // bbox - Optional bbox to use for resize (prevents duplicate getBBox call).
svgedit.select.Selector.prototype.resize = function(bbox) { svgedit.select.Selector.prototype.resize = function (bbox) {
var selectedBox = this.selectorRect, var selectedBox = this.selectorRect,
mgr = selectorManager_, mgr = selectorManager_,
selectedGrips = mgr.selectorGrips, selectedGrips = mgr.selectorGrips,
selected = this.selectedElement, selected = this.selectedElement,
sw = selected.getAttribute('stroke-width'), sw = selected.getAttribute('stroke-width'),
current_zoom = svgFactory_.currentZoom(); currentZoom = svgFactory_.currentZoom();
var offset = 1/current_zoom; var offset = 1 / currentZoom;
if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) { if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) {
offset += (sw/2); offset += (sw / 2);
} }
var tagName = selected.tagName; var tagName = selected.tagName;
if (tagName === 'text') { if (tagName === 'text') {
offset += 2/current_zoom; offset += 2 / currentZoom;
} }
// loop and transform our bounding box until we reach our first rotation // loop and transform our bounding box until we reach our first rotation
@@ -162,8 +161,8 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
// This should probably be handled somewhere else, but for now // This should probably be handled somewhere else, but for now
// it keeps the selection box correctly positioned when zoomed // it keeps the selection box correctly positioned when zoomed
m.e *= current_zoom; m.e *= currentZoom;
m.f *= current_zoom; m.f *= currentZoom;
if (!bbox) { if (!bbox) {
bbox = svgedit.utilities.getBBox(selected); bbox = svgedit.utilities.getBBox(selected);
@@ -173,23 +172,23 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
if (tagName === 'g' && !$.data(selected, 'gsvg')) { if (tagName === 'g' && !$.data(selected, 'gsvg')) {
// The bbox for a group does not include stroke vals, so we // The bbox for a group does not include stroke vals, so we
// get the bbox based on its children. // get the bbox based on its children.
var stroked_bbox = svgFactory_.getStrokedBBox(selected.childNodes); var strokedBbox = svgFactory_.getStrokedBBox(selected.childNodes);
if (stroked_bbox) { if (strokedBbox) {
bbox = stroked_bbox; bbox = strokedBbox;
} }
} }
// apply the transforms // apply the transforms
var l = bbox.x, t = bbox.y, w = bbox.width, h = bbox.height; var l = bbox.x, t = bbox.y, w = bbox.width, h = bbox.height;
bbox = {x:l, y:t, width:w, height:h}; bbox = {x: l, y: t, width: w, height: h};
// we need to handle temporary transforms too // we need to handle temporary transforms too
// if skewed, get its transformed box, then find its axis-aligned bbox // if skewed, get its transformed box, then find its axis-aligned bbox
//* // *
offset *= current_zoom; offset *= currentZoom;
var nbox = svgedit.math.transformBox(l*current_zoom, t*current_zoom, w*current_zoom, h*current_zoom, m), var nbox = svgedit.math.transformBox(l * currentZoom, t * currentZoom, w * currentZoom, h * currentZoom, m),
aabox = nbox.aabox, aabox = nbox.aabox,
nbax = aabox.x - offset, nbax = aabox.x - offset,
nbay = aabox.y - offset, nbay = aabox.y - offset,
@@ -197,8 +196,8 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
nbah = aabox.height + (offset * 2); nbah = aabox.height + (offset * 2);
// now if the shape is rotated, un-rotate it // now if the shape is rotated, un-rotate it
var cx = nbax + nbaw/2, var cx = nbax + nbaw / 2,
cy = nbay + nbah/2; cy = nbay + nbah / 2;
var angle = svgedit.utilities.getRotationAngle(selected); var angle = svgedit.utilities.getRotationAngle(selected);
if (angle) { if (angle) {
@@ -219,59 +218,58 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
var min = Math.min, max = Math.max; var min = Math.min, max = Math.max;
minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x) ) ) - offset; minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x))) - offset;
miny = min(miny, min(nbox.tr.y, min(nbox.bl.y, nbox.br.y) ) ) - offset; miny = min(miny, min(nbox.tr.y, min(nbox.bl.y, nbox.br.y))) - offset;
maxx = max(maxx, max(nbox.tr.x, max(nbox.bl.x, nbox.br.x) ) ) + offset; maxx = max(maxx, max(nbox.tr.x, max(nbox.bl.x, nbox.br.x))) + offset;
maxy = max(maxy, max(nbox.tr.y, max(nbox.bl.y, nbox.br.y) ) ) + offset; maxy = max(maxy, max(nbox.tr.y, max(nbox.bl.y, nbox.br.y))) + offset;
nbax = minx; nbax = minx;
nbay = miny; nbay = miny;
nbaw = (maxx-minx); nbaw = (maxx - minx);
nbah = (maxy-miny); nbah = (maxy - miny);
} }
var dstr = 'M' + nbax + ',' + nbay var dstr = 'M' + nbax + ',' + nbay +
+ ' L' + (nbax+nbaw) + ',' + nbay ' L' + (nbax + nbaw) + ',' + nbay +
+ ' ' + (nbax+nbaw) + ',' + (nbay+nbah) ' ' + (nbax + nbaw) + ',' + (nbay + nbah) +
+ ' ' + nbax + ',' + (nbay+nbah) + 'z'; ' ' + nbax + ',' + (nbay + nbah) + 'z';
selectedBox.setAttribute('d', dstr); selectedBox.setAttribute('d', dstr);
var xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : ''; var xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : '';
this.selectorGroup.setAttribute('transform', xform); this.selectorGroup.setAttribute('transform', xform);
// TODO(codedread): Is this if needed? // TODO(codedread): Is this if needed?
// if (selected === selectedElements[0]) { // if (selected === selectedElements[0]) {
this.gripCoords = { this.gripCoords = {
'nw': [nbax, nbay], 'nw': [nbax, nbay],
'ne': [nbax+nbaw, nbay], 'ne': [nbax + nbaw, nbay],
'sw': [nbax, nbay+nbah], 'sw': [nbax, nbay + nbah],
'se': [nbax+nbaw, nbay+nbah], 'se': [nbax + nbaw, nbay + nbah],
'n': [nbax + (nbaw)/2, nbay], 'n': [nbax + (nbaw) / 2, nbay],
'w': [nbax, nbay + (nbah)/2], 'w': [nbax, nbay + (nbah) / 2],
'e': [nbax + nbaw, nbay + (nbah)/2], 'e': [nbax + nbaw, nbay + (nbah) / 2],
's': [nbax + (nbaw)/2, nbay + nbah] 's': [nbax + (nbaw) / 2, nbay + nbah]
}; };
var dir; var dir;
for (dir in this.gripCoords) { for (dir in this.gripCoords) {
var coords = this.gripCoords[dir]; var coords = this.gripCoords[dir];
selectedGrips[dir].setAttribute('cx', coords[0]); selectedGrips[dir].setAttribute('cx', coords[0]);
selectedGrips[dir].setAttribute('cy', coords[1]); selectedGrips[dir].setAttribute('cy', coords[1]);
} }
// we want to go 20 pixels in the negative transformed y direction, ignoring scale // we want to go 20 pixels in the negative transformed y direction, ignoring scale
mgr.rotateGripConnector.setAttribute('x1', nbax + (nbaw)/2); mgr.rotateGripConnector.setAttribute('x1', nbax + (nbaw) / 2);
mgr.rotateGripConnector.setAttribute('y1', nbay); mgr.rotateGripConnector.setAttribute('y1', nbay);
mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw)/2); mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw) / 2);
mgr.rotateGripConnector.setAttribute('y2', nbay - (gripRadius*5)); mgr.rotateGripConnector.setAttribute('y2', nbay - (gripRadius * 5));
mgr.rotateGrip.setAttribute('cx', nbax + (nbaw)/2); mgr.rotateGrip.setAttribute('cx', nbax + (nbaw) / 2);
mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius*5)); mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius * 5));
// } // }
}; };
// Class: svgedit.select.SelectorManager // Class: svgedit.select.SelectorManager
svgedit.select.SelectorManager = function() { svgedit.select.SelectorManager = function () {
// this will hold the <g> element that contains all selector rects/grips // this will hold the <g> element that contains all selector rects/grips
this.selectorParentGroup = null; this.selectorParentGroup = null;
@@ -287,13 +285,13 @@ svgedit.select.SelectorManager = function() {
// this holds a reference to the grip elements // this holds a reference to the grip elements
this.selectorGrips = { this.selectorGrips = {
'nw': null, 'nw': null,
'n' : null, 'n': null,
'ne': null, 'ne': null,
'e' : null, 'e': null,
'se': null, 'se': null,
's' : null, 's': null,
'sw': null, 'sw': null,
'w' : null 'w': null
}; };
this.selectorGripsGroup = null; this.selectorGripsGroup = null;
@@ -305,7 +303,7 @@ svgedit.select.SelectorManager = function() {
// Function: svgedit.select.SelectorManager.initGroup // Function: svgedit.select.SelectorManager.initGroup
// Resets the parent selector group element // Resets the parent selector group element
svgedit.select.SelectorManager.prototype.initGroup = function() { svgedit.select.SelectorManager.prototype.initGroup = function () {
// remove old selector parent group if it existed // remove old selector parent group if it existed
if (this.selectorParentGroup && this.selectorParentGroup.parentNode) { if (this.selectorParentGroup && this.selectorParentGroup.parentNode) {
this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup); this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);
@@ -378,7 +376,7 @@ svgedit.select.SelectorManager.prototype.initGroup = function() {
); );
$.data(this.rotateGrip, 'type', 'rotate'); $.data(this.rotateGrip, 'type', 'rotate');
if ($('#canvasBackground').length) {return;} if ($('#canvasBackground').length) { return; }
var dims = config_.dimensions; var dims = config_.dimensions;
var canvasbg = svgFactory_.createSVGElement({ var canvasbg = svgFactory_.createSVGElement({
@@ -410,7 +408,7 @@ svgedit.select.SelectorManager.prototype.initGroup = function() {
// Both Firefox and WebKit are too slow with this filter region (especially at higher // Both Firefox and WebKit are too slow with this filter region (especially at higher
// zoom levels) and Opera has at least one bug // zoom levels) and Opera has at least one bug
// if (!svgedit.browser.isOpera()) rect.setAttribute('filter', 'url(#canvashadow)'); // if (!svgedit.browser.isOpera()) rect.setAttribute('filter', 'url(#canvashadow)');
canvasbg.appendChild(rect); canvasbg.appendChild(rect);
svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent()); svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent());
}; };
@@ -421,12 +419,12 @@ svgedit.select.SelectorManager.prototype.initGroup = function() {
// Parameters: // Parameters:
// elem - DOM element to get the selector for // elem - DOM element to get the selector for
// bbox - Optional bbox to use for reset (prevents duplicate getBBox call). // bbox - Optional bbox to use for reset (prevents duplicate getBBox call).
svgedit.select.SelectorManager.prototype.requestSelector = function(elem, bbox) { svgedit.select.SelectorManager.prototype.requestSelector = function (elem, bbox) {
if (elem == null) {return null;} if (elem == null) { return null; }
var i, var i,
N = this.selectors.length; N = this.selectors.length;
// If we've already acquired one for this element, return it. // If we've already acquired one for this element, return it.
if (typeof(this.selectorMap[elem.id]) == 'object') { if (typeof this.selectorMap[elem.id] === 'object') {
this.selectorMap[elem.id].locked = true; this.selectorMap[elem.id].locked = true;
return this.selectorMap[elem.id]; return this.selectorMap[elem.id];
} }
@@ -450,8 +448,8 @@ svgedit.select.SelectorManager.prototype.requestSelector = function(elem, bbox)
// //
// Parameters: // Parameters:
// elem - DOM element to remove the selector for // elem - DOM element to remove the selector for
svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) { svgedit.select.SelectorManager.prototype.releaseSelector = function (elem) {
if (elem == null) {return;} if (elem == null) { return; }
var i, var i,
N = this.selectors.length, N = this.selectors.length,
sel = this.selectorMap[elem.id]; sel = this.selectorMap[elem.id];
@@ -469,7 +467,7 @@ svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) {
// remove from DOM and store reference in JS but only if it exists in the DOM // remove from DOM and store reference in JS but only if it exists in the DOM
try { try {
sel.selectorGroup.setAttribute('display', 'none'); sel.selectorGroup.setAttribute('display', 'none');
} catch(e) { } } catch (e) {}
break; break;
} }
@@ -478,7 +476,7 @@ svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) {
// Function: svgedit.select.SelectorManager.getRubberBandBox // Function: svgedit.select.SelectorManager.getRubberBandBox
// Returns the rubberBandBox DOM element. This is the rectangle drawn by the user for selecting/zooming // Returns the rubberBandBox DOM element. This is the rectangle drawn by the user for selecting/zooming
svgedit.select.SelectorManager.prototype.getRubberBandBox = function() { svgedit.select.SelectorManager.prototype.getRubberBandBox = function () {
if (!this.rubberBandBox) { if (!this.rubberBandBox) {
this.rubberBandBox = this.selectorParentGroup.appendChild( this.rubberBandBox = this.selectorParentGroup.appendChild(
svgFactory_.createSVGElement({ svgFactory_.createSVGElement({
@@ -498,7 +496,6 @@ svgedit.select.SelectorManager.prototype.getRubberBandBox = function() {
return this.rubberBandBox; return this.rubberBandBox;
}; };
/** /**
* Interface: svgedit.select.SVGFactory * Interface: svgedit.select.SVGFactory
* An object that creates SVG elements for the canvas. * An object that creates SVG elements for the canvas.
@@ -521,7 +518,7 @@ svgedit.select.SelectorManager.prototype.getRubberBandBox = function() {
* config - an object containing configurable parameters (imgPath) * config - an object containing configurable parameters (imgPath)
* svgFactory - an object implementing the SVGFactory interface (see above). * svgFactory - an object implementing the SVGFactory interface (see above).
*/ */
svgedit.select.init = function(config, svgFactory) { svgedit.select.init = function (config, svgFactory) {
config_ = config; config_ = config;
svgFactory_ = svgFactory; svgFactory_ = svgFactory;
selectorManager_ = new svgedit.select.SelectorManager(); selectorManager_ = new svgedit.select.SelectorManager();
@@ -533,8 +530,7 @@ svgedit.select.init = function(config, svgFactory) {
* Returns: * Returns:
* The SelectorManager instance. * The SelectorManager instance.
*/ */
svgedit.select.getSelectorManager = function() { svgedit.select.getSelectorManager = function () {
return selectorManager_; return selectorManager_;
}; };
}());
}());

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var */
/* globals $, svgedit:true */
/** /**
* *
* Licensed under the MIT License * Licensed under the MIT License
@@ -19,10 +20,11 @@ svgedit = {
}; };
// return the svgedit.NS with key values switched and lowercase // return the svgedit.NS with key values switched and lowercase
svgedit.getReverseNS = function() {'use strict'; svgedit.getReverseNS = function () {
'use strict';
var reverseNS = {}; var reverseNS = {};
$.each(this.NS, function(name, URI) { $.each(this.NS, function (name, URI) {
reverseNS[URI] = name.toLowerCase(); reverseNS[URI] = name.toLowerCase();
}); });
return reverseNS; return reverseNS;
}; };

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var, eqeqeq */
/*jslint vars: true, eqeq: true*/ /* globals $, svgedit */
/** /**
* SVGTransformList * SVGTransformList
* *
@@ -12,7 +12,8 @@
// Dependencies: // Dependencies:
// 1) browser.js // 1) browser.js
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.transformlist) { if (!svgedit.transformlist) {
svgedit.transformlist = {}; svgedit.transformlist = {};
@@ -21,48 +22,49 @@ if (!svgedit.transformlist) {
var svgroot = document.createElementNS(svgedit.NS.SVG, 'svg'); var svgroot = document.createElementNS(svgedit.NS.SVG, 'svg');
// Helper function. // Helper function.
function transformToString(xform) { function transformToString (xform) {
var m = xform.matrix, var m = xform.matrix,
text = ''; text = '';
switch(xform.type) { switch (xform.type) {
case 1: // MATRIX case 1: // MATRIX
text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')'; text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')';
break; break;
case 2: // TRANSLATE case 2: // TRANSLATE
text = 'translate(' + m.e + ',' + m.f + ')'; text = 'translate(' + m.e + ',' + m.f + ')';
break; break;
case 3: // SCALE case 3: // SCALE
if (m.a == m.d) {text = 'scale(' + m.a + ')';} if (m.a == m.d) {
else {text = 'scale(' + m.a + ',' + m.d + ')';} text = 'scale(' + m.a + ')';
break; } else {
case 4: // ROTATE text = 'scale(' + m.a + ',' + m.d + ')';
var cx = 0, cy = 0; }
// this prevents divide by zero break;
if (xform.angle != 0) { case 4: // ROTATE
var K = 1 - m.a; var cx = 0, cy = 0;
cy = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b ); // this prevents divide by zero
cx = ( m.e - m.b * cy ) / K; if (xform.angle != 0) {
} var K = 1 - m.a;
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')'; cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b);
break; cx = (m.e - m.b * cy) / K;
}
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
break;
} }
return text; return text;
} }
/** /**
* Map of SVGTransformList objects. * Map of SVGTransformList objects.
*/ */
var listMap_ = {}; var listMap_ = {};
// ************************************************************************************** // **************************************************************************************
// SVGTransformList implementation for Webkit // SVGTransformList implementation for Webkit
// These methods do not currently raise any exceptions. // These methods do not currently raise any exceptions.
// These methods also do not check that transforms are being inserted. This is basically // 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. // implementing as much of SVGTransformList that we need to get the job done.
// //
// interface SVGEditTransformList { // interface SVGEditTransformList {
// attribute unsigned long numberOfItems; // attribute unsigned long numberOfItems;
// void clear ( ) // void clear ( )
// SVGTransform initialize ( in SVGTransform newItem ) // SVGTransform initialize ( in SVGTransform newItem )
@@ -75,13 +77,13 @@ var listMap_ = {};
// NOT IMPLEMENTED: SVGTransform consolidate ( ); // NOT IMPLEMENTED: SVGTransform consolidate ( );
// } // }
// ************************************************************************************** // **************************************************************************************
svgedit.transformlist.SVGTransformList = function(elem) { svgedit.transformlist.SVGTransformList = function (elem) {
this._elem = elem || null; this._elem = elem || null;
this._xforms = []; this._xforms = [];
// TODO: how do we capture the undo-ability in the changed transform list? // TODO: how do we capture the undo-ability in the changed transform list?
this._update = function() { this._update = function () {
var tstr = ''; var tstr = '';
var concatMatrix = svgroot.createSVGMatrix(); /* var concatMatrix = */ svgroot.createSVGMatrix();
var i; var i;
for (i = 0; i < this.numberOfItems; ++i) { for (i = 0; i < this.numberOfItems; ++i) {
var xform = this._list.getItem(i); var xform = this._list.getItem(i);
@@ -90,10 +92,10 @@ svgedit.transformlist.SVGTransformList = function(elem) {
this._elem.setAttribute('transform', tstr); this._elem.setAttribute('transform', tstr);
}; };
this._list = this; this._list = this;
this._init = function() { this._init = function () {
// Transform attribute parser // Transform attribute parser
var str = this._elem.getAttribute('transform'); var str = this._elem.getAttribute('transform');
if (!str) {return;} if (!str) { return; }
// TODO: Add skew support in future // TODO: Add skew support in future
var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
@@ -105,20 +107,20 @@ svgedit.transformlist.SVGTransformList = function(elem) {
var x = m[1]; var x = m[1];
var bits = x.split(/\s*\(/); var bits = x.split(/\s*\(/);
var name = bits[0]; var name = bits[0];
var val_bits = bits[1].match(/\s*(.*?)\s*\)/); var valBits = bits[1].match(/\s*(.*?)\s*\)/);
val_bits[1] = val_bits[1].replace(/(\d)-/g, '$1 -'); valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -');
var val_arr = val_bits[1].split(/[, ]+/); var valArr = valBits[1].split(/[, ]+/);
var letters = 'abcdef'.split(''); var letters = 'abcdef'.split('');
var mtx = svgroot.createSVGMatrix(); var mtx = svgroot.createSVGMatrix();
$.each(val_arr, function(i, item) { $.each(valArr, function (i, item) {
val_arr[i] = parseFloat(item); valArr[i] = parseFloat(item);
if (name == 'matrix') { if (name == 'matrix') {
mtx[letters[i]] = val_arr[i]; mtx[letters[i]] = valArr[i];
} }
}); });
var xform = svgroot.createSVGTransform(); var xform = svgroot.createSVGTransform();
var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1); var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1);
var values = name == 'matrix' ? [mtx] : val_arr; var values = name == 'matrix' ? [mtx] : valArr;
if (name == 'scale' && values.length == 1) { if (name == 'scale' && values.length == 1) {
values.push(values[0]); values.push(values[0]);
@@ -132,7 +134,7 @@ svgedit.transformlist.SVGTransformList = function(elem) {
} }
} }
}; };
this._removeFromOtherLists = function(item) { this._removeFromOtherLists = function (item) {
if (item) { if (item) {
// Check if this transform is already in a transformlist, and // Check if this transform is already in a transformlist, and
// remove it if so. // remove it if so.
@@ -156,25 +158,27 @@ svgedit.transformlist.SVGTransformList = function(elem) {
}; };
this.numberOfItems = 0; this.numberOfItems = 0;
this.clear = function() { this.clear = function () {
this.numberOfItems = 0; this.numberOfItems = 0;
this._xforms = []; this._xforms = [];
}; };
this.initialize = function(newItem) { this.initialize = function (newItem) {
this.numberOfItems = 1; this.numberOfItems = 1;
this._removeFromOtherLists(newItem); this._removeFromOtherLists(newItem);
this._xforms = [newItem]; this._xforms = [newItem];
}; };
this.getItem = function(index) { this.getItem = function (index) {
if (index < this.numberOfItems && index >= 0) { if (index < this.numberOfItems && index >= 0) {
return this._xforms[index]; return this._xforms[index];
} }
throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR var err = new Error('DOMException with code=INDEX_SIZE_ERR');
err.code = 1;
throw err;
}; };
this.insertItemBefore = function(newItem, index) { this.insertItemBefore = function (newItem, index) {
var retValue = null; var retValue = null;
if (index >= 0) { if (index >= 0) {
if (index < this.numberOfItems) { if (index < this.numberOfItems) {
@@ -187,22 +191,21 @@ svgedit.transformlist.SVGTransformList = function(elem) {
} }
newxforms[i] = newItem; newxforms[i] = newItem;
var j; var j;
for (j = i+1; i < this.numberOfItems; ++j, ++i) { for (j = i + 1; i < this.numberOfItems; ++j, ++i) {
newxforms[j] = this._xforms[i]; newxforms[j] = this._xforms[i];
} }
this.numberOfItems++; this.numberOfItems++;
this._xforms = newxforms; this._xforms = newxforms;
retValue = newItem; retValue = newItem;
this._list._update(); this._list._update();
} } else {
else {
retValue = this._list.appendItem(newItem); retValue = this._list.appendItem(newItem);
} }
} }
return retValue; return retValue;
}; };
this.replaceItem = function(newItem, index) { this.replaceItem = function (newItem, index) {
var retValue = null; var retValue = null;
if (index < this.numberOfItems && index >= 0) { if (index < this.numberOfItems && index >= 0) {
this._removeFromOtherLists(newItem); this._removeFromOtherLists(newItem);
@@ -213,7 +216,7 @@ svgedit.transformlist.SVGTransformList = function(elem) {
return retValue; return retValue;
}; };
this.removeItem = function(index) { this.removeItem = function (index) {
if (index < this.numberOfItems && index >= 0) { if (index < this.numberOfItems && index >= 0) {
var retValue = this._xforms[index]; var retValue = this._xforms[index];
var newxforms = new Array(this.numberOfItems - 1); var newxforms = new Array(this.numberOfItems - 1);
@@ -221,18 +224,20 @@ svgedit.transformlist.SVGTransformList = function(elem) {
for (i = 0; i < index; ++i) { for (i = 0; i < index; ++i) {
newxforms[i] = this._xforms[i]; newxforms[i] = this._xforms[i];
} }
for (j = i; j < this.numberOfItems-1; ++j, ++i) { for (j = i; j < this.numberOfItems - 1; ++j, ++i) {
newxforms[j] = this._xforms[i+1]; newxforms[j] = this._xforms[i + 1];
} }
this.numberOfItems--; this.numberOfItems--;
this._xforms = newxforms; this._xforms = newxforms;
this._list._update(); this._list._update();
return retValue; return retValue;
} }
throw {code: 1}; // DOMException with code=INDEX_SIZE_ERR var err = new Error('DOMException with code=INDEX_SIZE_ERR');
err.code = 1;
throw err;
}; };
this.appendItem = function(newItem) { this.appendItem = function (newItem) {
this._removeFromOtherLists(newItem); this._removeFromOtherLists(newItem);
this._xforms.push(newItem); this._xforms.push(newItem);
this.numberOfItems++; this.numberOfItems++;
@@ -241,8 +246,7 @@ svgedit.transformlist.SVGTransformList = function(elem) {
}; };
}; };
svgedit.transformlist.resetListMap = function () {
svgedit.transformlist.resetListMap = function() {
listMap_ = {}; listMap_ = {};
}; };
@@ -251,7 +255,7 @@ svgedit.transformlist.resetListMap = function() {
* Parameters: * Parameters:
* elem - a DOM Element * elem - a DOM Element
*/ */
svgedit.transformlist.removeElementFromListMap = function(elem) { svgedit.transformlist.removeElementFromListMap = function (elem) {
if (elem.id && listMap_[elem.id]) { if (elem.id && listMap_[elem.id]) {
delete listMap_[elem.id]; delete listMap_[elem.id];
} }
@@ -262,7 +266,7 @@ svgedit.transformlist.removeElementFromListMap = function(elem) {
// //
// Parameters: // Parameters:
// elem - DOM element to get a transformlist from // elem - DOM element to get a transformlist from
svgedit.transformlist.getTransformList = function(elem) { svgedit.transformlist.getTransformList = function (elem) {
if (!svgedit.browser.supportsNativeTransformLists()) { if (!svgedit.browser.supportsNativeTransformLists()) {
var id = elem.id || 'temp'; var id = elem.id || 'temp';
var t = listMap_[id]; var t = listMap_[id];
@@ -285,5 +289,4 @@ svgedit.transformlist.getTransformList = function(elem) {
return null; return null;
}; };
}());
}());

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,28 @@
/* eslint-disable no-var */
// http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ // http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/
function touchHandler(event) {'use strict'; function touchHandler (event) {
'use strict';
var simulatedEvent, var simulatedEvent,
touches = event.changedTouches, touches = event.changedTouches,
first = touches[0], first = touches[0],
type = ""; type = '';
switch (event.type) { switch (event.type) {
case "touchstart": type = "mousedown"; break; case 'touchstart': type = 'mousedown'; break;
case "touchmove": type = "mousemove"; break; case 'touchmove': type = 'mousemove'; break;
case "touchend": type = "mouseup"; break; case 'touchend': type = 'mouseup'; break;
default: return; default: return;
} }
// initMouseEvent(type, canBubble, cancelable, view, clickCount, // initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey, // screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget); // altKey, shiftKey, metaKey, button, relatedTarget);
simulatedEvent = document.createEvent("MouseEvent"); simulatedEvent = document.createEvent('MouseEvent');
simulatedEvent.initMouseEvent(type, true, true, window, 1, simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY, first.screenX, first.screenY,
first.clientX, first.clientY, false, first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null); false, false, false, 0/* left */, null);
if (touches.length < 2) { if (touches.length < 2) {
first.target.dispatchEvent(simulatedEvent); first.target.dispatchEvent(simulatedEvent);
event.preventDefault(); event.preventDefault();
@@ -30,4 +32,4 @@ function touchHandler(event) {'use strict';
document.addEventListener('touchstart', touchHandler, true); document.addEventListener('touchstart', touchHandler, true);
document.addEventListener('touchmove', touchHandler, true); document.addEventListener('touchmove', touchHandler, true);
document.addEventListener('touchend', touchHandler, true); document.addEventListener('touchend', touchHandler, true);
document.addEventListener('touchcancel', touchHandler, true); document.addEventListener('touchcancel', touchHandler, true);

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/ /* eslint-disable no-var */
/*jslint vars: true, eqeq: true*/ /* globals $, svgedit */
/** /**
* Package: svgedit.units * Package: svgedit.units
* *
@@ -12,7 +12,8 @@
// Dependencies: // Dependencies:
// 1) jQuery // 1) jQuery
(function() {'use strict'; (function () {
'use strict';
if (!svgedit.units) { if (!svgedit.units) {
svgedit.units = {}; svgedit.units = {};
@@ -23,8 +24,9 @@ var wAttrs = ['x', 'x1', 'cx', 'rx', 'width'];
var hAttrs = ['y', 'y1', 'cy', 'ry', 'height']; var hAttrs = ['y', 'y1', 'cy', 'ry', 'height'];
var unitAttrs = ['r', 'radius'].concat(wAttrs, hAttrs); var unitAttrs = ['r', 'radius'].concat(wAttrs, hAttrs);
// unused // unused
/*
var unitNumMap = { var unitNumMap = {
'%': 2, '%': 2,
'em': 3, 'em': 3,
'ex': 4, 'ex': 4,
'px': 5, 'px': 5,
@@ -34,7 +36,7 @@ var unitNumMap = {
'pt': 9, 'pt': 9,
'pc': 10 'pc': 10
}; };
*/
// Container of elements. // Container of elements.
var elementContainer_; var elementContainer_;
@@ -60,7 +62,7 @@ var typeMap_ = {};
* Parameters: * Parameters:
* elementContainer - an object implementing the ElementContainer interface. * elementContainer - an object implementing the ElementContainer interface.
*/ */
svgedit.units.init = function(elementContainer) { svgedit.units.init = function (elementContainer) {
elementContainer_ = elementContainer; elementContainer_ = elementContainer;
// Get correct em/ex values by creating a temporary SVG. // Get correct em/ex values by creating a temporary SVG.
@@ -92,7 +94,7 @@ svgedit.units.init = function(elementContainer) {
// Function: svgedit.units.getTypeMap // Function: svgedit.units.getTypeMap
// Returns the unit object with values for each unit // Returns the unit object with values for each unit
svgedit.units.getTypeMap = function() { svgedit.units.getTypeMap = function () {
return typeMap_; return typeMap_;
}; };
@@ -105,7 +107,7 @@ svgedit.units.getTypeMap = function() {
// Returns: // Returns:
// If a string/number was given, returns a Float. If an array, return a string // If a string/number was given, returns a Float. If an array, return a string
// with comma-seperated floats // with comma-seperated floats
svgedit.units.shortFloat = function(val) { svgedit.units.shortFloat = function (val) {
var digits = elementContainer_.getRoundDigits(); var digits = elementContainer_.getRoundDigits();
if (!isNaN(val)) { if (!isNaN(val)) {
// Note that + converts to Number // Note that + converts to Number
@@ -119,11 +121,11 @@ svgedit.units.shortFloat = function(val) {
// Function: svgedit.units.convertUnit // Function: svgedit.units.convertUnit
// Converts the number to given unit or baseUnit // Converts the number to given unit or baseUnit
svgedit.units.convertUnit = function(val, unit) { svgedit.units.convertUnit = function (val, unit) {
unit = unit || elementContainer_.getBaseUnit(); unit = unit || elementContainer_.getBaseUnit();
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]); // baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
// var val = baseVal.valueInSpecifiedUnits; // var val = baseVal.valueInSpecifiedUnits;
// baseVal.convertToSpecifiedUnits(1); // baseVal.convertToSpecifiedUnits(1);
return svgedit.units.shortFloat(val / typeMap_[unit]); return svgedit.units.shortFloat(val / typeMap_[unit]);
}; };
@@ -134,38 +136,38 @@ svgedit.units.convertUnit = function(val, unit) {
// elem - DOM element to be changed // elem - DOM element to be changed
// attr - String with the name of the attribute associated with the value // attr - String with the name of the attribute associated with the value
// val - String with the attribute value to convert // val - String with the attribute value to convert
svgedit.units.setUnitAttr = function(elem, attr, val) { svgedit.units.setUnitAttr = function (elem, attr, val) {
// if (!isNaN(val)) { // if (!isNaN(val)) {
// New value is a number, so check currently used unit // New value is a number, so check currently used unit
// var old_val = elem.getAttribute(attr); // var old_val = elem.getAttribute(attr);
// Enable this for alternate mode // Enable this for alternate mode
// if (old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) { // if (old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) {
// // Old value was a number, so get unit, then convert // // Old value was a number, so get unit, then convert
// var unit; // var unit;
// if (old_val.substr(-1) === '%') { // if (old_val.substr(-1) === '%') {
// var res = getResolution(); // var res = getResolution();
// unit = '%'; // unit = '%';
// val *= 100; // val *= 100;
// if (wAttrs.indexOf(attr) >= 0) { // if (wAttrs.indexOf(attr) >= 0) {
// val = val / res.w; // val = val / res.w;
// } else if (hAttrs.indexOf(attr) >= 0) { // } else if (hAttrs.indexOf(attr) >= 0) {
// val = val / res.h; // val = val / res.h;
// } else { // } else {
// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2); // return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2);
// } // }
// } else { // } else {
// if (elementContainer_.getBaseUnit() !== 'px') { // if (elementContainer_.getBaseUnit() !== 'px') {
// unit = elementContainer_.getBaseUnit(); // unit = elementContainer_.getBaseUnit();
// } else { // } else {
// unit = old_val.substr(-2); // unit = old_val.substr(-2);
// } // }
// val = val / typeMap_[unit]; // val = val / typeMap_[unit];
// } // }
// //
// val += unit; // val += unit;
// } // }
// } // }
elem.setAttribute(attr, val); elem.setAttribute(attr, val);
}; };
@@ -185,11 +187,11 @@ var attrsToConvert = {
// //
// Parameters: // Parameters:
// element - a DOM element whose attributes should be converted // element - a DOM element whose attributes should be converted
svgedit.units.convertAttrs = function(element) { svgedit.units.convertAttrs = function (element) {
var elName = element.tagName; var elName = element.tagName;
var unit = elementContainer_.getBaseUnit(); var unit = elementContainer_.getBaseUnit();
var attrs = attrsToConvert[elName]; var attrs = attrsToConvert[elName];
if (!attrs) {return;} if (!attrs) { return; }
var len = attrs.length; var len = attrs.length;
var i; var i;
@@ -201,26 +203,26 @@ svgedit.units.convertAttrs = function(element) {
element.setAttribute(attr, (cur / typeMap_[unit]) + unit); element.setAttribute(attr, (cur / typeMap_[unit]) + unit);
} }
// else { // else {
// Convert existing? // Convert existing?
// } // }
} }
} }
}; };
// Function: svgedit.units.convertToNum // Function: svgedit.units.convertToNum
// Converts given values to numbers. Attributes must be supplied in // Converts given values to numbers. Attributes must be supplied in
// case a percentage is given // case a percentage is given
// //
// Parameters: // Parameters:
// attr - String with the name of the attribute associated with the value // attr - String with the name of the attribute associated with the value
// val - String with the attribute value to convert // val - String with the attribute value to convert
svgedit.units.convertToNum = function(attr, val) { svgedit.units.convertToNum = function (attr, val) {
// Return a number if that's what it already is // Return a number if that's what it already is
if (!isNaN(val)) {return val-0;} if (!isNaN(val)) { return val - 0; }
var num; var num;
if (val.substr(-1) === '%') { if (val.substr(-1) === '%') {
// Deal with percentage, depends on attribute // Deal with percentage, depends on attribute
num = val.substr(0, val.length-1)/100; num = val.substr(0, val.length - 1) / 100;
var width = elementContainer_.getWidth(); var width = elementContainer_.getWidth();
var height = elementContainer_.getHeight(); var height = elementContainer_.getHeight();
@@ -230,10 +232,10 @@ svgedit.units.convertToNum = function(attr, val) {
if (hAttrs.indexOf(attr) >= 0) { if (hAttrs.indexOf(attr) >= 0) {
return num * height; return num * height;
} }
return num * Math.sqrt((width*width) + (height*height))/Math.sqrt(2); return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2);
} }
var unit = val.substr(-2); var unit = val.substr(-2);
num = val.substr(0, val.length-2); num = val.substr(0, val.length - 2);
// Note that this multiplication turns the string into a number // Note that this multiplication turns the string into a number
return num * typeMap_[unit]; return num * typeMap_[unit];
}; };
@@ -244,7 +246,7 @@ svgedit.units.convertToNum = function(attr, val) {
// Parameters: // Parameters:
// attr - String with the name of the attribute associated with the value // attr - String with the name of the attribute associated with the value
// val - String with the attribute value to check // val - String with the attribute value to check
svgedit.units.isValidUnit = function(attr, val, selectedElement) { svgedit.units.isValidUnit = function (attr, val, selectedElement) {
var valid = false; var valid = false;
if (unitAttrs.indexOf(attr) >= 0) { if (unitAttrs.indexOf(attr) >= 0) {
// True if it's just a number // True if it's just a number
@@ -253,13 +255,13 @@ svgedit.units.isValidUnit = function(attr, val, selectedElement) {
} else { } else {
// Not a number, check if it has a valid unit // Not a number, check if it has a valid unit
val = val.toLowerCase(); val = val.toLowerCase();
$.each(typeMap_, function(unit) { $.each(typeMap_, function (unit) {
if (valid) {return;} if (valid) { return; }
var re = new RegExp('^-?[\\d\\.]+' + unit + '$'); var re = new RegExp('^-?[\\d\\.]+' + unit + '$');
if (re.test(val)) {valid = true;} if (re.test(val)) { valid = true; }
}); });
} }
} else if (attr == 'id') { } else if (attr === 'id') {
// if we're trying to change the id, make sure it's not already present in the doc // if we're trying to change the id, make sure it's not already present in the doc
// and the id value is valid. // and the id value is valid.
@@ -271,12 +273,11 @@ svgedit.units.isValidUnit = function(attr, val, selectedElement) {
try { try {
var elem = elementContainer_.getElement(val); var elem = elementContainer_.getElement(val);
result = (elem == null || elem === selectedElement); result = (elem == null || elem === selectedElement);
} catch(e) {} } catch (e) {}
return result; return result;
} }
valid = true; valid = true;
return valid; return valid;
}; };
}());
}());