- 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
editor/jquery.js
editor/jspdf/jspdf.min.js
editor/jspdf/underscore-min.js
jgraduate/jpicker.min.js
jgraduate/jquery.jgraduate.js
jquery-ui
jquerybbq
js-hotkeys
spinbtn/JQuerySpinBtn.min.js
editor/jgraduate/jpicker.min.js
editor/jgraduate/jquery.jgraduate.min.js
editor/jquery-ui
editor/jquerybbq
editor/js-hotkeys
editor/spinbtn/JQuerySpinBtn.min.js
test/qunit
test/sinon
wave/json2.js

View File

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

View File

@@ -3,7 +3,7 @@
// CREATE A NEW FILE config.js AND ADD CONTENTS
// SUCH AS SHOWN BELOW INTO THAT FILE.
/*globals svgEditor*/
/* globals svgEditor */
/*
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
@@ -56,17 +56,17 @@ svgEditor.setConfig({
});
// OTHER CONFIG
svgEditor.setConfig({
svgEditor.setConfig({
// canvasName: 'default',
// canvas_expansion: 3,
// initFill: {
// color: 'FF0000', // solid red
// opacity: 1
// color: 'FF0000', // solid red
// opacity: 1
// },
// initStroke: {
// width: 5,
// color: '000000', // solid black
// opacity: 1
// width: 5,
// color: '000000', // solid black
// opacity: 1
// },
// initOpacity: 1,
// colorPickerCSS: null,

View File

@@ -1,66 +1,66 @@
/*globals $, svgEditor*/
/*jslint vars: true, eqeq: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgEditor */
/**
* Package: svgedit.contextmenu
*
*
* Licensed under the Apache License, Version 2
*
*
* Author: Adam Bender
*/
// Dependencies:
// 1) jQuery (for dom injection of context menus)
var svgedit = svgedit || {};
(function() {
var self = this;
if (!svgedit.contextmenu) {
svgedit.contextmenu = {};
var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
(function () {
var self = this;
if (!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 = {};
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;
}
if (menuItem.id in self.contextMenuExtensions) {
console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"');
return;
}
// Register menuItem action, see below for deferred menu dom injection
console.log("Registed contextmenu item: {id:"+ menuItem.id+", label:"+menuItem.label+"}");
self.contextMenuExtensions[menuItem.id] = menuItem;
//TODO: Need to consider how to handle custom enable/disable behavior
};
var hasCustomHandler = function(handlerKey) {
return self.contextMenuExtensions[handlerKey] && true;
};
var getCustomHandler = function(handlerKey) {
return self.contextMenuExtensions[handlerKey].action;
};
var injectExtendedContextMenuItemIntoDom = function(menuItem) {
if (Object.keys(self.contextMenuExtensions).length === 0) {
// all menuItems appear at the bottom of the menu in their own container.
// if this is the first extension menu we need to add the separator.
$("#cmenu_canvas").append("<li class='separator'>");
}
var shortcut = menuItem.shortcut || "";
$("#cmenu_canvas").append("<li class='disabled'><a href='#" + menuItem.id + "'>"
+ menuItem.label + "<span class='shortcut'>"
+ shortcut + "</span></a></li>");
};
// Defer injection to wait out initial menu processing. This probably goes away once all context
// menu behavior is brought here.
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;
if (menuItem.id in self.contextMenuExtensions) {
console.error('Cannot add extension "' + menuItem.id + '", an extension by that name already exists"');
return;
}
// Register menuItem action, see below for deferred menu dom injection
console.log('Registed contextmenu item: {id:' + menuItem.id + ', label:' + menuItem.label + '}');
self.contextMenuExtensions[menuItem.id] = menuItem;
// TODO: Need to consider how to handle custom enable/disable behavior
};
var hasCustomHandler = function (handlerKey) {
return self.contextMenuExtensions[handlerKey] && true;
};
var getCustomHandler = function (handlerKey) {
return self.contextMenuExtensions[handlerKey].action;
};
var injectExtendedContextMenuItemIntoDom = function (menuItem) {
if (Object.keys(self.contextMenuExtensions).length === 0) {
// all menuItems appear at the bottom of the menu in their own container.
// if this is the first extension menu we need to add the separator.
$('#cmenu_canvas').append("<li class='separator'>");
}
var shortcut = menuItem.shortcut || '';
$('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" +
menuItem.label + "<span class='shortcut'>" +
shortcut + '</span></a></li>');
};
// Defer injection to wait out initial menu processing. This probably goes away once all context
// menu behavior is brought here.
svgEditor.ready(function () {
var menuItem;
for (menuItem in self.contextMenuExtensions) {
injectExtendedContextMenuItemIntoDom(self.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 */
/*jslint vars: true, eqeq: true, forin: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgroot */
/**
* Coords.
*
@@ -16,17 +16,18 @@
// 6) units.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) {
svgedit.coords = {};
svgedit.coords = {};
}
// this is how we map paths to our preferred relative segment types
var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
/**
* @typedef editorContext
@@ -39,8 +40,8 @@ var editorContext_ = null;
/**
* @param {editorContext} editorContext
*/
svgedit.coords.init = function(editorContext) {
editorContext_ = editorContext;
svgedit.coords.init = function (editorContext) {
editorContext_ = editorContext;
};
/**
@@ -49,269 +50,267 @@ svgedit.coords.init = function(editorContext) {
* @param {object} changes - Object with changes to be remapped
* @param {SVGMatrix} m - Matrix object to use for remapping coordinates
*/
svgedit.coords.remapElement = function(selected, changes, m) {
var i, type,
remap = function(x, y) { return svgedit.math.transformPoint(x, y, m); },
scalew = function(w) { return m.a * w; },
scaleh = function(h) { return m.d * h; },
doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg',
finishUp = function() {
var o;
if (doSnapping) {
for (o in changes) {
changes[o] = svgedit.utilities.snapToGrid(changes[o]);
}
}
svgedit.utilities.assignAttributes(selected, changes, 1000, true);
},
box = svgedit.utilities.getBBox(selected);
svgedit.coords.remapElement = function (selected, changes, m) {
var i, type,
remap = function (x, y) { return svgedit.math.transformPoint(x, y, m); },
scalew = function (w) { return m.a * w; },
scaleh = function (h) { return m.d * h; },
doSnapping = editorContext_.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg',
finishUp = function () {
var o;
if (doSnapping) {
for (o in changes) {
changes[o] = svgedit.utilities.snapToGrid(changes[o]);
}
}
svgedit.utilities.assignAttributes(selected, changes, 1000, true);
},
box = svgedit.utilities.getBBox(selected);
for (i = 0; i < 2; i++) {
type = i === 0 ? 'fill' : 'stroke';
var attrVal = selected.getAttribute(type);
if (attrVal && attrVal.indexOf('url(') === 0) {
if (m.a < 0 || m.d < 0) {
var grad = svgedit.utilities.getRefElem(attrVal);
var newgrad = grad.cloneNode(true);
if (m.a < 0) {
// flip x
var x1 = newgrad.getAttribute('x1');
var x2 = newgrad.getAttribute('x2');
newgrad.setAttribute('x1', -(x1 - 1));
newgrad.setAttribute('x2', -(x2 - 1));
}
for (i = 0; i < 2; i++) {
type = i === 0 ? 'fill' : 'stroke';
var attrVal = selected.getAttribute(type);
if (attrVal && attrVal.indexOf('url(') === 0) {
if (m.a < 0 || m.d < 0) {
var grad = svgedit.utilities.getRefElem(attrVal);
var newgrad = grad.cloneNode(true);
if (m.a < 0) {
// flip x
var x1 = newgrad.getAttribute('x1');
var x2 = newgrad.getAttribute('x2');
newgrad.setAttribute('x1', -(x1 - 1));
newgrad.setAttribute('x2', -(x2 - 1));
}
if (m.d < 0) {
// flip y
var y1 = newgrad.getAttribute('y1');
var y2 = newgrad.getAttribute('y2');
newgrad.setAttribute('y1', -(y1 - 1));
newgrad.setAttribute('y2', -(y2 - 1));
}
newgrad.id = editorContext_.getDrawing().getNextId();
svgedit.utilities.findDefs().appendChild(newgrad);
selected.setAttribute(type, 'url(#' + newgrad.id + ')');
}
if (m.d < 0) {
// flip y
var y1 = newgrad.getAttribute('y1');
var y2 = newgrad.getAttribute('y2');
newgrad.setAttribute('y1', -(y1 - 1));
newgrad.setAttribute('y2', -(y2 - 1));
}
newgrad.id = editorContext_.getDrawing().getNextId();
svgedit.utilities.findDefs().appendChild(newgrad);
selected.setAttribute(type, 'url(#' + newgrad.id + ')');
}
// Not really working :(
// if (selected.tagName === 'path') {
// reorientGrads(selected, m);
// }
}
}
// Not really working :(
// if (selected.tagName === 'path') {
// reorientGrads(selected, m);
// }
}
}
var elName = selected.tagName;
var chlist, mt;
if (elName === 'g' || elName === 'text' || elName == 'tspan' || elName === 'use') {
// if it was a translate, then just update x,y
if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && (m.e != 0 || m.f != 0) ) {
// [T][M] = [M][T']
// therefore [T'] = [M_inv][T][M]
var existing = svgedit.math.transformListToTransform(selected).matrix,
t_new = svgedit.math.matrixMultiply(existing.inverse(), m, existing);
changes.x = parseFloat(changes.x) + t_new.e;
changes.y = parseFloat(changes.y) + t_new.f;
} else {
// we just absorb all matrices into the element and don't do any remapping
chlist = svgedit.transformlist.getTransformList(selected);
mt = svgroot.createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
chlist.clear();
chlist.appendItem(mt);
}
}
var c, pt, pt1, pt2, len;
// now we have a set of changes and an applied reduced transform list
// we apply the changes directly to the DOM
switch (elName) {
case 'foreignObject':
case 'rect':
case 'image':
// Allow images to be inverted (give them matrix when flipped)
if (elName === 'image' && (m.a < 0 || m.d < 0)) {
// Convert to matrix
chlist = svgedit.transformlist.getTransformList(selected);
mt = svgroot.createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
chlist.clear();
chlist.appendItem(mt);
} else {
pt1 = remap(changes.x, changes.y);
changes.width = scalew(changes.width);
changes.height = scaleh(changes.height);
changes.x = pt1.x + Math.min(0, changes.width);
changes.y = pt1.y + Math.min(0, changes.height);
changes.width = Math.abs(changes.width);
changes.height = Math.abs(changes.height);
}
finishUp();
break;
case 'ellipse':
c = remap(changes.cx, changes.cy);
changes.cx = c.x;
changes.cy = c.y;
changes.rx = scalew(changes.rx);
changes.ry = scaleh(changes.ry);
changes.rx = Math.abs(changes.rx);
changes.ry = Math.abs(changes.ry);
finishUp();
break;
case 'circle':
c = remap(changes.cx,changes.cy);
changes.cx = c.x;
changes.cy = c.y;
// take the minimum of the new selected box's dimensions for the new circle radius
var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m);
var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
changes.r = Math.min(w/2, h/2);
var elName = selected.tagName;
var chlist, mt;
if (elName === 'g' || elName === 'text' || elName == 'tspan' || elName === 'use') {
// if it was a translate, then just update x,y
if (m.a == 1 && m.b == 0 && m.c == 0 && m.d == 1 && (m.e != 0 || m.f != 0)) {
// [T][M] = [M][T']
// therefore [T'] = [M_inv][T][M]
var existing = svgedit.math.transformListToTransform(selected).matrix,
tNew = svgedit.math.matrixMultiply(existing.inverse(), m, existing);
changes.x = parseFloat(changes.x) + tNew.e;
changes.y = parseFloat(changes.y) + tNew.f;
} else {
// we just absorb all matrices into the element and don't do any remapping
chlist = svgedit.transformlist.getTransformList(selected);
mt = svgroot.createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
chlist.clear();
chlist.appendItem(mt);
}
}
var c, pt, pt1, pt2, len;
// now we have a set of changes and an applied reduced transform list
// we apply the changes directly to the DOM
switch (elName) {
case 'foreignObject':
case 'rect':
case 'image':
// Allow images to be inverted (give them matrix when flipped)
if (elName === 'image' && (m.a < 0 || m.d < 0)) {
// Convert to matrix
chlist = svgedit.transformlist.getTransformList(selected);
mt = svgroot.createSVGTransform();
mt.setMatrix(svgedit.math.matrixMultiply(svgedit.math.transformListToTransform(chlist).matrix, m));
chlist.clear();
chlist.appendItem(mt);
} else {
pt1 = remap(changes.x, changes.y);
changes.width = scalew(changes.width);
changes.height = scaleh(changes.height);
changes.x = pt1.x + Math.min(0, changes.width);
changes.y = pt1.y + Math.min(0, changes.height);
changes.width = Math.abs(changes.width);
changes.height = Math.abs(changes.height);
}
finishUp();
break;
case 'ellipse':
c = remap(changes.cx, changes.cy);
changes.cx = c.x;
changes.cy = c.y;
changes.rx = scalew(changes.rx);
changes.ry = scaleh(changes.ry);
changes.rx = Math.abs(changes.rx);
changes.ry = Math.abs(changes.ry);
finishUp();
break;
case 'circle':
c = remap(changes.cx, changes.cy);
changes.cx = c.x;
changes.cy = c.y;
// take the minimum of the new selected box's dimensions for the new circle radius
var tbox = svgedit.math.transformBox(box.x, box.y, box.width, box.height, m);
var w = tbox.tr.x - tbox.tl.x, h = tbox.bl.y - tbox.tl.y;
changes.r = Math.min(w / 2, h / 2);
if (changes.r) {changes.r = Math.abs(changes.r);}
finishUp();
break;
case 'line':
pt1 = remap(changes.x1, changes.y1);
pt2 = remap(changes.x2, changes.y2);
changes.x1 = pt1.x;
changes.y1 = pt1.y;
changes.x2 = pt2.x;
changes.y2 = pt2.y;
// deliberately fall through here
case 'text':
case 'tspan':
case 'use':
finishUp();
break;
case 'g':
var gsvg = $(selected).data('gsvg');
if (gsvg) {
svgedit.utilities.assignAttributes(gsvg, changes, 1000, true);
}
break;
case 'polyline':
case 'polygon':
len = changes.points.length;
for (i = 0; i < len; ++i) {
pt = changes.points[i];
pt = remap(pt.x, pt.y);
changes.points[i].x = pt.x;
changes.points[i].y = pt.y;
}
if (changes.r) { changes.r = Math.abs(changes.r); }
finishUp();
break;
case 'line':
pt1 = remap(changes.x1, changes.y1);
pt2 = remap(changes.x2, changes.y2);
changes.x1 = pt1.x;
changes.y1 = pt1.y;
changes.x2 = pt2.x;
changes.y2 = pt2.y;
// deliberately fall through here
case 'text':
case 'tspan':
case 'use':
finishUp();
break;
case 'g':
var gsvg = $(selected).data('gsvg');
if (gsvg) {
svgedit.utilities.assignAttributes(gsvg, changes, 1000, true);
}
break;
case 'polyline':
case 'polygon':
len = changes.points.length;
for (i = 0; i < len; ++i) {
pt = changes.points[i];
pt = remap(pt.x, pt.y);
changes.points[i].x = pt.x;
changes.points[i].y = pt.y;
}
len = changes.points.length;
var pstr = '';
for (i = 0; i < len; ++i) {
pt = changes.points[i];
pstr += pt.x + ',' + pt.y + ' ';
}
selected.setAttribute('points', pstr);
break;
case 'path':
var seg;
var segList = selected.pathSegList;
len = segList.numberOfItems;
changes.d = [];
for (i = 0; i < len; ++i) {
seg = segList.getItem(i);
changes.d[i] = {
type: seg.pathSegType,
x: seg.x,
y: seg.y,
x1: seg.x1,
y1: seg.y1,
x2: seg.x2,
y2: seg.y2,
r1: seg.r1,
r2: seg.r2,
angle: seg.angle,
largeArcFlag: seg.largeArcFlag,
sweepFlag: seg.sweepFlag
};
}
len = changes.points.length;
var pstr = '';
for (i = 0; i < len; ++i) {
pt = changes.points[i];
pstr += pt.x + ',' + pt.y + ' ';
}
selected.setAttribute('points', pstr);
break;
case 'path':
var seg;
var segList = selected.pathSegList;
len = segList.numberOfItems;
changes.d = [];
for (i = 0; i < len; ++i) {
seg = segList.getItem(i);
changes.d[i] = {
type: seg.pathSegType,
x: seg.x,
y: seg.y,
x1: seg.x1,
y1: seg.y1,
x2: seg.x2,
y2: seg.y2,
r1: seg.r1,
r2: seg.r2,
angle: seg.angle,
largeArcFlag: seg.largeArcFlag,
sweepFlag: seg.sweepFlag
};
}
len = changes.d.length;
var firstseg = changes.d[0],
currentpt = remap(firstseg.x, firstseg.y);
changes.d[0].x = currentpt.x;
changes.d[0].y = currentpt.y;
for (i = 1; i < len; ++i) {
seg = changes.d[i];
type = seg.type;
// if absolute or first segment, we want to remap x, y, x1, y1, x2, y2
// if relative, we want to scalew, scaleh
if (type % 2 == 0) { // absolute
var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands
thisy = (seg.y != undefined) ? seg.y : currentpt.y; // for H commands
pt = remap(thisx,thisy);
pt1 = remap(seg.x1, seg.y1);
pt2 = remap(seg.x2, seg.y2);
seg.x = pt.x;
seg.y = pt.y;
seg.x1 = pt1.x;
seg.y1 = pt1.y;
seg.x2 = pt2.x;
seg.y2 = pt2.y;
seg.r1 = scalew(seg.r1);
seg.r2 = scaleh(seg.r2);
}
else { // relative
seg.x = scalew(seg.x);
seg.y = scaleh(seg.y);
seg.x1 = scalew(seg.x1);
seg.y1 = scaleh(seg.y1);
seg.x2 = scalew(seg.x2);
seg.y2 = scaleh(seg.y2);
seg.r1 = scalew(seg.r1);
seg.r2 = scaleh(seg.r2);
}
} // for each segment
len = changes.d.length;
var firstseg = changes.d[0],
currentpt = remap(firstseg.x, firstseg.y);
changes.d[0].x = currentpt.x;
changes.d[0].y = currentpt.y;
for (i = 1; i < len; ++i) {
seg = changes.d[i];
type = seg.type;
// if absolute or first segment, we want to remap x, y, x1, y1, x2, y2
// if relative, we want to scalew, scaleh
if (type % 2 == 0) { // absolute
var thisx = (seg.x != undefined) ? seg.x : currentpt.x, // for V commands
thisy = (seg.y != undefined) ? seg.y : currentpt.y; // for H commands
pt = remap(thisx, thisy);
pt1 = remap(seg.x1, seg.y1);
pt2 = remap(seg.x2, seg.y2);
seg.x = pt.x;
seg.y = pt.y;
seg.x1 = pt1.x;
seg.y1 = pt1.y;
seg.x2 = pt2.x;
seg.y2 = pt2.y;
seg.r1 = scalew(seg.r1);
seg.r2 = scaleh(seg.r2);
} else { // relative
seg.x = scalew(seg.x);
seg.y = scaleh(seg.y);
seg.x1 = scalew(seg.x1);
seg.y1 = scaleh(seg.y1);
seg.x2 = scalew(seg.x2);
seg.y2 = scaleh(seg.y2);
seg.r1 = scalew(seg.r1);
seg.r2 = scaleh(seg.r2);
}
} // for each segment
var dstr = '';
len = changes.d.length;
for (i = 0; i < len; ++i) {
seg = changes.d[i];
type = seg.type;
dstr += pathMap[type];
switch (type) {
case 13: // relative horizontal line (h)
case 12: // absolute horizontal line (H)
dstr += seg.x + ' ';
break;
case 15: // relative vertical line (v)
case 14: // absolute vertical line (V)
dstr += seg.y + ' ';
break;
case 3: // relative move (m)
case 5: // relative line (l)
case 19: // relative smooth quad (t)
case 2: // absolute move (M)
case 4: // absolute line (L)
case 18: // absolute smooth quad (T)
dstr += seg.x + ',' + seg.y + ' ';
break;
case 7: // relative cubic (c)
case 6: // absolute cubic (C)
dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' +
seg.x + ',' + seg.y + ' ';
break;
case 9: // relative quad (q)
case 8: // absolute quad (Q)
dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' ';
break;
case 11: // relative elliptical arc (a)
case 10: // absolute elliptical arc (A)
dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + (+seg.largeArcFlag) +
' ' + (+seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' ';
break;
case 17: // relative smooth cubic (s)
case 16: // absolute smooth cubic (S)
dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' ';
break;
}
}
var dstr = '';
len = changes.d.length;
for (i = 0; i < len; ++i) {
seg = changes.d[i];
type = seg.type;
dstr += pathMap[type];
switch (type) {
case 13: // relative horizontal line (h)
case 12: // absolute horizontal line (H)
dstr += seg.x + ' ';
break;
case 15: // relative vertical line (v)
case 14: // absolute vertical line (V)
dstr += seg.y + ' ';
break;
case 3: // relative move (m)
case 5: // relative line (l)
case 19: // relative smooth quad (t)
case 2: // absolute move (M)
case 4: // absolute line (L)
case 18: // absolute smooth quad (T)
dstr += seg.x + ',' + seg.y + ' ';
break;
case 7: // relative cubic (c)
case 6: // absolute cubic (C)
dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' +
seg.x + ',' + seg.y + ' ';
break;
case 9: // relative quad (q)
case 8: // absolute quad (Q)
dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' ';
break;
case 11: // relative elliptical arc (a)
case 10: // absolute elliptical arc (A)
dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + (+seg.largeArcFlag) +
' ' + (+seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' ';
break;
case 17: // relative smooth cubic (s)
case 16: // absolute smooth cubic (S)
dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' ';
break;
}
}
selected.setAttribute('d', dstr);
break;
}
selected.setAttribute('d', dstr);
break;
}
};
}());

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/
/*jslint vars: true, eqeq: true, todo: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgedit */
/**
* Package: svgedit.draw
*
@@ -13,7 +13,8 @@
// 2) browser.js
// 3) svgutils.js
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.draw) {
svgedit.draw = {};
@@ -28,25 +29,22 @@ var RandomizeModes = {
ALWAYS_RANDOMIZE: 1,
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.
* The currentDrawing will have its nonce set if it doesn't already.
* @param {boolean} enableRandomization - flag indicating if documents should have randomized ids
* @param {svgedit.draw.Drawing} currentDrawing
*/
svgedit.draw.randomizeIds = function(enableRandomization, currentDrawing) {
randomize_ids = enableRandomization === false ?
RandomizeModes.NEVER_RANDOMIZE :
RandomizeModes.ALWAYS_RANDOMIZE;
svgedit.draw.randomizeIds = function (enableRandomization, currentDrawing) {
randomizeIds = enableRandomization === false
? RandomizeModes.NEVER_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));
} else if (randomize_ids == RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) {
} else if (randomizeIds == RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) {
currentDrawing.clearNonce();
}
};
@@ -56,12 +54,12 @@ svgedit.draw.randomizeIds = function(enableRandomization, currentDrawing) {
* @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object
* encapsulates. If the svgElem has a se:nonce attribute on it, then
* IDs will use the nonce as they are generated.
* @param {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 ||
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}
*/
this.svgElem_ = svgElem;
/**
* The latest object number used in this drawing.
* @type {number}
*/
this.obj_num = 0;
/**
* The prefix to prepend to each element id in the drawing.
* @type {String}
*/
this.idPrefix = opt_idPrefix || "svg_";
this.idPrefix = optIdPrefix || 'svg_';
/**
* An array of released element ids to immediately reuse.
* @type {Array.<number>}
@@ -120,9 +118,9 @@ svgedit.draw.Drawing = function(svgElem, opt_idPrefix) {
var n = this.svgElem_.getAttributeNS(NS.SE, 'nonce');
// If already set in the DOM, use the nonce throughout the document
// else, if randomizeIds(true) has been called, create and set the nonce.
if (!!n && randomize_ids != RandomizeModes.NEVER_RANDOMIZE) {
if (!!n && randomizeIds != RandomizeModes.NEVER_RANDOMIZE) {
this.nonce_ = n;
} else if (randomize_ids == RandomizeModes.ALWAYS_RANDOMIZE) {
} else if (randomizeIds == RandomizeModes.ALWAYS_RANDOMIZE) {
this.setNonce(Math.floor(Math.random() * 100001));
}
};
@@ -150,14 +148,14 @@ svgedit.draw.Drawing.prototype.getSvgElem = function () {
/**
* @returns {!string|number} The previously set nonce
*/
svgedit.draw.Drawing.prototype.getNonce = function() {
svgedit.draw.Drawing.prototype.getNonce = function () {
return this.nonce_;
};
/**
* @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.SE, 'se:nonce', n);
this.nonce_ = n;
@@ -177,9 +175,9 @@ svgedit.draw.Drawing.prototype.clearNonce = function () {
* @return {String} The latest object Id.
*/
svgedit.draw.Drawing.prototype.getId = function () {
return this.nonce_ ?
this.idPrefix + this.nonce_ + '_' + this.obj_num :
this.idPrefix + this.obj_num;
return this.nonce_
? this.idPrefix + this.nonce_ + '_' + this.obj_num
: this.idPrefix + this.obj_num;
};
/**
@@ -190,7 +188,7 @@ svgedit.draw.Drawing.prototype.getNextId = function () {
var oldObjNum = this.obj_num;
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.
// We need to temporarily use obj_num as that is what getId() depends on.
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) {
return false;
}
// push the released number into the released queue
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 {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;
};
@@ -262,7 +260,6 @@ svgedit.draw.Drawing.prototype.hasLayer = function (name) {
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.
* @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.
*/
svgedit.draw.Drawing.prototype.getCurrentLayer = function() {
svgedit.draw.Drawing.prototype.getCurrentLayer = function () {
return this.current_layer ? this.current_layer.getGroup() : null;
};
@@ -283,13 +280,13 @@ svgedit.draw.Drawing.prototype.getCurrentLayer = function() {
* Get a layer by name.
* @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];
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.
* @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.
*/
svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) {
var layer_count = this.getNumLayers();
if (!this.current_layer || newpos < 0 || newpos >= layer_count) {
var layerCount = this.getNumLayers();
if (!this.current_layer || newpos < 0 || newpos >= layerCount) {
return null;
}
var oldpos;
for (oldpos = 0; oldpos < layer_count; ++oldpos) {
if (this.all_layers[oldpos] == this.current_layer) {break;}
for (oldpos = 0; oldpos < layerCount; ++oldpos) {
if (this.all_layers[oldpos] == this.current_layer) { break; }
}
// 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 our new position is below us, we need to insert before the node after newpos
var refGroup = null;
var current_group = this.current_layer.getGroup();
var oldNextSibling = current_group.nextSibling;
if (newpos > oldpos ) {
if (newpos < layer_count-1) {
refGroup = this.all_layers[newpos+1].getGroup();
var currentGroup = this.current_layer.getGroup();
var oldNextSibling = currentGroup.nextSibling;
if (newpos > oldpos) {
if (newpos < layerCount - 1) {
refGroup = this.all_layers[newpos + 1].getGroup();
}
}
// if our new position is above us, we need to insert before the node at newpos
else {
} else {
refGroup = this.all_layers[newpos].getGroup();
}
this.svgElem_.insertBefore(current_group, refGroup);
this.svgElem_.insertBefore(currentGroup, refGroup);
this.identifyLayers();
this.setCurrentLayer(this.getLayerName(newpos));
return {
currentGroup: current_group,
currentGroup: currentGroup,
oldNextSibling: oldNextSibling
};
}
@@ -362,25 +358,25 @@ svgedit.draw.Drawing.prototype.setCurrentLayerPosition = function (newpos) {
};
svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
var current_group = this.current_layer.getGroup();
var prevGroup = $(current_group).prev()[0];
if (!prevGroup) {return;}
var currentGroup = this.current_layer.getGroup();
var prevGroup = $(currentGroup).prev()[0];
if (!prevGroup) { return; }
hrService.startBatchCommand('Merge Layer');
var layerNextSibling = current_group.nextSibling;
hrService.removeElement(current_group, layerNextSibling, this.svgElem_);
var layerNextSibling = currentGroup.nextSibling;
hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_);
while (current_group.firstChild) {
var child = current_group.firstChild;
while (currentGroup.firstChild) {
var child = currentGroup.firstChild;
if (child.localName == 'title') {
hrService.removeElement(child, child.nextSibling, current_group);
current_group.removeChild(child);
hrService.removeElement(child, child.nextSibling, currentGroup);
currentGroup.removeChild(child);
continue;
}
var oldNextSibling = child.nextSibling;
prevGroup.appendChild(child);
hrService.moveElement(child, oldNextSibling, current_group);
hrService.moveElement(child, oldNextSibling, currentGroup);
}
// 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);
if (index > 0) {
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);
delete this.layer_map[name];
}
@@ -399,7 +395,7 @@ svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
svgedit.draw.Drawing.prototype.mergeAllLayers = function (hrService) {
// 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');
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.
* @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];
if (layer) {
if (this.current_layer) {
@@ -428,13 +424,12 @@ svgedit.draw.Drawing.prototype.setCurrentLayer = function(name) {
return false;
};
/**
* Deletes the current layer from the drawing and then clears the selection.
* This function then calls the 'changed' handler. This is an undoable action.
* @returns {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) {
var oldLayerGroup = this.current_layer.removeGroup();
this.identifyLayers();
@@ -448,8 +443,8 @@ svgedit.draw.Drawing.prototype.deleteCurrentLayer = function() {
* @param group The group element to search in.
* @returns {string} The layer name or empty string.
*/
function findLayerNameInGroup(group) {
var name = $("title", group).text();
function findLayerNameInGroup (group) {
var name = $('title', group).text();
// Hack for Opera 10.60
if (!name && svgedit.browser.isOpera() && group.querySelectorAll) {
@@ -463,18 +458,18 @@ function findLayerNameInGroup(group) {
* @param {Array.<string>} existingLayerNames - Existing layer names.
* @returns {string} - The new name.
*/
function getNewLayerName(existingLayerNames) {
function getNewLayerName (existingLayerNames) {
var i = 1;
// TODO(codedread): What about internationalization of "Layer"?
while (existingLayerNames.indexOf(("Layer " + i)) >= 0) { i++; }
return "Layer " + i;
while (existingLayerNames.indexOf(('Layer ' + i)) >= 0) { i++; }
return 'Layer ' + i;
}
/**
* Updates layer system and sets the current layer to the
* 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.layer_map = {};
var numchildren = this.svgElem_.childNodes.length;
@@ -486,7 +481,7 @@ svgedit.draw.Drawing.prototype.identifyLayers = function() {
var child = this.svgElem_.childNodes.item(i);
// for each g, find its layer name
if (child && child.nodeType == 1) {
if (child.tagName == "g") {
if (child.tagName === 'g') {
childgroups = true;
var name = findLayerNameInGroup(child);
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.length > 0 || !childgroups) {
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
* 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) {
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
* also the current layer of this drawing.
*/
svgedit.draw.Drawing.prototype.cloneLayer = function(name, hrService) {
if (!this.current_layer) {return null;}
svgedit.draw.Drawing.prototype.cloneLayer = function (name, hrService) {
if (!this.current_layer) { return null; }
this.current_layer.deactivate();
// Check for duplicate 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
var currentGroup = this.current_layer.getGroup();
var layer = new svgedit.draw.Layer(name, currentGroup, this.svgElem_);
var group = layer.getGroup();
var group = layer.getGroup();
// Clone children
var children = currentGroup.childNodes;
var index;
for (index = 0; index < children.length; index++) {
var ch = children[index];
if (ch.localName == 'title') {continue;}
if (ch.localName == 'title') { continue; }
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.
* @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];
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
* 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') {
return null;
}
var layer = this.layer_map[layername];
if (!layer) {return null;}
if (!layer) { return null; }
layer.setVisible(bVisible);
return layer.getGroup();
};
/**
* 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
* @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
*/
svgedit.draw.Drawing.prototype.getLayerOpacity = function(layername) {
svgedit.draw.Drawing.prototype.getLayerOpacity = function (layername) {
var layer = this.layer_map[layername];
if (!layer) {return null;}
if (!layer) { return null; }
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 {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) {
return;
}
@@ -661,11 +655,9 @@ svgedit.draw.Drawing.prototype.setLayerOpacity = function(layername, opacity) {
* @param {Element} el - DOM element to clone
* @returns {Element}
*/
svgedit.draw.Drawing.prototype.copyElem = function(el) {
svgedit.draw.Drawing.prototype.copyElem = function (el) {
var self = this;
var getNextIdClosure = function() { return self.getNextId();}
return svgedit.utilities.copyElem(el, getNextIdClosure)
}
var getNextIdClosure = function () { return self.getNextId(); };
return svgedit.utilities.copyElem(el, getNextIdClosure);
};
}());

View File

@@ -1,79 +1,80 @@
/*globals $, EmbeddedSVGEdit*/
/*jslint vars: true */
var initEmbed;
/* eslint-disable no-var */
/* globals $, EmbeddedSVGEdit */
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
$(function () {'use strict';
var svgCanvas = null;
var frame;
$(function () {
'use strict';
initEmbed = function () {
var doc, mainButton;
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';
};
var svgCanvas = null;
var frame;
function handleSvgData(data, error) {
if (error) {
alert('error ' + error);
} else {
alert('Congratulations. Your SVG string is back in the host page, do with it what you will\n\n' + data);
}
}
initEmbed = function () {
var doc, mainButton;
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 loadSvg() {
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 handleSvgData (data, error) {
if (error) {
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() {
svgCanvas.getSvgString()(handleSvgData);
}
function exportPNG() {
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
function loadSvg () {
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 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) {
alert(data.dataurlstring);
});
svgCanvas.exportPDF(); // Accepts two args: optionalWindowName supplied back to bound exportPDF handler and optionalOutputType (defaults to dataurlstring)
return;
*/
var exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow'
);
return;
*/
var exportWindow = window.open(
'data:text/html;charset=utf-8,' + encodeURIComponent('<title>' + str + '</title><h1>' + str + '</h1>'),
'svg-edit-exportWindow'
);
svgCanvas.exportPDF(exportWindow.name);
}
// Add event handlers
$('#load').click(loadSvg);
$('#save').click(saveSvg);
$('#exportPNG').click(exportPNG);
$('#exportPDF').click(exportPDF);
$('body').append(
$('<iframe src="svg-editor.html?extensions=ext-xdomain-messaging.js' +
window.location.href.replace(/\?(.*)$/, '&$1') + // Append arguments to this file onto the iframe
'" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>'
)
);
frame = document.getElementById('svgedit');
}
// Add event handlers
$('#load').click(loadSvg);
$('#save').click(saveSvg);
$('#exportPNG').click(exportPNG);
$('#exportPDF').click(exportPDF);
$('body').append(
$('<iframe src="svg-editor.html?extensions=ext-xdomain-messaging.js' +
window.location.href.replace(/\?(.*)$/, '&$1') + // Append arguments to this file onto the iframe
'" width="900px" height="600px" id="svgedit" onload="initEmbed();"></iframe>'
)
);
frame = document.getElementById('svgedit');
});

View File

@@ -1,4 +1,5 @@
/*
/* eslint-disable no-var */
/*
Embedded SVG-edit API
General usage:
@@ -9,11 +10,11 @@ var svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
svgCanvas.setSvgString('string')
- Or if a callback is needed:
svgCanvas.setSvgString('string')(function(data, error){
if (error){
if (error){
// There was an error
} else{
} else{
// Handle data
}
}
})
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)})
*/
(function () {'use strict';
(function () {
'use strict';
var cbid = 0;
function getCallbackSetter (d) {
return function () {
var t = this, // New callback
args = [].slice.call(arguments),
cbid = t.send(d, args, function(){}); // The callback (currently it's nothing, but will be set later)
return function () {
var t = this, // New callback
args = [].slice.call(arguments),
cbid = t.send(d, args, function () {}); // The callback (currently it's nothing, but will be set later)
return function(newcallback){
t.callbacks[cbid] = newcallback; // Set callback
return function (newcallback) {
t.callbacks[cbid] = newcallback; // Set callback
};
};
};
}
/*
@@ -57,32 +59,32 @@ function getCallbackSetter (d) {
* of same domain control
*/
function addCallback (t, data) {
var result = data.result || data.error,
cbid = data.id;
if (t.callbacks[cbid]) {
if (data.result) {
t.callbacks[cbid](result);
} else {
t.callbacks[cbid](result, 'error');
var result = data.result || data.error,
cbid = data.id;
if (t.callbacks[cbid]) {
if (data.result) {
t.callbacks[cbid](result);
} else {
t.callbacks[cbid](result, 'error');
}
}
}
}
function messageListener (e) {
// We accept and post strings as opposed to objects for the sake of IE9 support; this
// will most likely be changed in the future
if (typeof e.data !== 'string') {
return;
}
var allowedOrigins = this.allowedOrigins,
data = e.data && JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
e.source !== this.frame.contentWindow ||
(allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1)
) {
return;
}
addCallback(this, data);
// We accept and post strings as opposed to objects for the sake of IE9 support; this
// will most likely be changed in the future
if (typeof e.data !== 'string') {
return;
}
var allowedOrigins = this.allowedOrigins,
data = e.data && JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svg-edit' ||
e.source !== this.frame.contentWindow ||
(allowedOrigins.indexOf('*') === -1 && allowedOrigins.indexOf(e.origin) === -1)
) {
return;
}
addCallback(this, data);
}
function getMessageListener (t) {
@@ -98,82 +100,79 @@ function getMessageListener (t) {
* If supplied, it should probably be the same as svgEditor's allowedOrigins
*/
function EmbeddedSVGEdit (frame, allowedOrigins) {
if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without 'new' keyword
return new EmbeddedSVGEdit(frame);
}
this.allowedOrigins = allowedOrigins || [];
// Initialize communication
this.frame = frame;
this.callbacks = {};
// List of functions extracted with this:
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
if (!(this instanceof EmbeddedSVGEdit)) { // Allow invocation without 'new' keyword
return new EmbeddedSVGEdit(frame);
}
this.allowedOrigins = allowedOrigins || [];
// Initialize communication
this.frame = frame;
this.callbacks = {};
// List of functions extracted with this:
// Run in firebug on http://svg-edit.googlecode.com/svn/trunk/docs/files/svgcanvas-js.html
// for (var i=0,q=[],f = document.querySelectorAll('div.CFunction h3.CTitle a'); i < f.length; i++) { q.push(f[i].name); }; q
// var functions = ['clearSelection', 'addToSelection', 'removeFromSelection', 'open', 'save', 'getSvgString', 'setSvgString',
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
// 'moveSelectedToLayer', 'clear'];
// 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',
// 'createLayer', 'deleteCurrentLayer', 'setCurrentLayer', 'renameCurrentLayer', 'setCurrentLayerPosition', 'setLayerVisibility',
// '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
// var svgCanvas = frame.contentWindow.svgCanvas;
// var l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} };
// alert("['" + l.join("', '") + "']");
// Run in svgedit itself
var i,
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'
];
// 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 l = []; for (var i in svgCanvas){ if (typeof svgCanvas[i] == 'function') { l.push(i);} };
// alert("['" + l.join("', '") + "']");
// Run in svgedit itself
var i,
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'
];
// TODO: rewrite the following, it's pretty scary.
for (i = 0; i < functions.length; i++) {
this[functions[i]] = getCallbackSetter(functions[i]);
}
// Older IE may need a polyfill for addEventListener, but so it would for SVG
window.addEventListener('message', getMessageListener(this), false);
// TODO: rewrite the following, it's pretty scary.
for (i = 0; i < functions.length; i++) {
this[functions[i]] = getCallbackSetter(functions[i]);
}
// Older IE may need a polyfill for addEventListener, but so it would for SVG
window.addEventListener('message', getMessageListener(this), false);
}
EmbeddedSVGEdit.prototype.send = function (name, args, callback){
var t = this;
cbid++;
EmbeddedSVGEdit.prototype.send = function (name, args, callback) {
var t = this;
cbid++;
this.callbacks[cbid] = callback;
setTimeout((function (cbid) {
return function () { // Delay for the callback to be set in case its synchronous
/*
* Todo: Handle non-JSON arguments and return values (undefined,
* nonfinite numbers, functions, and built-in objects like Date,
* RegExp), etc.? Allow promises instead of callbacks? Review
* SVG-Edit functions for whether JSON-able parameters can be
* made compatile with all API functionality
*/
// We accept and post strings for the sake of IE9 support
if (window.location.origin === t.frame.contentWindow.location.origin) {
// 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
// cross-domain as well, assuming we stick to the argument limitations
// of the current JSON-based communication API (e.g., not passing
// callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file.
var message = {id: cbid},
svgCanvas = t.frame.contentWindow.svgCanvas;
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
}
catch (err) {
message.error = err.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}), '*');
}
};
}(cbid)), 0);
this.callbacks[cbid] = callback;
setTimeout((function (cbid) {
return function () { // Delay for the callback to be set in case its synchronous
/*
* Todo: Handle non-JSON arguments and return values (undefined,
* nonfinite numbers, functions, and built-in objects like Date,
* RegExp), etc.? Allow promises instead of callbacks? Review
* SVG-Edit functions for whether JSON-able parameters can be
* made compatile with all API functionality
*/
// We accept and post strings for the sake of IE9 support
if (window.location.origin === t.frame.contentWindow.location.origin) {
// 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
// cross-domain as well, assuming we stick to the argument limitations
// of the current JSON-based communication API (e.g., not passing
// callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file.
var message = {id: cbid},
svgCanvas = t.frame.contentWindow.svgCanvas;
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) {
message.error = err.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}), '*');
}
};
}(cbid)), 0);
return cbid;
return cbid;
};
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
}());

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,20 +1,20 @@
/*globals svgEditor, svgedit, svgCanvas, $*/
/*jslint vars: true, eqeq: true, todo: true*/
/* eslint-disable no-var */
/* globals svgEditor, svgedit, svgCanvas, $ */
/*
* ext-foreignobject.js
*
* Licensed under the Apache License, Version 2
*
* Copyright(c) 2010 Jacques Distler
* Copyright(c) 2010 Alexis Deveria
* Copyright(c) 2010 Jacques Distler
* Copyright(c) 2010 Alexis Deveria
*
*/
svgEditor.addExtension("foreignObject", function(S) {
svgEditor.addExtension('foreignObject', function (S) {
var NS = svgedit.NS,
Utils = svgedit.utilities,
svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson,
// svgcontent = S.svgcontent,
// addElem = S.addSvgElementFromJson,
selElems,
editingforeign = false,
svgdoc = S.svgroot.parentNode.ownerDocument,
@@ -27,16 +27,16 @@ svgEditor.addExtension("foreignObject", function(S) {
$('#svg_source_textarea').css('height', height);
};
function showPanel(on) {
var fc_rules = $('#fc_rules');
if(!fc_rules.length) {
fc_rules = $('<style id="fc_rules"></style>').appendTo('head');
function showPanel (on) {
var fcRules = $('#fc_rules');
if (!fcRules.length) {
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);
}
function toggleSourceButtons(on) {
function toggleSourceButtons (on) {
$('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#foreign_save, #foreign_cancel').toggle(on);
}
@@ -50,7 +50,7 @@ svgEditor.addExtension("foreignObject", function(S) {
//
// Returns:
// This function returns false if the set was unsuccessful, true otherwise.
function setForeignString(xmlString) {
function setForeignString (xmlString) {
var elt = selElems[0];
try {
// 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
S.sanitizeSvg(newDoc.documentElement);
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
S.call("changed", [elt]);
S.call('changed', [elt]);
svgCanvas.clearSelection();
} catch(e) {
} catch (e) {
console.log(e);
return false;
}
@@ -68,9 +68,9 @@ svgEditor.addExtension("foreignObject", function(S) {
return true;
}
function showForeignEditor() {
function showForeignEditor () {
var elt = selElems[0];
if (!elt || editingforeign) {return;}
if (!elt || editingforeign) { return; }
editingforeign = true;
toggleSourceButtons(true);
elt.removeAttribute('fill');
@@ -82,78 +82,78 @@ svgEditor.addExtension("foreignObject", function(S) {
$('#svg_source_textarea').focus();
}
function setAttr(attr, val) {
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call("changed", selElems);
S.call('changed', selElems);
}
return {
name: "foreignObject",
svgicons: svgEditor.curConfig.extPath + "foreignobject-icons.xml",
name: 'foreignObject',
svgicons: svgEditor.curConfig.extPath + 'foreignobject-icons.xml',
buttons: [{
id: "tool_foreign",
type: "mode",
title: "Foreign Object Tool",
id: 'tool_foreign',
type: 'mode',
title: 'Foreign Object Tool',
events: {
'click': function() {
'click': function () {
svgCanvas.setMode('foreign');
}
}
},{
id: "edit_foreign",
type: "context",
panel: "foreignObject_panel",
title: "Edit ForeignObject Content",
}, {
id: 'edit_foreign',
type: 'context',
panel: 'foreignObject_panel',
title: 'Edit ForeignObject Content',
events: {
'click': function() {
'click': function () {
showForeignEditor();
}
}
}],
context_tools: [{
type: "input",
panel: "foreignObject_panel",
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's width",
id: "foreign_width",
label: "w",
id: 'foreign_width',
label: 'w',
size: 3,
events: {
change: function() {
change: function () {
setAttr('width', this.value);
}
}
},{
type: "input",
panel: "foreignObject_panel",
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's height",
id: "foreign_height",
label: "h",
id: 'foreign_height',
label: 'h',
events: {
change: function() {
change: function () {
setAttr('height', this.value);
}
}
}, {
type: "input",
panel: "foreignObject_panel",
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's font size",
id: "foreign_font_size",
label: "font-size",
id: 'foreign_font_size',
label: 'font-size',
size: 2,
defval: 16,
events: {
change: function() {
change: function () {
setAttr('font-size', this.value);
}
}
}
],
callback: function() {
callback: function () {
$('#foreignObject_panel').hide();
var endChanges = function() {
var endChanges = function () {
$('#svg_source_editor').hide();
editingforeign = false;
$('#svg_source_textarea').blur();
@@ -161,48 +161,46 @@ svgEditor.addExtension("foreignObject", function(S) {
};
// TODO: Needs to be done after orig icon loads
setTimeout(function() {
setTimeout(function () {
// Create source save/cancel buttons
var save = $('#tool_source_save').clone()
/* var save = */ $('#tool_source_save').clone()
.hide().attr('id', 'foreign_save').unbind()
.appendTo("#tool_source_back").click(function() {
if (!editingforeign) {return;}
.appendTo('#tool_source_back').click(function () {
if (!editingforeign) { return; }
if (!setForeignString($('#svg_source_textarea').val())) {
$.confirm("Errors found. Revert to original?", function(ok) {
if(!ok) {return false;}
$.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) { return false; }
endChanges();
});
} else {
endChanges();
}
// setSelectMode();
// setSelectMode();
});
var cancel = $('#tool_source_cancel').clone()
/* var cancel = */ $('#tool_source_cancel').clone()
.hide().attr('id', 'foreign_cancel').unbind()
.appendTo("#tool_source_back").click(function() {
.appendTo('#tool_source_back').click(function () {
endChanges();
});
}, 3000);
},
mouseDown: function(opts) {
var e = opts.event;
if(svgCanvas.getMode() == "foreign") {
mouseDown: function (opts) {
// var e = opts.event;
if (svgCanvas.getMode() === 'foreign') {
started = true;
newFO = S.addSvgElementFromJson({
"element": "foreignObject",
"attr": {
"x": opts.start_x,
"y": opts.start_y,
"id": S.getNextId(),
"font-size": 16, //cur_text.font_size,
"width": "48",
"height": "20",
"style": "pointer-events:inherit"
'element': 'foreignObject',
'attr': {
'x': opts.start_x,
'y': opts.start_y,
'id': S.getNextId(),
'font-size': 16, // cur_text.font_size,
'width': '48',
'height': '20',
'style': 'pointer-events:inherit'
}
});
var m = svgdoc.createElementNS(NS.MATH, 'math');
@@ -210,11 +208,11 @@ svgEditor.addExtension("foreignObject", function(S) {
m.setAttribute('display', 'inline');
var mi = svgdoc.createElementNS(NS.MATH, 'mi');
mi.setAttribute('mathvariant', 'normal');
mi.textContent = "\u03A6";
mi.textContent = '\u03A6';
var mo = svgdoc.createElementNS(NS.MATH, 'mo');
mo.textContent = "\u222A";
mo.textContent = '\u222A';
var mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
mi2.textContent = "\u2133";
mi2.textContent = '\u2133';
m.appendChild(mi);
m.appendChild(mo);
m.appendChild(mi2);
@@ -224,34 +222,32 @@ svgEditor.addExtension("foreignObject", function(S) {
};
}
},
mouseUp: function(opts) {
var e = opts.event;
if(svgCanvas.getMode() == "foreign" && started) {
var attrs = $(newFO).attr(["width", "height"]);
var keep = (attrs.width != 0 || attrs.height != 0);
mouseUp: function (opts) {
// var e = opts.event;
if (svgCanvas.getMode() === 'foreign' && started) {
var attrs = $(newFO).attr(['width', 'height']);
var keep = (attrs.width !== '0' || attrs.height !== '0');
svgCanvas.addToSelection([newFO], true);
return {
keep: keep,
element: newFO
};
}
},
selectedChanged: function(opts) {
selectedChanged: function (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
var i = selElems.length;
while(i--) {
while (i--) {
var elem = selElems[i];
if(elem && elem.tagName === 'foreignObject') {
if(opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute("font-size"));
$('#foreign_width').val(elem.getAttribute("width"));
$('#foreign_height').val(elem.getAttribute("height"));
if (elem && elem.tagName === 'foreignObject') {
if (opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute('font-size'));
$('#foreign_width').val(elem.getAttribute('width'));
$('#foreign_height').val(elem.getAttribute('height'));
showPanel(true);
} else {
showPanel(false);
@@ -261,8 +257,8 @@ svgEditor.addExtension("foreignObject", function(S) {
}
}
},
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, $*/
/*jslint vars: true*/
/* eslint-disable no-var */
/* globals svgEditor, svgedit, svgCanvas, $ */
/*
* ext-grid.js
*
@@ -14,7 +14,8 @@
// 1) units.js
// 2) everything else
svgEditor.addExtension('view_grid', function() { 'use strict';
svgEditor.addExtension('view_grid', function () {
'use strict';
var NS = svgedit.NS,
svgdoc = document.getElementById('svgcanvas').ownerDocument,
@@ -44,8 +45,8 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
assignAttributes(gridPattern, {
'id': 'gridpattern',
'patternUnits': 'userSpaceOnUse',
'x': 0, //-(value.strokeWidth / 2), // position for strokewidth
'y': 0, //-(value.strokeWidth / 2), // position for strokewidth
'x': 0, // -(value.strokeWidth / 2), // position for strokewidth
'y': 0, // -(value.strokeWidth / 2), // position for strokewidth
'width': 100,
'height': 100
});
@@ -74,56 +75,56 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
});
$('#canvasGrid').append(gridBox);
function updateGrid(zoom) {
function updateGrid (zoom) {
var i;
// TODO: Try this with <line> elements, then compare performance difference
var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
var u_multi = unit * zoom;
var uMulti = unit * zoom;
// Calculate the main number interval
var raw_m = 100 / u_multi;
var rawM = 100 / uMulti;
var multi = 1;
for (i = 0; i < intervals.length; i++) {
var num = intervals[i];
multi = num;
if (raw_m <= num) {
if (rawM <= num) {
break;
}
}
var big_int = multi * u_multi;
var bigInt = multi * uMulti;
// Set the canvas size to the width of the container
hcanvas.width = big_int;
hcanvas.height = big_int;
hcanvas.width = bigInt;
hcanvas.height = bigInt;
var ctx = hcanvas.getContext('2d');
var cur_d = 0.5;
var part = big_int / 10;
var curD = 0.5;
var part = bigInt / 10;
ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.curConfig.gridColor;
for (i = 1; i < 10; i++) {
var sub_d = Math.round(part * i) + 0.5;
// var line_num = (i % 2)?12:10;
var line_num = 0;
ctx.moveTo(sub_d, big_int);
ctx.lineTo(sub_d, line_num);
ctx.moveTo(big_int, sub_d);
ctx.lineTo(line_num ,sub_d);
var subD = Math.round(part * i) + 0.5;
// var lineNum = (i % 2)?12:10;
var lineNum = 0;
ctx.moveTo(subD, bigInt);
ctx.lineTo(subD, lineNum);
ctx.moveTo(bigInt, subD);
ctx.lineTo(lineNum, subD);
}
ctx.stroke();
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.moveTo(cur_d, big_int);
ctx.lineTo(cur_d, 0);
ctx.moveTo(curD, bigInt);
ctx.lineTo(curD, 0);
ctx.moveTo(big_int, cur_d);
ctx.lineTo(0, cur_d);
ctx.moveTo(bigInt, curD);
ctx.lineTo(0, curD);
ctx.stroke();
var datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', big_int);
gridimg.setAttribute('height', big_int);
gridimg.parentNode.setAttribute('width', big_int);
gridimg.parentNode.setAttribute('height', big_int);
gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', bigInt);
gridimg.parentNode.setAttribute('height', bigInt);
svgCanvas.setHref(gridimg, datauri);
}
@@ -138,8 +139,8 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
name: 'view_grid',
svgicons: svgEditor.curConfig.extPath + 'grid-icon.xml',
zoomChanged: function(zoom) {
if (showGrid) {updateGrid(zoom);}
zoomChanged: function (zoom) {
if (showGrid) { updateGrid(zoom); }
},
callback: function () {
if (showGrid) {
@@ -152,7 +153,7 @@ svgEditor.addExtension('view_grid', function() { 'use strict';
panel: 'editor_panel',
title: 'Show/Hide Grid',
events: {
click: function() {
click: function () {
svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate();
}

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, $*/
/*jslint vars: true, eqeq: true*/
/* eslint-disable no-var */
/* globals svgEditor, svgCanvas, $ */
/*
* ext-helloworld.js
*
@@ -8,73 +8,72 @@
* Copyright(c) 2010 Alexis Deveria
*
*/
/*
/*
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
user the point on the canvas that was clicked on.
*/
svgEditor.addExtension("Hello World", function() {'use strict';
return {
name: "Hello World",
// For more notes on how to make an icon file, see the source of
// the helloworld-icon.xml
svgicons: svgEditor.curConfig.extPath + "helloworld-icon.xml",
// Multiple buttons can be added in this array
buttons: [{
// Must match the icon ID in helloworld-icon.xml
id: "hello_world",
// This indicates that the button will be added to the "mode"
// button panel on the left side
type: "mode",
// Tooltip text
title: "Say 'Hello World'",
// Events
events: {
'click': function() {
// 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);
svgEditor.addExtension('Hello World', function () {
'use strict';
return {
name: 'Hello World',
// For more notes on how to make an icon file, see the source of
// the helloworld-icon.xml
svgicons: svgEditor.curConfig.extPath + 'helloworld-icon.xml',
// Multiple buttons can be added in this array
buttons: [{
// Must match the icon ID in helloworld-icon.xml
id: 'hello_world',
// This indicates that the button will be added to the "mode"
// button panel on the left side
type: 'mode',
// Tooltip text
title: "Say 'Hello World'",
// Events
events: {
'click': function () {
// 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);
}
}
};
});

View File

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

View File

@@ -1,23 +1,23 @@
/*globals svgEditor, svgCanvas, $*/
/*jslint vars: true, eqeq: true, todo: true */
/* eslint-disable no-var */
/* globals svgEditor, svgCanvas, $ */
/*
* ext-markers.js
*
* 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
*
* 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
*
*
* to simplify the coding and make the implementation as robust as possible,
* markers are not shared - every object has its own set of markers.
* this relationship is maintained by a naming convention between the
* ids of the markers and the ids of the object
*
*
* The following restrictions exist for simplicty of use and programming
* objects and their markers to have the same color
* marker size is fixed
@@ -32,236 +32,235 @@
*
*/
svgEditor.addExtension("Markers", function(S) {
svgEditor.addExtension('Markers', function (S) {
var // svgcontent = S.svgcontent,
addElem = S.addSvgElementFromJson,
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
// and add the associated icon(s) to marker-icons.svg
// 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
// remember that the coordinate system has +y downward
var marker_types = {
nomarker: {},
leftarrow:
{element:'path', attr:{d:'M0,50 L100,90 L70,50 L100,10 Z'}},
var markerTypes = {
nomarker: {},
leftarrow:
{element: 'path', attr: {d: 'M0,50 L100,90 L70,50 L100,10 Z'}},
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:
{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'}},
forwardslash:
{element:'path', attr:{d:'M30,100 L70,0'}},
{element: 'path', attr: {d: 'M30,100 L70,0'}},
reverseslash:
{element:'path', attr:{d:'M30,0 L70,100'}},
{element: 'path', attr: {d: 'M30,0 L70,100'}},
verticalslash:
{element:'path', attr:{d:'M50,0 L50,100'}},
{element: 'path', attr: {d: 'M50,0 L50,100'}},
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:
{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:
{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:
{element:'path', attr:{d:'M10,80 L50,20 L80,80 Z'}},
{element: 'path', attr: {d: 'M10,80 L50,20 L80,80 Z'}},
mcircle:
{element:'circle', attr:{r:30, cx:50, cy:50}}
{element: 'circle', attr: {r: 30, cx: 50, cy: 50}}
};
var lang_list = {
"en":[
{id: "start_marker_list", title: "Select start marker type" },
{id: "mid_marker_list", title: "Select mid marker type" },
{id: "end_marker_list", title: "Select end marker type" },
{id: "nomarker", title: "No Marker" },
{id: "leftarrow", title: "Left Arrow" },
{id: "rightarrow", title: "Right Arrow" },
{id: "textmarker", title: "Text Marker" },
{id: "forwardslash", title: "Forward Slash" },
{id: "reverseslash", title: "Reverse Slash" },
{id: "verticalslash", title: "Vertical Slash" },
{id: "box", title: "Box" },
{id: "star", title: "Star" },
{id: "xmark", title: "X" },
{id: "triangle", title: "Triangle" },
{id: "mcircle", title: "Circle" },
{id: "leftarrow_o", title: "Open Left Arrow" },
{id: "rightarrow_o", title: "Open Right Arrow" },
{id: "box_o", title: "Open Box" },
{id: "star_o", title: "Open Star" },
{id: "triangle_o", title: "Open Triangle" },
{id: "mcircle_o", title: "Open Circle" }
var langList = {
'en': [
{id: 'start_marker_list', title: 'Select start marker type'},
{id: 'mid_marker_list', title: 'Select mid marker type'},
{id: 'end_marker_list', title: 'Select end marker type'},
{id: 'nomarker', title: 'No Marker'},
{id: 'leftarrow', title: 'Left Arrow'},
{id: 'rightarrow', title: 'Right Arrow'},
{id: 'textmarker', title: 'Text Marker'},
{id: 'forwardslash', title: 'Forward Slash'},
{id: 'reverseslash', title: 'Reverse Slash'},
{id: 'verticalslash', title: 'Vertical Slash'},
{id: 'box', title: 'Box'},
{id: 'star', title: 'Star'},
{id: 'xmark', title: 'X'},
{id: 'triangle', title: 'Triangle'},
{id: 'mcircle', title: 'Circle'},
{id: 'leftarrow_o', title: 'Open Left Arrow'},
{id: 'rightarrow_o', title: 'Open Right Arrow'},
{id: 'box_o', title: 'Open Box'},
{id: 'star_o', title: 'Open Star'},
{id: 'triangle_o', title: 'Open Triangle'},
{id: 'mcircle_o', title: 'Open Circle'}
]
};
// duplicate shapes to support unfilled (open) marker types with an _o suffix
$.each(['leftarrow','rightarrow','box','star','mcircle','triangle'],function(i,v) {
marker_types[v+'_o'] = marker_types[v];
$.each(['leftarrow', 'rightarrow', 'box', 'star', 'mcircle', 'triangle'], function (i, v) {
markerTypes[v + '_o'] = markerTypes[v];
});
// elem = a graphic element will have an attribute like marker-start
// attr - marker-start, marker-mid, or marker-end
// returns the marker element that is linked to the graphic element
function getLinked(elem, attr) {
function getLinked (elem, attr) {
var str = elem.getAttribute(attr);
if(!str) {return null;}
var m = str.match(/\(\#(.*)\)/);
if(!m || m.length !== 2) {
if (!str) { return null; }
var m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) {
return null;
}
return S.getElem(m[1]);
}
function setIcon(pos,id) {
if (id.substr(0,1) !== '\\') {id = '\\textmarker';}
var ci = '#'+id_prefix+pos+'_'+id.substr(1);
svgEditor.setIcon('#cur_' + pos +'_marker_list', $(ci).children());
function setIcon (pos, id) {
if (id.substr(0, 1) !== '\\') { id = '\\textmarker'; }
var ci = '#' + idPrefix + pos + '_' + id.substr(1);
svgEditor.setIcon('#cur_' + pos + '_marker_list', $(ci).children());
$(ci).addClass('current').siblings().removeClass('current');
}
// toggles context tool panel off/on
//sets the controls with the selected element's settings
function showPanel(on) {
// sets the controls with the selected element's settings
function showPanel (on) {
$('#marker_panel').toggle(on);
if(on) {
if (on) {
var el = selElems[0];
var val;
var ci;
$.each(mtypes, function(i, pos) {
var m = getLinked(el, "marker-" + pos);
$.each(mtypes, function (i, pos) {
var m = getLinked(el, 'marker-' + pos);
var txtbox = $('#' + pos + '_marker');
if (!m) {
val = '\\nomarker';
ci = val;
txtbox.hide(); // hide text box
} 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;
ci = val;
if (val === '\\textmarker') {
val = m.lastChild.textContent;
//txtbox.show(); // show text box
// txtbox.show(); // show text box
} else {
txtbox.hide(); // hide text box
}
}
txtbox.val(val);
setIcon(pos,ci);
txtbox.val(val);
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);
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');
//NOTE: Safari didn't like a negative value in viewBox
//so we use a standardized 0 0 100 100
//with 50 50 being mapped to the marker position
// NOTE: Safari didn't like a negative value in viewBox
// so we use a standardized 0 0 100 100
// with 50 50 being mapped to the marker position
var refX = 50;
var refY = 50;
var viewBox = "0 0 100 100";
var viewBox = '0 0 100 100';
var markerWidth = 5;
var markerHeight = 5;
var strokeWidth = 10;
var se_type;
if (val.substr(0,1) === '\\') {se_type = val.substr(1);}
else {se_type = 'textmarker';}
var seType;
if (val.substr(0, 1) === '\\') {
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
marker = addElem({
"element": "marker",
"attr": {
"id": id,
"markerUnits": "strokeWidth",
"orient": "auto",
"style": "pointer-events:none",
"se_type": se_type
}
'element': 'marker',
'attr': {
'id': id,
'markerUnits': 'strokeWidth',
'orient': 'auto',
'style': 'pointer-events:none',
'se_type': seType
}
});
if (se_type != 'textmarker') {
var mel = addElem(marker_types[se_type]);
if (seType !== 'textmarker') {
var mel = addElem(markerTypes[seType]);
var fillcolor = color;
if (se_type.substr(-2) === '_o') {fillcolor = 'none';}
if (seType.substr(-2) === '_o') { fillcolor = 'none'; }
mel.setAttribute('fill', fillcolor);
mel.setAttribute('stroke', color);
mel.setAttribute('stroke-width', strokeWidth);
marker.appendChild(mel);
} else {
var text = addElem(marker_types[se_type]);
var text = addElem(markerTypes[seType]);
// have to add text to get bounding box
text.textContent = val;
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 bb = tb;
bb.x = 0;
bb.y = 0;
bb.width += pad*2;
bb.height += pad*2;
bb.width += pad * 2;
bb.height += pad * 2;
// shift text according to its size
text.setAttribute('x', pad);
text.setAttribute('y', bb.height - pad - tb.height/4); // kludge?
text.setAttribute('fill',color);
refX = bb.width/2 + pad;
refY = bb.height/2 + pad;
viewBox = bb.x + " " + bb.y + " " + bb.width + " " + bb.height;
markerWidth = bb.width/10;
markerHeight = bb.height/10;
text.setAttribute('y', bb.height - pad - tb.height / 4); // kludge?
text.setAttribute('fill', color);
refX = bb.width / 2 + pad;
refY = bb.height / 2 + pad;
viewBox = bb.x + ' ' + bb.y + ' ' + bb.width + ' ' + bb.height;
markerWidth = bb.width / 10;
markerHeight = bb.height / 10;
var box = addElem({
"element": "rect",
"attr": {
"x": bb.x,
"y": bb.y,
"width": bb.width,
"height": bb.height,
"fill": txt_box_bg,
"stroke": txt_box_border,
"stroke-width": txt_box_stroke_width
'element': 'rect',
'attr': {
'x': bb.x,
'y': bb.y,
'width': bb.width,
'height': bb.height,
'fill': txtBoxBg,
'stroke': txtBoxBorder,
'stroke-width': txtBoxStrokeWidth
}
});
marker.setAttribute("orient",0);
marker.setAttribute('orient', 0);
marker.appendChild(box);
marker.appendChild(text);
}
}
marker.setAttribute("viewBox",viewBox);
marker.setAttribute("markerWidth", markerWidth);
marker.setAttribute("markerHeight", markerHeight);
marker.setAttribute("refX", refX);
marker.setAttribute("refY", refY);
marker.setAttribute('viewBox', viewBox);
marker.setAttribute('markerWidth', markerWidth);
marker.setAttribute('markerHeight', markerHeight);
marker.setAttribute('refX', refX);
marker.setAttribute('refY', refY);
S.findDefs().appendChild(marker);
return marker;
}
function convertline(elem) {
function convertline (elem) {
// this routine came from the connectors extension
// 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
@@ -271,27 +270,27 @@ svgEditor.addExtension("Markers", function(S) {
var y2 = Number(elem.getAttribute('y2'));
var id = elem.id;
var mid_pt = (' '+((x1+x2)/2)+','+((y1+y2)/2) + ' ');
var midPt = (' ' + ((x1 + x2) / 2) + ',' + ((y1 + y2) / 2) + ' ');
var pline = addElem({
"element": "polyline",
"attr": {
"points": (x1+','+y1+ mid_pt +x2+','+y2),
"stroke": elem.getAttribute('stroke'),
"stroke-width": elem.getAttribute('stroke-width'),
"fill": "none",
"opacity": elem.getAttribute('opacity') || 1
'element': 'polyline',
'attr': {
'points': (x1 + ',' + y1 + midPt + x2 + ',' + y2),
'stroke': elem.getAttribute('stroke'),
'stroke-width': elem.getAttribute('stroke-width'),
'fill': 'none',
'opacity': elem.getAttribute('opacity') || 1
}
});
$.each(mtypes, function(i, pos) { // get any existing marker definitions
var nam = 'marker-'+pos;
$.each(mtypes, function (i, pos) { // get any existing marker definitions
var nam = 'marker-' + pos;
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();
batchCmd.addSubCommand(new S.RemoveElementCommand(elem, elem.parentNode));
batchCmd.addSubCommand(new S.InsertElementCommand(pline));
$(elem).after(pline).remove();
svgCanvas.clearSelection();
pline.id = id;
@@ -300,85 +299,85 @@ svgEditor.addExtension("Markers", function(S) {
return pline;
}
function setMarker() {
var poslist={'start_marker':'start','mid_marker':'mid','end_marker':'end'};
function setMarker () {
var poslist = {'start_marker': 'start', 'mid_marker': 'mid', 'end_marker': 'end'};
var pos = poslist[this.id];
var marker_name = 'marker-'+pos;
var markerName = 'marker-' + pos;
var val = this.value;
var el = selElems[0];
var marker = getLinked(el, marker_name);
if (marker) {$(marker).remove();}
el.removeAttribute(marker_name);
if (val == '') {val = '\\nomarker';}
if (val == '\\nomarker') {
setIcon(pos,val);
S.call("changed", selElems);
var marker = getLinked(el, markerName);
if (marker) { $(marker).remove(); }
el.removeAttribute(markerName);
if (val === '') { val = '\\nomarker'; }
if (val === '\\nomarker') {
setIcon(pos, val);
S.call('changed', selElems);
return;
}
// Set marker on element
var id = marker_prefix + pos + '_' + el.id;
var id = markerPrefix + pos + '_' + el.id;
addMarker(id, val);
svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")");
if (el.tagName === 'line' && pos == 'mid') {el = convertline(el);}
S.call("changed", selElems);
setIcon(pos,val);
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
S.call('changed', selElems);
setIcon(pos, val);
}
// called when the main system modifies an object
// this routine changes the associated markers to be the same color
function colorChanged(elem) {
function colorChanged (elem) {
var color = elem.getAttribute('stroke');
$.each(mtypes, function(i, pos) {
var marker = getLinked(elem, 'marker-'+pos);
if (!marker) {return;}
if (!marker.attributes.se_type) {return;} // not created by this extension
$.each(mtypes, function (i, pos) {
var marker = getLinked(elem, 'marker-' + pos);
if (!marker) { return; }
if (!marker.attributes.se_type) { return; } // not created by this extension
var ch = marker.lastElementChild;
if (!ch) {return;}
if (!ch) { return; }
var curfill = ch.getAttribute('fill');
var curstroke = ch.getAttribute('stroke');
if (curfill && curfill != 'none') {ch.setAttribute('fill', color);}
if (curstroke && curstroke != 'none') {ch.setAttribute('stroke', color);}
if (curfill && curfill !== 'none') { ch.setAttribute('fill', color); }
if (curstroke && curstroke !== 'none') { ch.setAttribute('stroke', color); }
});
}
// called when the main system creates or modifies an object
// primary purpose is create new markers for cloned objects
function updateReferences(el) {
function updateReferences (el) {
$.each(mtypes, function (i, pos) {
var id = marker_prefix + pos + '_' + el.id;
var marker_name = 'marker-'+pos;
var marker = getLinked(el, marker_name);
if (!marker || !marker.attributes.se_type) {return;} // not created by this extension
var url = el.getAttribute(marker_name);
var id = markerPrefix + pos + '_' + el.id;
var markerName = 'marker-' + pos;
var marker = getLinked(el, markerName);
if (!marker || !marker.attributes.se_type) { return; } // not created by this extension
var url = el.getAttribute(markerName);
if (url) {
var len = el.id.length;
var linkid = url.substr(-len-1, len);
if (el.id != linkid) {
var val = $('#'+pos + '_marker').attr('value');
var linkid = url.substr(-len - 1, len);
if (el.id !== linkid) {
var val = $('#' + pos + '_marker').attr('value');
addMarker(id, val);
svgCanvas.changeSelectedAttribute(marker_name, "url(#" + id + ")");
if (el.tagName === 'line' && pos == 'mid') {el = convertline(el);}
S.call("changed", selElems);
svgCanvas.changeSelectedAttribute(markerName, 'url(#' + id + ')');
if (el.tagName === 'line' && pos === 'mid') { el = convertline(el); }
S.call('changed', selElems);
}
}
});
}
// simulate a change event a text box that stores the current element's marker type
function triggerTextEntry(pos, val) {
$('#'+pos+'_marker').val(val);
$('#'+pos+'_marker').change();
function triggerTextEntry (pos, val) {
$('#' + pos + '_marker').val(val);
$('#' + pos + '_marker').change();
// var txtbox = $('#'+pos+'_marker');
// if (val.substr(0,1)=='\\') {txtbox.hide();}
// else {txtbox.show();}
}
function showTextPrompt(pos) {
var def = $('#'+pos+'_marker').val();
if (def.substr(0,1) === '\\') {def = '';}
$.prompt('Enter text for ' + pos + ' marker', def , function(txt) {
if (txt) {triggerTextEntry(pos, txt);}
function showTextPrompt (pos) {
var def = $('#' + pos + '_marker').val();
if (def.substr(0, 1) === '\\') { def = ''; }
$.prompt('Enter text for ' + pos + ' marker', def, function (txt) {
if (txt) { triggerTextEntry(pos, txt); }
});
}
@@ -406,66 +405,64 @@ svgEditor.addExtension("Markers", function(S) {
}
*/
// callback function for a toolbar button click
function setArrowFromButton(obj) {
function setArrowFromButton (obj) {
var parts = this.id.split('_');
var pos = parts[1];
var val = parts[2];
if (parts[3]) { val += '_' + parts[3];}
if (val != 'textmarker') {
triggerTextEntry(pos, '\\'+val);
if (parts[3]) { val += '_' + parts[3]; }
if (val !== 'textmarker') {
triggerTextEntry(pos, '\\' + val);
} else {
showTextPrompt(pos);
}
}
function getTitle(lang, id) {
var i, list = lang_list[lang];
function getTitle (lang, id) {
var i, list = langList[lang];
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 id;
}
// build the toolbar button array from the marker definitions
// TODO: need to incorporate language specific titles
function buildButtonList() {
var buttons=[];
function buildButtonList () {
var buttons = [];
// var i = 0;
/*
/*
buttons.push({
id:id_prefix + 'markers_off',
title:'Turn off all markers',
type:'context',
id: idPrefix + 'markers_off',
title: 'Turn off all markers',
type: 'context',
events: { 'click': setMarkerSet },
panel: 'marker_panel'
});
buttons.push({
id:id_prefix + 'markers_dimension',
title:'Dimension',
type:'context',
id: idPrefix + 'markers_dimension',
title: 'Dimension',
type: 'context',
events: { 'click': setMarkerSet },
panel: 'marker_panel'
});
buttons.push({
id:id_prefix + 'markers_label',
title:'Label',
type:'context',
id: idPrefix + 'markers_label',
title: 'Label',
type: 'context',
events: { 'click': setMarkerSet },
panel: 'marker_panel'
});
*/
$.each(mtypes, function (k, pos) {
var listname = pos + "_marker_list";
var listname = pos + '_marker_list';
var def = true;
$.each(marker_types, function (id, v) {
var title = getTitle('en', id);
$.each(markerTypes, function (id, v) {
var title = getTitle('en', String(id));
buttons.push({
id: id_prefix + pos + '_' + id,
id: idPrefix + pos + '_' + id,
svgicon: id,
title: title,
type: 'context',
@@ -481,99 +478,98 @@ svgEditor.addExtension("Markers", function(S) {
}
return {
name: "Markers",
svgicons: svgEditor.curConfig.extPath + "markers-icons.xml",
name: 'Markers',
svgicons: svgEditor.curConfig.extPath + 'markers-icons.xml',
buttons: buildButtonList(),
context_tools: [
{
type: "input",
panel: "marker_panel",
title: "Start marker",
id: "start_marker",
label: "s",
size: 3,
events: { change: setMarker }
},{
type: "button-select",
panel: "marker_panel",
title: getTitle('en', 'start_marker_list'),
id: "start_marker_list",
colnum: 3,
events: { change: setArrowFromButton }
},{
type: "input",
panel: "marker_panel",
title: "Middle marker",
id: "mid_marker",
label: "m",
defval: "",
size: 3,
events: { change: setMarker }
},{
type: "button-select",
panel: "marker_panel",
title: getTitle('en', 'mid_marker_list'),
id: "mid_marker_list",
colnum: 3,
events: { change: setArrowFromButton }
},{
type: "input",
panel: "marker_panel",
title: "End marker",
id: "end_marker",
label: "e",
size: 3,
events: { change: setMarker }
},{
type: "button-select",
panel: "marker_panel",
title: getTitle('en', 'end_marker_list'),
id: "end_marker_list",
colnum: 3,
events: { change: setArrowFromButton }
} ],
callback: function() {
{
type: 'input',
panel: 'marker_panel',
title: 'Start marker',
id: 'start_marker',
label: 's',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle('en', 'start_marker_list'),
id: 'start_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'Middle marker',
id: 'mid_marker',
label: 'm',
defval: '',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle('en', 'mid_marker_list'),
id: 'mid_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'End marker',
id: 'end_marker',
label: 'e',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle('en', 'end_marker_list'),
id: 'end_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}
],
callback: function () {
$('#marker_panel').addClass('toolset').hide();
},
addLangData: function(lang) {
return { data: lang_list[lang] };
addLangData: function (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) {
// Use this to update the current selected elements
//console.log('selectChanged',opts);
selElems = opts.elems;
var i = selElems.length;
var markerElems = ['line', 'path', 'polyline', 'polygon'];
var i = selElems.length;
var marker_elems = ['line','path','polyline','polygon'];
while(i--) {
var elem = selElems[i];
if(elem && $.inArray(elem.tagName, marker_elems) !== -1) {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true);
while (i--) {
var elem = selElems[i];
if (elem && $.inArray(elem.tagName, markerElems) !== -1) {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
} else {
showPanel(false);
}
}
},
},
elementChanged: function(opts) {
//console.log('elementChanged',opts);
var elem = opts.elems[0];
if (elem && (
elem.getAttribute("marker-start") ||
elem.getAttribute("marker-mid") ||
elem.getAttribute("marker-end")
)) {
colorChanged(elem);
updateReferences(elem);
elementChanged: function (opts) {
// console.log('elementChanged',opts);
var elem = opts.elems[0];
if (elem && (
elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end')
)) {
colorChanged(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, $*/
/*jslint es5: true, todo: true, vars: true*/
/* eslint-disable no-var */
/* globals MathJax, svgEditor, svgCanvas, $ */
/*
* ext-mathjax.js
*
@@ -9,265 +9,256 @@
*
*/
svgEditor.addExtension("mathjax", function() {'use strict';
// Configuration of the MathJax extention.
svgEditor.addExtension('mathjax', function () {
'use strict';
// Configuration of the MathJax extention.
// This will be added to the head tag before MathJax is loaded.
var /*mathjaxConfiguration = '<script type="text/x-mathjax-config">\
MathJax.Hub.Config({\
extensions: ["tex2jax.js"],\
jax: ["input/TeX","output/SVG"],\
showProcessingMessages: true,\
showMathMenu: false,\
showMathMenuMSIE: false,\
errorSettings: {\
message: ["[Math Processing Error]"],\
style: {color: "#CC0000", "font-style":"italic"}\
},\
elements: [],\
tex2jax: {\
ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\
},\
TeX: {\
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\
},\
"SVG": {\
}\
});\
</script>',*/
// 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',
math,
locationX,
locationY,
mathjaxLoaded = false,
uiStrings = svgEditor.uiStrings;
// This will be added to the head tag before MathJax is loaded.
var /* mathjaxConfiguration = '<script type="text/x-mathjax-config">\
MathJax.Hub.Config({\
extensions: ["tex2jax.js"],\
jax: ["input/TeX","output/SVG"],\
showProcessingMessages: true,\
showMathMenu: false,\
showMathMenuMSIE: false,\
errorSettings: {\
message: ["[Math Processing Error]"],\
style: {color: "#CC0000", "font-style":"italic"}\
},\
elements: [],\
tex2jax: {\
ignoreClass: "tex2jax_ignore2", processClass: "tex2jax_process2",\
},\
TeX: {\
extensions: ["AMSmath.js","AMSsymbols.js","noErrors.js","noUndefined.js"]\
},\
"SVG": {\
}\
});\
</script>', */
// 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',
math,
locationX,
locationY,
mathjaxLoaded = false,
uiStrings = svgEditor.uiStrings;
// TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
$.extend(uiStrings, {
mathjax: {
embed_svg: 'Save as mathematics',
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. ',
mathml_save_warning: 'Advised. The math will be saved as a figure.',
title: 'Mathematics code editor'
}
});
// TODO: Implement language support. Move these uiStrings to the locale files and the code to the langReady callback.
$.extend(uiStrings, {
mathjax: {
embed_svg: 'Save as mathematics',
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. ',
mathml_save_warning: 'Advised. The math will be saved as a figure.',
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();
// displaystyle to force MathJax NOT to use the inline style. Because it is
// less fancy!
MathJax.Hub.queue.Push(['Text', math, '\\displaystyle{' + code + '}']);
/*
* The MathJax library doesn't want to bloat your webpage so it creates
* every symbol (glymph) you need only once. These are saved in a <svg> on
* the top of your html document, just under the body tag. Each glymph has
* 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;
/*
* The MathJax library doesn't want to bloat your webpage so it creates
* every symbol (glymph) you need only once. These are saved in a <svg> on
* the top of your html document, just under the body tag. Each glymph has
* 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.
if ($(this).attr('href')) {
id = $(this).attr('href').slice(1); // Works in Chrome.
} else {
id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
}
// TODO: find a less pragmatic and more elegant solution to this.
if ($(this).attr('href')) {
id = $(this).attr('href').slice(1); // Works in Chrome.
} else {
id = $(this).attr('xlink:href').slice(1); // Works in Firefox.
}
var glymph = $('#' + id).clone().removeAttr('id');
x = $(this).attr('x');
y = $(this).attr('y');
transform = $(this).attr('transform');
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');
x = $(this).attr('x');
y = $(this).attr('y');
transform = $(this).attr('transform');
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);
}
);
}
return {
name: 'MathJax',
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">' +
'<!-- Here is where MathJax creates the math -->' +
'<div id="mathjax_creator" class="tex2jax_process" style="display:none">' +
'$${}$$' +
'</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();
return {
name: "MathJax",
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) {
// Make the MathEditor draggable.
$('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'});
$('<div id="mathjax">\
<!-- Here is where MathJax creates the math -->\
<div id="mathjax_creator" class="tex2jax_process" style="display:none">\
$${}$$\
</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();
// Add functionality and picture to cancel button.
$('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
.on('click touched', function () {
$('#mathjax').hide();
});
// Make the MathEditor draggable.
$('#mathjax_container').draggable({cancel: 'button,fieldset', containment: 'window'});
// Add functionality and picture to the save button.
$('#tool_mathjax_save').prepend($.getSvgIcon('ok', true))
.on('click touched', function () {
saveMath();
$('#mathjax').hide();
});
// Add functionality and picture to cancel button.
$('#tool_mathjax_cancel').prepend($.getSvgIcon('cancel', true))
.on("click touched", function() {
$('#mathjax').hide();
});
// MathJax preprocessing has to ignore most of the page.
$('body').addClass('tex2jax_ignore');
// Add functionality and picture to the save button.
$('#tool_mathjax_save').prepend($.getSvgIcon('ok', true))
.on("click touched", function() {
saveMath();
$('#mathjax').hide();
});
// Now get (and run) the MathJax Library.
$.getScript(mathjaxSrcSecure)
.done(function (script, textStatus) {
// When MathJax is loaded get the div where the math will be rendered.
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.
$('body').addClass('tex2jax_ignore');
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;
// Now get (and run) the MathJax Library.
$.getScript(mathjaxSrcSecure)
.done(function(script, textStatus) {
$('#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');
// When MathJax is loaded get the div where the math will be rendered.
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");
}
}
}],
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');
}
};
// Add the MathJax configuration.
// $(mathjaxConfiguration).appendTo('head');
}
};
});

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, $ */
/*jslint es5: true, vars: true*/
/* eslint-disable no-var */
/* globals svgEditor, svgedit, $ */
/*
* ext-overview_window.js
*
@@ -10,11 +10,12 @@
*/
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
// https://code.google.com/p/chromium/issues/detail?id=565120.
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);
if (chromeVersion < 49) {
return;
@@ -22,130 +23,129 @@ svgEditor.addExtension("overview_window", function() { 'use strict';
}
// Define and insert the base html element.
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\" style=\"position:relative; left:12px; top:0px;\">\
<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\">\
<use x=\"0\" y=\"0\" xlink:href=\"#svgroot\"> </use>\
</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>\
</div>\
</div>\
</div>";
$("#sidepanels").append(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" style="position:relative; left:12px; top:0px;">' +
'<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">' +
'<use x="0" y="0" xlink:href="#svgroot"> </use>' +
'</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>' +
'</div>' +
'</div>' +
'</div>';
$('#sidepanels').append(propsWindowHtml);
// Define dynamic animation of the view box.
var updateViewBox = function(){
var portHeight=parseFloat($("#workarea").css("height"));
var portWidth=parseFloat($("#workarea").css("width"));
var portX=$("#workarea").scrollLeft();
var portY=$("#workarea").scrollTop();
var windowWidth=parseFloat($("#svgcanvas").css("width"));
var windowHeight=parseFloat($("#svgcanvas").css("height"));
var overviewWidth=$("#overviewMiniView").attr("width");
var overviewHeight=$("#overviewMiniView").attr("height");
var viewBoxX=portX/windowWidth*overviewWidth;
var viewBoxY=portY/windowHeight*overviewHeight;
var viewBoxWidth=portWidth/windowWidth*overviewWidth;
var viewBoxHeight=portHeight/windowHeight*overviewHeight;
$("#overview_window_view_box").css("min-width",viewBoxWidth+"px");
$("#overview_window_view_box").css("min-height",viewBoxHeight+"px");
$("#overview_window_view_box").css("top",viewBoxY+"px");
$("#overview_window_view_box").css("left",viewBoxX+"px");
var updateViewBox = function () {
var portHeight = parseFloat($('#workarea').css('height'));
var portWidth = parseFloat($('#workarea').css('width'));
var portX = $('#workarea').scrollLeft();
var portY = $('#workarea').scrollTop();
var windowWidth = parseFloat($('#svgcanvas').css('width'));
var windowHeight = parseFloat($('#svgcanvas').css('height'));
var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxX = portX / windowWidth * overviewWidth;
var viewBoxY = portY / windowHeight * overviewHeight;
var viewBoxWidth = portWidth / windowWidth * overviewWidth;
var viewBoxHeight = portHeight / windowHeight * overviewHeight;
$('#overview_window_view_box').css('min-width', viewBoxWidth + 'px');
$('#overview_window_view_box').css('min-height', viewBoxHeight + 'px');
$('#overview_window_view_box').css('top', viewBoxY + 'px');
$('#overview_window_view_box').css('left', viewBoxX + 'px');
};
$("#workarea").scroll(function(){
if(!(overviewWindowGlobals.viewBoxDragging)){
$('#workarea').scroll(function () {
if (!(overviewWindowGlobals.viewBoxDragging)) {
updateViewBox();
}
});
$("#workarea").resize(updateViewBox);
$('#workarea').resize(updateViewBox);
updateViewBox();
// Compensate for changes in zoom and canvas size.
var updateViewDimensions= function(){
var viewWidth=$("#svgroot").attr("width");
var viewHeight=$("#svgroot").attr("height");
var viewX=640;
var viewY=480;
if(svgedit.browser.isIE())
{
var updateViewDimensions = function () {
var viewWidth = $('#svgroot').attr('width');
var viewHeight = $('#svgroot').attr('height');
var viewX = 640;
var viewY = 480;
if (svgedit.browser.isIE()) {
// 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.
// Either way the one that is noncompliant may become more compliant later.
//TAG:HACK
//TAG:VERSION_DEPENDENT
//TAG:BROWSER_SNIFFING
viewX=0;
viewY=0;
// TAG:HACK
// TAG:VERSION_DEPENDENT
// TAG:BROWSER_SNIFFING
viewX = 0;
viewY = 0;
}
var svgWidth_old=$("#overviewMiniView").attr("width");
var svgHeight_new=viewHeight/viewWidth*svgWidth_old;
$("#overviewMiniView").attr("viewBox",viewX+" "+viewY+" "+viewWidth+" "+viewHeight);
$("#overviewMiniView").attr("height",svgHeight_new);
var svgWidthOld = $('#overviewMiniView').attr('width');
var svgHeightNew = viewHeight / viewWidth * svgWidthOld;
$('#overviewMiniView').attr('viewBox', viewX + ' ' + viewY + ' ' + viewWidth + ' ' + viewHeight);
$('#overviewMiniView').attr('height', svgHeightNew);
updateViewBox();
};
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);
$("#workarea").scrollTop(portY);
// 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);
$('#workarea').scrollTop(portY);
};
$( "#overview_window_view_box" ).draggable({ containment: "parent"
,drag: updateViewPortFromViewBox
,start:function(){overviewWindowGlobals.viewBoxDragging=true; }
,stop :function(){overviewWindowGlobals.viewBoxDragging=false;}
});
$("#overviewMiniView").click(function(evt){
$('#overview_window_view_box').draggable({
containment: 'parent',
drag: updateViewPortFromViewBox,
start: function () { overviewWindowGlobals.viewBoxDragging = true; },
stop: function () { overviewWindowGlobals.viewBoxDragging = false; }
});
$('#overviewMiniView').click(function (evt) {
// Firefox doesn't support evt.offsetX and evt.offsetY.
var mouseX=(evt.offsetX || evt.originalEvent.layerX);
var mouseY=(evt.offsetY || evt.originalEvent.layerY);
var overviewWidth =$("#overviewMiniView").attr("width" );
var overviewHeight=$("#overviewMiniView").attr("height");
var viewBoxWidth =parseFloat($("#overview_window_view_box").css("min-width" ));
var viewBoxHeight=parseFloat($("#overview_window_view_box").css("min-height"));
var viewBoxX=mouseX - 0.5 * viewBoxWidth;
var viewBoxY=mouseY- 0.5 * viewBoxHeight;
//deal with constraints
if(viewBoxX<0){
viewBoxX=0;
var mouseX = (evt.offsetX || evt.originalEvent.layerX);
var mouseY = (evt.offsetY || evt.originalEvent.layerY);
var overviewWidth = $('#overviewMiniView').attr('width');
var overviewHeight = $('#overviewMiniView').attr('height');
var viewBoxWidth = parseFloat($('#overview_window_view_box').css('min-width'));
var viewBoxHeight = parseFloat($('#overview_window_view_box').css('min-height'));
var viewBoxX = mouseX - 0.5 * viewBoxWidth;
var viewBoxY = mouseY - 0.5 * viewBoxHeight;
// deal with constraints
if (viewBoxX < 0) {
viewBoxX = 0;
}
if(viewBoxY<0){
viewBoxY=0;
if (viewBoxY < 0) {
viewBoxY = 0;
}
if(viewBoxX+viewBoxWidth>overviewWidth){
viewBoxX=overviewWidth-viewBoxWidth;
if (viewBoxX + viewBoxWidth > overviewWidth) {
viewBoxX = overviewWidth - viewBoxWidth;
}
if(viewBoxY+viewBoxHeight>overviewHeight){
viewBoxY=overviewHeight-viewBoxHeight;
if (viewBoxY + viewBoxHeight > overviewHeight) {
viewBoxY = overviewHeight - viewBoxHeight;
}
$("#overview_window_view_box").css("top",viewBoxY+"px");
$("#overview_window_view_box").css("left",viewBoxX+"px");
$('#overview_window_view_box').css('top', viewBoxY + 'px');
$('#overview_window_view_box').css('left', viewBoxX + 'px');
updateViewPortFromViewBox();
});
return {
name: "overview window",
name: 'overview window',
canvasUpdated: updateViewDimensions,
workareaResized: updateViewBox
};

View File

@@ -1,5 +1,4 @@
/*globals svgEditor, svgCanvas*/
/*jslint eqeq: true*/
/* globals svgEditor, svgCanvas */
/*
* ext-panning.js
*
@@ -8,12 +7,13 @@
* Copyright(c) 2013 Luis Aguirre
*
*/
/*
/*
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 {
name: 'Extension Panning',
svgicons: svgEditor.curConfig.extPath + 'ext-panning.xml',
@@ -22,19 +22,19 @@ svgEditor.addExtension('ext-panning', function() {'use strict';
type: 'mode',
title: 'Panning',
events: {
click: function() {
click: function () {
svgCanvas.setMode('ext-panning');
}
}
}],
mouseDown: function() {
if (svgCanvas.getMode() == 'ext-panning') {
mouseDown: function () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true);
return {started: true};
}
},
mouseUp: function() {
if (svgCanvas.getMode() == 'ext-panning') {
mouseUp: function () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false);
return {
keep: false,

View File

@@ -1,7 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg">
<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">
<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>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 732 B

After

Width:  |  Height:  |  Size: 724 B

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgedit, svgCanvas, canvg, $*/
/*jslint eqeq: true, browser:true*/
/* eslint-disable no-var */
/* globals svgEditor, svgedit, svgCanvas, canvg, $ */
/*
* ext-server_opensave.js
*
@@ -9,15 +9,15 @@
*
*/
svgEditor.addExtension("server_opensave", {
callback: function() {
svgEditor.addExtension('server_opensave', {
callback: function () {
'use strict';
function getFileNameFromTitle () {
var title = svgCanvas.getDocumentTitle();
// 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
}
function clientDownloadSupport (filename, suffix, uri) {
@@ -29,17 +29,17 @@ svgEditor.addExtension("server_opensave", {
return true;
}
}
var open_svg_action, import_svg_action, import_img_action,
open_svg_form, import_svg_form, import_img_form,
save_svg_action = svgEditor.curConfig.extPath + 'filesave.php',
save_img_action = svgEditor.curConfig.extPath + 'filesave.php',
var openSvgAction, importSvgAction, importImgAction,
openSvgForm, importSvgForm, importImgForm,
saveSvgAction = svgEditor.curConfig.extPath + 'filesave.php',
saveImgAction = svgEditor.curConfig.extPath + 'filesave.php',
// Create upload target (hidden iframe)
cancelled = false,
Utils = svgedit.utilities;
$('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
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
filename = getFileNameFromTitle();
@@ -49,7 +49,7 @@ svgEditor.addExtension("server_opensave", {
$('<form>').attr({
method: 'post',
action: save_svg_action,
action: saveSvgAction,
target: 'output_frame'
}).append('<input type="hidden" name="output_svg" value="' + xhtmlEscape(svg) + '">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
@@ -64,7 +64,7 @@ svgEditor.addExtension("server_opensave", {
}
$('<form>').attr({
method: 'post',
action: save_img_action,
action: saveImgAction,
target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="application/pdf">')
@@ -73,46 +73,46 @@ svgEditor.addExtension("server_opensave", {
.submit().remove();
},
// Todo: Integrate this extension with a new built-in exportWindowType, "download"
exportImage: function(win, data) {
exportImage: function (win, data) {
var c,
issues = data.issues,
mimeType = data.mimeType,
quality = data.quality;
if(!$('#export_canvas').length) {
if (!$('#export_canvas').length) {
$('<canvas>', {id: 'export_canvas'}).hide().appendTo('body');
}
c = $('#export_canvas')[0];
c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH;
Utils.buildCanvgCallback(function () {
canvg(c, data.svg, {renderCallback: function() {
canvg(c, data.svg, {renderCallback: function () {
var pre, filename, suffix,
datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType),
// uiStrings = svgEditor.uiStrings,
note = '';
// Check if there are issues
if (issues.length) {
pre = "\n \u2022 ";
note += ("\n\n" + pre + issues.join(pre));
}
if(note.length) {
pre = '\n \u2022 ';
note += ('\n\n' + pre + issues.join(pre));
}
if (note.length) {
alert(note);
}
filename = getFileNameFromTitle();
suffix = '.' + data.type.toLowerCase();
if (clientDownloadSupport(filename, suffix, datauri)) {
return;
}
$('<form>').attr({
method: 'post',
action: save_img_action,
action: saveImgAction,
target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="' + mimeType + '">')
@@ -125,81 +125,80 @@ svgEditor.addExtension("server_opensave", {
});
// Do nothing if client support is found
if (window.FileReader) {return;}
if (window.FileReader) { return; }
// Change these to appropriate script file
open_svg_action = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
import_svg_action = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
import_img_action = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
openSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=load_svg';
importSvgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_svg';
importImgAction = svgEditor.curConfig.extPath + 'fileopen.php?type=import_img';
// Set up function for PHP uploader to use
svgEditor.processFile = function(str64, type) {
svgEditor.processFile = function (str64, type) {
var xmlstr;
if (cancelled) {
cancelled = false;
return;
}
$('#dialog_box').hide();
if (type !== 'import_img') {
xmlstr = Utils.decode64(str64);
}
switch (type) {
case 'load_svg':
svgCanvas.clear();
svgCanvas.setSvgString(xmlstr);
svgEditor.updateCanvas();
break;
case 'import_svg':
svgCanvas.importSvgString(xmlstr);
svgEditor.updateCanvas();
break;
case 'import_img':
svgCanvas.setGoodImage(str64);
break;
case 'load_svg':
svgCanvas.clear();
svgCanvas.setSvgString(xmlstr);
svgEditor.updateCanvas();
break;
case 'import_svg':
svgCanvas.importSvgString(xmlstr);
svgEditor.updateCanvas();
break;
case 'import_img':
svgCanvas.setGoodImage(str64);
break;
}
};
// Create upload form
open_svg_form = $('<form>');
open_svg_form.attr({
openSvgForm = $('<form>');
openSvgForm.attr({
enctype: 'multipart/form-data',
method: 'post',
action: open_svg_action,
action: openSvgAction,
target: 'output_frame'
});
// Create import form
import_svg_form = open_svg_form.clone().attr('action', import_svg_action);
importSvgForm = openSvgForm.clone().attr('action', importSvgAction);
// Create image form
import_img_form = open_svg_form.clone().attr('action', import_img_action);
// It appears necessary to rebuild this input every time a file is
importImgForm = openSvgForm.clone().attr('action', importImgAction);
// 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.
function rebuildInput(form) {
function rebuildInput (form) {
form.empty();
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()
form.submit();
rebuildInput(form);
$.process_cancel("Uploading...", function() {
$.process_cancel('Uploading...', function () {
cancelled = true;
$('#dialog_box').hide();
});
}
if(form[0] == open_svg_form[0]) {
inp.change(function() {
if (form[0] === openSvgForm[0]) {
inp.change(function () {
// This takes care of the "are you sure" dialog box
svgEditor.openPrep(function(ok) {
if(!ok) {
svgEditor.openPrep(function (ok) {
if (!ok) {
rebuildInput(form);
return;
}
@@ -207,22 +206,21 @@ svgEditor.addExtension("server_opensave", {
});
});
} else {
inp.change(function() {
inp.change(function () {
// This submits the form, which returns the file data using svgEditor.processFile()
submit();
});
}
}
// Create the input elements
rebuildInput(open_svg_form);
rebuildInput(import_svg_form);
rebuildInput(import_img_form);
rebuildInput(openSvgForm);
rebuildInput(importSvgForm);
rebuildInput(importImgForm);
// Add forms to buttons
$("#tool_open").show().prepend(open_svg_form);
$("#tool_import").show().prepend(import_svg_form);
$("#tool_image").prepend(import_img_form);
$('#tool_open').show().prepend(openSvgForm);
$('#tool_import').show().prepend(importSvgForm);
$('#tool_image').prepend(importImgForm);
}
});

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*globals svgEditor, svgCanvas, $, widget*/
/*jslint vars: true, eqeq: true, regexp: true, continue: true*/
/* eslint-disable no-var */
/* globals svgEditor, svgCanvas, $, widget */
/*
* ext-storage.js
*
@@ -26,7 +26,7 @@ TODOS
2. We might provide control of storage settings through the UI besides the
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,
// 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;
@@ -53,8 +53,7 @@ svgEditor.addExtension('storage', function() {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
});
}
else {
} else {
loc.href += (loc.href.indexOf('?') > -1 ? '&' : '?') + val;
}
}
@@ -63,22 +62,21 @@ svgEditor.addExtension('storage', function() {
var name = 'svgedit-' + svgEditor.curConfig.canvasName;
if (!val) {
storage.removeItem(name);
}
else {
} else {
storage.setItem(name, val);
}
}
}
function expireCookie (cookie) {
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
}
function removeStoragePrefCookie () {
expireCookie('store');
}
function emptyStorage() {
function emptyStorage () {
setSVGContentStorage('');
var name;
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
@@ -103,14 +101,14 @@ svgEditor.addExtension('storage', function() {
* 3. Use localStorage (where available) or cookies to set preferences.
*/
function setupBeforeUnloadListener () {
window.addEventListener('beforeunload', function(e) {
window.addEventListener('beforeunload', function (e) {
// Don't save anything unless the user opted in to storage
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
return;
}
var key;
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
@@ -121,18 +119,16 @@ svgEditor.addExtension('storage', function() {
for (key in curPrefs) {
if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
var val = curPrefs[key],
store = (val != undefined);
store = (val !== undefined);
key = 'svg-edit-' + key;
if (!store) {
continue;
}
if (storage) {
storage.setItem(key, val);
}
else if (window.widget) {
} else if (window.widget) {
widget.setPreferenceForKey(val, key);
}
else {
} else {
val = encodeURIComponent(val);
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.
)) {
var options = [];
if (storage) {
options.unshift(
@@ -203,8 +198,7 @@ svgEditor.addExtension('storage', function() {
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefsOnly},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefsOrContent}
);
}
else {
} else {
options.unshift(
{value: 'prefsOnly', text: uiStrings.confirmSetStorage.storagePrefs},
{value: 'noPrefsOrContent', text: uiStrings.confirmSetStorage.storageNoPrefs}
@@ -242,8 +236,7 @@ svgEditor.addExtension('storage', function() {
replaceStoragePrompt();
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();
if (pref && // If the user explicitly expresses wish for no storage
emptyStorageOnDecline
@@ -259,21 +252,21 @@ svgEditor.addExtension('storage', function() {
// Reset width/height of dialog (e.g., for use by Export)
$('#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_container')[0].style.height = oldContainerHeight;
// It should be enough to (conditionally) add to storage on
// beforeunload, but if we wished to update immediately,
// we might wish to try setting:
// svgEditor.setConfig({noStorageOnLoad: true});
// and then call:
// svgEditor.loadContentAndPrefs();
// We don't check for noStorageOnLoad here because
// the prompt gives the user the option to store data
setupBeforeUnloadListener();
svgEditor.storagePromptClosed = true;
},
null,
@@ -284,8 +277,7 @@ svgEditor.addExtension('storage', function() {
tooltip: uiStrings.confirmSetStorage.rememberTooltip
}
);
}
else if (!noStorageOnLoad || forceStorage) {
} else if (!noStorageOnLoad || forceStorage) {
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
Todos:
1. See WebAppFind Readme for SVG-related todos
*/
(function () {'use strict';
(function () {
'use strict';
var pathID,
saveMessage = 'webapp-save',
readMessage = 'webapp-read',
excludedMessages = [readMessage, saveMessage];
saveMessage = 'webapp-save',
readMessage = 'webapp-read',
excludedMessages = [readMessage, saveMessage];
window.addEventListener('message', function(e) {
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
) {
return;
}
var svgString,
messageType = e.data[0];
switch (messageType) {
case 'webapp-view':
// Populate the contents
pathID = e.data[1];
svgString = e.data[2];
svgEditor.loadFromString(svgString);
/*if ($('#tool_save_file')) {
$('#tool_save_file').disabled = false;
}*/
break;
case 'webapp-save-end':
alert('save complete for pathID ' + e.data[1] + '!');
break;
default:
throw 'Unexpected mode';
}
window.addEventListener('message', function (e) {
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
) {
return;
}
var svgString,
messageType = e.data[0];
switch (messageType) {
case 'webapp-view':
// Populate the contents
pathID = e.data[1];
svgString = e.data[2];
svgEditor.loadFromString(svgString);
/* if ($('#tool_save_file')) {
$('#tool_save_file').disabled = false;
} */
break;
case 'webapp-save-end':
alert('save complete for pathID ' + e.data[1] + '!');
break;
default:
throw new Error('Unexpected mode');
}
}, 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)
svgEditor.addExtension('WebAppFind', function() {
return {
name: 'WebAppFind',
svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg',
buttons: [{
id: 'webappfind_save', //
type: 'app_menu',
title: 'Save Image back to Disk',
position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
events: {
click: function () {
if (!pathID) { // Not ready yet as haven't received first payload
return;
}
window.postMessage([saveMessage, pathID, svgEditor.canvas.getSvgString()], window.location.origin);
}
}
}]
};
svgEditor.addExtension('WebAppFind', function () {
return {
name: 'WebAppFind',
svgicons: svgEditor.curConfig.extPath + 'webappfind-icon.svg',
buttons: [{
id: 'webappfind_save', //
type: 'app_menu',
title: 'Save Image back to Disk',
position: 4, // Before 0-based index position 4 (after the regular "Save Image (S)")
events: {
click: function () {
if (!pathID) { // Not ready yet as haven't received first payload
return;
}
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),
* but an API common for cross-domain and same domain use can be found
* in embedapi.js with a demo at embedapi.html
*/
/*globals svgEditor, svgCanvas*/
svgEditor.addExtension('xdomain-messaging', function() {'use strict';
svgEditor.addExtension('xdomain-messaging', function () {
'use strict';
try {
window.addEventListener('message', function(e) {
window.addEventListener('message', function (e) {
// We accept and post strings for the sake of IE9 support
if (typeof e.data !== 'string' || e.data.charAt() === '|') {
return;
@@ -35,8 +37,7 @@ svgEditor.addExtension('xdomain-messaging', function() {'use strict';
}
e.source.postMessage(JSON.stringify(message), '*');
}, false);
}
catch (err) {
} catch (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
// return it to the editor
if (!isset($_REQUEST['type'])) {
echo "No type given";
echo 'No type given';
exit;
}
$type = $_REQUEST['type'];
if (!in_array($type, array('load_svg', 'import_svg', 'import_img'))) {
echo "Not a recognized type";
echo 'Not a recognized type';
exit;
}
require('allowedMimeTypes.php');
$file = $_FILES['svg_file']['tmp_name'];
$output = file_get_contents($file);
$prefix = '';
// Make Data URL prefix for import image
if ($type == 'import_img') {
$info = getimagesize($file);
if (!in_array($info['mime'], $allowedMimeTypesBySuffix)) {
echo "Disallowed MIME for supplied file";
echo 'Disallowed MIME for supplied file';
exit;
}
$prefix = 'data:' . $info['mime'] . ';base64,';
@@ -45,7 +45,7 @@
<meta charset="utf-8" />
<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)
echo $prefix . base64_encode($output);

View File

@@ -44,17 +44,17 @@ if ($suffix == '.svg') {
$contents = base64_decode(substr($contents, $pos));
}
header("Cache-Control: public");
header("Content-Description: File Transfer");
header('Cache-Control: public');
header('Content-Description: File Transfer');
// See http://tools.ietf.org/html/rfc6266#section-4.1
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)
$file
));
header("Content-Type: " . $mime);
header("Content-Transfer-Encoding: binary");
header('Content-Type: ' . $mime);
header('Content-Transfer-Encoding: binary');
echo $contents;
?>
?>

View File

@@ -2,6 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>-</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js"></script>
</head>
<body>
@@ -11,59 +12,6 @@
<br>
<a href="../../images/logo.png">logo.png</a>
<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>
<script src="index.js"></script>
</body>
</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*/
/*jslint vars: true, eqeq: true, continue: true, forin: true*/
/* eslint-disable no-var */
/* globals svgedit */
/**
* Package: svedit.history
*
@@ -13,7 +13,8 @@
// 2) svgtransformlist.js
// 3) svgutils.js
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.history) {
svgedit.history = {};
@@ -27,7 +28,7 @@ svgedit.history.HistoryEventTypes = {
AFTER_UNAPPLY: 'after_unapply'
};
var removedElements = {};
// var removedElements = {};
/**
* 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 {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.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.oldParent = oldParent;
this.newNextSibling = elem.nextSibling;
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.getText = function() {
svgedit.history.MoveElementCommand.prototype.getText = function () {
return this.text;
};
@@ -80,7 +81,7 @@ svgedit.history.MoveElementCommand.prototype.getText = function() {
* Re-positions the element
* @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.
if (handler) {
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
* @param {handleHistoryEvent: function}
*/
svgedit.history.MoveElementCommand.prototype.unapply = function(handler) {
svgedit.history.MoveElementCommand.prototype.unapply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
}
@@ -111,11 +112,10 @@ svgedit.history.MoveElementCommand.prototype.unapply = function(handler) {
// Function: svgedit.history.MoveElementCommand.elements
// Returns array with element associated with this command
svgedit.history.MoveElementCommand.prototype.elements = function() {
svgedit.history.MoveElementCommand.prototype.elements = function () {
return [this.elem];
};
// Class: svgedit.history.InsertElementCommand
// implements svgedit.history.HistoryCommand
// History command for an element that was added to the DOM
@@ -123,23 +123,23 @@ svgedit.history.MoveElementCommand.prototype.elements = function() {
// Parameters:
// elem - The newly added DOM element
// 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.text = text || ("Create " + elem.tagName);
this.text = text || ('Create ' + elem.tagName);
this.parent = elem.parentNode;
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;
// Function: svgedit.history.InsertElementCommand.getText
svgedit.history.InsertElementCommand.prototype.getText = function() {
svgedit.history.InsertElementCommand.prototype.getText = function () {
return this.text;
};
// Function: svgedit.history.InsertElementCommand.apply
// Re-Inserts the new element
svgedit.history.InsertElementCommand.prototype.apply = function(handler) {
svgedit.history.InsertElementCommand.prototype.apply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
}
@@ -153,7 +153,7 @@ svgedit.history.InsertElementCommand.prototype.apply = function(handler) {
// Function: svgedit.history.InsertElementCommand.unapply
// Removes the element
svgedit.history.InsertElementCommand.prototype.unapply = function(handler) {
svgedit.history.InsertElementCommand.prototype.unapply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
}
@@ -168,11 +168,10 @@ svgedit.history.InsertElementCommand.prototype.unapply = function(handler) {
// Function: svgedit.history.InsertElementCommand.elements
// Returns array with element associated with this command
svgedit.history.InsertElementCommand.prototype.elements = function() {
svgedit.history.InsertElementCommand.prototype.elements = function () {
return [this.elem];
};
// Class: svgedit.history.RemoveElementCommand
// implements svgedit.history.HistoryCommand
// 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
// oldParent - The DOM element's parent
// 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.text = text || ("Delete " + elem.tagName);
this.text = text || ('Delete ' + elem.tagName);
this.nextSibling = oldNextSibling;
this.parent = oldParent;
// special hack for webkit: remove this element's entry in the svgTransformLists map
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;
// Function: svgedit.history.RemoveElementCommand.getText
svgedit.history.RemoveElementCommand.prototype.getText = function() {
svgedit.history.RemoveElementCommand.prototype.getText = function () {
return this.text;
};
// Function: RemoveElementCommand.apply
// Re-removes the new element
svgedit.history.RemoveElementCommand.prototype.apply = function(handler) {
svgedit.history.RemoveElementCommand.prototype.apply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
}
@@ -217,7 +216,7 @@ svgedit.history.RemoveElementCommand.prototype.apply = function(handler) {
// Function: RemoveElementCommand.unapply
// Re-adds the new element
svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
svgedit.history.RemoveElementCommand.prototype.unapply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
}
@@ -225,12 +224,11 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
svgedit.transformlist.removeElementFromListMap(this.elem);
if (this.nextSibling == null) {
if (window.console) {
console.log('Error: reference element was lost');
}
console.log('Error: reference element was lost');
}
}
this.parent.insertBefore(this.elem, this.nextSibling);
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
}
@@ -238,11 +236,10 @@ svgedit.history.RemoveElementCommand.prototype.unapply = function(handler) {
// Function: RemoveElementCommand.elements
// Returns array with element associated with this command
svgedit.history.RemoveElementCommand.prototype.elements = function() {
svgedit.history.RemoveElementCommand.prototype.elements = function () {
return [this.elem];
};
// Class: svgedit.history.ChangeElementCommand
// implements svgedit.history.HistoryCommand
// 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
// 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
svgedit.history.ChangeElementCommand = function(elem, attrs, text) {
svgedit.history.ChangeElementCommand = function (elem, attrs, text) {
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.oldValues = attrs;
var attr;
for (attr in attrs) {
if (attr == "#text") {this.newValues[attr] = elem.textContent;}
else if (attr == "#href") {this.newValues[attr] = svgedit.utilities.getHref(elem);}
else {this.newValues[attr] = elem.getAttribute(attr);}
if (attr === '#text') {
this.newValues[attr] = elem.textContent;
} 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;
// Function: svgedit.history.ChangeElementCommand.getText
svgedit.history.ChangeElementCommand.prototype.getText = function() {
svgedit.history.ChangeElementCommand.prototype.getText = function () {
return this.text;
};
// Function: svgedit.history.ChangeElementCommand.apply
// Performs the stored change action
svgedit.history.ChangeElementCommand.prototype.apply = function(handler) {
svgedit.history.ChangeElementCommand.prototype.apply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
}
var bChangedTransform = false;
var attr;
for (attr in this.newValues ) {
for (attr in this.newValues) {
if (this.newValues[attr]) {
if (attr == "#text") {this.elem.textContent = this.newValues[attr];}
else if (attr == "#href") {svgedit.utilities.setHref(this.elem, this.newValues[attr]);}
else {this.elem.setAttribute(attr, this.newValues[attr]);}
}
else {
if (attr == "#text") {
this.elem.textContent = "";
if (attr === '#text') {
this.elem.textContent = this.newValues[attr];
} else if (attr === '#href') {
svgedit.utilities.setHref(this.elem, this.newValues[attr]);
} else {
this.elem.setAttribute(attr, this.newValues[attr]);
}
else {
this.elem.setAttribute(attr, "");
} else {
if (attr === '#text') {
this.elem.textContent = '';
} else {
this.elem.setAttribute(attr, '');
this.elem.removeAttribute(attr);
}
}
if (attr == "transform") { bChangedTransform = true; }
if (attr === 'transform') { bChangedTransform = true; }
}
// relocate rotational transform, if necessary
if (!bChangedTransform) {
var angle = svgedit.utilities.getRotationAngle(this.elem);
if (angle) {
// TODO: These instances of elem either need to be declared as global
// (which would not be good for conflicts) or declare/use this.elem
var bbox = elem.getBBox();
var cx = bbox.x + bbox.width/2,
cy = bbox.y + bbox.height/2;
var rotate = ["rotate(", angle, " ", cx, ",", cy, ")"].join('');
if (rotate != elem.getAttribute("transform")) {
elem.setAttribute("transform", rotate);
var bbox = this.elem.getBBox();
var cx = bbox.x + bbox.width / 2,
cy = bbox.y + bbox.height / 2;
var rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join('');
if (rotate !== this.elem.getAttribute('transform')) {
this.elem.setAttribute('transform', rotate);
}
}
}
@@ -325,39 +326,41 @@ svgedit.history.ChangeElementCommand.prototype.apply = function(handler) {
// Function: svgedit.history.ChangeElementCommand.unapply
// Reverses the stored change action
svgedit.history.ChangeElementCommand.prototype.unapply = function(handler) {
svgedit.history.ChangeElementCommand.prototype.unapply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
}
var bChangedTransform = false;
var attr;
for (attr in this.oldValues ) {
for (attr in this.oldValues) {
if (this.oldValues[attr]) {
if (attr == "#text") {this.elem.textContent = this.oldValues[attr];}
else if (attr == "#href") {svgedit.utilities.setHref(this.elem, this.oldValues[attr]);}
else {
if (attr === '#text') {
this.elem.textContent = this.oldValues[attr];
} else if (attr === '#href') {
svgedit.utilities.setHref(this.elem, this.oldValues[attr]);
} else {
this.elem.setAttribute(attr, this.oldValues[attr]);
}
}
else {
if (attr == "#text") {
this.elem.textContent = "";
} else {
if (attr === '#text') {
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
if (!bChangedTransform) {
var angle = svgedit.utilities.getRotationAngle(this.elem);
if (angle) {
var bbox = elem.getBBox();
var cx = bbox.x + bbox.width/2,
cy = bbox.y + bbox.height/2;
var rotate = ["rotate(", angle, " ", cx, ",", cy, ")"].join('');
if (rotate != elem.getAttribute("transform")) {
elem.setAttribute("transform", rotate);
var bbox = this.elem.getBBox();
var cx = bbox.x + bbox.width / 2,
cy = bbox.y + bbox.height / 2;
var rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join('');
if (rotate !== this.elem.getAttribute('transform')) {
this.elem.setAttribute('transform', rotate);
}
}
}
@@ -374,37 +377,35 @@ svgedit.history.ChangeElementCommand.prototype.unapply = function(handler) {
// Function: ChangeElementCommand.elements
// Returns array with element associated with this command
svgedit.history.ChangeElementCommand.prototype.elements = function() {
svgedit.history.ChangeElementCommand.prototype.elements = function () {
return [this.elem];
};
// 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
// and they both affect the same element, then collapse the two commands into one
// Class: svgedit.history.BatchCommand
// implements svgedit.history.HistoryCommand
// History command that can contain/execute multiple other commands
//
// Parameters:
// text - An optional string visible to user related to this change
svgedit.history.BatchCommand = function(text) {
this.text = text || "Batch Command";
svgedit.history.BatchCommand = function (text) {
this.text = text || 'Batch Command';
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;
// Function: svgedit.history.BatchCommand.getText
svgedit.history.BatchCommand.prototype.getText = function() {
svgedit.history.BatchCommand.prototype.getText = function () {
return this.text;
};
// Function: svgedit.history.BatchCommand.apply
// Runs "apply" on all subcommands
svgedit.history.BatchCommand.prototype.apply = function(handler) {
svgedit.history.BatchCommand.prototype.apply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
}
@@ -422,13 +423,13 @@ svgedit.history.BatchCommand.prototype.apply = function(handler) {
// Function: svgedit.history.BatchCommand.unapply
// Runs "unapply" on all subcommands
svgedit.history.BatchCommand.prototype.unapply = function(handler) {
svgedit.history.BatchCommand.prototype.unapply = function (handler) {
if (handler) {
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
}
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);
}
@@ -439,14 +440,14 @@ svgedit.history.BatchCommand.prototype.unapply = function(handler) {
// Function: svgedit.history.BatchCommand.elements
// 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 cmd = this.stack.length;
while (cmd--) {
var thisElems = this.stack[cmd].elements();
var elem = thisElems.length;
while (elem--) {
if (elems.indexOf(thisElems[elem]) == -1) {elems.push(thisElems[elem]);}
if (elems.indexOf(thisElems[elem]) === -1) { elems.push(thisElems[elem]); }
}
}
return elems;
@@ -457,22 +458,21 @@ svgedit.history.BatchCommand.prototype.elements = function() {
//
// Parameters:
// 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);
};
// Function: svgedit.history.BatchCommand.isEmpty
// 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;
};
// Class: svgedit.history.UndoManager
// Parameters:
// historyEventHandler - an object that conforms to the HistoryEventHandler interface
// (see above)
svgedit.history.UndoManager = function(historyEventHandler) {
svgedit.history.UndoManager = function (historyEventHandler) {
this.handler_ = historyEventHandler || null;
this.undoStackPointer = 0;
this.undoStack = [];
@@ -485,7 +485,7 @@ svgedit.history.UndoManager = function(historyEventHandler) {
// Function: svgedit.history.UndoManager.resetUndoStack
// 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.undoStackPointer = 0;
};
@@ -493,34 +493,34 @@ svgedit.history.UndoManager.prototype.resetUndoStack = function() {
// Function: svgedit.history.UndoManager.getUndoStackSize
// Returns:
// 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;
};
// Function: svgedit.history.UndoManager.getRedoStackSize
// Returns:
// 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;
};
// Function: svgedit.history.UndoManager.getNextUndoCommandText
// Returns:
// String associated with the next undo command
svgedit.history.UndoManager.prototype.getNextUndoCommandText = function() {
return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer-1].getText() : "";
svgedit.history.UndoManager.prototype.getNextUndoCommandText = function () {
return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer - 1].getText() : '';
};
// Function: svgedit.history.UndoManager.getNextRedoCommandText
// Returns:
// String associated with the next redo command
svgedit.history.UndoManager.prototype.getNextRedoCommandText = function() {
return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : "";
svgedit.history.UndoManager.prototype.getNextRedoCommandText = function () {
return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : '';
};
// Function: svgedit.history.UndoManager.undo
// Performs an undo step
svgedit.history.UndoManager.prototype.undo = function() {
svgedit.history.UndoManager.prototype.undo = function () {
if (this.undoStackPointer > 0) {
var cmd = this.undoStack[--this.undoStackPointer];
cmd.unapply(this.handler_);
@@ -529,7 +529,7 @@ svgedit.history.UndoManager.prototype.undo = function() {
// Function: svgedit.history.UndoManager.redo
// 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) {
var cmd = this.undoStack[this.undoStackPointer++];
cmd.apply(this.handler_);
@@ -541,7 +541,7 @@ svgedit.history.UndoManager.prototype.redo = function() {
//
// Parameters:
// 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
// (right now each keystroke is saved as a separate command that includes the
// entire text contents of the text element)
@@ -556,24 +556,23 @@ svgedit.history.UndoManager.prototype.addCommandToHistory = function(cmd) {
this.undoStackPointer = this.undoStack.length;
};
// Function: svgedit.history.UndoManager.beginUndoableChange
// This function tells the canvas to remember the old values of the
// attrName attribute for each element sent in. The elements and values
// are stored on a stack, so the next call to finishUndoableChange() will
// This function tells the canvas to remember the old values of the
// attrName attribute for each element sent in. The elements and values
// are stored on a stack, so the next call to finishUndoableChange() will
// pop the elements and old values off the stack, gets the current values
// from the DOM and uses all of these to construct the undo-able command.
//
// Parameters:
// attrName - The name of the attribute 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 i = elems.length;
var oldValues = new Array(i), elements = new Array(i);
while (i--) {
var elem = elems[i];
if (elem == null) {continue;}
if (elem == null) { continue; }
elements[i] = elem;
oldValues[i] = elem.getAttribute(attrName);
}
@@ -591,23 +590,22 @@ svgedit.history.UndoManager.prototype.beginUndoableChange = function(attrName, e
//
// Returns:
// Batch command object with resulting changes
svgedit.history.UndoManager.prototype.finishUndoableChange = function() {
svgedit.history.UndoManager.prototype.finishUndoableChange = function () {
var p = this.undoChangeStackPointer--;
var changeset = this.undoableChangeStack[p];
var i = changeset.elements.length;
var attrName = changeset.attrName;
var batchCmd = new svgedit.history.BatchCommand("Change " + attrName);
var batchCmd = new svgedit.history.BatchCommand('Change ' + attrName);
while (i--) {
var elem = changeset.elements[i];
if (elem == null) {continue;}
if (elem == null) { continue; }
var changes = {};
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));
}
}
this.undoableChangeStack[p] = null;
return batchCmd;
};
}());

View File

@@ -1,5 +1,5 @@
/*globals svgedit*/
/*jslint vars: true, eqeq: true */
/* eslint-disable no-var */
/* globals svgedit */
/**
* Package: svgedit.history
*
@@ -11,8 +11,8 @@
// Dependencies:
// 1) history.js
(function() {
'use strict';
(function () {
'use strict';
if (!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.
* See singleton: HistoryRecordingService.NO_HISTORY
*/
var HistoryRecordingService = history.HistoryRecordingService = function(undoManager) {
var HistoryRecordingService = history.HistoryRecordingService = function (undoManager) {
this.undoManager_ = undoManager;
this.currentBatchCommand_ = null;
this.batchCommandStack_ = [];
@@ -76,8 +76,8 @@ HistoryRecordingService.NO_HISTORY = new HistoryRecordingService();
* @param {string} text - Optional string describing the batch command.
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.startBatchCommand = function(text) {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.startBatchCommand = function (text) {
if (!this.undoManager_) { return this; }
this.currentBatchCommand_ = new history.BatchCommand(text);
this.batchCommandStack_.push(this.currentBatchCommand_);
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.
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.endBatchCommand = function() {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.endBatchCommand = function () {
if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) {
var batchCommand = this.currentBatchCommand_;
this.batchCommandStack_.pop();
var length = this.batchCommandStack_.length;
this.currentBatchCommand_ = length ? this.batchCommandStack_[length-1] : null;
this.currentBatchCommand_ = length ? this.batchCommandStack_[length - 1] : null;
this.addCommand_(batchCommand);
}
return this;
@@ -107,8 +107,8 @@ HistoryRecordingService.prototype.endBatchCommand = function() {
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.moveElement = function(elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.moveElement = function (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text));
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
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.insertElement = function(elem, text) {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.insertElement = function (elem, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.InsertElementCommand(elem, text));
return this;
};
/**
* Add a RemoveElementCommand to the history or current batch command
* @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
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.removeElement = function(elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.removeElement = function (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text));
return this;
};
/**
* Add a ChangeElementCommand to the history or current batch command
* @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
* @returns {svgedit.history.HistoryRecordingService}
*/
HistoryRecordingService.prototype.changeElement = function(elem, attrs, text) {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.changeElement = function (elem, attrs, text) {
if (!this.undoManager_) { return this; }
this.addCommand_(new history.ChangeElementCommand(elem, attrs, text));
return this;
};
@@ -160,14 +158,12 @@ HistoryRecordingService.prototype.changeElement = function(elem, attrs, text) {
* @returns {svgedit.history.HistoryRecordingService}
* @private
*/
HistoryRecordingService.prototype.addCommand_ = function(cmd) {
if (!this.undoManager_) {return this;}
HistoryRecordingService.prototype.addCommand_ = function (cmd) {
if (!this.undoManager_) { return this; }
if (this.currentBatchCommand_) {
this.currentBatchCommand_.addSubCommand(cmd);
} else {
this.undoManager_.addCommandToHistory(cmd);
}
};
}());

115
editor/jquery-svg.js vendored
View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/*globals svgedit*/
/*jslint vars: true, eqeq: true */
/* eslint-disable no-var, eqeqeq */
/* globals svgedit */
/**
* Package: svedit.math
*
@@ -11,7 +11,7 @@
// Dependencies:
// None.
/**
* @typedef AngleCoord45
* @type {object}
@@ -20,7 +20,8 @@
* @property {number} a - The angle at which to snap
*/
(function() {'use strict';
(function () {
'use strict';
if (!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
*/
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)
* @param {SVGMatrix} m - The matrix object to check
* @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);
};
/**
* This function tries to return a SVGMatrix that is the multiplication m1*m2.
* 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
*/
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) {
var m1 = args[i-1];
var m1 = args[i - 1];
m = m1.multiply(m);
}
if (Math.abs(m.a) < NEAR_ZERO) {m.a = 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.d) < NEAR_ZERO) {m.d = 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.a) < NEAR_ZERO) { m.a = 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.d) < NEAR_ZERO) { m.d = 0; }
if (Math.abs(m.e) < NEAR_ZERO) { m.e = 0; }
if (Math.abs(m.f) < NEAR_ZERO) { m.f = 0; }
return m;
};
@@ -85,11 +84,11 @@ svgedit.math.matrixMultiply = function (matr) {
* @returns {boolean} Whether or not a matrix transform was found
*/
svgedit.math.hasMatrixTransform = function (tlist) {
if (!tlist) {return false;}
if (!tlist) { return false; }
var num = tlist.numberOfItems;
while (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;
};
@@ -164,15 +163,14 @@ svgedit.math.transformListToTransform = function (tlist, min, max) {
var i;
for (i = min; i <= max; ++i) {
// if our indices are out of range, just use a harmless identity matrix
var mtom = (i >= 0 && i < tlist.numberOfItems ?
tlist.getItem(i).matrix :
svg.createSVGMatrix());
var mtom = (i >= 0 && i < tlist.numberOfItems
? tlist.getItem(i).matrix
: svg.createSVGMatrix());
m = svgedit.math.matrixMultiply(m, mtom);
}
return svg.createSVGTransformFromMatrix(m);
};
/**
* Get the matrix object for a given element
* @param {Element} elem - The DOM element to check
@@ -183,7 +181,6 @@ svgedit.math.getMatrix = function (elem) {
return svgedit.math.transformListToTransform(tlist).matrix;
};
/**
* Returns a 45 degree angle coordinate associated with the two given
* coordinates
@@ -208,7 +205,6 @@ svgedit.math.snapToAngle = function (x1, y1, x2, y2) {
};
};
/**
* Check if two rectangles (BBoxes objects) intersect each other
* @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 + r2.height) > r1.y;
};
}());

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit, svgroot*/
/*jslint vars: true, eqeq: true, continue: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgedit, svgroot */
/**
* Package: svgedit.path
*
@@ -15,7 +15,8 @@
// 3) math.js
// 4) svgutils.js
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.path) {
svgedit.path = {};
@@ -41,33 +42,33 @@ var segData = {
var pathFuncs = [];
var link_control_pts = true;
var linkControlPts = true;
// Stores references to paths via IDs.
// TODO: Make this cross-document happy.
var pathData = {};
svgedit.path.setLinkControlPoints = function(lcp) {
link_control_pts = lcp;
svgedit.path.setLinkControlPoints = function (lcp) {
linkControlPts = lcp;
};
svgedit.path.path = null;
var editorContext_ = null;
svgedit.path.init = function(editorContext) {
svgedit.path.init = function (editorContext) {
editorContext_ = editorContext;
pathFuncs = [0, 'ClosePath'];
var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc',
'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth'];
$.each(pathFuncsStrs, function(i, s) {
pathFuncs.push(s+'Abs');
pathFuncs.push(s+'Rel');
$.each(pathFuncsStrs, function (i, s) {
pathFuncs.push(s + 'Abs');
pathFuncs.push(s + 'Rel');
});
};
svgedit.path.insertItemBefore = function(elem, newseg, index) {
svgedit.path.insertItemBefore = function (elem, newseg, index) {
// Support insertItemBefore on paths for FF2
var list = elem.pathSegList;
@@ -78,13 +79,13 @@ svgedit.path.insertItemBefore = function(elem, newseg, index) {
var len = list.numberOfItems;
var arr = [];
var i;
for (i=0; i < len; i++) {
var cur_seg = list.getItem(i);
arr.push(cur_seg);
for (i = 0; i < len; i++) {
var curSeg = list.getItem(i);
arr.push(curSeg);
}
list.clear();
for (i=0; i < len; i++) {
if (i == index) { //index+1
for (i = 0; i < len; i++) {
if (i == index) { // index + 1
list.appendItem(newseg);
}
list.appendItem(arr[i]);
@@ -92,20 +93,20 @@ svgedit.path.insertItemBefore = function(elem, newseg, index) {
};
// 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 i, out = [];
for (i = 0; i < len; i++) {
out[i] = seg_item[arr[i]];
out[i] = segItem[arr[i]];
}
return out;
};
svgedit.path.getGripPt = function(seg, alt_pt) {
svgedit.path.getGripPt = function (seg, altPt) {
var out = {
x: alt_pt? alt_pt.x : seg.item.x,
y: alt_pt? alt_pt.y : seg.item.y
}, path = seg.path;
x: altPt ? altPt.x : seg.item.x,
y: altPt ? altPt.y : seg.item.y
}, path = seg.path;
if (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;
};
svgedit.path.getPointFromGrip = function(pt, path) {
svgedit.path.getPointFromGrip = function (pt, path) {
var out = {
x: pt.x,
y: pt.y
@@ -136,11 +137,11 @@ svgedit.path.getPointFromGrip = function(pt, path) {
return out;
};
svgedit.path.addPointGrip = function(index, x, y) {
svgedit.path.addPointGrip = function (index, x, y) {
// create the container of all the point grips
var pointGripContainer = svgedit.path.getGripContainer();
var pointGrip = svgedit.utilities.getElem('pathpointgrip_'+index);
var pointGrip = svgedit.utilities.getElem('pathpointgrip_' + index);
// create it
if (!pointGrip) {
pointGrip = document.createElementNS(NS.SVG, 'circle');
@@ -157,8 +158,8 @@ svgedit.path.addPointGrip = function(index, x, y) {
});
pointGrip = pointGripContainer.appendChild(pointGrip);
var grip = $('#pathpointgrip_'+index);
grip.dblclick(function() {
var grip = $('#pathpointgrip_' + index);
grip.dblclick(function () {
if (svgedit.path.path) {
svgedit.path.path.setSegType();
}
@@ -175,7 +176,7 @@ svgedit.path.addPointGrip = function(index, x, y) {
return pointGrip;
};
svgedit.path.getGripContainer = function() {
svgedit.path.getGripContainer = function () {
var c = svgedit.utilities.getElem('pathpointgrip_container');
if (!c) {
var parent = svgedit.utilities.getElem('selectorParentGroup');
@@ -185,9 +186,9 @@ svgedit.path.getGripContainer = function() {
return c;
};
svgedit.path.addCtrlGrip = function(id) {
var pointGrip = svgedit.utilities.getElem('ctrlpointgrip_'+id);
if (pointGrip) {return pointGrip;}
svgedit.path.addCtrlGrip = function (id) {
var pointGrip = svgedit.utilities.getElem('ctrlpointgrip_' + id);
if (pointGrip) { return pointGrip; }
pointGrip = document.createElementNS(NS.SVG, 'circle');
svgedit.utilities.assignAttributes(pointGrip, {
@@ -205,13 +206,13 @@ svgedit.path.addCtrlGrip = function(id) {
return pointGrip;
};
svgedit.path.getCtrlLine = function(id) {
var ctrlLine = svgedit.utilities.getElem('ctrlLine_'+id);
if (ctrlLine) {return ctrlLine;}
svgedit.path.getCtrlLine = function (id) {
var ctrlLine = svgedit.utilities.getElem('ctrlLine_' + id);
if (ctrlLine) { return ctrlLine; }
ctrlLine = document.createElementNS(NS.SVG, 'line');
svgedit.utilities.assignAttributes(ctrlLine, {
'id': 'ctrlLine_'+id,
'id': 'ctrlLine_' + id,
'stroke': '#555',
'stroke-width': 1,
'style': 'pointer-events:none'
@@ -220,7 +221,7 @@ svgedit.path.getCtrlLine = function(id) {
return ctrlLine;
};
svgedit.path.getPointGrip = function(seg, update) {
svgedit.path.getPointGrip = function (seg, update) {
var index = seg.index;
var pointGrip = svgedit.path.addPointGrip(index);
@@ -236,17 +237,17 @@ svgedit.path.getPointGrip = function(seg, update) {
return pointGrip;
};
svgedit.path.getControlPoints = function(seg) {
svgedit.path.getControlPoints = function (seg) {
var item = seg.item;
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 pointGripContainer = svgedit.path.getGripContainer();
/* var pointGripContainer = */ svgedit.path.getGripContainer();
// 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;
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 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 pt = svgedit.path.getGripPt(seg, {x: item['x' + i], y: item['y' + i]});
var gpt = svgedit.path.getGripPt(seg, {x: segItems[i - 1].x, y: segItems[i - 1].y});
svgedit.utilities.assignAttributes(ctrlLine, {
'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.
svgedit.path.replacePathSeg = function(type, index, pts, elem) {
svgedit.path.replacePathSeg = function (type, index, pts, elem) {
var path = elem || svgedit.path.path.elem;
var func = 'createSVGPathSeg' + pathFuncs[type];
@@ -295,8 +296,8 @@ svgedit.path.replacePathSeg = function(type, index, pts, elem) {
var arr = [];
var i;
for (i = 0; i < len; i++) {
var cur_seg = segList.getItem(i);
arr.push(cur_seg);
var curSeg = segList.getItem(i);
arr.push(curSeg);
}
segList.clear();
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 segLine = svgedit.utilities.getElem('segline_' + index);
if (!segLine) {
@@ -322,7 +323,7 @@ svgedit.path.getSegSelector = function(seg, update) {
'fill': 'none',
'stroke': '#0FF',
'stroke-width': 2,
'style':'pointer-events:none',
'style': 'pointer-events:none',
'd': 'M0,0 0,0'
});
pointGripContainer.appendChild(segLine);
@@ -342,9 +343,9 @@ svgedit.path.getSegSelector = function(seg, update) {
var pts = svgedit.path.ptObjToArr(seg.type, seg.item, true);
var i;
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+1] = pt.y;
pts[i + 1] = pt.y;
}
svgedit.path.replacePathSeg(seg.type, 1, pts, segLine);
@@ -354,56 +355,55 @@ svgedit.path.getSegSelector = function(seg, update) {
// Function: smoothControlPoints
// Takes three points and creates a smoother line based on them
//
// Parameters:
//
// Parameters:
// ct1 - Object with x and y values (first control point)
// ct2 - Object with x and y values (second control point)
// pt - Object with x and y values (third point)
//
// Returns:
// Returns:
// 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
var x1 = ct1.x - pt.x,
y1 = ct1.y - pt.y,
x2 = ct2.x - pt.x,
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),
angleb = Math.atan2(y2, x2),
r1 = Math.sqrt(x1*x1+y1*y1),
r2 = Math.sqrt(x2*x2+y2*y2),
r1 = Math.sqrt(x1 * x1 + y1 * y1),
r2 = Math.sqrt(x2 * x2 + y2 * y2),
nct1 = editorContext_.getSVGRoot().createSVGPoint(),
nct2 = editorContext_.getSVGRoot().createSVGPoint();
if (anglea < 0) { anglea += 2*Math.PI; }
if (angleb < 0) { angleb += 2*Math.PI; }
if (anglea < 0) { anglea += 2 * Math.PI; }
if (angleb < 0) { angleb += 2 * Math.PI; }
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) {
new_anglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff);
new_angleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff);
}
else {
new_anglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff);
new_angleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
newAnglea = angleBetween < Math.PI ? (anglea + angleDiff) : (anglea - angleDiff);
newAngleb = angleBetween < Math.PI ? (angleb - angleDiff) : (angleb + angleDiff);
} else {
newAnglea = angleBetween < Math.PI ? (anglea - angleDiff) : (anglea + angleDiff);
newAngleb = angleBetween < Math.PI ? (angleb + angleDiff) : (angleb - angleDiff);
}
// rotate the points
nct1.x = r1 * Math.cos(new_anglea) + pt.x;
nct1.y = r1 * Math.sin(new_anglea) + pt.y;
nct2.x = r2 * Math.cos(new_angleb) + pt.x;
nct2.y = r2 * Math.sin(new_angleb) + pt.y;
nct1.x = r1 * Math.cos(newAnglea) + pt.x;
nct1.y = r1 * Math.sin(newAnglea) + pt.y;
nct2.x = r2 * Math.cos(newAngleb) + pt.x;
nct2.y = r2 * Math.sin(newAngleb) + pt.y;
return [nct1, nct2];
}
return undefined;
};
svgedit.path.Segment = function(index, item) {
svgedit.path.Segment = function (index, item) {
this.selected = false;
this.index = index;
this.item = item;
@@ -414,7 +414,7 @@ svgedit.path.Segment = function(index, item) {
this.segsel = null;
};
svgedit.path.Segment.prototype.showCtrlPts = function(y) {
svgedit.path.Segment.prototype.showCtrlPts = function (y) {
var i;
for (i in this.ctrlpts) {
if (this.ctrlpts.hasOwnProperty(i)) {
@@ -423,12 +423,12 @@ svgedit.path.Segment.prototype.showCtrlPts = function(y) {
}
};
svgedit.path.Segment.prototype.selectCtrls = function(y) {
$('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2').
attr('fill', y ? '#0FF' : '#EEE');
svgedit.path.Segment.prototype.selectCtrls = function (y) {
$('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2')
.attr('fill', y ? '#0FF' : '#EEE');
};
svgedit.path.Segment.prototype.show = function(y) {
svgedit.path.Segment.prototype.show = function (y) {
if (this.ptgrip) {
this.ptgrip.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) {
this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F');
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.ctrlpts = svgedit.path.getControlPoints(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) {
var pt = svgedit.path.getGripPt(this);
svgedit.utilities.assignAttributes(this.ptgrip, {
@@ -475,23 +475,23 @@ svgedit.path.Segment.prototype.update = function(full) {
}
};
svgedit.path.Segment.prototype.move = function(dx, dy) {
var cur_pts, item = this.item;
svgedit.path.Segment.prototype.move = function (dx, dy) {
var curPts, item = this.item;
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];
} 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) {
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];
svgedit.path.replacePathSeg(this.next.type, this.next.index, next_pts);
svgedit.path.replacePathSeg(this.next.type, this.next.index, nextPts);
}
if (this.mate) {
@@ -504,26 +504,26 @@ svgedit.path.Segment.prototype.move = function(dx, dy) {
}
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;
if (num == 2) {
anum = 1;
seg = this.next;
if (!seg) {return;}
if (!seg) { return; }
pt = this.item;
} else {
anum = 2;
seg = this.prev;
if (!seg) {return;}
if (!seg) { return; }
pt = seg.item;
}
var item = seg.item;
item['x' + anum ] = pt.x + (pt.x - this.item['x' + num]);
item['y' + anum ] = pt.y + (pt.y - this.item['y' + num]);
item['x' + anum] = pt.x + (pt.x - this.item['x' + num]);
item['y' + anum] = pt.y + (pt.y - this.item['y' + num]);
var pts = [item.x, item.y,
item.x1, item.y1,
@@ -533,30 +533,30 @@ svgedit.path.Segment.prototype.setLinked = function(num) {
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;
item['x' + num] += dx;
item['y' + num] += dy;
var pts = [item.x,item.y,
item.x1,item.y1, item.x2,item.y2];
var pts = [item.x, item.y,
item.x1, item.y1, item.x2, item.y2];
svgedit.path.replacePathSeg(this.type, this.index, pts);
this.update(true);
};
svgedit.path.Segment.prototype.setType = function(new_type, pts) {
svgedit.path.replacePathSeg(new_type, this.index, pts);
this.type = new_type;
svgedit.path.Segment.prototype.setType = function (newType, pts) {
svgedit.path.replacePathSeg(newType, this.index, pts);
this.type = newType;
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.update(true);
};
svgedit.path.Path = function(elem) {
svgedit.path.Path = function (elem) {
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;
@@ -568,11 +568,13 @@ svgedit.path.Path = function(elem) {
};
// Reset path data
svgedit.path.Path.prototype.init = function() {
svgedit.path.Path.prototype.init = function () {
// Hide all grips, etc
//fixed, needed to work on all found elements, not just first
$(svgedit.path.getGripContainer()).find('*').each( function() { $(this).attr('display', 'none') });
// fixed, needed to work on all found elements, not just first
$(svgedit.path.getGripContainer()).find('*').each(function () {
$(this).attr('display', 'none');
});
var segList = this.elem.pathSegList;
var len = segList.numberOfItems;
@@ -590,58 +592,58 @@ svgedit.path.Path.prototype.init = function() {
}
var segs = this.segs;
var start_i = null;
var startI = null;
for (i = 0; i < len; i++) {
var seg = segs[i];
var next_seg = (i+1) >= len ? null : segs[i+1];
var prev_seg = (i-1) < 0 ? null : segs[i-1];
var start_seg;
var nextSeg = (i + 1) >= len ? null : segs[i + 1];
var prevSeg = (i - 1) < 0 ? null : segs[i - 1];
var startSeg;
if (seg.type === 2) {
if (prev_seg && prev_seg.type !== 1) {
if (prevSeg && prevSeg.type !== 1) {
// New sub-path, last one is open,
// so add a grip to last sub-path's first point
start_seg = segs[start_i];
start_seg.next = segs[start_i+1];
start_seg.next.prev = start_seg;
start_seg.addGrip();
startSeg = segs[startI];
startSeg.next = segs[startI + 1];
startSeg.next.prev = startSeg;
startSeg.addGrip();
}
// Remember that this is a starter seg
start_i = i;
} else if (next_seg && next_seg.type === 1) {
startI = i;
} else if (nextSeg && nextSeg.type === 1) {
// This is the last real segment of a closed sub-path
// 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
seg.next.prev = seg;
seg.mate = segs[start_i];
seg.mate = segs[startI];
seg.addGrip();
if (this.first_seg == null) {
this.first_seg = seg;
}
} else if (!next_seg) {
} else if (!nextSeg) {
if (seg.type !== 1) {
// Last seg, doesn't close so add a grip
// to last sub-path's first point
start_seg = segs[start_i];
start_seg.next = segs[start_i+1];
start_seg.next.prev = start_seg;
start_seg.addGrip();
startSeg = segs[startI];
startSeg.next = segs[startI + 1];
startSeg.next.prev = startSeg;
startSeg.addGrip();
seg.addGrip();
if (!this.first_seg) {
// 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"
seg.addGrip();
// Don't set its "next" if it's an "M"
if (next_seg && next_seg.type !== 2) {
seg.next = next_seg;
if (nextSeg && nextSeg.type !== 2) {
seg.next = nextSeg;
seg.next.prev = seg;
}
}
@@ -649,44 +651,44 @@ svgedit.path.Path.prototype.init = function() {
return this;
};
svgedit.path.Path.prototype.eachSeg = function(fn) {
svgedit.path.Path.prototype.eachSeg = function (fn) {
var i;
var len = this.segs.length;
for (i = 0; i < len; 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
var seg = this.segs[index];
if (!seg.prev) {return;}
if (!seg.prev) { return; }
var prev = seg.prev;
var newseg, new_x, new_y;
switch(seg.item.pathSegType) {
var newseg, newX, newY;
switch (seg.item.pathSegType) {
case 4:
new_x = (seg.item.x + prev.item.x) / 2;
new_y = (seg.item.y + prev.item.y) / 2;
newseg = this.elem.createSVGPathSegLinetoAbs(new_x, new_y);
newX = (seg.item.x + prev.item.x) / 2;
newY = (seg.item.y + prev.item.y) / 2;
newseg = this.elem.createSVGPathSegLinetoAbs(newX, newY);
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
var p0_x = (prev.item.x + seg.item.x1)/2;
var p1_x = (seg.item.x1 + seg.item.x2)/2;
var p2_x = (seg.item.x2 + seg.item.x)/2;
var p01_x = (p0_x + p1_x)/2;
var p12_x = (p1_x + p2_x)/2;
new_x = (p01_x + p12_x)/2;
var p0_y = (prev.item.y + seg.item.y1)/2;
var p1_y = (seg.item.y1 + seg.item.y2)/2;
var p2_y = (seg.item.y2 + seg.item.y)/2;
var p01_y = (p0_y + p1_y)/2;
var p12_y = (p1_y + p2_y)/2;
new_y = (p01_y + p12_y)/2;
newseg = this.elem.createSVGPathSegCurvetoCubicAbs(new_x, new_y, p0_x, p0_y, p01_x, p01_y);
var pts = [seg.item.x, seg.item.y, p12_x, p12_y, p2_x, p2_y];
var p0x = (prev.item.x + seg.item.x1) / 2;
var p1x = (seg.item.x1 + seg.item.x2) / 2;
var p2x = (seg.item.x2 + seg.item.x) / 2;
var p01x = (p0x + p1x) / 2;
var p12x = (p1x + p2x) / 2;
newX = (p01x + p12x) / 2;
var p0y = (prev.item.y + seg.item.y1) / 2;
var p1y = (seg.item.y1 + seg.item.y2) / 2;
var p2y = (seg.item.y2 + seg.item.y) / 2;
var p01y = (p0y + p1y) / 2;
var p12y = (p1y + p2y) / 2;
newY = (p01y + p12y) / 2;
newseg = this.elem.createSVGPathSegCurvetoCubicAbs(newX, newY, p0x, p0y, p01x, p01y);
var pts = [seg.item.x, seg.item.y, p12x, p12y, p2x, p2y];
svgedit.path.replacePathSeg(seg.type, index, pts);
break;
}
@@ -694,7 +696,7 @@ svgedit.path.Path.prototype.addSeg = function(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 list = this.elem.pathSegList;
@@ -712,7 +714,7 @@ svgedit.path.Path.prototype.deleteSeg = function(index) {
list.removeItem(seg.mate.index);
} else if (!seg.prev) {
// 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];
svgedit.path.replacePathSeg(2, seg.next.index, pt);
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;
// Check if subpath is already open
svgedit.path.path.eachSeg(function(i) {
if (i <= index) {return true;}
svgedit.path.path.eachSeg(function (i) {
if (i <= index) { return true; }
if (this.type === 2) {
// Found M first, so open
return false;
@@ -740,7 +742,7 @@ svgedit.path.Path.prototype.subpathIsClosed = function(index) {
return closed;
};
svgedit.path.Path.prototype.removePtFromSelection = function(index) {
svgedit.path.Path.prototype.removePtFromSelection = function (index) {
var pos = this.selected_pts.indexOf(index);
if (pos == -1) {
return;
@@ -749,21 +751,21 @@ svgedit.path.Path.prototype.removePtFromSelection = function(index) {
this.selected_pts.splice(pos, 1);
};
svgedit.path.Path.prototype.clearSelection = function() {
this.eachSeg(function() {
svgedit.path.Path.prototype.clearSelection = function () {
this.eachSeg(function () {
// 'this' is the segment here
this.select(false);
});
this.selected_pts = [];
};
svgedit.path.Path.prototype.storeD = function() {
svgedit.path.Path.prototype.storeD = function () {
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
this.eachSeg(function() {
this.eachSeg(function () {
// 'this' is the segment here
this.show(y);
});
@@ -774,90 +776,90 @@ svgedit.path.Path.prototype.show = function(y) {
};
// 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;
while(i--) {
while (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]];
seg.moveCtrl(this.dragctrl, d_x, d_y);
if (link_control_pts) {
seg.moveCtrl(this.dragctrl, dx, dy);
if (linkControlPts) {
seg.setLinked(this.dragctrl);
}
};
svgedit.path.Path.prototype.setSegType = function(new_type) {
svgedit.path.Path.prototype.setSegType = function (newType) {
this.storeD();
var i = this.selected_pts.length;
var text;
while(i--) {
var sel_pt = this.selected_pts[i];
while (i--) {
var selPt = this.selected_pts[i];
// Selected seg
var cur = this.segs[sel_pt];
var cur = this.segs[selPt];
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';
// 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 cur_y = cur.item.y;
var prev_x = prev.item.x;
var prev_y = prev.item.y;
var curX = cur.item.x;
var curY = cur.item.y;
var prevX = prev.item.x;
var prevY = prev.item.y;
var points;
switch ( new_type ) {
switch (newType) {
case 6:
if (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 {
var diff_x = cur_x - prev_x;
var diff_y = cur_y - prev_y;
var diffX = curX - prevX;
var diffY = curY - prevY;
// get control points from straight line segment
/*
var ct1_x = (prev_x + (diff_y/2));
var ct1_y = (prev_y - (diff_x/2));
var ct2_x = (cur_x + (diff_y/2));
var ct2_y = (cur_y - (diff_x/2));
var ct1x = (prevX + (diffY/2));
var ct1y = (prevY - (diffX/2));
var ct2x = (curX + (diffY/2));
var ct2y = (curY - (diffX/2));
*/
//create control points on the line to preserve the shape (WRS)
var ct1_x = (prev_x + (diff_x/3));
var ct1_y = (prev_y + (diff_y/3));
var ct2_x = (cur_x - (diff_x/3));
var ct2_y = (cur_y - (diff_y/3));
points = [cur_x, cur_y, ct1_x, ct1_y, ct2_x, ct2_y];
// create control points on the line to preserve the shape (WRS)
var ct1x = (prevX + (diffX / 3));
var ct1y = (prevY + (diffY / 3));
var ct2x = (curX - (diffX / 3));
var ct2y = (curY - (diffY / 3));
points = [curX, curY, ct1x, ct1y, ct2x, ct2y];
}
break;
case 4:
points = [cur_x, cur_y];
points = [curX, curY];
// Store original prevve segment nums
cur.olditem = cur.item;
break;
}
cur.setType(new_type, points);
cur.setType(newType, points);
}
svgedit.path.path.endChanges(text);
};
svgedit.path.Path.prototype.selectPt = function(pt, ctrl_num) {
svgedit.path.Path.prototype.selectPt = function (pt, ctrlNum) {
this.clearSelection();
if (pt == null) {
this.eachSeg(function(i) {
this.eachSeg(function (i) {
// 'this' is the segment here.
if (this.prev) {
pt = i;
@@ -865,17 +867,17 @@ svgedit.path.Path.prototype.selectPt = function(pt, ctrl_num) {
});
}
this.addPtsToSelection(pt);
if (ctrl_num) {
this.dragctrl = ctrl_num;
if (ctrlNum) {
this.dragctrl = ctrlNum;
if (link_control_pts) {
this.segs[pt].setLinked(ctrl_num);
if (linkControlPts) {
this.segs[pt].setLinked(ctrlNum);
}
}
};
// Update position of all points
svgedit.path.Path.prototype.update = function() {
svgedit.path.Path.prototype.update = function () {
var elem = this.elem;
if (svgedit.utilities.getRotationAngle(elem)) {
this.matrix = svgedit.math.getMatrix(elem);
@@ -885,7 +887,7 @@ svgedit.path.Path.prototype.update = function() {
this.imatrix = null;
}
this.eachSeg(function(i) {
this.eachSeg(function (i) {
this.item = elem.pathSegList.getItem(i);
this.update();
});
@@ -893,7 +895,7 @@ svgedit.path.Path.prototype.update = function() {
return this;
};
svgedit.path.getPath_ = function(elem) {
svgedit.path.getPath_ = function (elem) {
var p = pathData[elem.id];
if (!p) {
p = pathData[elem.id] = new svgedit.path.Path(elem);
@@ -901,16 +903,16 @@ svgedit.path.getPath_ = function(elem) {
return p;
};
svgedit.path.removePath_ = function(id) {
if (id in pathData) {delete pathData[id];}
svgedit.path.removePath_ = function (id) {
if (id in pathData) { delete pathData[id]; }
};
var newcx, newcy, oldcx, oldcy, angle;
var getRotVals = function(x, y) {
var getRotVals = function (x, y) {
var dx = x - oldcx;
var dy = y - oldcy;
// 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;
dx = r * Math.cos(theta) + oldcx;
dy = r * Math.sin(theta) + oldcy;
@@ -922,7 +924,7 @@ var getRotVals = function(x, y) {
dx -= newcx;
dy -= newcy;
r = Math.sqrt(dx*dx + dy*dy);
r = Math.sqrt(dx * dx + dy * dy);
theta = Math.atan2(dy, dx) - angle;
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:
// 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
// This is because we want the path to remember its rotation
// TODO: This is still using ye olde transform methods, can probably
// be optimized or even taken care of by recalculateDimensions
svgedit.path.recalcRotatedPath = function() {
var current_path = svgedit.path.path.elem;
angle = svgedit.utilities.getRotationAngle(current_path, true);
if (!angle) {return;}
// selectedBBoxes[0] = svgedit.path.path.oldbbox;
var box = svgedit.utilities.getBBox(current_path),
oldbox = svgedit.path.path.oldbbox; //selectedBBoxes[0],
oldcx = oldbox.x + oldbox.width/2;
oldcy = oldbox.y + oldbox.height/2;
newcx = box.x + box.width/2;
newcy = box.y + box.height/2;
svgedit.path.recalcRotatedPath = function () {
var currentPath = svgedit.path.path.elem;
angle = svgedit.utilities.getRotationAngle(currentPath, true);
if (!angle) { return; }
// selectedBBoxes[0] = svgedit.path.path.oldbbox;
var box = svgedit.utilities.getBBox(currentPath),
oldbox = svgedit.path.path.oldbbox; // selectedBBoxes[0],
oldcx = oldbox.x + oldbox.width / 2;
oldcy = oldbox.y + oldbox.height / 2;
newcx = box.x + box.width / 2;
newcy = box.y + box.height / 2;
// un-rotate the new center to the proper position
var dx = newcx - oldcx,
dy = newcy - oldcy,
r = Math.sqrt(dx*dx + dy*dy),
r = Math.sqrt(dx * dx + dy * dy),
theta = Math.atan2(dy, dx) + angle;
newcx = r * Math.cos(theta) + oldcx;
newcy = r * Math.sin(theta) + oldcy;
var list = current_path.pathSegList,
var list = currentPath.pathSegList,
i = list.numberOfItems;
while (i) {
i -= 1;
var seg = list.getItem(i),
type = seg.pathSegType;
if (type == 1) {continue;}
if (type == 1) { continue; }
var rvals = getRotVals(seg.x, seg.y),
points = [rvals.x, rvals.y];
if (seg.x1 != null && seg.x2 != null) {
var c_vals1 = getRotVals(seg.x1, seg.y1);
var c_vals2 = getRotVals(seg.x2, seg.y2);
points.splice(points.length, 0, c_vals1.x , c_vals1.y, c_vals2.x, c_vals2.y);
var cVals1 = getRotVals(seg.x1, seg.y1);
var cVals2 = getRotVals(seg.x2, seg.y2);
points.splice(points.length, 0, cVals1.x, cVals1.y, cVals2.x, cVals2.y);
}
svgedit.path.replacePathSeg(type, i, points);
} // loop for each point
box = svgedit.utilities.getBBox(current_path);
// selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y;
// selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height;
box = svgedit.utilities.getBBox(currentPath);
// selectedBBoxes[0].x = box.x; selectedBBoxes[0].y = box.y;
// selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height;
// now we must set the new transform to be rotated around the new center
var R_nc = svgroot.createSVGTransform(),
tlist = svgedit.transformlist.getTransformList(current_path);
R_nc.setRotate((angle * 180.0 / Math.PI), newcx, newcy);
tlist.replaceItem(R_nc,0);
var Rnc = svgroot.createSVGTransform(),
tlist = svgedit.transformlist.getTransformList(currentPath);
Rnc.setRotate((angle * 180.0 / Math.PI), newcx, newcy);
tlist.replaceItem(Rnc, 0);
};
// ====================================
// Public API starts here
svgedit.path.clearData = function() {
svgedit.path.clearData = function () {
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*/
/*jslint vars: true, eqeq: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgedit */
/**
* Package: svgedit.sanitize
*
@@ -15,98 +15,99 @@
// 3) browser.js
// 4) svgutils.js
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.sanitize) {
svgedit.sanitize = {};
svgedit.sanitize = {};
}
var NS = svgedit.NS,
REVERSE_NS = svgedit.getReverseNS();
REVERSE_NS = svgedit.getReverseNS();
// this defines which elements and attributes that we support
var svgWhiteList_ = {
// 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"],
"circle": ["class", "clip-path", "clip-rule", "cx", "cy", "fill", "fill-opacity", "fill-rule", "filter", "id", "mask", "opacity", "r", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform"],
"clipPath": ["class", "clipPathUnits", "id"],
"defs": [],
"style" : ["type"],
"desc": [],
"ellipse": ["class", "clip-path", "clip-rule", "cx", "cy", "fill", "fill-opacity", "fill-rule", "filter", "id", "mask", "opacity", "requiredFeatures", "rx", "ry", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform"],
"feGaussianBlur": ["class", "color-interpolation-filters", "id", "requiredFeatures", "stdDeviation"],
"filter": ["class", "color-interpolation-filters", "filterRes", "filterUnits", "height", "id", "primitiveUnits", "requiredFeatures", "width", "x", "xlink:href", "y"],
"foreignObject": ["class", "font-size", "height", "id", "opacity", "requiredFeatures", "style", "transform", "width", "x", "y"],
"g": ["class", "clip-path", "clip-rule", "id", "display", "fill", "fill-opacity", "fill-rule", "filter", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "font-family", "font-size", "font-style", "font-weight", "text-anchor"],
"image": ["class", "clip-path", "clip-rule", "filter", "height", "id", "mask", "opacity", "requiredFeatures", "style", "systemLanguage", "transform", "width", "x", "xlink:href", "xlink:title", "y"],
"line": ["class", "clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "id", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "x1", "x2", "y1", "y2"],
"linearGradient": ["class", "id", "gradientTransform", "gradientUnits", "requiredFeatures", "spreadMethod", "systemLanguage", "x1", "x2", "xlink:href", "y1", "y2"],
"marker": ["id", "class", "markerHeight", "markerUnits", "markerWidth", "orient", "preserveAspectRatio", "refX", "refY", "systemLanguage", "viewBox"],
"mask": ["class", "height", "id", "maskContentUnits", "maskUnits", "width", "x", "y"],
"metadata": ["class", "id"],
"path": ["class", "clip-path", "clip-rule", "d", "fill", "fill-opacity", "fill-rule", "filter", "id", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform"],
"pattern": ["class", "height", "id", "patternContentUnits", "patternTransform", "patternUnits", "requiredFeatures", "style", "systemLanguage", "viewBox", "width", "x", "xlink:href", "y"],
"polygon": ["class", "clip-path", "clip-rule", "id", "fill", "fill-opacity", "fill-rule", "filter", "id", "class", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "points", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform"],
"polyline": ["class", "clip-path", "clip-rule", "id", "fill", "fill-opacity", "fill-rule", "filter", "marker-end", "marker-mid", "marker-start", "mask", "opacity", "points", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform"],
"radialGradient": ["class", "cx", "cy", "fx", "fy", "gradientTransform", "gradientUnits", "id", "r", "requiredFeatures", "spreadMethod", "systemLanguage", "xlink:href"],
"rect": ["class", "clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "height", "id", "mask", "opacity", "requiredFeatures", "rx", "ry", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "width", "x", "y"],
"stop": ["class", "id", "offset", "requiredFeatures", "stop-color", "stop-opacity", "style", "systemLanguage"],
"svg": ["class", "clip-path", "clip-rule", "filter", "id", "height", "mask", "preserveAspectRatio", "requiredFeatures", "style", "systemLanguage", "viewBox", "width", "x", "xmlns", "xmlns:se", "xmlns:xlink", "y"],
"switch": ["class", "id", "requiredFeatures", "systemLanguage"],
"symbol": ["class", "fill", "fill-opacity", "fill-rule", "filter", "font-family", "font-size", "font-style", "font-weight", "id", "opacity", "preserveAspectRatio", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "transform", "viewBox"],
"text": ["class", "clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "font-family", "font-size", "font-style", "font-weight", "id", "mask", "opacity", "requiredFeatures", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "text-anchor", "transform", "x", "xml:space", "y"],
"textPath": ["class", "id", "method", "requiredFeatures", "spacing", "startOffset", "style", "systemLanguage", "transform", "xlink:href"],
"title": [],
"tspan": ["class", "clip-path", "clip-rule", "dx", "dy", "fill", "fill-opacity", "fill-rule", "filter", "font-family", "font-size", "font-style", "font-weight", "id", "mask", "opacity", "requiredFeatures", "rotate", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "systemLanguage", "text-anchor", "textLength", "transform", "x", "xml:space", "y"],
"use": ["class", "clip-path", "clip-rule", "fill", "fill-opacity", "fill-rule", "filter", "height", "id", "mask", "stroke", "stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", "stroke-width", "style", "transform", "width", "x", "xlink:href", "y"],
// 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'],
'circle': ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'clipPath': ['class', 'clipPathUnits', 'id'],
'defs': [],
'style': ['type'],
'desc': [],
'ellipse': ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'feGaussianBlur': ['class', 'color-interpolation-filters', 'id', 'requiredFeatures', 'stdDeviation'],
'filter': ['class', 'color-interpolation-filters', 'filterRes', 'filterUnits', 'height', 'id', 'primitiveUnits', 'requiredFeatures', 'width', 'x', 'xlink:href', 'y'],
'foreignObject': ['class', 'font-size', 'height', 'id', 'opacity', 'requiredFeatures', 'style', 'transform', 'width', 'x', 'y'],
'g': ['class', 'clip-path', 'clip-rule', 'id', 'display', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'font-family', 'font-size', 'font-style', 'font-weight', 'text-anchor'],
'image': ['class', 'clip-path', 'clip-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'style', 'systemLanguage', 'transform', 'width', 'x', 'xlink:href', 'xlink:title', 'y'],
'line': ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'x1', 'x2', 'y1', 'y2'],
'linearGradient': ['class', 'id', 'gradientTransform', 'gradientUnits', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'x1', 'x2', 'xlink:href', 'y1', 'y2'],
'marker': ['id', 'class', 'markerHeight', 'markerUnits', 'markerWidth', 'orient', 'preserveAspectRatio', 'refX', 'refY', 'systemLanguage', 'viewBox'],
'mask': ['class', 'height', 'id', 'maskContentUnits', 'maskUnits', 'width', 'x', 'y'],
'metadata': ['class', 'id'],
'path': ['class', 'clip-path', 'clip-rule', 'd', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'pattern': ['class', 'height', 'id', 'patternContentUnits', 'patternTransform', 'patternUnits', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xlink:href', 'y'],
'polygon': ['class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'class', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'polyline': ['class', 'clip-path', 'clip-rule', 'id', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'opacity', 'points', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'],
'radialGradient': ['class', 'cx', 'cy', 'fx', 'fy', 'gradientTransform', 'gradientUnits', 'id', 'r', 'requiredFeatures', 'spreadMethod', 'systemLanguage', 'xlink:href'],
'rect': ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y'],
'stop': ['class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage'],
'svg': ['class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y'],
'switch': ['class', 'id', 'requiredFeatures', 'systemLanguage'],
'symbol': ['class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox'],
'text': ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y'],
'textPath': ['class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href'],
'title': [],
'tspan': ['class', 'clip-path', 'clip-rule', 'dx', 'dy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'rotate', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'textLength', 'transform', 'x', 'xml:space', 'y'],
'use': ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'transform', 'width', 'x', 'xlink:href', 'y'],
// MathML Elements
"annotation": ["encoding"],
"annotation-xml": ["encoding"],
"maction": ["actiontype", "other", "selection"],
"math": ["class", "id", "display", "xmlns"],
"menclose": ["notation"],
"merror": [],
"mfrac": ["linethickness"],
"mi": ["mathvariant"],
"mmultiscripts": [],
"mn": [],
"mo": ["fence", "lspace", "maxsize", "minsize", "rspace", "stretchy"],
"mover": [],
"mpadded": ["lspace", "width", "height", "depth", "voffset"],
"mphantom": [],
"mprescripts": [],
"mroot": [],
"mrow": ["xlink:href", "xlink:type", "xmlns:xlink"],
"mspace": ["depth", "height", "width"],
"msqrt": [],
"mstyle": ["displaystyle", "mathbackground", "mathcolor", "mathvariant", "scriptlevel"],
"msub": [],
"msubsup": [],
"msup": [],
"mtable": ["align", "columnalign", "columnlines", "columnspacing", "displaystyle", "equalcolumns", "equalrows", "frame", "rowalign", "rowlines", "rowspacing", "width"],
"mtd": ["columnalign", "columnspan", "rowalign", "rowspan"],
"mtext": [],
"mtr": ["columnalign", "rowalign"],
"munder": [],
"munderover": [],
"none": [],
"semantics": []
// MathML Elements
'annotation': ['encoding'],
'annotation-xml': ['encoding'],
'maction': ['actiontype', 'other', 'selection'],
'math': ['class', 'id', 'display', 'xmlns'],
'menclose': ['notation'],
'merror': [],
'mfrac': ['linethickness'],
'mi': ['mathvariant'],
'mmultiscripts': [],
'mn': [],
'mo': ['fence', 'lspace', 'maxsize', 'minsize', 'rspace', 'stretchy'],
'mover': [],
'mpadded': ['lspace', 'width', 'height', 'depth', 'voffset'],
'mphantom': [],
'mprescripts': [],
'mroot': [],
'mrow': ['xlink:href', 'xlink:type', 'xmlns:xlink'],
'mspace': ['depth', 'height', 'width'],
'msqrt': [],
'mstyle': ['displaystyle', 'mathbackground', 'mathcolor', 'mathvariant', 'scriptlevel'],
'msub': [],
'msubsup': [],
'msup': [],
'mtable': ['align', 'columnalign', 'columnlines', 'columnspacing', 'displaystyle', 'equalcolumns', 'equalrows', 'frame', 'rowalign', 'rowlines', 'rowspacing', 'width'],
'mtd': ['columnalign', 'columnspan', 'rowalign', 'rowspan'],
'mtext': [],
'mtr': ['columnalign', 'rowalign'],
'munder': [],
'munderover': [],
'none': [],
'semantics': []
};
// Produce a Namespace-aware version of svgWhitelist
var svgWhiteListNS_ = {};
$.each(svgWhiteList_, function(elt, atts){
var attNS = {};
$.each(atts, function(i, att){
if (att.indexOf(':') >= 0) {
var v = att.split(':');
attNS[v[1]] = NS[(v[0]).toUpperCase()];
} else {
attNS[att] = att == 'xmlns' ? NS.XMLNS : null;
}
});
svgWhiteListNS_[elt] = attNS;
$.each(svgWhiteList_, function (elt, atts) {
var attNS = {};
$.each(atts, function (i, att) {
if (att.indexOf(':') >= 0) {
var v = att.split(':');
attNS[v[1]] = NS[(v[0]).toUpperCase()];
} else {
attNS[att] = att == 'xmlns' ? NS.XMLNS : null;
}
});
svgWhiteListNS_[elt] = attNS;
});
// Function: svgedit.sanitize.sanitizeSvg
@@ -115,145 +116,141 @@ $.each(svgWhiteList_, function(elt, atts){
//
// Parameters:
// node - The DOM element to be checked (we'll also check its children)
svgedit.sanitize.sanitizeSvg = function(node) {
// Cleanup text nodes
if (node.nodeType == 3) { // 3 == TEXT_NODE
// Trim whitespace
node.nodeValue = node.nodeValue.replace(/^\s+|\s+$/g, '');
// Remove if empty
if (node.nodeValue.length === 0) {
node.parentNode.removeChild(node);
}
}
svgedit.sanitize.sanitizeSvg = function (node) {
// Cleanup text nodes
if (node.nodeType == 3) { // 3 == TEXT_NODE
// Trim whitespace
node.nodeValue = node.nodeValue.replace(/^\s+|\s+$/g, '');
// Remove if empty
if (node.nodeValue.length === 0) {
node.parentNode.removeChild(node);
}
}
// We only care about element nodes.
// Automatically return for all non-element nodes, such as comments, etc.
if (node.nodeType != 1) { // 1 == ELEMENT_NODE
return;
}
// We only care about element nodes.
// Automatically return for all non-element nodes, such as comments, etc.
if (node.nodeType != 1) { // 1 == ELEMENT_NODE
return;
}
var doc = node.ownerDocument;
var parent = node.parentNode;
// can parent ever be null here? I think the root node's parent is the document...
if (!doc || !parent) {
return;
}
var doc = node.ownerDocument;
var parent = node.parentNode;
// can parent ever be null here? I think the root node's parent is the document...
if (!doc || !parent) {
return;
}
var allowedAttrs = svgWhiteList_[node.nodeName];
var allowedAttrsNS = svgWhiteListNS_[node.nodeName];
var i;
// if this element is supported, sanitize it
if (typeof allowedAttrs !== 'undefined') {
var allowedAttrs = svgWhiteList_[node.nodeName];
var allowedAttrsNS = svgWhiteListNS_[node.nodeName];
var i;
// if this element is supported, sanitize it
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 = [];
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);
}
// Add spaces before negative signs where necessary
if (svgedit.browser.isGecko()) {
switch (attrName) {
case 'transform':
case 'gradientTransform':
case 'patternTransform':
var val = attr.value.replace(/(\d)-/g, '$1 -');
node.setAttribute(attrName, val);
break;
}
}
// Add spaces before negative signs where necessary
if (svgedit.browser.isGecko()) {
switch (attrName) {
case 'transform':
case 'gradientTransform':
case 'patternTransform':
var val = attr.value.replace(/(\d)-/g, '$1 -');
node.setAttribute(attrName, val);
break;
}
}
// For the style attribute, rewrite it in terms of XML presentational attributes
if (attrName == 'style') {
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');
}
}
// For the style attribute, rewrite it in terms of XML presentational attributes
if (attrName == 'style') {
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) {
node.setAttributeNS(NS.SE, attr[0], attr[1]);
});
$.each(seAttrs, function(i, attr) {
node.setAttributeNS(NS.SE, attr[0], attr[1]);
});
// for some elements that have a xlink:href, ensure the URI refers to a local element
// (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
// (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');
}
}
// Safari crashes on a <use> without a xlink:href, so we just remove the node here
if (node.nodeName == 'use' && !svgedit.utilities.getHref(node)) {
parent.removeChild(node);
return;
}
// if the element has attributes pointing to a non-local reference,
// need to remove the attribute
$.each(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], function (i, attr) {
var val = node.getAttribute(attr);
if (val) {
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
if (node.nodeName == 'use' && !svgedit.utilities.getHref(node)) {
parent.removeChild(node);
return;
}
// if the element has attributes pointing to a non-local reference,
// need to remove the attribute
$.each(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], function(i, attr) {
var val = node.getAttribute(attr);
if (val) {
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
i = node.childNodes.length;
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));
}
// recurse to children
i = node.childNodes.length;
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
parent.removeChild(node);
// remove this node from the document altogether
parent.removeChild(node);
// call sanitizeSvg on each of those children
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*/
/*jslint vars: true, eqeq: true, forin: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgedit */
/**
* Package: svedit.select
*
@@ -16,7 +16,8 @@
// 4) math.js
// 5) svgutils.js
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.select) {
svgedit.select = {};
@@ -34,7 +35,7 @@ var gripRadius = svgedit.browser.isTouch() ? 10 : 4;
// id - integer to internally indentify the selector
// elem - DOM element associated with this selector
// 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.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.gripCoords = {
'nw': null,
'n' : null,
'n': null,
'ne': null,
'e' : null,
'e': null,
'se': null,
's' : null,
's': null,
'sw': null,
'w' : null
'w': null
};
this.reset(this.selectedElement, bbox);
};
// Function: svgedit.select.Selector.reset
// Used to reset the id and element that the selector is attached to
//
// Parameters:
// e - DOM element associated with this selector
// 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.selectedElement = e;
this.resize(bbox);
this.selectorGroup.setAttribute('display', 'inline');
};
// Function: svgedit.select.Selector.updateGripCursors
// Updates cursors for corner grips on rotation so arrows point the right way
//
// Parameters:
// angle - Float indicating current rotation angle in degrees
svgedit.select.Selector.prototype.updateGripCursors = function(angle) {
svgedit.select.Selector.prototype.updateGripCursors = function (angle) {
var dir,
dir_arr = [],
dirArr = [],
steps = Math.round(angle / 45);
if (steps < 0) {steps += 8;}
if (steps < 0) { steps += 8; }
for (dir in selectorManager_.selectorGrips) {
dir_arr.push(dir);
dirArr.push(dir);
}
while (steps > 0) {
dir_arr.push(dir_arr.shift());
dirArr.push(dirArr.shift());
steps--;
}
var i = 0;
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++;
}
};
@@ -125,7 +124,7 @@ svgedit.select.Selector.prototype.updateGripCursors = function(angle) {
//
// Parameters:
// 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';
selectorManager_.selectorGripsGroup.setAttribute('display', bShow);
var elem = this.selectedElement;
@@ -139,21 +138,21 @@ svgedit.select.Selector.prototype.showGrips = function(show) {
// Function: svgedit.select.Selector.resize
// Updates the selector to match the element's size
// 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,
mgr = selectorManager_,
selectedGrips = mgr.selectorGrips,
selected = this.selectedElement,
sw = selected.getAttribute('stroke-width'),
current_zoom = svgFactory_.currentZoom();
var offset = 1/current_zoom;
currentZoom = svgFactory_.currentZoom();
var offset = 1 / currentZoom;
if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) {
offset += (sw/2);
offset += (sw / 2);
}
var tagName = selected.tagName;
if (tagName === 'text') {
offset += 2/current_zoom;
offset += 2 / currentZoom;
}
// 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
// it keeps the selection box correctly positioned when zoomed
m.e *= current_zoom;
m.f *= current_zoom;
m.e *= currentZoom;
m.f *= currentZoom;
if (!bbox) {
bbox = svgedit.utilities.getBBox(selected);
@@ -173,23 +172,23 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
if (tagName === 'g' && !$.data(selected, 'gsvg')) {
// The bbox for a group does not include stroke vals, so we
// get the bbox based on its children.
var stroked_bbox = svgFactory_.getStrokedBBox(selected.childNodes);
if (stroked_bbox) {
bbox = stroked_bbox;
var strokedBbox = svgFactory_.getStrokedBBox(selected.childNodes);
if (strokedBbox) {
bbox = strokedBbox;
}
}
// apply the transforms
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
// 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,
nbax = aabox.x - offset,
nbay = aabox.y - offset,
@@ -197,8 +196,8 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
nbah = aabox.height + (offset * 2);
// now if the shape is rotated, un-rotate it
var cx = nbax + nbaw/2,
cy = nbay + nbah/2;
var cx = nbax + nbaw / 2,
cy = nbay + nbah / 2;
var angle = svgedit.utilities.getRotationAngle(selected);
if (angle) {
@@ -219,59 +218,58 @@ svgedit.select.Selector.prototype.resize = function(bbox) {
var min = Math.min, max = Math.max;
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;
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;
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;
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;
nbax = minx;
nbay = miny;
nbaw = (maxx-minx);
nbah = (maxy-miny);
nbaw = (maxx - minx);
nbah = (maxy - miny);
}
var dstr = 'M' + nbax + ',' + nbay
+ ' L' + (nbax+nbaw) + ',' + nbay
+ ' ' + (nbax+nbaw) + ',' + (nbay+nbah)
+ ' ' + nbax + ',' + (nbay+nbah) + 'z';
var dstr = 'M' + nbax + ',' + nbay +
' L' + (nbax + nbaw) + ',' + nbay +
' ' + (nbax + nbaw) + ',' + (nbay + nbah) +
' ' + nbax + ',' + (nbay + nbah) + 'z';
selectedBox.setAttribute('d', dstr);
var xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : '';
this.selectorGroup.setAttribute('transform', xform);
// TODO(codedread): Is this if needed?
// if (selected === selectedElements[0]) {
this.gripCoords = {
'nw': [nbax, nbay],
'ne': [nbax+nbaw, nbay],
'sw': [nbax, nbay+nbah],
'se': [nbax+nbaw, nbay+nbah],
'n': [nbax + (nbaw)/2, nbay],
'w': [nbax, nbay + (nbah)/2],
'e': [nbax + nbaw, nbay + (nbah)/2],
's': [nbax + (nbaw)/2, nbay + nbah]
};
var dir;
for (dir in this.gripCoords) {
var coords = this.gripCoords[dir];
selectedGrips[dir].setAttribute('cx', coords[0]);
selectedGrips[dir].setAttribute('cy', coords[1]);
}
// if (selected === selectedElements[0]) {
this.gripCoords = {
'nw': [nbax, nbay],
'ne': [nbax + nbaw, nbay],
'sw': [nbax, nbay + nbah],
'se': [nbax + nbaw, nbay + nbah],
'n': [nbax + (nbaw) / 2, nbay],
'w': [nbax, nbay + (nbah) / 2],
'e': [nbax + nbaw, nbay + (nbah) / 2],
's': [nbax + (nbaw) / 2, nbay + nbah]
};
var dir;
for (dir in this.gripCoords) {
var coords = this.gripCoords[dir];
selectedGrips[dir].setAttribute('cx', coords[0]);
selectedGrips[dir].setAttribute('cy', coords[1]);
}
// we want to go 20 pixels in the negative transformed y direction, ignoring scale
mgr.rotateGripConnector.setAttribute('x1', nbax + (nbaw)/2);
mgr.rotateGripConnector.setAttribute('y1', nbay);
mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw)/2);
mgr.rotateGripConnector.setAttribute('y2', nbay - (gripRadius*5));
// we want to go 20 pixels in the negative transformed y direction, ignoring scale
mgr.rotateGripConnector.setAttribute('x1', nbax + (nbaw) / 2);
mgr.rotateGripConnector.setAttribute('y1', nbay);
mgr.rotateGripConnector.setAttribute('x2', nbax + (nbaw) / 2);
mgr.rotateGripConnector.setAttribute('y2', nbay - (gripRadius * 5));
mgr.rotateGrip.setAttribute('cx', nbax + (nbaw)/2);
mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius*5));
// }
mgr.rotateGrip.setAttribute('cx', nbax + (nbaw) / 2);
mgr.rotateGrip.setAttribute('cy', nbay - (gripRadius * 5));
// }
};
// 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.selectorParentGroup = null;
@@ -287,13 +285,13 @@ svgedit.select.SelectorManager = function() {
// this holds a reference to the grip elements
this.selectorGrips = {
'nw': null,
'n' : null,
'n': null,
'ne': null,
'e' : null,
'e': null,
'se': null,
's' : null,
's': null,
'sw': null,
'w' : null
'w': null
};
this.selectorGripsGroup = null;
@@ -305,7 +303,7 @@ svgedit.select.SelectorManager = function() {
// Function: svgedit.select.SelectorManager.initGroup
// 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
if (this.selectorParentGroup && this.selectorParentGroup.parentNode) {
this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);
@@ -378,7 +376,7 @@ svgedit.select.SelectorManager.prototype.initGroup = function() {
);
$.data(this.rotateGrip, 'type', 'rotate');
if ($('#canvasBackground').length) {return;}
if ($('#canvasBackground').length) { return; }
var dims = config_.dimensions;
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
// 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);
svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent());
};
@@ -421,12 +419,12 @@ svgedit.select.SelectorManager.prototype.initGroup = function() {
// Parameters:
// elem - DOM element to get the selector for
// bbox - Optional bbox to use for reset (prevents duplicate getBBox call).
svgedit.select.SelectorManager.prototype.requestSelector = function(elem, bbox) {
if (elem == null) {return null;}
svgedit.select.SelectorManager.prototype.requestSelector = function (elem, bbox) {
if (elem == null) { return null; }
var i,
N = this.selectors.length;
// 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;
return this.selectorMap[elem.id];
}
@@ -450,8 +448,8 @@ svgedit.select.SelectorManager.prototype.requestSelector = function(elem, bbox)
//
// Parameters:
// elem - DOM element to remove the selector for
svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) {
if (elem == null) {return;}
svgedit.select.SelectorManager.prototype.releaseSelector = function (elem) {
if (elem == null) { return; }
var i,
N = this.selectors.length,
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
try {
sel.selectorGroup.setAttribute('display', 'none');
} catch(e) { }
} catch (e) {}
break;
}
@@ -478,7 +476,7 @@ svgedit.select.SelectorManager.prototype.releaseSelector = function(elem) {
// Function: svgedit.select.SelectorManager.getRubberBandBox
// 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) {
this.rubberBandBox = this.selectorParentGroup.appendChild(
svgFactory_.createSVGElement({
@@ -498,7 +496,6 @@ svgedit.select.SelectorManager.prototype.getRubberBandBox = function() {
return this.rubberBandBox;
};
/**
* Interface: svgedit.select.SVGFactory
* 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)
* svgFactory - an object implementing the SVGFactory interface (see above).
*/
svgedit.select.init = function(config, svgFactory) {
svgedit.select.init = function (config, svgFactory) {
config_ = config;
svgFactory_ = svgFactory;
selectorManager_ = new svgedit.select.SelectorManager();
@@ -533,8 +530,7 @@ svgedit.select.init = function(config, svgFactory) {
* Returns:
* The SelectorManager instance.
*/
svgedit.select.getSelectorManager = function() {
svgedit.select.getSelectorManager = function () {
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
@@ -19,10 +20,11 @@ svgedit = {
};
// return the svgedit.NS with key values switched and lowercase
svgedit.getReverseNS = function() {'use strict';
svgedit.getReverseNS = function () {
'use strict';
var reverseNS = {};
$.each(this.NS, function(name, URI) {
$.each(this.NS, function (name, URI) {
reverseNS[URI] = name.toLowerCase();
});
return reverseNS;
};
};

View File

@@ -1,5 +1,5 @@
/*globals $, svgedit*/
/*jslint vars: true, eqeq: true*/
/* eslint-disable no-var, eqeqeq */
/* globals $, svgedit */
/**
* SVGTransformList
*
@@ -12,7 +12,8 @@
// Dependencies:
// 1) browser.js
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.transformlist) {
svgedit.transformlist = {};
@@ -21,48 +22,49 @@ if (!svgedit.transformlist) {
var svgroot = document.createElementNS(svgedit.NS.SVG, 'svg');
// Helper function.
function transformToString(xform) {
function transformToString (xform) {
var m = xform.matrix,
text = '';
switch(xform.type) {
case 1: // MATRIX
text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')';
break;
case 2: // TRANSLATE
text = 'translate(' + m.e + ',' + m.f + ')';
break;
case 3: // SCALE
if (m.a == m.d) {text = 'scale(' + m.a + ')';}
else {text = 'scale(' + m.a + ',' + m.d + ')';}
break;
case 4: // ROTATE
var cx = 0, cy = 0;
// this prevents divide by zero
if (xform.angle != 0) {
var K = 1 - m.a;
cy = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b );
cx = ( m.e - m.b * cy ) / K;
}
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
break;
switch (xform.type) {
case 1: // MATRIX
text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')';
break;
case 2: // TRANSLATE
text = 'translate(' + m.e + ',' + m.f + ')';
break;
case 3: // SCALE
if (m.a == m.d) {
text = 'scale(' + m.a + ')';
} else {
text = 'scale(' + m.a + ',' + m.d + ')';
}
break;
case 4: // ROTATE
var cx = 0, cy = 0;
// this prevents divide by zero
if (xform.angle != 0) {
var K = 1 - m.a;
cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b);
cx = (m.e - m.b * cy) / K;
}
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
break;
}
return text;
}
/**
* Map of SVGTransformList objects.
*/
var listMap_ = {};
// **************************************************************************************
// SVGTransformList implementation for Webkit
// SVGTransformList implementation for Webkit
// These methods do not currently raise any exceptions.
// These methods also do not check that transforms are being inserted. This is basically
// implementing as much of SVGTransformList that we need to get the job done.
//
// interface SVGEditTransformList {
// interface SVGEditTransformList {
// attribute unsigned long numberOfItems;
// void clear ( )
// SVGTransform initialize ( in SVGTransform newItem )
@@ -75,13 +77,13 @@ var listMap_ = {};
// NOT IMPLEMENTED: SVGTransform consolidate ( );
// }
// **************************************************************************************
svgedit.transformlist.SVGTransformList = function(elem) {
svgedit.transformlist.SVGTransformList = function (elem) {
this._elem = elem || null;
this._xforms = [];
// TODO: how do we capture the undo-ability in the changed transform list?
this._update = function() {
this._update = function () {
var tstr = '';
var concatMatrix = svgroot.createSVGMatrix();
/* var concatMatrix = */ svgroot.createSVGMatrix();
var i;
for (i = 0; i < this.numberOfItems; ++i) {
var xform = this._list.getItem(i);
@@ -90,10 +92,10 @@ svgedit.transformlist.SVGTransformList = function(elem) {
this._elem.setAttribute('transform', tstr);
};
this._list = this;
this._init = function() {
this._init = function () {
// Transform attribute parser
var str = this._elem.getAttribute('transform');
if (!str) {return;}
if (!str) { return; }
// TODO: Add skew support in future
var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
@@ -105,20 +107,20 @@ svgedit.transformlist.SVGTransformList = function(elem) {
var x = m[1];
var bits = x.split(/\s*\(/);
var name = bits[0];
var val_bits = bits[1].match(/\s*(.*?)\s*\)/);
val_bits[1] = val_bits[1].replace(/(\d)-/g, '$1 -');
var val_arr = val_bits[1].split(/[, ]+/);
var valBits = bits[1].match(/\s*(.*?)\s*\)/);
valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -');
var valArr = valBits[1].split(/[, ]+/);
var letters = 'abcdef'.split('');
var mtx = svgroot.createSVGMatrix();
$.each(val_arr, function(i, item) {
val_arr[i] = parseFloat(item);
$.each(valArr, function (i, item) {
valArr[i] = parseFloat(item);
if (name == 'matrix') {
mtx[letters[i]] = val_arr[i];
mtx[letters[i]] = valArr[i];
}
});
var xform = svgroot.createSVGTransform();
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) {
values.push(values[0]);
@@ -132,7 +134,7 @@ svgedit.transformlist.SVGTransformList = function(elem) {
}
}
};
this._removeFromOtherLists = function(item) {
this._removeFromOtherLists = function (item) {
if (item) {
// Check if this transform is already in a transformlist, and
// remove it if so.
@@ -156,25 +158,27 @@ svgedit.transformlist.SVGTransformList = function(elem) {
};
this.numberOfItems = 0;
this.clear = function() {
this.clear = function () {
this.numberOfItems = 0;
this._xforms = [];
};
this.initialize = function(newItem) {
this.initialize = function (newItem) {
this.numberOfItems = 1;
this._removeFromOtherLists(newItem);
this._xforms = [newItem];
};
this.getItem = function(index) {
this.getItem = function (index) {
if (index < this.numberOfItems && index >= 0) {
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;
if (index >= 0) {
if (index < this.numberOfItems) {
@@ -187,22 +191,21 @@ svgedit.transformlist.SVGTransformList = function(elem) {
}
newxforms[i] = newItem;
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];
}
this.numberOfItems++;
this._xforms = newxforms;
retValue = newItem;
this._list._update();
}
else {
} else {
retValue = this._list.appendItem(newItem);
}
}
return retValue;
};
this.replaceItem = function(newItem, index) {
this.replaceItem = function (newItem, index) {
var retValue = null;
if (index < this.numberOfItems && index >= 0) {
this._removeFromOtherLists(newItem);
@@ -213,7 +216,7 @@ svgedit.transformlist.SVGTransformList = function(elem) {
return retValue;
};
this.removeItem = function(index) {
this.removeItem = function (index) {
if (index < this.numberOfItems && index >= 0) {
var retValue = this._xforms[index];
var newxforms = new Array(this.numberOfItems - 1);
@@ -221,18 +224,20 @@ svgedit.transformlist.SVGTransformList = function(elem) {
for (i = 0; i < index; ++i) {
newxforms[i] = this._xforms[i];
}
for (j = i; j < this.numberOfItems-1; ++j, ++i) {
newxforms[j] = this._xforms[i+1];
for (j = i; j < this.numberOfItems - 1; ++j, ++i) {
newxforms[j] = this._xforms[i + 1];
}
this.numberOfItems--;
this._xforms = newxforms;
this._list._update();
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._xforms.push(newItem);
this.numberOfItems++;
@@ -241,8 +246,7 @@ svgedit.transformlist.SVGTransformList = function(elem) {
};
};
svgedit.transformlist.resetListMap = function() {
svgedit.transformlist.resetListMap = function () {
listMap_ = {};
};
@@ -251,7 +255,7 @@ svgedit.transformlist.resetListMap = function() {
* Parameters:
* elem - a DOM Element
*/
svgedit.transformlist.removeElementFromListMap = function(elem) {
svgedit.transformlist.removeElementFromListMap = function (elem) {
if (elem.id && listMap_[elem.id]) {
delete listMap_[elem.id];
}
@@ -262,7 +266,7 @@ svgedit.transformlist.removeElementFromListMap = function(elem) {
//
// Parameters:
// elem - DOM element to get a transformlist from
svgedit.transformlist.getTransformList = function(elem) {
svgedit.transformlist.getTransformList = function (elem) {
if (!svgedit.browser.supportsNativeTransformLists()) {
var id = elem.id || 'temp';
var t = listMap_[id];
@@ -285,5 +289,4 @@ svgedit.transformlist.getTransformList = function(elem) {
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/
function touchHandler(event) {'use strict';
function touchHandler (event) {
'use strict';
var simulatedEvent,
touches = event.changedTouches,
first = touches[0],
type = "";
type = '';
switch (event.type) {
case "touchstart": type = "mousedown"; break;
case "touchmove": type = "mousemove"; break;
case "touchend": type = "mouseup"; break;
default: return;
case 'touchstart': type = 'mousedown'; break;
case 'touchmove': type = 'mousemove'; break;
case 'touchend': type = 'mouseup'; break;
default: return;
}
// initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// initMouseEvent(type, canBubble, cancelable, view, clickCount,
// screenX, screenY, clientX, clientY, ctrlKey,
// altKey, shiftKey, metaKey, button, relatedTarget);
simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent = document.createEvent('MouseEvent');
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/* left */, null);
if (touches.length < 2) {
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
@@ -30,4 +32,4 @@ function touchHandler(event) {'use strict';
document.addEventListener('touchstart', touchHandler, true);
document.addEventListener('touchmove', 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*/
/*jslint vars: true, eqeq: true*/
/* eslint-disable no-var */
/* globals $, svgedit */
/**
* Package: svgedit.units
*
@@ -12,7 +12,8 @@
// Dependencies:
// 1) jQuery
(function() {'use strict';
(function () {
'use strict';
if (!svgedit.units) {
svgedit.units = {};
@@ -23,8 +24,9 @@ var wAttrs = ['x', 'x1', 'cx', 'rx', 'width'];
var hAttrs = ['y', 'y1', 'cy', 'ry', 'height'];
var unitAttrs = ['r', 'radius'].concat(wAttrs, hAttrs);
// unused
/*
var unitNumMap = {
'%': 2,
'%': 2,
'em': 3,
'ex': 4,
'px': 5,
@@ -34,7 +36,7 @@ var unitNumMap = {
'pt': 9,
'pc': 10
};
*/
// Container of elements.
var elementContainer_;
@@ -60,7 +62,7 @@ var typeMap_ = {};
* Parameters:
* elementContainer - an object implementing the ElementContainer interface.
*/
svgedit.units.init = function(elementContainer) {
svgedit.units.init = function (elementContainer) {
elementContainer_ = elementContainer;
// Get correct em/ex values by creating a temporary SVG.
@@ -92,7 +94,7 @@ svgedit.units.init = function(elementContainer) {
// Function: svgedit.units.getTypeMap
// Returns the unit object with values for each unit
svgedit.units.getTypeMap = function() {
svgedit.units.getTypeMap = function () {
return typeMap_;
};
@@ -105,7 +107,7 @@ svgedit.units.getTypeMap = function() {
// Returns:
// If a string/number was given, returns a Float. If an array, return a string
// with comma-seperated floats
svgedit.units.shortFloat = function(val) {
svgedit.units.shortFloat = function (val) {
var digits = elementContainer_.getRoundDigits();
if (!isNaN(val)) {
// Note that + converts to Number
@@ -119,11 +121,11 @@ svgedit.units.shortFloat = function(val) {
// Function: svgedit.units.convertUnit
// Converts the number to given unit or baseUnit
svgedit.units.convertUnit = function(val, unit) {
svgedit.units.convertUnit = function (val, unit) {
unit = unit || elementContainer_.getBaseUnit();
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
// var val = baseVal.valueInSpecifiedUnits;
// baseVal.convertToSpecifiedUnits(1);
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
// var val = baseVal.valueInSpecifiedUnits;
// baseVal.convertToSpecifiedUnits(1);
return svgedit.units.shortFloat(val / typeMap_[unit]);
};
@@ -134,38 +136,38 @@ svgedit.units.convertUnit = function(val, unit) {
// elem - DOM element to be changed
// attr - String with the name of the attribute associated with the value
// val - String with the attribute value to convert
svgedit.units.setUnitAttr = function(elem, attr, val) {
// if (!isNaN(val)) {
// New value is a number, so check currently used unit
// var old_val = elem.getAttribute(attr);
svgedit.units.setUnitAttr = function (elem, attr, val) {
// if (!isNaN(val)) {
// New value is a number, so check currently used unit
// var old_val = elem.getAttribute(attr);
// Enable this for alternate mode
// if (old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) {
// // Old value was a number, so get unit, then convert
// var unit;
// if (old_val.substr(-1) === '%') {
// var res = getResolution();
// unit = '%';
// val *= 100;
// if (wAttrs.indexOf(attr) >= 0) {
// val = val / res.w;
// } else if (hAttrs.indexOf(attr) >= 0) {
// val = val / res.h;
// } else {
// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2);
// }
// } else {
// if (elementContainer_.getBaseUnit() !== 'px') {
// unit = elementContainer_.getBaseUnit();
// } else {
// unit = old_val.substr(-2);
// }
// val = val / typeMap_[unit];
// }
//
// val += unit;
// }
// }
// Enable this for alternate mode
// if (old_val !== null && (isNaN(old_val) || elementContainer_.getBaseUnit() !== 'px')) {
// // Old value was a number, so get unit, then convert
// var unit;
// if (old_val.substr(-1) === '%') {
// var res = getResolution();
// unit = '%';
// val *= 100;
// if (wAttrs.indexOf(attr) >= 0) {
// val = val / res.w;
// } else if (hAttrs.indexOf(attr) >= 0) {
// val = val / res.h;
// } else {
// return val / Math.sqrt((res.w*res.w) + (res.h*res.h))/Math.sqrt(2);
// }
// } else {
// if (elementContainer_.getBaseUnit() !== 'px') {
// unit = elementContainer_.getBaseUnit();
// } else {
// unit = old_val.substr(-2);
// }
// val = val / typeMap_[unit];
// }
//
// val += unit;
// }
// }
elem.setAttribute(attr, val);
};
@@ -185,11 +187,11 @@ var attrsToConvert = {
//
// Parameters:
// element - a DOM element whose attributes should be converted
svgedit.units.convertAttrs = function(element) {
svgedit.units.convertAttrs = function (element) {
var elName = element.tagName;
var unit = elementContainer_.getBaseUnit();
var attrs = attrsToConvert[elName];
if (!attrs) {return;}
if (!attrs) { return; }
var len = attrs.length;
var i;
@@ -201,26 +203,26 @@ svgedit.units.convertAttrs = function(element) {
element.setAttribute(attr, (cur / typeMap_[unit]) + unit);
}
// else {
// Convert existing?
// Convert existing?
// }
}
}
};
// 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
//
// Parameters:
// attr - String with the name of the attribute associated with the value
// val - String with the attribute value to convert
svgedit.units.convertToNum = function(attr, val) {
svgedit.units.convertToNum = function (attr, val) {
// Return a number if that's what it already is
if (!isNaN(val)) {return val-0;}
if (!isNaN(val)) { return val - 0; }
var num;
if (val.substr(-1) === '%') {
// 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 height = elementContainer_.getHeight();
@@ -230,10 +232,10 @@ svgedit.units.convertToNum = function(attr, val) {
if (hAttrs.indexOf(attr) >= 0) {
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);
num = val.substr(0, val.length-2);
num = val.substr(0, val.length - 2);
// Note that this multiplication turns the string into a number
return num * typeMap_[unit];
};
@@ -244,7 +246,7 @@ svgedit.units.convertToNum = function(attr, val) {
// Parameters:
// attr - String with the name of the attribute associated with the value
// val - String with the attribute value to check
svgedit.units.isValidUnit = function(attr, val, selectedElement) {
svgedit.units.isValidUnit = function (attr, val, selectedElement) {
var valid = false;
if (unitAttrs.indexOf(attr) >= 0) {
// True if it's just a number
@@ -253,13 +255,13 @@ svgedit.units.isValidUnit = function(attr, val, selectedElement) {
} else {
// Not a number, check if it has a valid unit
val = val.toLowerCase();
$.each(typeMap_, function(unit) {
if (valid) {return;}
$.each(typeMap_, function (unit) {
if (valid) { return; }
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
// and the id value is valid.
@@ -271,12 +273,11 @@ svgedit.units.isValidUnit = function(attr, val, selectedElement) {
try {
var elem = elementContainer_.getElement(val);
result = (elem == null || elem === selectedElement);
} catch(e) {}
} catch (e) {}
return result;
}
valid = true;
return valid;
};
}());
}());