Change all tab indentations to 2sp indentation. Addresses issue #37
parent
89cbab7217
commit
4043c6e537
|
@ -16,20 +16,20 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.browser) {
|
||||
svgedit.browser = {};
|
||||
svgedit.browser = {};
|
||||
}
|
||||
|
||||
// alias
|
||||
var NS = svgedit.NS;
|
||||
|
||||
var supportsSvg_ = (function () {
|
||||
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
|
||||
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
|
||||
}());
|
||||
|
||||
svgedit.browser.supportsSvg = function () { return supportsSvg_; };
|
||||
if (!svgedit.browser.supportsSvg()) {
|
||||
window.location = 'browser-not-supported.html';
|
||||
return;
|
||||
window.location = 'browser-not-supported.html';
|
||||
return;
|
||||
}
|
||||
|
||||
var userAgent = navigator.userAgent;
|
||||
|
@ -46,120 +46,120 @@ var isMac_ = userAgent.indexOf('Macintosh') >= 0;
|
|||
var isTouch_ = 'ontouchstart' in window;
|
||||
|
||||
var supportsSelectors_ = (function () {
|
||||
return !!svg.querySelector;
|
||||
return !!svg.querySelector;
|
||||
}());
|
||||
|
||||
var supportsXpath_ = (function () {
|
||||
return !!document.evaluate;
|
||||
return !!document.evaluate;
|
||||
}());
|
||||
|
||||
// segList functions (for FF1.5 and 2.0)
|
||||
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);
|
||||
try {
|
||||
seglist.replaceItem(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
var seglist = path.pathSegList;
|
||||
var seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.replaceItem(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
}());
|
||||
|
||||
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);
|
||||
try {
|
||||
seglist.insertItemBefore(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,10');
|
||||
var seglist = path.pathSegList;
|
||||
var seg = path.createSVGPathSegLinetoAbs(5, 5);
|
||||
try {
|
||||
seglist.insertItemBefore(seg, 1);
|
||||
return true;
|
||||
} catch (err) {}
|
||||
return false;
|
||||
}());
|
||||
|
||||
// text character positioning (for IE9)
|
||||
var supportsGoodTextCharPos_ = (function () {
|
||||
var svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgroot);
|
||||
svgcontent.setAttribute('x', 5);
|
||||
svgroot.appendChild(svgcontent);
|
||||
var text = document.createElementNS(NS.SVG, 'text');
|
||||
text.textContent = 'a';
|
||||
svgcontent.appendChild(text);
|
||||
var pos = text.getStartPositionOfChar(0).x;
|
||||
document.documentElement.removeChild(svgroot);
|
||||
return (pos === 0);
|
||||
var svgroot = document.createElementNS(NS.SVG, 'svg');
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgroot);
|
||||
svgcontent.setAttribute('x', 5);
|
||||
svgroot.appendChild(svgcontent);
|
||||
var text = document.createElementNS(NS.SVG, 'text');
|
||||
text.textContent = 'a';
|
||||
svgcontent.appendChild(text);
|
||||
var pos = text.getStartPositionOfChar(0).x;
|
||||
document.documentElement.removeChild(svgroot);
|
||||
return (pos === 0);
|
||||
}());
|
||||
|
||||
var supportsPathBBox_ = (function () {
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
|
||||
svgcontent.appendChild(path);
|
||||
var bbox = path.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
return (bbox.height > 4 && bbox.height < 5);
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
|
||||
svgcontent.appendChild(path);
|
||||
var bbox = path.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
return (bbox.height > 4 && bbox.height < 5);
|
||||
}());
|
||||
|
||||
// Support for correct bbox sizing on groups with horizontal/vertical lines
|
||||
var supportsHVLineContainerBBox_ = (function () {
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,0');
|
||||
var path2 = document.createElementNS(NS.SVG, 'path');
|
||||
path2.setAttribute('d', 'M5,0 15,0');
|
||||
var g = document.createElementNS(NS.SVG, 'g');
|
||||
g.appendChild(path);
|
||||
g.appendChild(path2);
|
||||
svgcontent.appendChild(g);
|
||||
var bbox = g.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
|
||||
return (bbox.width === 15);
|
||||
var svgcontent = document.createElementNS(NS.SVG, 'svg');
|
||||
document.documentElement.appendChild(svgcontent);
|
||||
var path = document.createElementNS(NS.SVG, 'path');
|
||||
path.setAttribute('d', 'M0,0 10,0');
|
||||
var path2 = document.createElementNS(NS.SVG, 'path');
|
||||
path2.setAttribute('d', 'M5,0 15,0');
|
||||
var g = document.createElementNS(NS.SVG, 'g');
|
||||
g.appendChild(path);
|
||||
g.appendChild(path2);
|
||||
svgcontent.appendChild(g);
|
||||
var bbox = g.getBBox();
|
||||
document.documentElement.removeChild(svgcontent);
|
||||
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
|
||||
return (bbox.width === 15);
|
||||
}());
|
||||
|
||||
var supportsEditableText_ = (function () {
|
||||
// TODO: Find better way to check support for this
|
||||
return isOpera_;
|
||||
// TODO: Find better way to check support for this
|
||||
return isOpera_;
|
||||
}());
|
||||
|
||||
var supportsGoodDecimals_ = (function () {
|
||||
// Correct decimals on clone attributes (Opera < 10.5/win/non-en)
|
||||
var rect = document.createElementNS(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' +
|
||||
'Please upgrade to the <a href="http://opera.com">latest version</a> in which the problems have been fixed.');
|
||||
}
|
||||
return retValue;
|
||||
// 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' +
|
||||
'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 rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('style', 'vector-effect:non-scaling-stroke');
|
||||
return rect.style.vectorEffect === 'non-scaling-stroke';
|
||||
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 rect = document.createElementNS(NS.SVG, 'rect');
|
||||
var rxform = rect.transform.baseVal;
|
||||
var t1 = svg.createSVGTransform();
|
||||
rxform.appendItem(t1);
|
||||
var r1 = rxform.getItem(0);
|
||||
return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
|
||||
r1.type === t1.type && r1.angle === t1.angle &&
|
||||
r1.matrix.a === t1.matrix.a &&
|
||||
r1.matrix.b === t1.matrix.b &&
|
||||
r1.matrix.c === t1.matrix.c &&
|
||||
r1.matrix.d === t1.matrix.d &&
|
||||
r1.matrix.e === t1.matrix.e &&
|
||||
r1.matrix.f === t1.matrix.f;
|
||||
var rect = document.createElementNS(NS.SVG, 'rect');
|
||||
var rxform = rect.transform.baseVal;
|
||||
var t1 = svg.createSVGTransform();
|
||||
rxform.appendItem(t1);
|
||||
var r1 = rxform.getItem(0);
|
||||
return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
|
||||
r1.type === t1.type && r1.angle === t1.angle &&
|
||||
r1.matrix.a === t1.matrix.a &&
|
||||
r1.matrix.b === t1.matrix.b &&
|
||||
r1.matrix.c === t1.matrix.c &&
|
||||
r1.matrix.d === t1.matrix.d &&
|
||||
r1.matrix.e === t1.matrix.e &&
|
||||
r1.matrix.f === t1.matrix.f;
|
||||
}());
|
||||
|
||||
// Public API
|
||||
|
|
|
@ -21,86 +21,86 @@ See svg-editor.js for documentation on using setConfig().
|
|||
|
||||
// URL OVERRIDE CONFIG
|
||||
svgEditor.setConfig({
|
||||
/**
|
||||
To override the ability for URLs to set URL-based SVG content,
|
||||
uncomment the following:
|
||||
*/
|
||||
// preventURLContentLoading: true,
|
||||
/**
|
||||
To override the ability for URLs to set other configuration (including
|
||||
extension config), uncomment the following:
|
||||
*/
|
||||
// preventAllURLConfig: true,
|
||||
/**
|
||||
To override the ability for URLs to set their own extensions,
|
||||
uncomment the following (note that if setConfig() is used in
|
||||
extension code, it will still be additive to extensions,
|
||||
however):
|
||||
*/
|
||||
// lockExtensions: true,
|
||||
/**
|
||||
To override the ability for URLs to set URL-based SVG content,
|
||||
uncomment the following:
|
||||
*/
|
||||
// preventURLContentLoading: true,
|
||||
/**
|
||||
To override the ability for URLs to set other configuration (including
|
||||
extension config), uncomment the following:
|
||||
*/
|
||||
// preventAllURLConfig: true,
|
||||
/**
|
||||
To override the ability for URLs to set their own extensions,
|
||||
uncomment the following (note that if setConfig() is used in
|
||||
extension code, it will still be additive to extensions,
|
||||
however):
|
||||
*/
|
||||
// lockExtensions: true,
|
||||
});
|
||||
|
||||
svgEditor.setConfig({
|
||||
/*
|
||||
Provide default values here which differ from that of the editor but
|
||||
which the URL can override
|
||||
*/
|
||||
/*
|
||||
Provide default values here which differ from that of the editor but
|
||||
which the URL can override
|
||||
*/
|
||||
}, {allowInitialUserOverride: true});
|
||||
|
||||
// EXTENSION CONFIG
|
||||
svgEditor.setConfig({
|
||||
extensions: [
|
||||
// 'ext-overview_window.js', 'ext-markers.js', 'ext-connector.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-imagelib.js', 'ext-grid.js', 'ext-polygon.js', 'ext-star.js', 'ext-panning.js', 'ext-storage.js'
|
||||
]
|
||||
// , noDefaultExtensions: false, // noDefaultExtensions can only be meaningfully used in config.js or in the URL
|
||||
extensions: [
|
||||
// 'ext-overview_window.js', 'ext-markers.js', 'ext-connector.js', 'ext-eyedropper.js', 'ext-shapes.js', 'ext-imagelib.js', 'ext-grid.js', 'ext-polygon.js', 'ext-star.js', 'ext-panning.js', 'ext-storage.js'
|
||||
]
|
||||
// , noDefaultExtensions: false, // noDefaultExtensions can only be meaningfully used in config.js or in the URL
|
||||
});
|
||||
|
||||
// OTHER CONFIG
|
||||
svgEditor.setConfig({
|
||||
// canvasName: 'default',
|
||||
// canvas_expansion: 3,
|
||||
// initFill: {
|
||||
// color: 'FF0000', // solid red
|
||||
// opacity: 1
|
||||
// },
|
||||
// initStroke: {
|
||||
// width: 5,
|
||||
// color: '000000', // solid black
|
||||
// opacity: 1
|
||||
// },
|
||||
// initOpacity: 1,
|
||||
// colorPickerCSS: null,
|
||||
// initTool: 'select',
|
||||
// exportWindowType: 'new', // 'same'
|
||||
// wireframe: false,
|
||||
// showlayers: false,
|
||||
// no_save_warning: false,
|
||||
// PATH CONFIGURATION
|
||||
// imgPath: 'images/',
|
||||
// langPath: 'locale/',
|
||||
// extPath: 'extensions/',
|
||||
// jGraduatePath: 'jgraduate/images/',
|
||||
/*
|
||||
Uncomment the following to allow at least same domain (embedded) access,
|
||||
including file:// access.
|
||||
Setting as `['*']` would allow any domain to access but would be unsafe to
|
||||
data privacy and integrity.
|
||||
*/
|
||||
// allowedOrigins: [window.location.origin || 'null'], // May be 'null' (as a string) when used as a file:// URL
|
||||
// DOCUMENT PROPERTIES
|
||||
// dimensions: [640, 480],
|
||||
// EDITOR OPTIONS
|
||||
// gridSnapping: false,
|
||||
// gridColor: '#000',
|
||||
// baseUnit: 'px',
|
||||
// snappingStep: 10,
|
||||
// showRulers: true,
|
||||
// EXTENSION-RELATED (GRID)
|
||||
// showGrid: false, // Set by ext-grid.js
|
||||
// EXTENSION-RELATED (STORAGE)
|
||||
// noStorageOnLoad: false, // Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
|
||||
// forceStorage: false, // Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
|
||||
// emptyStorageOnDecline: true, // Used by ext-storage.js; empty any prior storage if the user declines to store
|
||||
// canvasName: 'default',
|
||||
// canvas_expansion: 3,
|
||||
// initFill: {
|
||||
// color: 'FF0000', // solid red
|
||||
// opacity: 1
|
||||
// },
|
||||
// initStroke: {
|
||||
// width: 5,
|
||||
// color: '000000', // solid black
|
||||
// opacity: 1
|
||||
// },
|
||||
// initOpacity: 1,
|
||||
// colorPickerCSS: null,
|
||||
// initTool: 'select',
|
||||
// exportWindowType: 'new', // 'same'
|
||||
// wireframe: false,
|
||||
// showlayers: false,
|
||||
// no_save_warning: false,
|
||||
// PATH CONFIGURATION
|
||||
// imgPath: 'images/',
|
||||
// langPath: 'locale/',
|
||||
// extPath: 'extensions/',
|
||||
// jGraduatePath: 'jgraduate/images/',
|
||||
/*
|
||||
Uncomment the following to allow at least same domain (embedded) access,
|
||||
including file:// access.
|
||||
Setting as `['*']` would allow any domain to access but would be unsafe to
|
||||
data privacy and integrity.
|
||||
*/
|
||||
// allowedOrigins: [window.location.origin || 'null'], // May be 'null' (as a string) when used as a file:// URL
|
||||
// DOCUMENT PROPERTIES
|
||||
// dimensions: [640, 480],
|
||||
// EDITOR OPTIONS
|
||||
// gridSnapping: false,
|
||||
// gridColor: '#000',
|
||||
// baseUnit: 'px',
|
||||
// snappingStep: 10,
|
||||
// showRulers: true,
|
||||
// EXTENSION-RELATED (GRID)
|
||||
// showGrid: false, // Set by ext-grid.js
|
||||
// EXTENSION-RELATED (STORAGE)
|
||||
// noStorageOnLoad: false, // Some interaction with ext-storage.js; prevent even the loading of previously saved local storage
|
||||
// forceStorage: false, // Some interaction with ext-storage.js; strongly discouraged from modification as it bypasses user privacy by preventing them from choosing whether to keep local storage or not
|
||||
// emptyStorageOnDecline: true, // Used by ext-storage.js; empty any prior storage if the user declines to store
|
||||
});
|
||||
|
||||
// PREF CHANGES
|
||||
|
@ -118,29 +118,29 @@ As with configuration, one may use allowInitialUserOverride, but
|
|||
are hard-coded here regardless of URL or prior user storage setting.
|
||||
*/
|
||||
svgEditor.setConfig(
|
||||
{
|
||||
// lang: '', // Set dynamically within locale.js if not previously set
|
||||
// iconsize: '', // Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise
|
||||
/**
|
||||
* When showing the preferences dialog, svg-editor.js currently relies
|
||||
* on curPrefs instead of $.pref, so allowing an override for bkgd_color
|
||||
* means that this value won't have priority over block auto-detection as
|
||||
* far as determining which color shows initially in the preferences
|
||||
* dialog (though it can be changed and saved).
|
||||
*/
|
||||
// bkgd_color: '#FFF',
|
||||
// bkgd_url: '',
|
||||
// img_save: 'embed',
|
||||
// Only shows in UI as far as alert notices
|
||||
// save_notice_done: false,
|
||||
// export_notice_done: false
|
||||
}
|
||||
{
|
||||
// lang: '', // Set dynamically within locale.js if not previously set
|
||||
// iconsize: '', // Will default to 's' if the window height is smaller than the minimum height and 'm' otherwise
|
||||
/**
|
||||
* When showing the preferences dialog, svg-editor.js currently relies
|
||||
* on curPrefs instead of $.pref, so allowing an override for bkgd_color
|
||||
* means that this value won't have priority over block auto-detection as
|
||||
* far as determining which color shows initially in the preferences
|
||||
* dialog (though it can be changed and saved).
|
||||
*/
|
||||
// bkgd_color: '#FFF',
|
||||
// bkgd_url: '',
|
||||
// img_save: 'embed',
|
||||
// Only shows in UI as far as alert notices
|
||||
// save_notice_done: false,
|
||||
// export_notice_done: false
|
||||
}
|
||||
);
|
||||
svgEditor.setConfig(
|
||||
{
|
||||
// Indicate pref settings here if you wish to allow user storage or URL settings
|
||||
// to be able to override your default preferences (unless other config options
|
||||
// have already explicitly prevented one or the other)
|
||||
},
|
||||
{allowInitialUserOverride: true}
|
||||
{
|
||||
// Indicate pref settings here if you wish to allow user storage or URL settings
|
||||
// to be able to override your default preferences (unless other config options
|
||||
// have already explicitly prevented one or the other)
|
||||
},
|
||||
{allowInitialUserOverride: true}
|
||||
);
|
||||
|
|
|
@ -13,51 +13,51 @@ var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
|
|||
(function () {
|
||||
var self = this;
|
||||
if (!svgedit.contextmenu) {
|
||||
svgedit.contextmenu = {};
|
||||
svgedit.contextmenu = {};
|
||||
}
|
||||
self.contextMenuExtensions = {};
|
||||
var menuItemIsValid = function (menuItem) {
|
||||
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action === 'function';
|
||||
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
|
||||
// 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;
|
||||
return self.contextMenuExtensions[handlerKey] && true;
|
||||
};
|
||||
var getCustomHandler = function (handlerKey) {
|
||||
return self.contextMenuExtensions[handlerKey].action;
|
||||
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>');
|
||||
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]);
|
||||
}
|
||||
var menuItem;
|
||||
for (menuItem in self.contextMenuExtensions) {
|
||||
injectExtendedContextMenuItemIntoDom(self.contextMenuExtensions[menuItem]);
|
||||
}
|
||||
});
|
||||
svgedit.contextmenu.resetCustomMenus = function () { self.contextMenuExtensions = {}; };
|
||||
svgedit.contextmenu.add = addContextMenuItem;
|
||||
|
|
510
editor/coords.js
510
editor/coords.js
|
@ -22,12 +22,12 @@ var svgedit = svgedit || {}; // eslint-disable-line no-use-before-define
|
|||
'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'];
|
||||
'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
|
||||
|
||||
/**
|
||||
* @typedef editorContext
|
||||
|
@ -41,7 +41,7 @@ var editorContext_ = null;
|
|||
* @param {editorContext} editorContext
|
||||
*/
|
||||
svgedit.coords.init = function (editorContext) {
|
||||
editorContext_ = editorContext;
|
||||
editorContext_ = editorContext;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -51,266 +51,266 @@ svgedit.coords.init = function (editorContext) {
|
|||
* @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);
|
||||
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,
|
||||
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);
|
||||
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;
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
|
704
editor/draw.js
704
editor/draw.js
|
@ -17,7 +17,7 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.draw) {
|
||||
svgedit.draw = {};
|
||||
svgedit.draw = {};
|
||||
}
|
||||
// alias
|
||||
var NS = svgedit.NS;
|
||||
|
@ -25,9 +25,9 @@ var NS = svgedit.NS;
|
|||
var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(',');
|
||||
|
||||
var RandomizeModes = {
|
||||
LET_DOCUMENT_DECIDE: 0,
|
||||
ALWAYS_RANDOMIZE: 1,
|
||||
NEVER_RANDOMIZE: 2
|
||||
LET_DOCUMENT_DECIDE: 0,
|
||||
ALWAYS_RANDOMIZE: 1,
|
||||
NEVER_RANDOMIZE: 2
|
||||
};
|
||||
var randomizeIds = RandomizeModes.LET_DOCUMENT_DECIDE;
|
||||
|
||||
|
@ -38,15 +38,15 @@ var randomizeIds = RandomizeModes.LET_DOCUMENT_DECIDE;
|
|||
* @param {svgedit.draw.Drawing} currentDrawing
|
||||
*/
|
||||
svgedit.draw.randomizeIds = function (enableRandomization, currentDrawing) {
|
||||
randomizeIds = enableRandomization === false
|
||||
? RandomizeModes.NEVER_RANDOMIZE
|
||||
: RandomizeModes.ALWAYS_RANDOMIZE;
|
||||
randomizeIds = enableRandomization === false
|
||||
? RandomizeModes.NEVER_RANDOMIZE
|
||||
: RandomizeModes.ALWAYS_RANDOMIZE;
|
||||
|
||||
if (randomizeIds === RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) {
|
||||
currentDrawing.setNonce(Math.floor(Math.random() * 100001));
|
||||
} else if (randomizeIds === RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) {
|
||||
currentDrawing.clearNonce();
|
||||
}
|
||||
if (randomizeIds === RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) {
|
||||
currentDrawing.setNonce(Math.floor(Math.random() * 100001));
|
||||
} else if (randomizeIds === RandomizeModes.NEVER_RANDOMIZE && currentDrawing.getNonce()) {
|
||||
currentDrawing.clearNonce();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -57,72 +57,72 @@ svgedit.draw.randomizeIds = function (enableRandomization, currentDrawing) {
|
|||
* @param {String=svg_} [optIdPrefix] - The ID prefix to use.
|
||||
*/
|
||||
svgedit.draw.Drawing = function (svgElem, optIdPrefix) {
|
||||
if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI ||
|
||||
svgElem.tagName !== 'svg' || svgElem.namespaceURI !== NS.SVG) {
|
||||
throw new Error('Error: svgedit.draw.Drawing instance initialized without a <svg> element');
|
||||
}
|
||||
if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI ||
|
||||
svgElem.tagName !== 'svg' || svgElem.namespaceURI !== NS.SVG) {
|
||||
throw new Error('Error: svgedit.draw.Drawing instance initialized without a <svg> element');
|
||||
}
|
||||
|
||||
/**
|
||||
* The SVG DOM Element that represents this drawing.
|
||||
* @type {SVGSVGElement}
|
||||
*/
|
||||
this.svgElem_ = svgElem;
|
||||
/**
|
||||
* The SVG DOM Element that represents this drawing.
|
||||
* @type {SVGSVGElement}
|
||||
*/
|
||||
this.svgElem_ = svgElem;
|
||||
|
||||
/**
|
||||
* The latest object number used in this drawing.
|
||||
* @type {number}
|
||||
*/
|
||||
this.obj_num = 0;
|
||||
/**
|
||||
* The 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 = optIdPrefix || 'svg_';
|
||||
/**
|
||||
* The prefix to prepend to each element id in the drawing.
|
||||
* @type {String}
|
||||
*/
|
||||
this.idPrefix = optIdPrefix || 'svg_';
|
||||
|
||||
/**
|
||||
* An array of released element ids to immediately reuse.
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.releasedNums = [];
|
||||
/**
|
||||
* An array of released element ids to immediately reuse.
|
||||
* @type {Array.<number>}
|
||||
*/
|
||||
this.releasedNums = [];
|
||||
|
||||
/**
|
||||
* The z-ordered array of Layer objects. Each layer has a name
|
||||
* and group element.
|
||||
* The first layer is the one at the bottom of the rendering.
|
||||
* @type {Array.<Layer>}
|
||||
*/
|
||||
this.all_layers = [];
|
||||
/**
|
||||
* The z-ordered array of Layer objects. Each layer has a name
|
||||
* and group element.
|
||||
* The first layer is the one at the bottom of the rendering.
|
||||
* @type {Array.<Layer>}
|
||||
*/
|
||||
this.all_layers = [];
|
||||
|
||||
/**
|
||||
* Map of all_layers by name.
|
||||
*
|
||||
* Note: Layers are ordered, but referenced externally by name; so, we need both container
|
||||
* types depending on which function is called (i.e. all_layers and layer_map).
|
||||
*
|
||||
* @type {Object.<string, Layer>}
|
||||
*/
|
||||
this.layer_map = {};
|
||||
/**
|
||||
* Map of all_layers by name.
|
||||
*
|
||||
* Note: Layers are ordered, but referenced externally by name; so, we need both container
|
||||
* types depending on which function is called (i.e. all_layers and layer_map).
|
||||
*
|
||||
* @type {Object.<string, Layer>}
|
||||
*/
|
||||
this.layer_map = {};
|
||||
|
||||
/**
|
||||
* The current layer being used.
|
||||
* @type {Layer}
|
||||
*/
|
||||
this.current_layer = null;
|
||||
/**
|
||||
* The current layer being used.
|
||||
* @type {Layer}
|
||||
*/
|
||||
this.current_layer = null;
|
||||
|
||||
/**
|
||||
* The nonce to use to uniquely identify elements across drawings.
|
||||
* @type {!String}
|
||||
*/
|
||||
this.nonce_ = '';
|
||||
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 && randomizeIds !== RandomizeModes.NEVER_RANDOMIZE) {
|
||||
this.nonce_ = n;
|
||||
} else if (randomizeIds === RandomizeModes.ALWAYS_RANDOMIZE) {
|
||||
this.setNonce(Math.floor(Math.random() * 100001));
|
||||
}
|
||||
/**
|
||||
* The nonce to use to uniquely identify elements across drawings.
|
||||
* @type {!String}
|
||||
*/
|
||||
this.nonce_ = '';
|
||||
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 && randomizeIds !== RandomizeModes.NEVER_RANDOMIZE) {
|
||||
this.nonce_ = n;
|
||||
} else if (randomizeIds === RandomizeModes.ALWAYS_RANDOMIZE) {
|
||||
this.setNonce(Math.floor(Math.random() * 100001));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -130,44 +130,44 @@ svgedit.draw.Drawing = function (svgElem, optIdPrefix) {
|
|||
* @returns {Element} SVG element within the root SVGSVGElement
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getElem_ = function (id) {
|
||||
if (this.svgElem_.querySelector) {
|
||||
// querySelector lookup
|
||||
return this.svgElem_.querySelector('#' + id);
|
||||
}
|
||||
// jQuery lookup: twice as slow as xpath in FF
|
||||
return $(this.svgElem_).find('[id=' + id + ']')[0];
|
||||
if (this.svgElem_.querySelector) {
|
||||
// querySelector lookup
|
||||
return this.svgElem_.querySelector('#' + id);
|
||||
}
|
||||
// jQuery lookup: twice as slow as xpath in FF
|
||||
return $(this.svgElem_).find('[id=' + id + ']')[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {SVGSVGElement}
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getSvgElem = function () {
|
||||
return this.svgElem_;
|
||||
return this.svgElem_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {!string|number} The previously set nonce
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getNonce = function () {
|
||||
return this.nonce_;
|
||||
return this.nonce_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {!string|number} n The nonce to set
|
||||
*/
|
||||
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;
|
||||
this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
|
||||
this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n);
|
||||
this.nonce_ = n;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears any previously set nonce
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.clearNonce = function () {
|
||||
// We deliberately leave any se:nonce attributes alone,
|
||||
// we just don't use it to randomize ids.
|
||||
this.nonce_ = '';
|
||||
// We deliberately leave any se:nonce attributes alone,
|
||||
// we just don't use it to randomize ids.
|
||||
this.nonce_ = '';
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -175,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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -185,35 +185,35 @@ svgedit.draw.Drawing.prototype.getId = function () {
|
|||
* @return {String} The next object Id to use.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getNextId = function () {
|
||||
var oldObjNum = this.obj_num;
|
||||
var restoreOldObjNum = false;
|
||||
var oldObjNum = this.obj_num;
|
||||
var restoreOldObjNum = false;
|
||||
|
||||
// If there are any released numbers in the release stack,
|
||||
// use the last one instead of the next obj_num.
|
||||
// We need to temporarily use obj_num as that is what getId() depends on.
|
||||
if (this.releasedNums.length > 0) {
|
||||
this.obj_num = this.releasedNums.pop();
|
||||
restoreOldObjNum = true;
|
||||
} else {
|
||||
// If we are not using a released id, then increment the obj_num.
|
||||
this.obj_num++;
|
||||
}
|
||||
// If there are any released numbers in the release stack,
|
||||
// use the last one instead of the next obj_num.
|
||||
// We need to temporarily use obj_num as that is what getId() depends on.
|
||||
if (this.releasedNums.length > 0) {
|
||||
this.obj_num = this.releasedNums.pop();
|
||||
restoreOldObjNum = true;
|
||||
} else {
|
||||
// If we are not using a released id, then increment the obj_num.
|
||||
this.obj_num++;
|
||||
}
|
||||
|
||||
// Ensure the ID does not exist.
|
||||
var id = this.getId();
|
||||
while (this.getElem_(id)) {
|
||||
if (restoreOldObjNum) {
|
||||
this.obj_num = oldObjNum;
|
||||
restoreOldObjNum = false;
|
||||
}
|
||||
this.obj_num++;
|
||||
id = this.getId();
|
||||
}
|
||||
// Restore the old object number if required.
|
||||
if (restoreOldObjNum) {
|
||||
this.obj_num = oldObjNum;
|
||||
}
|
||||
return id;
|
||||
// Ensure the ID does not exist.
|
||||
var id = this.getId();
|
||||
while (this.getElem_(id)) {
|
||||
if (restoreOldObjNum) {
|
||||
this.obj_num = oldObjNum;
|
||||
restoreOldObjNum = false;
|
||||
}
|
||||
this.obj_num++;
|
||||
id = this.getId();
|
||||
}
|
||||
// Restore the old object number if required.
|
||||
if (restoreOldObjNum) {
|
||||
this.obj_num = oldObjNum;
|
||||
}
|
||||
return id;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -224,24 +224,24 @@ svgedit.draw.Drawing.prototype.getNextId = function () {
|
|||
* @returns {boolean} True if the id was valid to be released, false otherwise.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.releaseId = function (id) {
|
||||
// confirm if this is a valid id for this Document, else return false
|
||||
var front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : '');
|
||||
if (typeof id !== 'string' || id.indexOf(front) !== 0) {
|
||||
return false;
|
||||
}
|
||||
// extract the obj_num of this id
|
||||
var num = parseInt(id.substr(front.length), 10);
|
||||
// confirm if this is a valid id for this Document, else return false
|
||||
var front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : '');
|
||||
if (typeof id !== 'string' || id.indexOf(front) !== 0) {
|
||||
return false;
|
||||
}
|
||||
// extract the obj_num of this id
|
||||
var num = parseInt(id.substr(front.length), 10);
|
||||
|
||||
// if we didn't get a positive number or we already released this number
|
||||
// then return false.
|
||||
if (typeof num !== 'number' || num <= 0 || this.releasedNums.indexOf(num) !== -1) {
|
||||
return false;
|
||||
}
|
||||
// if we didn't get a positive number or we already released this number
|
||||
// then return false.
|
||||
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);
|
||||
// push the released number into the released queue
|
||||
this.releasedNums.push(num);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -249,7 +249,7 @@ svgedit.draw.Drawing.prototype.releaseId = function (id) {
|
|||
* @returns {integer} The number of layers in the current drawing.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getNumLayers = function () {
|
||||
return this.all_layers.length;
|
||||
return this.all_layers.length;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -257,7 +257,7 @@ svgedit.draw.Drawing.prototype.getNumLayers = function () {
|
|||
* @param {string} name - The layer name to check
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.hasLayer = function (name) {
|
||||
return this.layer_map[name] !== undefined;
|
||||
return this.layer_map[name] !== undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -266,14 +266,14 @@ svgedit.draw.Drawing.prototype.hasLayer = function (name) {
|
|||
* @returns {string} The name of the ith layer (or the empty string if none found)
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getLayerName = function (i) {
|
||||
return i >= 0 && i < this.getNumLayers() ? this.all_layers[i].getName() : '';
|
||||
return i >= 0 && i < this.getNumLayers() ? this.all_layers[i].getName() : '';
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {SVGGElement} The SVGGElement representing the current layer.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getCurrentLayer = function () {
|
||||
return this.current_layer ? this.current_layer.getGroup() : null;
|
||||
return this.current_layer ? this.current_layer.getGroup() : null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -281,8 +281,8 @@ svgedit.draw.Drawing.prototype.getCurrentLayer = function () {
|
|||
* @returns {SVGGElement} The SVGGElement representing the named layer or null.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getLayerByName = function (name) {
|
||||
var layer = this.layer_map[name];
|
||||
return layer ? layer.getGroup() : null;
|
||||
var layer = this.layer_map[name];
|
||||
return layer ? layer.getGroup() : null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -291,7 +291,7 @@ svgedit.draw.Drawing.prototype.getLayerByName = function (name) {
|
|||
* @returns {string} The name of the currently active layer (or the empty string if none found).
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getCurrentLayerName = function () {
|
||||
return this.current_layer ? this.current_layer.getName() : '';
|
||||
return this.current_layer ? this.current_layer.getName() : '';
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -301,16 +301,16 @@ svgedit.draw.Drawing.prototype.getCurrentLayerName = function () {
|
|||
* @returns {string|null} The new name if changed; otherwise, null.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.setCurrentLayerName = function (name, hrService) {
|
||||
var finalName = null;
|
||||
if (this.current_layer) {
|
||||
var oldName = this.current_layer.getName();
|
||||
finalName = this.current_layer.setName(name, hrService);
|
||||
if (finalName) {
|
||||
delete this.layer_map[oldName];
|
||||
this.layer_map[finalName] = this.current_layer;
|
||||
}
|
||||
}
|
||||
return finalName;
|
||||
var finalName = null;
|
||||
if (this.current_layer) {
|
||||
var oldName = this.current_layer.getName();
|
||||
finalName = this.current_layer.setName(name, hrService);
|
||||
if (finalName) {
|
||||
delete this.layer_map[oldName];
|
||||
this.layer_map[finalName] = this.current_layer;
|
||||
}
|
||||
}
|
||||
return finalName;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -319,89 +319,89 @@ 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 layerCount = this.getNumLayers();
|
||||
if (!this.current_layer || newpos < 0 || newpos >= layerCount) {
|
||||
return null;
|
||||
}
|
||||
var layerCount = this.getNumLayers();
|
||||
if (!this.current_layer || newpos < 0 || newpos >= layerCount) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var oldpos;
|
||||
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 === layerCount) { return null; }
|
||||
var oldpos;
|
||||
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 === 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 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 {
|
||||
refGroup = this.all_layers[newpos].getGroup();
|
||||
}
|
||||
this.svgElem_.insertBefore(currentGroup, refGroup);
|
||||
if (oldpos !== newpos) {
|
||||
// if our new position is below us, we need to insert before the node after newpos
|
||||
var refGroup = null;
|
||||
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 {
|
||||
refGroup = this.all_layers[newpos].getGroup();
|
||||
}
|
||||
this.svgElem_.insertBefore(currentGroup, refGroup);
|
||||
|
||||
this.identifyLayers();
|
||||
this.setCurrentLayer(this.getLayerName(newpos));
|
||||
this.identifyLayers();
|
||||
this.setCurrentLayer(this.getLayerName(newpos));
|
||||
|
||||
return {
|
||||
currentGroup: currentGroup,
|
||||
oldNextSibling: oldNextSibling
|
||||
};
|
||||
}
|
||||
return null;
|
||||
return {
|
||||
currentGroup: currentGroup,
|
||||
oldNextSibling: oldNextSibling
|
||||
};
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
svgedit.draw.Drawing.prototype.mergeLayer = function (hrService) {
|
||||
var currentGroup = this.current_layer.getGroup();
|
||||
var prevGroup = $(currentGroup).prev()[0];
|
||||
if (!prevGroup) { return; }
|
||||
var currentGroup = this.current_layer.getGroup();
|
||||
var prevGroup = $(currentGroup).prev()[0];
|
||||
if (!prevGroup) { return; }
|
||||
|
||||
hrService.startBatchCommand('Merge Layer');
|
||||
hrService.startBatchCommand('Merge Layer');
|
||||
|
||||
var layerNextSibling = currentGroup.nextSibling;
|
||||
hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_);
|
||||
var layerNextSibling = currentGroup.nextSibling;
|
||||
hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_);
|
||||
|
||||
while (currentGroup.firstChild) {
|
||||
var child = currentGroup.firstChild;
|
||||
if (child.localName === 'title') {
|
||||
hrService.removeElement(child, child.nextSibling, currentGroup);
|
||||
currentGroup.removeChild(child);
|
||||
continue;
|
||||
}
|
||||
var oldNextSibling = child.nextSibling;
|
||||
prevGroup.appendChild(child);
|
||||
hrService.moveElement(child, oldNextSibling, currentGroup);
|
||||
}
|
||||
while (currentGroup.firstChild) {
|
||||
var child = currentGroup.firstChild;
|
||||
if (child.localName === 'title') {
|
||||
hrService.removeElement(child, child.nextSibling, currentGroup);
|
||||
currentGroup.removeChild(child);
|
||||
continue;
|
||||
}
|
||||
var oldNextSibling = child.nextSibling;
|
||||
prevGroup.appendChild(child);
|
||||
hrService.moveElement(child, oldNextSibling, currentGroup);
|
||||
}
|
||||
|
||||
// Remove current layer's group
|
||||
this.current_layer.removeGroup();
|
||||
// Remove the current layer and set the previous layer as the new current layer
|
||||
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.all_layers.splice(index, 1);
|
||||
delete this.layer_map[name];
|
||||
}
|
||||
// Remove current layer's group
|
||||
this.current_layer.removeGroup();
|
||||
// Remove the current layer and set the previous layer as the new current layer
|
||||
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.all_layers.splice(index, 1);
|
||||
delete this.layer_map[name];
|
||||
}
|
||||
|
||||
hrService.endBatchCommand();
|
||||
hrService.endBatchCommand();
|
||||
};
|
||||
|
||||
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];
|
||||
// Set the current layer to the last layer.
|
||||
this.current_layer = this.all_layers[this.all_layers.length - 1];
|
||||
|
||||
hrService.startBatchCommand('Merge all Layers');
|
||||
while (this.all_layers.length > 1) {
|
||||
this.mergeLayer(hrService);
|
||||
}
|
||||
hrService.endBatchCommand();
|
||||
hrService.startBatchCommand('Merge all Layers');
|
||||
while (this.all_layers.length > 1) {
|
||||
this.mergeLayer(hrService);
|
||||
}
|
||||
hrService.endBatchCommand();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -412,16 +412,16 @@ svgedit.draw.Drawing.prototype.mergeAllLayers = function (hrService) {
|
|||
* @returns {boolean} true if the current layer was switched, otherwise false
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.setCurrentLayer = function (name) {
|
||||
var layer = this.layer_map[name];
|
||||
if (layer) {
|
||||
if (this.current_layer) {
|
||||
this.current_layer.deactivate();
|
||||
}
|
||||
this.current_layer = layer;
|
||||
this.current_layer.activate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
var layer = this.layer_map[name];
|
||||
if (layer) {
|
||||
if (this.current_layer) {
|
||||
this.current_layer.deactivate();
|
||||
}
|
||||
this.current_layer = layer;
|
||||
this.current_layer.activate();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -430,12 +430,12 @@ svgedit.draw.Drawing.prototype.setCurrentLayer = function (name) {
|
|||
* @returns {SVGGElement} The SVGGElement of the layer removed or null.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.deleteCurrentLayer = function () {
|
||||
if (this.current_layer && this.getNumLayers() > 1) {
|
||||
var oldLayerGroup = this.current_layer.removeGroup();
|
||||
this.identifyLayers();
|
||||
return oldLayerGroup;
|
||||
}
|
||||
return null;
|
||||
if (this.current_layer && this.getNumLayers() > 1) {
|
||||
var oldLayerGroup = this.current_layer.removeGroup();
|
||||
this.identifyLayers();
|
||||
return oldLayerGroup;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -444,13 +444,13 @@ svgedit.draw.Drawing.prototype.deleteCurrentLayer = function () {
|
|||
* @returns {string} The layer name or empty string.
|
||||
*/
|
||||
function findLayerNameInGroup (group) {
|
||||
var name = $('title', group).text();
|
||||
var name = $('title', group).text();
|
||||
|
||||
// Hack for Opera 10.60
|
||||
if (!name && svgedit.browser.isOpera() && group.querySelectorAll) {
|
||||
name = $(group.querySelectorAll('title')).text();
|
||||
}
|
||||
return name;
|
||||
// Hack for Opera 10.60
|
||||
if (!name && svgedit.browser.isOpera() && group.querySelectorAll) {
|
||||
name = $(group.querySelectorAll('title')).text();
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -459,10 +459,10 @@ function findLayerNameInGroup (group) {
|
|||
* @returns {string} - The new name.
|
||||
*/
|
||||
function getNewLayerName (existingLayerNames) {
|
||||
var i = 1;
|
||||
// TODO(codedread): What about internationalization of "Layer"?
|
||||
while (existingLayerNames.indexOf(('Layer ' + i)) >= 0) { i++; }
|
||||
return 'Layer ' + i;
|
||||
var i = 1;
|
||||
// TODO(codedread): What about internationalization of "Layer"?
|
||||
while (existingLayerNames.indexOf(('Layer ' + i)) >= 0) { i++; }
|
||||
return 'Layer ' + i;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -470,46 +470,46 @@ function getNewLayerName (existingLayerNames) {
|
|||
* top-most layer (last <g> child of this drawing).
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.identifyLayers = function () {
|
||||
this.all_layers = [];
|
||||
this.layer_map = {};
|
||||
var numchildren = this.svgElem_.childNodes.length;
|
||||
// loop through all children of SVG element
|
||||
var orphans = [], layernames = [];
|
||||
var layer = null;
|
||||
var childgroups = false;
|
||||
for (var i = 0; i < numchildren; ++i) {
|
||||
var child = this.svgElem_.childNodes.item(i);
|
||||
// for each g, find its layer name
|
||||
if (child && child.nodeType === 1) {
|
||||
if (child.tagName === 'g') {
|
||||
childgroups = true;
|
||||
var name = findLayerNameInGroup(child);
|
||||
if (name) {
|
||||
layernames.push(name);
|
||||
layer = new svgedit.draw.Layer(name, child);
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
} else {
|
||||
// if group did not have a name, it is an orphan
|
||||
orphans.push(child);
|
||||
}
|
||||
} else if (~visElems.indexOf(child.nodeName)) {
|
||||
// Child is "visible" (i.e. not a <title> or <defs> element), so it is an orphan
|
||||
orphans.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.all_layers = [];
|
||||
this.layer_map = {};
|
||||
var numchildren = this.svgElem_.childNodes.length;
|
||||
// loop through all children of SVG element
|
||||
var orphans = [], layernames = [];
|
||||
var layer = null;
|
||||
var childgroups = false;
|
||||
for (var i = 0; i < numchildren; ++i) {
|
||||
var child = this.svgElem_.childNodes.item(i);
|
||||
// for each g, find its layer name
|
||||
if (child && child.nodeType === 1) {
|
||||
if (child.tagName === 'g') {
|
||||
childgroups = true;
|
||||
var name = findLayerNameInGroup(child);
|
||||
if (name) {
|
||||
layernames.push(name);
|
||||
layer = new svgedit.draw.Layer(name, child);
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
} else {
|
||||
// if group did not have a name, it is an orphan
|
||||
orphans.push(child);
|
||||
}
|
||||
} else if (~visElems.indexOf(child.nodeName)) {
|
||||
// Child is "visible" (i.e. not a <title> or <defs> element), so it is an orphan
|
||||
orphans.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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_);
|
||||
layer.appendChildren(orphans);
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
} else {
|
||||
layer.activate();
|
||||
}
|
||||
this.current_layer = layer;
|
||||
// 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_);
|
||||
layer.appendChildren(orphans);
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
} else {
|
||||
layer.activate();
|
||||
}
|
||||
this.current_layer = layer;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -521,27 +521,27 @@ svgedit.draw.Drawing.prototype.identifyLayers = function () {
|
|||
* also the current layer of this drawing.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.createLayer = function (name, hrService) {
|
||||
if (this.current_layer) {
|
||||
this.current_layer.deactivate();
|
||||
}
|
||||
// Check for duplicate name.
|
||||
if (name === undefined || name === null || name === '' || this.layer_map[name]) {
|
||||
name = getNewLayerName(Object.keys(this.layer_map));
|
||||
}
|
||||
if (this.current_layer) {
|
||||
this.current_layer.deactivate();
|
||||
}
|
||||
// Check for duplicate name.
|
||||
if (name === undefined || name === null || name === '' || this.layer_map[name]) {
|
||||
name = getNewLayerName(Object.keys(this.layer_map));
|
||||
}
|
||||
|
||||
// Crate new layer and add to DOM as last layer
|
||||
var layer = new svgedit.draw.Layer(name, null, this.svgElem_);
|
||||
// Like to assume hrService exists, but this is backwards compatible with old version of createLayer.
|
||||
if (hrService) {
|
||||
hrService.startBatchCommand('Create Layer');
|
||||
hrService.insertElement(layer.getGroup());
|
||||
hrService.endBatchCommand();
|
||||
}
|
||||
// Crate new layer and add to DOM as last layer
|
||||
var layer = new svgedit.draw.Layer(name, null, this.svgElem_);
|
||||
// Like to assume hrService exists, but this is backwards compatible with old version of createLayer.
|
||||
if (hrService) {
|
||||
hrService.startBatchCommand('Create Layer');
|
||||
hrService.insertElement(layer.getGroup());
|
||||
hrService.endBatchCommand();
|
||||
}
|
||||
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
this.current_layer = layer;
|
||||
return layer.getGroup();
|
||||
this.all_layers.push(layer);
|
||||
this.layer_map[name] = layer;
|
||||
this.current_layer = layer;
|
||||
return layer.getGroup();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -552,43 +552,43 @@ svgedit.draw.Drawing.prototype.createLayer = function (name, hrService) {
|
|||
* also the current layer of this drawing.
|
||||
*/
|
||||
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]) {
|
||||
name = getNewLayerName(Object.keys(this.layer_map));
|
||||
}
|
||||
if (!this.current_layer) { return null; }
|
||||
this.current_layer.deactivate();
|
||||
// Check for duplicate name.
|
||||
if (name === undefined || name === null || name === '' || this.layer_map[name]) {
|
||||
name = getNewLayerName(Object.keys(this.layer_map));
|
||||
}
|
||||
|
||||
// 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();
|
||||
// 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();
|
||||
|
||||
// Clone children
|
||||
var children = currentGroup.childNodes;
|
||||
var index;
|
||||
for (index = 0; index < children.length; index++) {
|
||||
var ch = children[index];
|
||||
if (ch.localName === 'title') { continue; }
|
||||
group.appendChild(this.copyElem(ch));
|
||||
}
|
||||
// Clone children
|
||||
var children = currentGroup.childNodes;
|
||||
var index;
|
||||
for (index = 0; index < children.length; index++) {
|
||||
var ch = children[index];
|
||||
if (ch.localName === 'title') { continue; }
|
||||
group.appendChild(this.copyElem(ch));
|
||||
}
|
||||
|
||||
if (hrService) {
|
||||
hrService.startBatchCommand('Duplicate Layer');
|
||||
hrService.insertElement(group);
|
||||
hrService.endBatchCommand();
|
||||
}
|
||||
if (hrService) {
|
||||
hrService.startBatchCommand('Duplicate Layer');
|
||||
hrService.insertElement(group);
|
||||
hrService.endBatchCommand();
|
||||
}
|
||||
|
||||
// Update layer containers and current_layer.
|
||||
index = this.all_layers.indexOf(this.current_layer);
|
||||
if (index >= 0) {
|
||||
this.all_layers.splice(index + 1, 0, layer);
|
||||
} else {
|
||||
this.all_layers.push(layer);
|
||||
}
|
||||
this.layer_map[name] = layer;
|
||||
this.current_layer = layer;
|
||||
return group;
|
||||
// Update layer containers and current_layer.
|
||||
index = this.all_layers.indexOf(this.current_layer);
|
||||
if (index >= 0) {
|
||||
this.all_layers.splice(index + 1, 0, layer);
|
||||
} else {
|
||||
this.all_layers.push(layer);
|
||||
}
|
||||
this.layer_map[name] = layer;
|
||||
this.current_layer = layer;
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -598,8 +598,8 @@ svgedit.draw.Drawing.prototype.cloneLayer = function (name, hrService) {
|
|||
* @returns {boolean} The visibility state of the layer, or false if the layer name was invalid.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getLayerVisibility = function (layername) {
|
||||
var layer = this.layer_map[layername];
|
||||
return layer ? layer.isVisible() : false;
|
||||
var layer = this.layer_map[layername];
|
||||
return layer ? layer.isVisible() : false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -612,13 +612,13 @@ svgedit.draw.Drawing.prototype.getLayerVisibility = function (layername) {
|
|||
* layername was valid, otherwise null.
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.setLayerVisibility = function (layername, bVisible) {
|
||||
if (typeof bVisible !== 'boolean') {
|
||||
return null;
|
||||
}
|
||||
var layer = this.layer_map[layername];
|
||||
if (!layer) { return null; }
|
||||
layer.setVisible(bVisible);
|
||||
return layer.getGroup();
|
||||
if (typeof bVisible !== 'boolean') {
|
||||
return null;
|
||||
}
|
||||
var layer = this.layer_map[layername];
|
||||
if (!layer) { return null; }
|
||||
layer.setVisible(bVisible);
|
||||
return layer.getGroup();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -628,9 +628,9 @@ svgedit.draw.Drawing.prototype.setLayerVisibility = function (layername, bVisibl
|
|||
* if layername is not a valid layer
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.getLayerOpacity = function (layername) {
|
||||
var layer = this.layer_map[layername];
|
||||
if (!layer) { return null; }
|
||||
return layer.getOpacity();
|
||||
var layer = this.layer_map[layername];
|
||||
if (!layer) { return null; }
|
||||
return layer.getOpacity();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -641,13 +641,13 @@ svgedit.draw.Drawing.prototype.getLayerOpacity = function (layername) {
|
|||
* @param {number} opacity - A float value in the range 0.0-1.0
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.setLayerOpacity = function (layername, opacity) {
|
||||
if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) {
|
||||
return;
|
||||
}
|
||||
var layer = this.layer_map[layername];
|
||||
if (layer) {
|
||||
layer.setOpacity(opacity);
|
||||
}
|
||||
if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) {
|
||||
return;
|
||||
}
|
||||
var layer = this.layer_map[layername];
|
||||
if (layer) {
|
||||
layer.setOpacity(opacity);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -656,8 +656,8 @@ svgedit.draw.Drawing.prototype.setLayerOpacity = function (layername, opacity) {
|
|||
* @returns {Element}
|
||||
*/
|
||||
svgedit.draw.Drawing.prototype.copyElem = function (el) {
|
||||
var self = this;
|
||||
var getNextIdClosure = function () { return self.getNextId(); };
|
||||
return svgedit.utilities.copyElem(el, getNextIdClosure);
|
||||
var self = this;
|
||||
var getNextIdClosure = function () { return self.getNextId(); };
|
||||
return svgedit.utilities.copyElem(el, getNextIdClosure);
|
||||
};
|
||||
}());
|
||||
|
|
|
@ -5,76 +5,76 @@ 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';
|
||||
'use strict';
|
||||
|
||||
var svgCanvas = null;
|
||||
var frame;
|
||||
var svgCanvas = null;
|
||||
var frame;
|
||||
|
||||
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';
|
||||
};
|
||||
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 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 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 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 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 saveSvg () {
|
||||
svgCanvas.getSvgString()(handleSvgData);
|
||||
}
|
||||
|
||||
function exportPNG () {
|
||||
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
function exportPDF () {
|
||||
var str = frame.contentWindow.svgEditor.uiStrings.notification.loadingImage;
|
||||
|
||||
/**
|
||||
// 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;
|
||||
*/
|
||||
/**
|
||||
// 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'
|
||||
);
|
||||
svgCanvas.exportPDF(exportWindow.name);
|
||||
}
|
||||
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');
|
||||
});
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Embed API</title>
|
||||
<script src="jquery.js"></script>
|
||||
<script src="embedapi.js"></script>
|
||||
<script src="embedapi-dom.js"></script>
|
||||
<meta charset="utf-8" />
|
||||
<title>Embed API</title>
|
||||
<script src="jquery.js"></script>
|
||||
<script src="embedapi.js"></script>
|
||||
<script src="embedapi-dom.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<button id="load">Load example</button>
|
||||
<button id="save">Save data</button>
|
||||
<button id="exportPNG">Export data to PNG</button>
|
||||
<button id="exportPDF">Export data to PDF</button>
|
||||
<br/>
|
||||
<button id="load">Load example</button>
|
||||
<button id="save">Save data</button>
|
||||
<button id="exportPNG">Export data to PNG</button>
|
||||
<button id="exportPDF">Export data to PDF</button>
|
||||
<br/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -10,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){
|
||||
// There was an error
|
||||
} else{
|
||||
// Handle data
|
||||
}
|
||||
if (error){
|
||||
// There was an error
|
||||
} else{
|
||||
// Handle data
|
||||
}
|
||||
})
|
||||
|
||||
Everything is done with the same API as the real svg-edit,
|
||||
|
@ -42,15 +42,15 @@ blah.clearSelection('woot', 'blah', 1337, [1, 2, 3, 4, 5, 'moo'], -42, {a: 'tree
|
|||
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
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -59,38 +59,38 @@ 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) {
|
||||
return function (e) {
|
||||
messageListener.call(t, e);
|
||||
};
|
||||
return function (e) {
|
||||
messageListener.call(t, e);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -100,77 +100,77 @@ 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]);
|
||||
}
|
||||
// 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);
|
||||
// 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++;
|
||||
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
|
||||
|
|
|
@ -17,15 +17,15 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.history) {
|
||||
svgedit.history = {};
|
||||
svgedit.history = {};
|
||||
}
|
||||
|
||||
// Group: Undo/Redo history management
|
||||
svgedit.history.HistoryEventTypes = {
|
||||
BEFORE_APPLY: 'before_apply',
|
||||
AFTER_APPLY: 'after_apply',
|
||||
BEFORE_UNAPPLY: 'before_unapply',
|
||||
AFTER_UNAPPLY: 'after_unapply'
|
||||
BEFORE_APPLY: 'before_apply',
|
||||
AFTER_APPLY: 'after_apply',
|
||||
BEFORE_UNAPPLY: 'before_unapply',
|
||||
AFTER_UNAPPLY: 'after_unapply'
|
||||
};
|
||||
|
||||
// var removedElements = {};
|
||||
|
@ -63,18 +63,18 @@ svgedit.history.HistoryEventTypes = {
|
|||
* @param {string} [text] - An optional string visible to user related to this change
|
||||
*/
|
||||
svgedit.history.MoveElementCommand = function (elem, oldNextSibling, oldParent, text) {
|
||||
this.elem = elem;
|
||||
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;
|
||||
this.elem = elem;
|
||||
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.prototype.type = svgedit.history.MoveElementCommand.type;
|
||||
|
||||
svgedit.history.MoveElementCommand.prototype.getText = function () {
|
||||
return this.text;
|
||||
return this.text;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -82,16 +82,16 @@ svgedit.history.MoveElementCommand.prototype.getText = function () {
|
|||
* @param {handleHistoryEvent: function}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
// TODO(codedread): Refactor this common event code into a base HistoryCommand class.
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
|
||||
this.elem = this.newParent.insertBefore(this.elem, this.newNextSibling);
|
||||
this.elem = this.newParent.insertBefore(this.elem, this.newNextSibling);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -99,21 +99,21 @@ svgedit.history.MoveElementCommand.prototype.apply = function (handler) {
|
|||
* @param {handleHistoryEvent: function}
|
||||
*/
|
||||
svgedit.history.MoveElementCommand.prototype.unapply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
|
||||
this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling);
|
||||
this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.MoveElementCommand.elements
|
||||
// Returns array with element associated with this command
|
||||
svgedit.history.MoveElementCommand.prototype.elements = function () {
|
||||
return [this.elem];
|
||||
return [this.elem];
|
||||
};
|
||||
|
||||
// Class: svgedit.history.InsertElementCommand
|
||||
|
@ -124,52 +124,52 @@ svgedit.history.MoveElementCommand.prototype.elements = function () {
|
|||
// elem - The newly added DOM element
|
||||
// text - An optional string visible to user related to this change
|
||||
svgedit.history.InsertElementCommand = function (elem, text) {
|
||||
this.elem = elem;
|
||||
this.text = text || ('Create ' + elem.tagName);
|
||||
this.parent = elem.parentNode;
|
||||
this.nextSibling = this.elem.nextSibling;
|
||||
this.elem = elem;
|
||||
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.prototype.type = svgedit.history.InsertElementCommand.type;
|
||||
|
||||
// Function: svgedit.history.InsertElementCommand.getText
|
||||
svgedit.history.InsertElementCommand.prototype.getText = function () {
|
||||
return this.text;
|
||||
return this.text;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.InsertElementCommand.apply
|
||||
// Re-Inserts the new element
|
||||
svgedit.history.InsertElementCommand.prototype.apply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
|
||||
this.elem = this.parent.insertBefore(this.elem, this.nextSibling);
|
||||
this.elem = this.parent.insertBefore(this.elem, this.nextSibling);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.InsertElementCommand.unapply
|
||||
// Removes the element
|
||||
svgedit.history.InsertElementCommand.prototype.unapply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
|
||||
this.parent = this.elem.parentNode;
|
||||
this.elem = this.elem.parentNode.removeChild(this.elem);
|
||||
this.parent = this.elem.parentNode;
|
||||
this.elem = this.elem.parentNode.removeChild(this.elem);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.InsertElementCommand.elements
|
||||
// Returns array with element associated with this command
|
||||
svgedit.history.InsertElementCommand.prototype.elements = function () {
|
||||
return [this.elem];
|
||||
return [this.elem];
|
||||
};
|
||||
|
||||
// Class: svgedit.history.RemoveElementCommand
|
||||
|
@ -182,62 +182,62 @@ svgedit.history.InsertElementCommand.prototype.elements = function () {
|
|||
// 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) {
|
||||
this.elem = elem;
|
||||
this.text = text || ('Delete ' + elem.tagName);
|
||||
this.nextSibling = oldNextSibling;
|
||||
this.parent = oldParent;
|
||||
this.elem = elem;
|
||||
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);
|
||||
// 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.prototype.type = svgedit.history.RemoveElementCommand.type;
|
||||
|
||||
// Function: svgedit.history.RemoveElementCommand.getText
|
||||
svgedit.history.RemoveElementCommand.prototype.getText = function () {
|
||||
return this.text;
|
||||
return this.text;
|
||||
};
|
||||
|
||||
// Function: RemoveElementCommand.apply
|
||||
// Re-removes the new element
|
||||
svgedit.history.RemoveElementCommand.prototype.apply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
|
||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||
this.parent = this.elem.parentNode;
|
||||
this.elem = this.parent.removeChild(this.elem);
|
||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||
this.parent = this.elem.parentNode;
|
||||
this.elem = this.parent.removeChild(this.elem);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: RemoveElementCommand.unapply
|
||||
// Re-adds the new element
|
||||
svgedit.history.RemoveElementCommand.prototype.unapply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
|
||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||
if (this.nextSibling == null) {
|
||||
if (window.console) {
|
||||
console.log('Error: reference element was lost');
|
||||
}
|
||||
}
|
||||
this.parent.insertBefore(this.elem, this.nextSibling);
|
||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||
if (this.nextSibling == null) {
|
||||
if (window.console) {
|
||||
console.log('Error: reference element was lost');
|
||||
}
|
||||
}
|
||||
this.parent.insertBefore(this.elem, this.nextSibling);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: RemoveElementCommand.elements
|
||||
// Returns array with element associated with this command
|
||||
svgedit.history.RemoveElementCommand.prototype.elements = function () {
|
||||
return [this.elem];
|
||||
return [this.elem];
|
||||
};
|
||||
|
||||
// Class: svgedit.history.ChangeElementCommand
|
||||
|
@ -250,135 +250,135 @@ svgedit.history.RemoveElementCommand.prototype.elements = function () {
|
|||
// 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) {
|
||||
this.elem = elem;
|
||||
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);
|
||||
}
|
||||
}
|
||||
this.elem = elem;
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
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 () {
|
||||
return this.text;
|
||||
return this.text;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.ChangeElementCommand.apply
|
||||
// Performs the stored change action
|
||||
svgedit.history.ChangeElementCommand.prototype.apply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
|
||||
var bChangedTransform = false;
|
||||
var attr;
|
||||
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 = '';
|
||||
} else {
|
||||
this.elem.setAttribute(attr, '');
|
||||
this.elem.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
var bChangedTransform = false;
|
||||
var attr;
|
||||
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 = '';
|
||||
} 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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
// relocate rotational transform, if necessary
|
||||
if (!bChangedTransform) {
|
||||
var angle = svgedit.utilities.getRotationAngle(this.elem);
|
||||
if (angle) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.ChangeElementCommand.unapply
|
||||
// Reverses the stored change action
|
||||
svgedit.history.ChangeElementCommand.prototype.unapply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
|
||||
var bChangedTransform = false;
|
||||
var attr;
|
||||
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 {
|
||||
this.elem.setAttribute(attr, this.oldValues[attr]);
|
||||
}
|
||||
} else {
|
||||
if (attr === '#text') {
|
||||
this.elem.textContent = '';
|
||||
} else {
|
||||
this.elem.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
if (attr === 'transform') { bChangedTransform = true; }
|
||||
}
|
||||
// relocate rotational transform, if necessary
|
||||
if (!bChangedTransform) {
|
||||
var angle = svgedit.utilities.getRotationAngle(this.elem);
|
||||
if (angle) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
var bChangedTransform = false;
|
||||
var attr;
|
||||
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 {
|
||||
this.elem.setAttribute(attr, this.oldValues[attr]);
|
||||
}
|
||||
} else {
|
||||
if (attr === '#text') {
|
||||
this.elem.textContent = '';
|
||||
} else {
|
||||
this.elem.removeAttribute(attr);
|
||||
}
|
||||
}
|
||||
if (attr === 'transform') { bChangedTransform = true; }
|
||||
}
|
||||
// relocate rotational transform, if necessary
|
||||
if (!bChangedTransform) {
|
||||
var angle = svgedit.utilities.getRotationAngle(this.elem);
|
||||
if (angle) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove transformlist to prevent confusion that causes bugs like 575.
|
||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||
// Remove transformlist to prevent confusion that causes bugs like 575.
|
||||
svgedit.transformlist.removeElementFromListMap(this.elem);
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
};
|
||||
|
||||
// Function: ChangeElementCommand.elements
|
||||
// Returns array with element associated with this command
|
||||
svgedit.history.ChangeElementCommand.prototype.elements = function () {
|
||||
return [this.elem];
|
||||
return [this.elem];
|
||||
};
|
||||
|
||||
// TODO: create a 'typing' command object that tracks changes in text
|
||||
|
@ -392,65 +392,65 @@ svgedit.history.ChangeElementCommand.prototype.elements = function () {
|
|||
// Parameters:
|
||||
// text - An optional string visible to user related to this change
|
||||
svgedit.history.BatchCommand = function (text) {
|
||||
this.text = text || 'Batch Command';
|
||||
this.stack = [];
|
||||
this.text = text || 'Batch Command';
|
||||
this.stack = [];
|
||||
};
|
||||
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 () {
|
||||
return this.text;
|
||||
return this.text;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.BatchCommand.apply
|
||||
// Runs "apply" on all subcommands
|
||||
svgedit.history.BatchCommand.prototype.apply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_APPLY, this);
|
||||
}
|
||||
|
||||
var i,
|
||||
len = this.stack.length;
|
||||
for (i = 0; i < len; ++i) {
|
||||
this.stack[i].apply(handler);
|
||||
}
|
||||
var i,
|
||||
len = this.stack.length;
|
||||
for (i = 0; i < len; ++i) {
|
||||
this.stack[i].apply(handler);
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_APPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.BatchCommand.unapply
|
||||
// Runs "unapply" on all subcommands
|
||||
svgedit.history.BatchCommand.prototype.unapply = function (handler) {
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.BEFORE_UNAPPLY, this);
|
||||
}
|
||||
|
||||
var i;
|
||||
for (i = this.stack.length - 1; i >= 0; i--) {
|
||||
this.stack[i].unapply(handler);
|
||||
}
|
||||
var i;
|
||||
for (i = this.stack.length - 1; i >= 0; i--) {
|
||||
this.stack[i].unapply(handler);
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
if (handler) {
|
||||
handler.handleHistoryEvent(svgedit.history.HistoryEventTypes.AFTER_UNAPPLY, this);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.BatchCommand.elements
|
||||
// Iterate through all our subcommands and returns all the elements we are changing
|
||||
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]); }
|
||||
}
|
||||
}
|
||||
return elems;
|
||||
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]); }
|
||||
}
|
||||
}
|
||||
return elems;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.BatchCommand.addSubCommand
|
||||
|
@ -459,13 +459,13 @@ svgedit.history.BatchCommand.prototype.elements = function () {
|
|||
// Parameters:
|
||||
// cmd - The undo command object to add
|
||||
svgedit.history.BatchCommand.prototype.addSubCommand = function (cmd) {
|
||||
this.stack.push(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 () {
|
||||
return this.stack.length === 0;
|
||||
return this.stack.length === 0;
|
||||
};
|
||||
|
||||
// Class: svgedit.history.UndoManager
|
||||
|
@ -473,67 +473,67 @@ svgedit.history.BatchCommand.prototype.isEmpty = function () {
|
|||
// historyEventHandler - an object that conforms to the HistoryEventHandler interface
|
||||
// (see above)
|
||||
svgedit.history.UndoManager = function (historyEventHandler) {
|
||||
this.handler_ = historyEventHandler || null;
|
||||
this.undoStackPointer = 0;
|
||||
this.undoStack = [];
|
||||
this.handler_ = historyEventHandler || null;
|
||||
this.undoStackPointer = 0;
|
||||
this.undoStack = [];
|
||||
|
||||
// this is the stack that stores the original values, the elements and
|
||||
// the attribute name for begin/finish
|
||||
this.undoChangeStackPointer = -1;
|
||||
this.undoableChangeStack = [];
|
||||
// this is the stack that stores the original values, the elements and
|
||||
// the attribute name for begin/finish
|
||||
this.undoChangeStackPointer = -1;
|
||||
this.undoableChangeStack = [];
|
||||
};
|
||||
|
||||
// Function: svgedit.history.UndoManager.resetUndoStack
|
||||
// Resets the undo stack, effectively clearing the undo/redo history
|
||||
svgedit.history.UndoManager.prototype.resetUndoStack = function () {
|
||||
this.undoStack = [];
|
||||
this.undoStackPointer = 0;
|
||||
this.undoStack = [];
|
||||
this.undoStackPointer = 0;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.UndoManager.getUndoStackSize
|
||||
// Returns:
|
||||
// Integer with the current size of the undo history stack
|
||||
svgedit.history.UndoManager.prototype.getUndoStackSize = function () {
|
||||
return this.undoStackPointer;
|
||||
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 () {
|
||||
return this.undoStack.length - this.undoStackPointer;
|
||||
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() : '';
|
||||
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() : '';
|
||||
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 () {
|
||||
if (this.undoStackPointer > 0) {
|
||||
var cmd = this.undoStack[--this.undoStackPointer];
|
||||
cmd.unapply(this.handler_);
|
||||
}
|
||||
if (this.undoStackPointer > 0) {
|
||||
var cmd = this.undoStack[--this.undoStackPointer];
|
||||
cmd.unapply(this.handler_);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.UndoManager.redo
|
||||
// Performs a redo step
|
||||
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_);
|
||||
}
|
||||
if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
|
||||
var cmd = this.undoStack[this.undoStackPointer++];
|
||||
cmd.apply(this.handler_);
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.history.UndoManager.addCommandToHistory
|
||||
|
@ -542,18 +542,18 @@ svgedit.history.UndoManager.prototype.redo = function () {
|
|||
// Parameters:
|
||||
// cmd - The command object to add
|
||||
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)
|
||||
// TODO: consider limiting the history that we store here (need to do some slicing)
|
||||
// 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)
|
||||
// TODO: consider limiting the history that we store here (need to do some slicing)
|
||||
|
||||
// if our stack pointer is not at the end, then we have to remove
|
||||
// all commands after the pointer and insert the new command
|
||||
if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
|
||||
this.undoStack = this.undoStack.splice(0, this.undoStackPointer);
|
||||
}
|
||||
this.undoStack.push(cmd);
|
||||
this.undoStackPointer = this.undoStack.length;
|
||||
// if our stack pointer is not at the end, then we have to remove
|
||||
// all commands after the pointer and insert the new command
|
||||
if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
|
||||
this.undoStack = this.undoStack.splice(0, this.undoStackPointer);
|
||||
}
|
||||
this.undoStack.push(cmd);
|
||||
this.undoStackPointer = this.undoStack.length;
|
||||
};
|
||||
|
||||
// Function: svgedit.history.UndoManager.beginUndoableChange
|
||||
|
@ -567,20 +567,20 @@ svgedit.history.UndoManager.prototype.addCommandToHistory = function (cmd) {
|
|||
// attrName - The name of the attribute being changed
|
||||
// elems - Array of DOM elements being changed
|
||||
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; }
|
||||
elements[i] = elem;
|
||||
oldValues[i] = elem.getAttribute(attrName);
|
||||
}
|
||||
this.undoableChangeStack[p] = {
|
||||
'attrName': attrName,
|
||||
'oldValues': oldValues,
|
||||
'elements': elements
|
||||
};
|
||||
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; }
|
||||
elements[i] = elem;
|
||||
oldValues[i] = elem.getAttribute(attrName);
|
||||
}
|
||||
this.undoableChangeStack[p] = {
|
||||
'attrName': attrName,
|
||||
'oldValues': oldValues,
|
||||
'elements': elements
|
||||
};
|
||||
};
|
||||
|
||||
// Function: svgedit.history.UndoManager.finishUndoableChange
|
||||
|
@ -591,21 +591,21 @@ svgedit.history.UndoManager.prototype.beginUndoableChange = function (attrName,
|
|||
// Returns:
|
||||
// Batch command object with resulting changes
|
||||
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);
|
||||
while (i--) {
|
||||
var elem = changeset.elements[i];
|
||||
if (elem == null) { continue; }
|
||||
var changes = {};
|
||||
changes[attrName] = changeset.oldValues[i];
|
||||
if (changes[attrName] !== elem.getAttribute(attrName)) {
|
||||
batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(elem, changes, attrName));
|
||||
}
|
||||
}
|
||||
this.undoableChangeStack[p] = null;
|
||||
return batchCmd;
|
||||
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);
|
||||
while (i--) {
|
||||
var elem = changeset.elements[i];
|
||||
if (elem == null) { continue; }
|
||||
var changes = {};
|
||||
changes[attrName] = changeset.oldValues[i];
|
||||
if (changes[attrName] !== elem.getAttribute(attrName)) {
|
||||
batchCmd.addSubCommand(new svgedit.history.ChangeElementCommand(elem, changes, attrName));
|
||||
}
|
||||
}
|
||||
this.undoableChangeStack[p] = null;
|
||||
return batchCmd;
|
||||
};
|
||||
}());
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.history) {
|
||||
svgedit.history = {};
|
||||
svgedit.history = {};
|
||||
}
|
||||
var history = svgedit.history;
|
||||
|
||||
|
@ -58,9 +58,9 @@ var history = svgedit.history;
|
|||
* See singleton: HistoryRecordingService.NO_HISTORY
|
||||
*/
|
||||
var HistoryRecordingService = history.HistoryRecordingService = function (undoManager) {
|
||||
this.undoManager_ = undoManager;
|
||||
this.currentBatchCommand_ = null;
|
||||
this.batchCommandStack_ = [];
|
||||
this.undoManager_ = undoManager;
|
||||
this.currentBatchCommand_ = null;
|
||||
this.batchCommandStack_ = [];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -77,10 +77,10 @@ HistoryRecordingService.NO_HISTORY = new HistoryRecordingService();
|
|||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
HistoryRecordingService.prototype.startBatchCommand = function (text) {
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.currentBatchCommand_ = new history.BatchCommand(text);
|
||||
this.batchCommandStack_.push(this.currentBatchCommand_);
|
||||
return this;
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.currentBatchCommand_ = new history.BatchCommand(text);
|
||||
this.batchCommandStack_.push(this.currentBatchCommand_);
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -88,15 +88,15 @@ HistoryRecordingService.prototype.startBatchCommand = function (text) {
|
|||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
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.addCommand_(batchCommand);
|
||||
}
|
||||
return this;
|
||||
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.addCommand_(batchCommand);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -108,9 +108,9 @@ HistoryRecordingService.prototype.endBatchCommand = function () {
|
|||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
HistoryRecordingService.prototype.moveElement = function (elem, oldNextSibling, oldParent, text) {
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text));
|
||||
return this;
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.MoveElementCommand(elem, oldNextSibling, oldParent, text));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -120,9 +120,9 @@ HistoryRecordingService.prototype.moveElement = function (elem, oldNextSibling,
|
|||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
HistoryRecordingService.prototype.insertElement = function (elem, text) {
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.InsertElementCommand(elem, text));
|
||||
return this;
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.InsertElementCommand(elem, text));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -134,9 +134,9 @@ HistoryRecordingService.prototype.insertElement = function (elem, text) {
|
|||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
HistoryRecordingService.prototype.removeElement = function (elem, oldNextSibling, oldParent, text) {
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text));
|
||||
return this;
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.RemoveElementCommand(elem, oldNextSibling, oldParent, text));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -147,9 +147,9 @@ HistoryRecordingService.prototype.removeElement = function (elem, oldNextSibling
|
|||
* @returns {svgedit.history.HistoryRecordingService}
|
||||
*/
|
||||
HistoryRecordingService.prototype.changeElement = function (elem, attrs, text) {
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.ChangeElementCommand(elem, attrs, text));
|
||||
return this;
|
||||
if (!this.undoManager_) { return this; }
|
||||
this.addCommand_(new history.ChangeElementCommand(elem, attrs, text));
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -159,11 +159,11 @@ HistoryRecordingService.prototype.changeElement = function (elem, attrs, text) {
|
|||
* @private
|
||||
*/
|
||||
HistoryRecordingService.prototype.addCommand_ = function (cmd) {
|
||||
if (!this.undoManager_) { return this; }
|
||||
if (this.currentBatchCommand_) {
|
||||
this.currentBatchCommand_.addSubCommand(cmd);
|
||||
} else {
|
||||
this.undoManager_.addCommandToHistory(cmd);
|
||||
}
|
||||
if (!this.undoManager_) { return this; }
|
||||
if (this.currentBatchCommand_) {
|
||||
this.currentBatchCommand_.addSubCommand(cmd);
|
||||
} else {
|
||||
this.undoManager_.addCommandToHistory(cmd);
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
|
148
editor/layer.js
148
editor/layer.js
|
@ -17,7 +17,7 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.draw) {
|
||||
svgedit.draw = {};
|
||||
svgedit.draw = {};
|
||||
}
|
||||
var NS = svgedit.NS;
|
||||
|
||||
|
@ -39,29 +39,29 @@ var NS = svgedit.NS;
|
|||
* a new layer to the document.
|
||||
*/
|
||||
var Layer = svgedit.draw.Layer = function (name, group, svgElem) {
|
||||
this.name_ = name;
|
||||
this.group_ = svgElem ? null : group;
|
||||
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 layerTitle = svgdoc.createElementNS(NS.SVG, 'title');
|
||||
layerTitle.textContent = name;
|
||||
this.group_.appendChild(layerTitle);
|
||||
if (group) {
|
||||
$(group).after(this.group_);
|
||||
} else {
|
||||
svgElem.appendChild(this.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 layerTitle = svgdoc.createElementNS(NS.SVG, 'title');
|
||||
layerTitle.textContent = name;
|
||||
this.group_.appendChild(layerTitle);
|
||||
if (group) {
|
||||
$(group).after(this.group_);
|
||||
} else {
|
||||
svgElem.appendChild(this.group_);
|
||||
}
|
||||
}
|
||||
|
||||
addLayerClass(this.group_);
|
||||
svgedit.utilities.walkTree(this.group_, function (e) {
|
||||
e.setAttribute('style', 'pointer-events:inherit');
|
||||
});
|
||||
addLayerClass(this.group_);
|
||||
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');
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -79,7 +79,7 @@ Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)');
|
|||
* @returns {string} The layer name
|
||||
*/
|
||||
Layer.prototype.getName = function () {
|
||||
return this.name_;
|
||||
return this.name_;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -87,21 +87,21 @@ Layer.prototype.getName = function () {
|
|||
* @returns {SVGGElement} The layer SVG group
|
||||
*/
|
||||
Layer.prototype.getGroup = function () {
|
||||
return this.group_;
|
||||
return this.group_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Active this layer so it takes pointer events.
|
||||
*/
|
||||
Layer.prototype.activate = function () {
|
||||
this.group_.setAttribute('style', 'pointer-events:all');
|
||||
this.group_.setAttribute('style', 'pointer-events:all');
|
||||
};
|
||||
|
||||
/**
|
||||
* Deactive this layer so it does NOT take pointer events.
|
||||
*/
|
||||
Layer.prototype.deactivate = function () {
|
||||
this.group_.setAttribute('style', 'pointer-events:none');
|
||||
this.group_.setAttribute('style', 'pointer-events:none');
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -109,11 +109,11 @@ Layer.prototype.deactivate = function () {
|
|||
* @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');
|
||||
if (oldDisplay !== expected) {
|
||||
this.group_.setAttribute('display', expected);
|
||||
}
|
||||
var expected = visible === undefined || visible ? 'inline' : 'none';
|
||||
var oldDisplay = this.group_.getAttribute('display');
|
||||
if (oldDisplay !== expected) {
|
||||
this.group_.setAttribute('display', expected);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -121,7 +121,7 @@ Layer.prototype.setVisible = function (visible) {
|
|||
* @returns {boolean} True if visible.
|
||||
*/
|
||||
Layer.prototype.isVisible = function () {
|
||||
return this.group_.getAttribute('display') !== 'none';
|
||||
return this.group_.getAttribute('display') !== 'none';
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -129,11 +129,11 @@ Layer.prototype.isVisible = function () {
|
|||
* @returns {number} Opacity value.
|
||||
*/
|
||||
Layer.prototype.getOpacity = function () {
|
||||
var opacity = this.group_.getAttribute('opacity');
|
||||
if (opacity === null || opacity === undefined) {
|
||||
return 1;
|
||||
}
|
||||
return parseFloat(opacity);
|
||||
var opacity = this.group_.getAttribute('opacity');
|
||||
if (opacity === null || opacity === undefined) {
|
||||
return 1;
|
||||
}
|
||||
return parseFloat(opacity);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -142,9 +142,9 @@ Layer.prototype.getOpacity = function () {
|
|||
* @param {number} opacity - A float value in the range 0.0-1.0
|
||||
*/
|
||||
Layer.prototype.setOpacity = function (opacity) {
|
||||
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
|
||||
this.group_.setAttribute('opacity', opacity);
|
||||
}
|
||||
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
|
||||
this.group_.setAttribute('opacity', opacity);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -152,20 +152,20 @@ Layer.prototype.setOpacity = function (opacity) {
|
|||
* @param {SVGGElement} children - The children to append to this layer.
|
||||
*/
|
||||
Layer.prototype.appendChildren = function (children) {
|
||||
for (var i = 0; i < children.length; ++i) {
|
||||
this.group_.appendChild(children[i]);
|
||||
}
|
||||
for (var i = 0; i < children.length; ++i) {
|
||||
this.group_.appendChild(children[i]);
|
||||
}
|
||||
};
|
||||
|
||||
Layer.prototype.getTitleElement = function () {
|
||||
var len = this.group_.childNodes.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
var child = this.group_.childNodes.item(i);
|
||||
if (child && child.tagName === 'title') {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
var len = this.group_.childNodes.length;
|
||||
for (var i = 0; i < len; ++i) {
|
||||
var child = this.group_.childNodes.item(i);
|
||||
if (child && child.tagName === 'title') {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -175,20 +175,20 @@ Layer.prototype.getTitleElement = function () {
|
|||
* @returns {string|null} The new name if changed; otherwise, null.
|
||||
*/
|
||||
Layer.prototype.setName = function (name, hrService) {
|
||||
var previousName = this.name_;
|
||||
name = svgedit.utilities.toXml(name);
|
||||
// now change the underlying title element contents
|
||||
var title = this.getTitleElement();
|
||||
if (title) {
|
||||
$(title).empty();
|
||||
title.textContent = name;
|
||||
this.name_ = name;
|
||||
if (hrService) {
|
||||
hrService.changeElement(title, {'#text': previousName});
|
||||
}
|
||||
return this.name_;
|
||||
}
|
||||
return null;
|
||||
var previousName = this.name_;
|
||||
name = svgedit.utilities.toXml(name);
|
||||
// now change the underlying title element contents
|
||||
var title = this.getTitleElement();
|
||||
if (title) {
|
||||
$(title).empty();
|
||||
title.textContent = name;
|
||||
this.name_ = name;
|
||||
if (hrService) {
|
||||
hrService.changeElement(title, {'#text': previousName});
|
||||
}
|
||||
return this.name_;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -197,10 +197,10 @@ Layer.prototype.setName = function (name, hrService) {
|
|||
* @returns {SVGGElement} The layer SVG group that was just removed.
|
||||
*/
|
||||
Layer.prototype.removeGroup = function () {
|
||||
var parent = this.group_.parentNode;
|
||||
var group = parent.removeChild(this.group_);
|
||||
this.group_ = undefined;
|
||||
return group;
|
||||
var parent = this.group_.parentNode;
|
||||
var group = parent.removeChild(this.group_);
|
||||
this.group_ = undefined;
|
||||
return group;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -210,11 +210,11 @@ Layer.prototype.removeGroup = function () {
|
|||
* @param {SVGGElement} elem - The SVG element to update
|
||||
*/
|
||||
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)) {
|
||||
elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME);
|
||||
}
|
||||
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)) {
|
||||
elem.setAttribute('class', classes + ' ' + Layer.CLASS_NAME);
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
|
158
editor/math.js
158
editor/math.js
|
@ -24,7 +24,7 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.math) {
|
||||
svgedit.math = {};
|
||||
svgedit.math = {};
|
||||
}
|
||||
|
||||
// Constants
|
||||
|
@ -42,7 +42,7 @@ 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};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -52,7 +52,7 @@ svgedit.math.transformPoint = function (x, y, m) {
|
|||
* @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0
|
||||
*/
|
||||
svgedit.math.isIdentity = function (m) {
|
||||
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
|
||||
return (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,20 +62,20 @@ 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];
|
||||
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; }
|
||||
while (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; }
|
||||
|
||||
return m;
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -84,13 +84,13 @@ svgedit.math.matrixMultiply = function (matr) {
|
|||
* @returns {boolean} Whether or not a matrix transform was found
|
||||
*/
|
||||
svgedit.math.hasMatrixTransform = function (tlist) {
|
||||
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; }
|
||||
}
|
||||
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; }
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -112,30 +112,30 @@ svgedit.math.hasMatrixTransform = function (tlist) {
|
|||
* height - Float with the axis-aligned height coordinate
|
||||
*/
|
||||
svgedit.math.transformBox = function (l, t, w, h, m) {
|
||||
var transformPoint = svgedit.math.transformPoint,
|
||||
var transformPoint = svgedit.math.transformPoint,
|
||||
|
||||
tl = transformPoint(l, t, m),
|
||||
tr = transformPoint((l + w), t, m),
|
||||
bl = transformPoint(l, (t + h), m),
|
||||
br = transformPoint((l + w), (t + h), m),
|
||||
tl = transformPoint(l, t, m),
|
||||
tr = transformPoint((l + w), t, m),
|
||||
bl = transformPoint(l, (t + h), m),
|
||||
br = transformPoint((l + w), (t + h), m),
|
||||
|
||||
minx = Math.min(tl.x, tr.x, bl.x, br.x),
|
||||
maxx = Math.max(tl.x, tr.x, bl.x, br.x),
|
||||
miny = Math.min(tl.y, tr.y, bl.y, br.y),
|
||||
maxy = Math.max(tl.y, tr.y, bl.y, br.y);
|
||||
minx = Math.min(tl.x, tr.x, bl.x, br.x),
|
||||
maxx = Math.max(tl.x, tr.x, bl.x, br.x),
|
||||
miny = Math.min(tl.y, tr.y, bl.y, br.y),
|
||||
maxy = Math.max(tl.y, tr.y, bl.y, br.y);
|
||||
|
||||
return {
|
||||
tl: tl,
|
||||
tr: tr,
|
||||
bl: bl,
|
||||
br: br,
|
||||
aabox: {
|
||||
x: minx,
|
||||
y: miny,
|
||||
width: (maxx - minx),
|
||||
height: (maxy - miny)
|
||||
}
|
||||
};
|
||||
return {
|
||||
tl: tl,
|
||||
tr: tr,
|
||||
bl: bl,
|
||||
br: br,
|
||||
aabox: {
|
||||
x: minx,
|
||||
y: miny,
|
||||
width: (maxx - minx),
|
||||
height: (maxy - miny)
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -150,25 +150,25 @@ svgedit.math.transformBox = function (l, t, w, h, m) {
|
|||
* @returns {Object} A single matrix transform object
|
||||
*/
|
||||
svgedit.math.transformListToTransform = function (tlist, min, max) {
|
||||
if (tlist == null) {
|
||||
// Or should tlist = null have been prevented before this?
|
||||
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix());
|
||||
}
|
||||
min = min || 0;
|
||||
max = max || (tlist.numberOfItems - 1);
|
||||
min = parseInt(min, 10);
|
||||
max = parseInt(max, 10);
|
||||
if (min > max) { var temp = max; max = min; min = temp; }
|
||||
var m = svg.createSVGMatrix();
|
||||
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());
|
||||
m = svgedit.math.matrixMultiply(m, mtom);
|
||||
}
|
||||
return svg.createSVGTransformFromMatrix(m);
|
||||
if (tlist == null) {
|
||||
// Or should tlist = null have been prevented before this?
|
||||
return svg.createSVGTransformFromMatrix(svg.createSVGMatrix());
|
||||
}
|
||||
min = min || 0;
|
||||
max = max || (tlist.numberOfItems - 1);
|
||||
min = parseInt(min, 10);
|
||||
max = parseInt(max, 10);
|
||||
if (min > max) { var temp = max; max = min; min = temp; }
|
||||
var m = svg.createSVGMatrix();
|
||||
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());
|
||||
m = svgedit.math.matrixMultiply(m, mtom);
|
||||
}
|
||||
return svg.createSVGTransformFromMatrix(m);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -177,8 +177,8 @@ svgedit.math.transformListToTransform = function (tlist, min, max) {
|
|||
* @returns {SVGMatrix} The matrix object associated with the element's transformlist
|
||||
*/
|
||||
svgedit.math.getMatrix = function (elem) {
|
||||
var tlist = svgedit.transformlist.getTransformList(elem);
|
||||
return svgedit.math.transformListToTransform(tlist).matrix;
|
||||
var tlist = svgedit.transformlist.getTransformList(elem);
|
||||
return svgedit.math.transformListToTransform(tlist).matrix;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -191,18 +191,18 @@ svgedit.math.getMatrix = function (elem) {
|
|||
* @returns {AngleCoord45}
|
||||
*/
|
||||
svgedit.math.snapToAngle = function (x1, y1, x2, y2) {
|
||||
var snap = Math.PI / 4; // 45 degrees
|
||||
var dx = x2 - x1;
|
||||
var dy = y2 - y1;
|
||||
var angle = Math.atan2(dy, dx);
|
||||
var dist = Math.sqrt(dx * dx + dy * dy);
|
||||
var snapangle = Math.round(angle / snap) * snap;
|
||||
var snap = Math.PI / 4; // 45 degrees
|
||||
var dx = x2 - x1;
|
||||
var dy = y2 - y1;
|
||||
var angle = Math.atan2(dy, dx);
|
||||
var dist = Math.sqrt(dx * dx + dy * dy);
|
||||
var snapangle = Math.round(angle / snap) * snap;
|
||||
|
||||
return {
|
||||
x: x1 + dist * Math.cos(snapangle),
|
||||
y: y1 + dist * Math.sin(snapangle),
|
||||
a: snapangle
|
||||
};
|
||||
return {
|
||||
x: x1 + dist * Math.cos(snapangle),
|
||||
y: y1 + dist * Math.sin(snapangle),
|
||||
a: snapangle
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -212,9 +212,9 @@ svgedit.math.snapToAngle = function (x1, y1, x2, y2) {
|
|||
* @returns {boolean} True if rectangles intersect
|
||||
*/
|
||||
svgedit.math.rectsIntersect = function (r1, r2) {
|
||||
return r2.x < (r1.x + r1.width) &&
|
||||
(r2.x + r2.width) > r1.x &&
|
||||
r2.y < (r1.y + r1.height) &&
|
||||
(r2.y + r2.height) > r1.y;
|
||||
return r2.x < (r1.x + r1.width) &&
|
||||
(r2.x + r2.width) > r1.x &&
|
||||
r2.y < (r1.y + r1.height) &&
|
||||
(r2.y + r2.height) > r1.y;
|
||||
};
|
||||
}());
|
||||
|
|
1414
editor/path.js
1414
editor/path.js
File diff suppressed because it is too large
Load Diff
1534
editor/pathseg.js
1534
editor/pathseg.js
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -19,95 +19,95 @@
|
|||
'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;
|
||||
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
|
||||
|
@ -117,140 +117,140 @@ $.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);
|
||||
}
|
||||
}
|
||||
// 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 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 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);
|
||||
}
|
||||
|
||||
// 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]); }
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
|
716
editor/select.js
716
editor/select.js
|
@ -20,7 +20,7 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.select) {
|
||||
svgedit.select = {};
|
||||
svgedit.select = {};
|
||||
}
|
||||
|
||||
var svgFactory_;
|
||||
|
@ -36,50 +36,50 @@ var gripRadius = svgedit.browser.isTouch() ? 10 : 4;
|
|||
// 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) {
|
||||
// this is the selector's unique number
|
||||
this.id = id;
|
||||
// this is the selector's unique number
|
||||
this.id = id;
|
||||
|
||||
// this holds a reference to the element for which this selector is being used
|
||||
this.selectedElement = elem;
|
||||
// this holds a reference to the element for which this selector is being used
|
||||
this.selectedElement = elem;
|
||||
|
||||
// this is a flag used internally to track whether the selector is being used or not
|
||||
this.locked = true;
|
||||
// this is a flag used internally to track whether the selector is being used or not
|
||||
this.locked = true;
|
||||
|
||||
// this holds a reference to the <g> element that holds all visual elements of the selector
|
||||
this.selectorGroup = svgFactory_.createSVGElement({
|
||||
'element': 'g',
|
||||
'attr': {'id': ('selectorGroup' + this.id)}
|
||||
});
|
||||
// this holds a reference to the <g> element that holds all visual elements of the selector
|
||||
this.selectorGroup = svgFactory_.createSVGElement({
|
||||
'element': 'g',
|
||||
'attr': {'id': ('selectorGroup' + this.id)}
|
||||
});
|
||||
|
||||
// this holds a reference to the path rect
|
||||
this.selectorRect = this.selectorGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'path',
|
||||
'attr': {
|
||||
'id': ('selectedBox' + this.id),
|
||||
'fill': 'none',
|
||||
'stroke': '#22C',
|
||||
'stroke-width': '1',
|
||||
'stroke-dasharray': '5,5',
|
||||
// need to specify this so that the rect is not selectable
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
})
|
||||
);
|
||||
// this holds a reference to the path rect
|
||||
this.selectorRect = this.selectorGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'path',
|
||||
'attr': {
|
||||
'id': ('selectedBox' + this.id),
|
||||
'fill': 'none',
|
||||
'stroke': '#22C',
|
||||
'stroke-width': '1',
|
||||
'stroke-dasharray': '5,5',
|
||||
// need to specify this so that the rect is not selectable
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// this holds a reference to the grip coordinates for this selector
|
||||
this.gripCoords = {
|
||||
'nw': null,
|
||||
'n': null,
|
||||
'ne': null,
|
||||
'e': null,
|
||||
'se': null,
|
||||
's': null,
|
||||
'sw': null,
|
||||
'w': null
|
||||
};
|
||||
// this holds a reference to the grip coordinates for this selector
|
||||
this.gripCoords = {
|
||||
'nw': null,
|
||||
'n': null,
|
||||
'ne': null,
|
||||
'e': null,
|
||||
'se': null,
|
||||
's': null,
|
||||
'sw': null,
|
||||
'w': null
|
||||
};
|
||||
|
||||
this.reset(this.selectedElement, bbox);
|
||||
this.reset(this.selectedElement, bbox);
|
||||
};
|
||||
|
||||
// Function: svgedit.select.Selector.reset
|
||||
|
@ -89,10 +89,10 @@ svgedit.select.Selector = function (id, elem, bbox) {
|
|||
// 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) {
|
||||
this.locked = true;
|
||||
this.selectedElement = e;
|
||||
this.resize(bbox);
|
||||
this.selectorGroup.setAttribute('display', 'inline');
|
||||
this.locked = true;
|
||||
this.selectedElement = e;
|
||||
this.resize(bbox);
|
||||
this.selectorGroup.setAttribute('display', 'inline');
|
||||
};
|
||||
|
||||
// Function: svgedit.select.Selector.updateGripCursors
|
||||
|
@ -101,22 +101,22 @@ svgedit.select.Selector.prototype.reset = function (e, bbox) {
|
|||
// Parameters:
|
||||
// angle - Float indicating current rotation angle in degrees
|
||||
svgedit.select.Selector.prototype.updateGripCursors = function (angle) {
|
||||
var dir,
|
||||
dirArr = [],
|
||||
steps = Math.round(angle / 45);
|
||||
if (steps < 0) { steps += 8; }
|
||||
for (dir in selectorManager_.selectorGrips) {
|
||||
dirArr.push(dir);
|
||||
}
|
||||
while (steps > 0) {
|
||||
dirArr.push(dirArr.shift());
|
||||
steps--;
|
||||
}
|
||||
var i = 0;
|
||||
for (dir in selectorManager_.selectorGrips) {
|
||||
selectorManager_.selectorGrips[dir].setAttribute('style', ('cursor:' + dirArr[i] + '-resize'));
|
||||
i++;
|
||||
}
|
||||
var dir,
|
||||
dirArr = [],
|
||||
steps = Math.round(angle / 45);
|
||||
if (steps < 0) { steps += 8; }
|
||||
for (dir in selectorManager_.selectorGrips) {
|
||||
dirArr.push(dir);
|
||||
}
|
||||
while (steps > 0) {
|
||||
dirArr.push(dirArr.shift());
|
||||
steps--;
|
||||
}
|
||||
var i = 0;
|
||||
for (dir in selectorManager_.selectorGrips) {
|
||||
selectorManager_.selectorGrips[dir].setAttribute('style', ('cursor:' + dirArr[i] + '-resize'));
|
||||
i++;
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.select.Selector.showGrips
|
||||
|
@ -125,292 +125,292 @@ 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) {
|
||||
var bShow = show ? 'inline' : 'none';
|
||||
selectorManager_.selectorGripsGroup.setAttribute('display', bShow);
|
||||
var elem = this.selectedElement;
|
||||
this.hasGrips = show;
|
||||
if (elem && show) {
|
||||
this.selectorGroup.appendChild(selectorManager_.selectorGripsGroup);
|
||||
this.updateGripCursors(svgedit.utilities.getRotationAngle(elem));
|
||||
}
|
||||
var bShow = show ? 'inline' : 'none';
|
||||
selectorManager_.selectorGripsGroup.setAttribute('display', bShow);
|
||||
var elem = this.selectedElement;
|
||||
this.hasGrips = show;
|
||||
if (elem && show) {
|
||||
this.selectorGroup.appendChild(selectorManager_.selectorGripsGroup);
|
||||
this.updateGripCursors(svgedit.utilities.getRotationAngle(elem));
|
||||
}
|
||||
};
|
||||
|
||||
// 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) {
|
||||
var selectedBox = this.selectorRect,
|
||||
mgr = selectorManager_,
|
||||
selectedGrips = mgr.selectorGrips,
|
||||
selected = this.selectedElement,
|
||||
sw = selected.getAttribute('stroke-width'),
|
||||
currentZoom = svgFactory_.currentZoom();
|
||||
var offset = 1 / currentZoom;
|
||||
if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) {
|
||||
offset += (sw / 2);
|
||||
}
|
||||
var selectedBox = this.selectorRect,
|
||||
mgr = selectorManager_,
|
||||
selectedGrips = mgr.selectorGrips,
|
||||
selected = this.selectedElement,
|
||||
sw = selected.getAttribute('stroke-width'),
|
||||
currentZoom = svgFactory_.currentZoom();
|
||||
var offset = 1 / currentZoom;
|
||||
if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) {
|
||||
offset += (sw / 2);
|
||||
}
|
||||
|
||||
var tagName = selected.tagName;
|
||||
if (tagName === 'text') {
|
||||
offset += 2 / currentZoom;
|
||||
}
|
||||
var tagName = selected.tagName;
|
||||
if (tagName === 'text') {
|
||||
offset += 2 / currentZoom;
|
||||
}
|
||||
|
||||
// loop and transform our bounding box until we reach our first rotation
|
||||
var tlist = svgedit.transformlist.getTransformList(selected);
|
||||
var m = svgedit.math.transformListToTransform(tlist).matrix;
|
||||
// loop and transform our bounding box until we reach our first rotation
|
||||
var tlist = svgedit.transformlist.getTransformList(selected);
|
||||
var m = svgedit.math.transformListToTransform(tlist).matrix;
|
||||
|
||||
// This should probably be handled somewhere else, but for now
|
||||
// it keeps the selection box correctly positioned when zoomed
|
||||
m.e *= currentZoom;
|
||||
m.f *= currentZoom;
|
||||
// This should probably be handled somewhere else, but for now
|
||||
// it keeps the selection box correctly positioned when zoomed
|
||||
m.e *= currentZoom;
|
||||
m.f *= currentZoom;
|
||||
|
||||
if (!bbox) {
|
||||
bbox = svgedit.utilities.getBBox(selected);
|
||||
}
|
||||
// TODO: svgedit.utilities.getBBox (previous line) already knows to call getStrokedBBox when tagName === 'g'. Remove this?
|
||||
// TODO: svgedit.utilities.getBBox doesn't exclude 'gsvg' and calls getStrokedBBox for any 'g'. Should getBBox be updated?
|
||||
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 strokedBbox = svgFactory_.getStrokedBBox(selected.childNodes);
|
||||
if (strokedBbox) {
|
||||
bbox = strokedBbox;
|
||||
}
|
||||
}
|
||||
if (!bbox) {
|
||||
bbox = svgedit.utilities.getBBox(selected);
|
||||
}
|
||||
// TODO: svgedit.utilities.getBBox (previous line) already knows to call getStrokedBBox when tagName === 'g'. Remove this?
|
||||
// TODO: svgedit.utilities.getBBox doesn't exclude 'gsvg' and calls getStrokedBBox for any 'g'. Should getBBox be updated?
|
||||
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 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};
|
||||
// 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};
|
||||
|
||||
// we need to handle temporary transforms too
|
||||
// if skewed, get its transformed box, then find its axis-aligned bbox
|
||||
// we need to handle temporary transforms too
|
||||
// if skewed, get its transformed box, then find its axis-aligned bbox
|
||||
|
||||
// *
|
||||
offset *= currentZoom;
|
||||
// *
|
||||
offset *= currentZoom;
|
||||
|
||||
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,
|
||||
nbaw = aabox.width + (offset * 2),
|
||||
nbah = aabox.height + (offset * 2);
|
||||
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,
|
||||
nbaw = aabox.width + (offset * 2),
|
||||
nbah = aabox.height + (offset * 2);
|
||||
|
||||
// now if the shape is rotated, un-rotate it
|
||||
var cx = nbax + nbaw / 2,
|
||||
cy = nbay + nbah / 2;
|
||||
// now if the shape is rotated, un-rotate it
|
||||
var cx = nbax + nbaw / 2,
|
||||
cy = nbay + nbah / 2;
|
||||
|
||||
var angle = svgedit.utilities.getRotationAngle(selected);
|
||||
if (angle) {
|
||||
var rot = svgFactory_.svgRoot().createSVGTransform();
|
||||
rot.setRotate(-angle, cx, cy);
|
||||
var rotm = rot.matrix;
|
||||
nbox.tl = svgedit.math.transformPoint(nbox.tl.x, nbox.tl.y, rotm);
|
||||
nbox.tr = svgedit.math.transformPoint(nbox.tr.x, nbox.tr.y, rotm);
|
||||
nbox.bl = svgedit.math.transformPoint(nbox.bl.x, nbox.bl.y, rotm);
|
||||
nbox.br = svgedit.math.transformPoint(nbox.br.x, nbox.br.y, rotm);
|
||||
var angle = svgedit.utilities.getRotationAngle(selected);
|
||||
if (angle) {
|
||||
var rot = svgFactory_.svgRoot().createSVGTransform();
|
||||
rot.setRotate(-angle, cx, cy);
|
||||
var rotm = rot.matrix;
|
||||
nbox.tl = svgedit.math.transformPoint(nbox.tl.x, nbox.tl.y, rotm);
|
||||
nbox.tr = svgedit.math.transformPoint(nbox.tr.x, nbox.tr.y, rotm);
|
||||
nbox.bl = svgedit.math.transformPoint(nbox.bl.x, nbox.bl.y, rotm);
|
||||
nbox.br = svgedit.math.transformPoint(nbox.br.x, nbox.br.y, rotm);
|
||||
|
||||
// calculate the axis-aligned bbox
|
||||
var tl = nbox.tl;
|
||||
var minx = tl.x,
|
||||
miny = tl.y,
|
||||
maxx = tl.x,
|
||||
maxy = tl.y;
|
||||
// calculate the axis-aligned bbox
|
||||
var tl = nbox.tl;
|
||||
var minx = tl.x,
|
||||
miny = tl.y,
|
||||
maxx = tl.x,
|
||||
maxy = tl.y;
|
||||
|
||||
var min = Math.min, max = Math.max;
|
||||
var min = Math.min, max = Math.max;
|
||||
|
||||
minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x))) - offset;
|
||||
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);
|
||||
}
|
||||
nbax = minx;
|
||||
nbay = miny;
|
||||
nbaw = (maxx - minx);
|
||||
nbah = (maxy - miny);
|
||||
}
|
||||
|
||||
var dstr = 'M' + nbax + ',' + nbay +
|
||||
' L' + (nbax + nbaw) + ',' + nbay +
|
||||
' ' + (nbax + nbaw) + ',' + (nbay + nbah) +
|
||||
' ' + nbax + ',' + (nbay + nbah) + 'z';
|
||||
selectedBox.setAttribute('d', dstr);
|
||||
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);
|
||||
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]);
|
||||
}
|
||||
// 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]);
|
||||
}
|
||||
|
||||
// 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 () {
|
||||
// this will hold the <g> element that contains all selector rects/grips
|
||||
this.selectorParentGroup = null;
|
||||
// this will hold the <g> element that contains all selector rects/grips
|
||||
this.selectorParentGroup = null;
|
||||
|
||||
// this is a special rect that is used for multi-select
|
||||
this.rubberBandBox = null;
|
||||
// this is a special rect that is used for multi-select
|
||||
this.rubberBandBox = null;
|
||||
|
||||
// this will hold objects of type svgedit.select.Selector (see above)
|
||||
this.selectors = [];
|
||||
// this will hold objects of type svgedit.select.Selector (see above)
|
||||
this.selectors = [];
|
||||
|
||||
// this holds a map of SVG elements to their Selector object
|
||||
this.selectorMap = {};
|
||||
// this holds a map of SVG elements to their Selector object
|
||||
this.selectorMap = {};
|
||||
|
||||
// this holds a reference to the grip elements
|
||||
this.selectorGrips = {
|
||||
'nw': null,
|
||||
'n': null,
|
||||
'ne': null,
|
||||
'e': null,
|
||||
'se': null,
|
||||
's': null,
|
||||
'sw': null,
|
||||
'w': null
|
||||
};
|
||||
// this holds a reference to the grip elements
|
||||
this.selectorGrips = {
|
||||
'nw': null,
|
||||
'n': null,
|
||||
'ne': null,
|
||||
'e': null,
|
||||
'se': null,
|
||||
's': null,
|
||||
'sw': null,
|
||||
'w': null
|
||||
};
|
||||
|
||||
this.selectorGripsGroup = null;
|
||||
this.rotateGripConnector = null;
|
||||
this.rotateGrip = null;
|
||||
this.selectorGripsGroup = null;
|
||||
this.rotateGripConnector = null;
|
||||
this.rotateGrip = null;
|
||||
|
||||
this.initGroup();
|
||||
this.initGroup();
|
||||
};
|
||||
|
||||
// Function: svgedit.select.SelectorManager.initGroup
|
||||
// Resets the parent selector group element
|
||||
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);
|
||||
}
|
||||
// remove old selector parent group if it existed
|
||||
if (this.selectorParentGroup && this.selectorParentGroup.parentNode) {
|
||||
this.selectorParentGroup.parentNode.removeChild(this.selectorParentGroup);
|
||||
}
|
||||
|
||||
// create parent selector group and add it to svgroot
|
||||
this.selectorParentGroup = svgFactory_.createSVGElement({
|
||||
'element': 'g',
|
||||
'attr': {'id': 'selectorParentGroup'}
|
||||
});
|
||||
this.selectorGripsGroup = svgFactory_.createSVGElement({
|
||||
'element': 'g',
|
||||
'attr': {'display': 'none'}
|
||||
});
|
||||
this.selectorParentGroup.appendChild(this.selectorGripsGroup);
|
||||
svgFactory_.svgRoot().appendChild(this.selectorParentGroup);
|
||||
// create parent selector group and add it to svgroot
|
||||
this.selectorParentGroup = svgFactory_.createSVGElement({
|
||||
'element': 'g',
|
||||
'attr': {'id': 'selectorParentGroup'}
|
||||
});
|
||||
this.selectorGripsGroup = svgFactory_.createSVGElement({
|
||||
'element': 'g',
|
||||
'attr': {'display': 'none'}
|
||||
});
|
||||
this.selectorParentGroup.appendChild(this.selectorGripsGroup);
|
||||
svgFactory_.svgRoot().appendChild(this.selectorParentGroup);
|
||||
|
||||
this.selectorMap = {};
|
||||
this.selectors = [];
|
||||
this.rubberBandBox = null;
|
||||
this.selectorMap = {};
|
||||
this.selectors = [];
|
||||
this.rubberBandBox = null;
|
||||
|
||||
// add the corner grips
|
||||
var dir;
|
||||
for (dir in this.selectorGrips) {
|
||||
var grip = svgFactory_.createSVGElement({
|
||||
'element': 'circle',
|
||||
'attr': {
|
||||
'id': ('selectorGrip_resize_' + dir),
|
||||
'fill': '#22C',
|
||||
'r': gripRadius,
|
||||
'style': ('cursor:' + dir + '-resize'),
|
||||
// This expands the mouse-able area of the grips making them
|
||||
// easier to grab with the mouse.
|
||||
// This works in Opera and WebKit, but does not work in Firefox
|
||||
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
|
||||
'stroke-width': 2,
|
||||
'pointer-events': 'all'
|
||||
}
|
||||
});
|
||||
// add the corner grips
|
||||
var dir;
|
||||
for (dir in this.selectorGrips) {
|
||||
var grip = svgFactory_.createSVGElement({
|
||||
'element': 'circle',
|
||||
'attr': {
|
||||
'id': ('selectorGrip_resize_' + dir),
|
||||
'fill': '#22C',
|
||||
'r': gripRadius,
|
||||
'style': ('cursor:' + dir + '-resize'),
|
||||
// This expands the mouse-able area of the grips making them
|
||||
// easier to grab with the mouse.
|
||||
// This works in Opera and WebKit, but does not work in Firefox
|
||||
// see https://bugzilla.mozilla.org/show_bug.cgi?id=500174
|
||||
'stroke-width': 2,
|
||||
'pointer-events': 'all'
|
||||
}
|
||||
});
|
||||
|
||||
$.data(grip, 'dir', dir);
|
||||
$.data(grip, 'type', 'resize');
|
||||
this.selectorGrips[dir] = this.selectorGripsGroup.appendChild(grip);
|
||||
}
|
||||
$.data(grip, 'dir', dir);
|
||||
$.data(grip, 'type', 'resize');
|
||||
this.selectorGrips[dir] = this.selectorGripsGroup.appendChild(grip);
|
||||
}
|
||||
|
||||
// add rotator elems
|
||||
this.rotateGripConnector = this.selectorGripsGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'line',
|
||||
'attr': {
|
||||
'id': ('selectorGrip_rotateconnector'),
|
||||
'stroke': '#22C',
|
||||
'stroke-width': '1'
|
||||
}
|
||||
})
|
||||
);
|
||||
// add rotator elems
|
||||
this.rotateGripConnector = this.selectorGripsGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'line',
|
||||
'attr': {
|
||||
'id': ('selectorGrip_rotateconnector'),
|
||||
'stroke': '#22C',
|
||||
'stroke-width': '1'
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
this.rotateGrip = this.selectorGripsGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'circle',
|
||||
'attr': {
|
||||
'id': 'selectorGrip_rotate',
|
||||
'fill': 'lime',
|
||||
'r': gripRadius,
|
||||
'stroke': '#22C',
|
||||
'stroke-width': 2,
|
||||
'style': 'cursor:url(' + config_.imgPath + 'rotate.png) 12 12, auto;'
|
||||
}
|
||||
})
|
||||
);
|
||||
$.data(this.rotateGrip, 'type', 'rotate');
|
||||
this.rotateGrip = this.selectorGripsGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'circle',
|
||||
'attr': {
|
||||
'id': 'selectorGrip_rotate',
|
||||
'fill': 'lime',
|
||||
'r': gripRadius,
|
||||
'stroke': '#22C',
|
||||
'stroke-width': 2,
|
||||
'style': 'cursor:url(' + config_.imgPath + 'rotate.png) 12 12, auto;'
|
||||
}
|
||||
})
|
||||
);
|
||||
$.data(this.rotateGrip, 'type', 'rotate');
|
||||
|
||||
if ($('#canvasBackground').length) { return; }
|
||||
if ($('#canvasBackground').length) { return; }
|
||||
|
||||
var dims = config_.dimensions;
|
||||
var canvasbg = svgFactory_.createSVGElement({
|
||||
'element': 'svg',
|
||||
'attr': {
|
||||
'id': 'canvasBackground',
|
||||
'width': dims[0],
|
||||
'height': dims[1],
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'overflow': (svgedit.browser.isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
});
|
||||
var dims = config_.dimensions;
|
||||
var canvasbg = svgFactory_.createSVGElement({
|
||||
'element': 'svg',
|
||||
'attr': {
|
||||
'id': 'canvasBackground',
|
||||
'width': dims[0],
|
||||
'height': dims[1],
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'overflow': (svgedit.browser.isWebkit() ? 'none' : 'visible'), // Chrome 7 has a problem with this when zooming out
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
});
|
||||
|
||||
var rect = svgFactory_.createSVGElement({
|
||||
'element': 'rect',
|
||||
'attr': {
|
||||
'width': '100%',
|
||||
'height': '100%',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'stroke-width': 1,
|
||||
'stroke': '#000',
|
||||
'fill': '#FFF',
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
});
|
||||
var rect = svgFactory_.createSVGElement({
|
||||
'element': 'rect',
|
||||
'attr': {
|
||||
'width': '100%',
|
||||
'height': '100%',
|
||||
'x': 0,
|
||||
'y': 0,
|
||||
'stroke-width': 1,
|
||||
'stroke': '#000',
|
||||
'fill': '#FFF',
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
});
|
||||
|
||||
// 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)');
|
||||
canvasbg.appendChild(rect);
|
||||
svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent());
|
||||
// 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)');
|
||||
canvasbg.appendChild(rect);
|
||||
svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent());
|
||||
};
|
||||
|
||||
// Function: svgedit.select.SelectorManager.requestSelector
|
||||
|
@ -420,27 +420,27 @@ svgedit.select.SelectorManager.prototype.initGroup = function () {
|
|||
// 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; }
|
||||
var i,
|
||||
N = this.selectors.length;
|
||||
// If we've already acquired one for this element, return it.
|
||||
if (typeof this.selectorMap[elem.id] === 'object') {
|
||||
this.selectorMap[elem.id].locked = true;
|
||||
return this.selectorMap[elem.id];
|
||||
}
|
||||
for (i = 0; i < N; ++i) {
|
||||
if (this.selectors[i] && !this.selectors[i].locked) {
|
||||
this.selectors[i].locked = true;
|
||||
this.selectors[i].reset(elem, bbox);
|
||||
this.selectorMap[elem.id] = this.selectors[i];
|
||||
return this.selectors[i];
|
||||
}
|
||||
}
|
||||
// if we reached here, no available selectors were found, we create one
|
||||
this.selectors[N] = new svgedit.select.Selector(N, elem, bbox);
|
||||
this.selectorParentGroup.appendChild(this.selectors[N].selectorGroup);
|
||||
this.selectorMap[elem.id] = this.selectors[N];
|
||||
return this.selectors[N];
|
||||
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') {
|
||||
this.selectorMap[elem.id].locked = true;
|
||||
return this.selectorMap[elem.id];
|
||||
}
|
||||
for (i = 0; i < N; ++i) {
|
||||
if (this.selectors[i] && !this.selectors[i].locked) {
|
||||
this.selectors[i].locked = true;
|
||||
this.selectors[i].reset(elem, bbox);
|
||||
this.selectorMap[elem.id] = this.selectors[i];
|
||||
return this.selectors[i];
|
||||
}
|
||||
}
|
||||
// if we reached here, no available selectors were found, we create one
|
||||
this.selectors[N] = new svgedit.select.Selector(N, elem, bbox);
|
||||
this.selectorParentGroup.appendChild(this.selectors[N].selectorGroup);
|
||||
this.selectorMap[elem.id] = this.selectors[N];
|
||||
return this.selectors[N];
|
||||
};
|
||||
|
||||
// Function: svgedit.select.SelectorManager.releaseSelector
|
||||
|
@ -449,51 +449,51 @@ 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; }
|
||||
var i,
|
||||
N = this.selectors.length,
|
||||
sel = this.selectorMap[elem.id];
|
||||
if (!sel.locked) {
|
||||
// TODO(codedread): Ensure this exists in this module.
|
||||
console.log('WARNING! selector was released but was already unlocked');
|
||||
}
|
||||
for (i = 0; i < N; ++i) {
|
||||
if (this.selectors[i] && this.selectors[i] === sel) {
|
||||
delete this.selectorMap[elem.id];
|
||||
sel.locked = false;
|
||||
sel.selectedElement = null;
|
||||
sel.showGrips(false);
|
||||
if (elem == null) { return; }
|
||||
var i,
|
||||
N = this.selectors.length,
|
||||
sel = this.selectorMap[elem.id];
|
||||
if (!sel.locked) {
|
||||
// TODO(codedread): Ensure this exists in this module.
|
||||
console.log('WARNING! selector was released but was already unlocked');
|
||||
}
|
||||
for (i = 0; i < N; ++i) {
|
||||
if (this.selectors[i] && this.selectors[i] === sel) {
|
||||
delete this.selectorMap[elem.id];
|
||||
sel.locked = false;
|
||||
sel.selectedElement = null;
|
||||
sel.showGrips(false);
|
||||
|
||||
// remove from DOM and store reference in JS but only if it exists in the DOM
|
||||
try {
|
||||
sel.selectorGroup.setAttribute('display', 'none');
|
||||
} catch (e) {}
|
||||
// remove from DOM and store reference in JS but only if it exists in the DOM
|
||||
try {
|
||||
sel.selectorGroup.setAttribute('display', 'none');
|
||||
} catch (e) {}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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 () {
|
||||
if (!this.rubberBandBox) {
|
||||
this.rubberBandBox = this.selectorParentGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'rect',
|
||||
'attr': {
|
||||
'id': 'selectorRubberBand',
|
||||
'fill': '#22C',
|
||||
'fill-opacity': 0.15,
|
||||
'stroke': '#22C',
|
||||
'stroke-width': 0.5,
|
||||
'display': 'none',
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
return this.rubberBandBox;
|
||||
if (!this.rubberBandBox) {
|
||||
this.rubberBandBox = this.selectorParentGroup.appendChild(
|
||||
svgFactory_.createSVGElement({
|
||||
'element': 'rect',
|
||||
'attr': {
|
||||
'id': 'selectorRubberBand',
|
||||
'fill': '#22C',
|
||||
'fill-opacity': 0.15,
|
||||
'stroke': '#22C',
|
||||
'stroke-width': 0.5,
|
||||
'display': 'none',
|
||||
'style': 'pointer-events:none'
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
return this.rubberBandBox;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -519,9 +519,9 @@ svgedit.select.SelectorManager.prototype.getRubberBandBox = function () {
|
|||
* svgFactory - an object implementing the SVGFactory interface (see above).
|
||||
*/
|
||||
svgedit.select.init = function (config, svgFactory) {
|
||||
config_ = config;
|
||||
svgFactory_ = svgFactory;
|
||||
selectorManager_ = new svgedit.select.SelectorManager();
|
||||
config_ = config;
|
||||
svgFactory_ = svgFactory;
|
||||
selectorManager_ = new svgedit.select.SelectorManager();
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -531,6 +531,6 @@ svgedit.select.init = function (config, svgFactory) {
|
|||
* The SelectorManager instance.
|
||||
*/
|
||||
svgedit.select.getSelectorManager = function () {
|
||||
return selectorManager_;
|
||||
return selectorManager_;
|
||||
};
|
||||
}());
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
10282
editor/svg-editor.js
10282
editor/svg-editor.js
File diff suppressed because it is too large
Load Diff
10420
editor/svgcanvas.js
10420
editor/svgcanvas.js
File diff suppressed because it is too large
Load Diff
|
@ -7,24 +7,24 @@
|
|||
*/
|
||||
|
||||
svgedit = {
|
||||
// common namepaces constants in alpha order
|
||||
NS: {
|
||||
HTML: 'http://www.w3.org/1999/xhtml',
|
||||
MATH: 'http://www.w3.org/1998/Math/MathML',
|
||||
SE: 'http://svg-edit.googlecode.com',
|
||||
SVG: 'http://www.w3.org/2000/svg',
|
||||
XLINK: 'http://www.w3.org/1999/xlink',
|
||||
XML: 'http://www.w3.org/XML/1998/namespace',
|
||||
XMLNS: 'http://www.w3.org/2000/xmlns/' // see http://www.w3.org/TR/REC-xml-names/#xmlReserved
|
||||
}
|
||||
// common namepaces constants in alpha order
|
||||
NS: {
|
||||
HTML: 'http://www.w3.org/1999/xhtml',
|
||||
MATH: 'http://www.w3.org/1998/Math/MathML',
|
||||
SE: 'http://svg-edit.googlecode.com',
|
||||
SVG: 'http://www.w3.org/2000/svg',
|
||||
XLINK: 'http://www.w3.org/1999/xlink',
|
||||
XML: 'http://www.w3.org/XML/1998/namespace',
|
||||
XMLNS: 'http://www.w3.org/2000/xmlns/' // see http://www.w3.org/TR/REC-xml-names/#xmlReserved
|
||||
}
|
||||
};
|
||||
|
||||
// return the svgedit.NS with key values switched and lowercase
|
||||
svgedit.getReverseNS = function () {
|
||||
'use strict';
|
||||
var reverseNS = {};
|
||||
$.each(this.NS, function (name, URI) {
|
||||
reverseNS[URI] = name.toLowerCase();
|
||||
});
|
||||
return reverseNS;
|
||||
'use strict';
|
||||
var reverseNS = {};
|
||||
$.each(this.NS, function (name, URI) {
|
||||
reverseNS[URI] = name.toLowerCase();
|
||||
});
|
||||
return reverseNS;
|
||||
};
|
||||
|
|
|
@ -16,41 +16,41 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.transformlist) {
|
||||
svgedit.transformlist = {};
|
||||
svgedit.transformlist = {};
|
||||
}
|
||||
|
||||
var svgroot = document.createElementNS(svgedit.NS.SVG, 'svg');
|
||||
|
||||
// Helper function.
|
||||
function transformToString (xform) {
|
||||
var m = xform.matrix,
|
||||
text = '';
|
||||
switch (xform.type) {
|
||||
case 1: // MATRIX
|
||||
text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')';
|
||||
break;
|
||||
case 2: // TRANSLATE
|
||||
text = 'translate(' + m.e + ',' + m.f + ')';
|
||||
break;
|
||||
case 3: // SCALE
|
||||
if (m.a === m.d) {
|
||||
text = 'scale(' + m.a + ')';
|
||||
} else {
|
||||
text = 'scale(' + m.a + ',' + m.d + ')';
|
||||
}
|
||||
break;
|
||||
case 4: // ROTATE
|
||||
var cx = 0, cy = 0;
|
||||
// this prevents divide by zero
|
||||
if (xform.angle !== 0) {
|
||||
var K = 1 - m.a;
|
||||
cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b);
|
||||
cx = (m.e - m.b * cy) / K;
|
||||
}
|
||||
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
|
||||
break;
|
||||
}
|
||||
return text;
|
||||
var m = xform.matrix,
|
||||
text = '';
|
||||
switch (xform.type) {
|
||||
case 1: // MATRIX
|
||||
text = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')';
|
||||
break;
|
||||
case 2: // TRANSLATE
|
||||
text = 'translate(' + m.e + ',' + m.f + ')';
|
||||
break;
|
||||
case 3: // SCALE
|
||||
if (m.a === m.d) {
|
||||
text = 'scale(' + m.a + ')';
|
||||
} else {
|
||||
text = 'scale(' + m.a + ',' + m.d + ')';
|
||||
}
|
||||
break;
|
||||
case 4: // ROTATE
|
||||
var cx = 0, cy = 0;
|
||||
// this prevents divide by zero
|
||||
if (xform.angle !== 0) {
|
||||
var K = 1 - m.a;
|
||||
cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b);
|
||||
cx = (m.e - m.b * cy) / K;
|
||||
}
|
||||
text = 'rotate(' + xform.angle + ' ' + cx + ',' + cy + ')';
|
||||
break;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,176 +78,176 @@ var listMap_ = {};
|
|||
// }
|
||||
// **************************************************************************************
|
||||
svgedit.transformlist.SVGTransformList = function (elem) {
|
||||
this._elem = elem || null;
|
||||
this._xforms = [];
|
||||
// TODO: how do we capture the undo-ability in the changed transform list?
|
||||
this._update = function () {
|
||||
var tstr = '';
|
||||
/* var concatMatrix = */ svgroot.createSVGMatrix();
|
||||
var i;
|
||||
for (i = 0; i < this.numberOfItems; ++i) {
|
||||
var xform = this._list.getItem(i);
|
||||
tstr += transformToString(xform) + ' ';
|
||||
}
|
||||
this._elem.setAttribute('transform', tstr);
|
||||
};
|
||||
this._list = this;
|
||||
this._init = function () {
|
||||
// Transform attribute parser
|
||||
var str = this._elem.getAttribute('transform');
|
||||
if (!str) { return; }
|
||||
this._elem = elem || null;
|
||||
this._xforms = [];
|
||||
// TODO: how do we capture the undo-ability in the changed transform list?
|
||||
this._update = function () {
|
||||
var tstr = '';
|
||||
/* var concatMatrix = */ svgroot.createSVGMatrix();
|
||||
var i;
|
||||
for (i = 0; i < this.numberOfItems; ++i) {
|
||||
var xform = this._list.getItem(i);
|
||||
tstr += transformToString(xform) + ' ';
|
||||
}
|
||||
this._elem.setAttribute('transform', tstr);
|
||||
};
|
||||
this._list = this;
|
||||
this._init = function () {
|
||||
// Transform attribute parser
|
||||
var str = this._elem.getAttribute('transform');
|
||||
if (!str) { return; }
|
||||
|
||||
// TODO: Add skew support in future
|
||||
var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
|
||||
var m = true;
|
||||
while (m) {
|
||||
m = str.match(re);
|
||||
str = str.replace(re, '');
|
||||
if (m && m[1]) {
|
||||
var x = m[1];
|
||||
var bits = x.split(/\s*\(/);
|
||||
var name = bits[0];
|
||||
var 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(valArr, function (i, item) {
|
||||
valArr[i] = parseFloat(item);
|
||||
if (name === 'matrix') {
|
||||
mtx[letters[i]] = valArr[i];
|
||||
}
|
||||
});
|
||||
var xform = svgroot.createSVGTransform();
|
||||
var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1);
|
||||
var values = name === 'matrix' ? [mtx] : valArr;
|
||||
// TODO: Add skew support in future
|
||||
var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/;
|
||||
var m = true;
|
||||
while (m) {
|
||||
m = str.match(re);
|
||||
str = str.replace(re, '');
|
||||
if (m && m[1]) {
|
||||
var x = m[1];
|
||||
var bits = x.split(/\s*\(/);
|
||||
var name = bits[0];
|
||||
var 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(valArr, function (i, item) {
|
||||
valArr[i] = parseFloat(item);
|
||||
if (name === 'matrix') {
|
||||
mtx[letters[i]] = valArr[i];
|
||||
}
|
||||
});
|
||||
var xform = svgroot.createSVGTransform();
|
||||
var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1);
|
||||
var values = name === 'matrix' ? [mtx] : valArr;
|
||||
|
||||
if (name === 'scale' && values.length === 1) {
|
||||
values.push(values[0]);
|
||||
} else if (name === 'translate' && values.length === 1) {
|
||||
values.push(0);
|
||||
} else if (name === 'rotate' && values.length === 1) {
|
||||
values.push(0, 0);
|
||||
}
|
||||
xform[fname].apply(xform, values);
|
||||
this._list.appendItem(xform);
|
||||
}
|
||||
}
|
||||
};
|
||||
this._removeFromOtherLists = function (item) {
|
||||
if (item) {
|
||||
// Check if this transform is already in a transformlist, and
|
||||
// remove it if so.
|
||||
var found = false;
|
||||
var id;
|
||||
for (id in listMap_) {
|
||||
var tl = listMap_[id];
|
||||
var i, len;
|
||||
for (i = 0, len = tl._xforms.length; i < len; ++i) {
|
||||
if (tl._xforms[i] === item) {
|
||||
found = true;
|
||||
tl.removeItem(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if (name === 'scale' && values.length === 1) {
|
||||
values.push(values[0]);
|
||||
} else if (name === 'translate' && values.length === 1) {
|
||||
values.push(0);
|
||||
} else if (name === 'rotate' && values.length === 1) {
|
||||
values.push(0, 0);
|
||||
}
|
||||
xform[fname].apply(xform, values);
|
||||
this._list.appendItem(xform);
|
||||
}
|
||||
}
|
||||
};
|
||||
this._removeFromOtherLists = function (item) {
|
||||
if (item) {
|
||||
// Check if this transform is already in a transformlist, and
|
||||
// remove it if so.
|
||||
var found = false;
|
||||
var id;
|
||||
for (id in listMap_) {
|
||||
var tl = listMap_[id];
|
||||
var i, len;
|
||||
for (i = 0, len = tl._xforms.length; i < len; ++i) {
|
||||
if (tl._xforms[i] === item) {
|
||||
found = true;
|
||||
tl.removeItem(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.numberOfItems = 0;
|
||||
this.clear = function () {
|
||||
this.numberOfItems = 0;
|
||||
this._xforms = [];
|
||||
};
|
||||
this.numberOfItems = 0;
|
||||
this.clear = function () {
|
||||
this.numberOfItems = 0;
|
||||
this._xforms = [];
|
||||
};
|
||||
|
||||
this.initialize = function (newItem) {
|
||||
this.numberOfItems = 1;
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms = [newItem];
|
||||
};
|
||||
this.initialize = function (newItem) {
|
||||
this.numberOfItems = 1;
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms = [newItem];
|
||||
};
|
||||
|
||||
this.getItem = function (index) {
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
return this._xforms[index];
|
||||
}
|
||||
var err = new Error('DOMException with code=INDEX_SIZE_ERR');
|
||||
err.code = 1;
|
||||
throw err;
|
||||
};
|
||||
this.getItem = function (index) {
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
return this._xforms[index];
|
||||
}
|
||||
var err = new Error('DOMException with code=INDEX_SIZE_ERR');
|
||||
err.code = 1;
|
||||
throw err;
|
||||
};
|
||||
|
||||
this.insertItemBefore = function (newItem, index) {
|
||||
var retValue = null;
|
||||
if (index >= 0) {
|
||||
if (index < this.numberOfItems) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
var newxforms = new Array(this.numberOfItems + 1);
|
||||
// TODO: use array copying and slicing
|
||||
var i;
|
||||
for (i = 0; i < index; ++i) {
|
||||
newxforms[i] = this._xforms[i];
|
||||
}
|
||||
newxforms[i] = newItem;
|
||||
var j;
|
||||
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 {
|
||||
retValue = this._list.appendItem(newItem);
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
};
|
||||
this.insertItemBefore = function (newItem, index) {
|
||||
var retValue = null;
|
||||
if (index >= 0) {
|
||||
if (index < this.numberOfItems) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
var newxforms = new Array(this.numberOfItems + 1);
|
||||
// TODO: use array copying and slicing
|
||||
var i;
|
||||
for (i = 0; i < index; ++i) {
|
||||
newxforms[i] = this._xforms[i];
|
||||
}
|
||||
newxforms[i] = newItem;
|
||||
var j;
|
||||
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 {
|
||||
retValue = this._list.appendItem(newItem);
|
||||
}
|
||||
}
|
||||
return retValue;
|
||||
};
|
||||
|
||||
this.replaceItem = function (newItem, index) {
|
||||
var retValue = null;
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms[index] = newItem;
|
||||
retValue = newItem;
|
||||
this._list._update();
|
||||
}
|
||||
return retValue;
|
||||
};
|
||||
this.replaceItem = function (newItem, index) {
|
||||
var retValue = null;
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms[index] = newItem;
|
||||
retValue = newItem;
|
||||
this._list._update();
|
||||
}
|
||||
return retValue;
|
||||
};
|
||||
|
||||
this.removeItem = function (index) {
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
var retValue = this._xforms[index];
|
||||
var newxforms = new Array(this.numberOfItems - 1);
|
||||
var i, j;
|
||||
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];
|
||||
}
|
||||
this.numberOfItems--;
|
||||
this._xforms = newxforms;
|
||||
this._list._update();
|
||||
return retValue;
|
||||
}
|
||||
var err = new Error('DOMException with code=INDEX_SIZE_ERR');
|
||||
err.code = 1;
|
||||
throw err;
|
||||
};
|
||||
this.removeItem = function (index) {
|
||||
if (index < this.numberOfItems && index >= 0) {
|
||||
var retValue = this._xforms[index];
|
||||
var newxforms = new Array(this.numberOfItems - 1);
|
||||
var i, j;
|
||||
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];
|
||||
}
|
||||
this.numberOfItems--;
|
||||
this._xforms = newxforms;
|
||||
this._list._update();
|
||||
return retValue;
|
||||
}
|
||||
var err = new Error('DOMException with code=INDEX_SIZE_ERR');
|
||||
err.code = 1;
|
||||
throw err;
|
||||
};
|
||||
|
||||
this.appendItem = function (newItem) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms.push(newItem);
|
||||
this.numberOfItems++;
|
||||
this._list._update();
|
||||
return newItem;
|
||||
};
|
||||
this.appendItem = function (newItem) {
|
||||
this._removeFromOtherLists(newItem);
|
||||
this._xforms.push(newItem);
|
||||
this.numberOfItems++;
|
||||
this._list._update();
|
||||
return newItem;
|
||||
};
|
||||
};
|
||||
|
||||
svgedit.transformlist.resetListMap = function () {
|
||||
listMap_ = {};
|
||||
listMap_ = {};
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -256,9 +256,9 @@ svgedit.transformlist.resetListMap = function () {
|
|||
* elem - a DOM Element
|
||||
*/
|
||||
svgedit.transformlist.removeElementFromListMap = function (elem) {
|
||||
if (elem.id && listMap_[elem.id]) {
|
||||
delete listMap_[elem.id];
|
||||
}
|
||||
if (elem.id && listMap_[elem.id]) {
|
||||
delete listMap_[elem.id];
|
||||
}
|
||||
};
|
||||
|
||||
// Function: getTransformList
|
||||
|
@ -267,26 +267,26 @@ svgedit.transformlist.removeElementFromListMap = function (elem) {
|
|||
// Parameters:
|
||||
// elem - DOM element to get a transformlist from
|
||||
svgedit.transformlist.getTransformList = function (elem) {
|
||||
if (!svgedit.browser.supportsNativeTransformLists()) {
|
||||
var id = elem.id || 'temp';
|
||||
var t = listMap_[id];
|
||||
if (!t || id === 'temp') {
|
||||
listMap_[id] = new svgedit.transformlist.SVGTransformList(elem);
|
||||
listMap_[id]._init();
|
||||
t = listMap_[id];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
if (elem.transform) {
|
||||
return elem.transform.baseVal;
|
||||
}
|
||||
if (elem.gradientTransform) {
|
||||
return elem.gradientTransform.baseVal;
|
||||
}
|
||||
if (elem.patternTransform) {
|
||||
return elem.patternTransform.baseVal;
|
||||
}
|
||||
if (!svgedit.browser.supportsNativeTransformLists()) {
|
||||
var id = elem.id || 'temp';
|
||||
var t = listMap_[id];
|
||||
if (!t || id === 'temp') {
|
||||
listMap_[id] = new svgedit.transformlist.SVGTransformList(elem);
|
||||
listMap_[id]._init();
|
||||
t = listMap_[id];
|
||||
}
|
||||
return t;
|
||||
}
|
||||
if (elem.transform) {
|
||||
return elem.transform.baseVal;
|
||||
}
|
||||
if (elem.gradientTransform) {
|
||||
return elem.gradientTransform.baseVal;
|
||||
}
|
||||
if (elem.patternTransform) {
|
||||
return elem.patternTransform.baseVal;
|
||||
}
|
||||
|
||||
return null;
|
||||
return null;
|
||||
};
|
||||
}());
|
||||
|
|
1782
editor/svgutils.js
1782
editor/svgutils.js
File diff suppressed because it is too large
Load Diff
|
@ -1,32 +1,32 @@
|
|||
/* eslint-disable no-var */
|
||||
// http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/
|
||||
function touchHandler (event) {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
var simulatedEvent,
|
||||
touches = event.changedTouches,
|
||||
first = touches[0],
|
||||
type = '';
|
||||
switch (event.type) {
|
||||
case 'touchstart': type = 'mousedown'; break;
|
||||
case 'touchmove': type = 'mousemove'; break;
|
||||
case 'touchend': type = 'mouseup'; break;
|
||||
default: return;
|
||||
}
|
||||
var simulatedEvent,
|
||||
touches = event.changedTouches,
|
||||
first = touches[0],
|
||||
type = '';
|
||||
switch (event.type) {
|
||||
case 'touchstart': type = 'mousedown'; break;
|
||||
case 'touchmove': type = 'mousemove'; break;
|
||||
case 'touchend': type = 'mouseup'; break;
|
||||
default: return;
|
||||
}
|
||||
|
||||
// initMouseEvent(type, canBubble, cancelable, view, clickCount,
|
||||
// screenX, screenY, clientX, clientY, ctrlKey,
|
||||
// altKey, shiftKey, metaKey, button, relatedTarget);
|
||||
// initMouseEvent(type, canBubble, cancelable, view, clickCount,
|
||||
// screenX, screenY, clientX, clientY, ctrlKey,
|
||||
// altKey, shiftKey, metaKey, button, relatedTarget);
|
||||
|
||||
simulatedEvent = document.createEvent('MouseEvent');
|
||||
simulatedEvent.initMouseEvent(type, true, true, window, 1,
|
||||
first.screenX, first.screenY,
|
||||
first.clientX, first.clientY, false,
|
||||
false, false, false, 0/* left */, null);
|
||||
if (touches.length < 2) {
|
||||
first.target.dispatchEvent(simulatedEvent);
|
||||
event.preventDefault();
|
||||
}
|
||||
simulatedEvent = document.createEvent('MouseEvent');
|
||||
simulatedEvent.initMouseEvent(type, true, true, window, 1,
|
||||
first.screenX, first.screenY,
|
||||
first.clientX, first.clientY, false,
|
||||
false, false, false, 0/* left */, null);
|
||||
if (touches.length < 2) {
|
||||
first.target.dispatchEvent(simulatedEvent);
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('touchstart', touchHandler, true);
|
||||
|
|
310
editor/units.js
310
editor/units.js
|
@ -16,7 +16,7 @@
|
|||
'use strict';
|
||||
|
||||
if (!svgedit.units) {
|
||||
svgedit.units = {};
|
||||
svgedit.units = {};
|
||||
}
|
||||
|
||||
var NS = svgedit.NS;
|
||||
|
@ -26,15 +26,15 @@ var unitAttrs = ['r', 'radius'].concat(wAttrs, hAttrs);
|
|||
// unused
|
||||
/*
|
||||
var unitNumMap = {
|
||||
'%': 2,
|
||||
'em': 3,
|
||||
'ex': 4,
|
||||
'px': 5,
|
||||
'cm': 6,
|
||||
'mm': 7,
|
||||
'in': 8,
|
||||
'pt': 9,
|
||||
'pc': 10
|
||||
'%': 2,
|
||||
'em': 3,
|
||||
'ex': 4,
|
||||
'px': 5,
|
||||
'cm': 6,
|
||||
'mm': 7,
|
||||
'in': 8,
|
||||
'pt': 9,
|
||||
'pc': 10
|
||||
};
|
||||
*/
|
||||
// Container of elements.
|
||||
|
@ -63,31 +63,31 @@ var typeMap_ = {};
|
|||
* elementContainer - an object implementing the ElementContainer interface.
|
||||
*/
|
||||
svgedit.units.init = function (elementContainer) {
|
||||
elementContainer_ = elementContainer;
|
||||
elementContainer_ = elementContainer;
|
||||
|
||||
// Get correct em/ex values by creating a temporary SVG.
|
||||
var svg = document.createElementNS(NS.SVG, 'svg');
|
||||
document.body.appendChild(svg);
|
||||
var rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('width', '1em');
|
||||
rect.setAttribute('height', '1ex');
|
||||
rect.setAttribute('x', '1in');
|
||||
svg.appendChild(rect);
|
||||
var bb = rect.getBBox();
|
||||
document.body.removeChild(svg);
|
||||
// Get correct em/ex values by creating a temporary SVG.
|
||||
var svg = document.createElementNS(NS.SVG, 'svg');
|
||||
document.body.appendChild(svg);
|
||||
var rect = document.createElementNS(NS.SVG, 'rect');
|
||||
rect.setAttribute('width', '1em');
|
||||
rect.setAttribute('height', '1ex');
|
||||
rect.setAttribute('x', '1in');
|
||||
svg.appendChild(rect);
|
||||
var bb = rect.getBBox();
|
||||
document.body.removeChild(svg);
|
||||
|
||||
var inch = bb.x;
|
||||
typeMap_ = {
|
||||
'em': bb.width,
|
||||
'ex': bb.height,
|
||||
'in': inch,
|
||||
'cm': inch / 2.54,
|
||||
'mm': inch / 25.4,
|
||||
'pt': inch / 72,
|
||||
'pc': inch / 6,
|
||||
'px': 1,
|
||||
'%': 0
|
||||
};
|
||||
var inch = bb.x;
|
||||
typeMap_ = {
|
||||
'em': bb.width,
|
||||
'ex': bb.height,
|
||||
'in': inch,
|
||||
'cm': inch / 2.54,
|
||||
'mm': inch / 25.4,
|
||||
'pt': inch / 72,
|
||||
'pc': inch / 6,
|
||||
'px': 1,
|
||||
'%': 0
|
||||
};
|
||||
};
|
||||
|
||||
// Group: Unit conversion functions
|
||||
|
@ -95,7 +95,7 @@ svgedit.units.init = function (elementContainer) {
|
|||
// Function: svgedit.units.getTypeMap
|
||||
// Returns the unit object with values for each unit
|
||||
svgedit.units.getTypeMap = function () {
|
||||
return typeMap_;
|
||||
return typeMap_;
|
||||
};
|
||||
|
||||
// Function: svgedit.units.shortFloat
|
||||
|
@ -108,25 +108,25 @@ svgedit.units.getTypeMap = function () {
|
|||
// If a string/number was given, returns a Float. If an array, return a string
|
||||
// with comma-separated floats
|
||||
svgedit.units.shortFloat = function (val) {
|
||||
var digits = elementContainer_.getRoundDigits();
|
||||
if (!isNaN(val)) {
|
||||
// Note that + converts to Number
|
||||
return +((+val).toFixed(digits));
|
||||
}
|
||||
if ($.isArray(val)) {
|
||||
return svgedit.units.shortFloat(val[0]) + ',' + svgedit.units.shortFloat(val[1]);
|
||||
}
|
||||
return parseFloat(val).toFixed(digits) - 0;
|
||||
var digits = elementContainer_.getRoundDigits();
|
||||
if (!isNaN(val)) {
|
||||
// Note that + converts to Number
|
||||
return +((+val).toFixed(digits));
|
||||
}
|
||||
if ($.isArray(val)) {
|
||||
return svgedit.units.shortFloat(val[0]) + ',' + svgedit.units.shortFloat(val[1]);
|
||||
}
|
||||
return parseFloat(val).toFixed(digits) - 0;
|
||||
};
|
||||
|
||||
// Function: svgedit.units.convertUnit
|
||||
// Converts the number to given unit or baseUnit
|
||||
svgedit.units.convertUnit = function (val, unit) {
|
||||
unit = unit || elementContainer_.getBaseUnit();
|
||||
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
|
||||
// var val = baseVal.valueInSpecifiedUnits;
|
||||
// baseVal.convertToSpecifiedUnits(1);
|
||||
return svgedit.units.shortFloat(val / typeMap_[unit]);
|
||||
unit = unit || elementContainer_.getBaseUnit();
|
||||
// baseVal.convertToSpecifiedUnits(unitNumMap[unit]);
|
||||
// var val = baseVal.valueInSpecifiedUnits;
|
||||
// baseVal.convertToSpecifiedUnits(1);
|
||||
return svgedit.units.shortFloat(val / typeMap_[unit]);
|
||||
};
|
||||
|
||||
// Function: svgedit.units.setUnitAttr
|
||||
|
@ -137,49 +137,49 @@ svgedit.units.convertUnit = function (val, unit) {
|
|||
// 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);
|
||||
// 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;
|
||||
// }
|
||||
// }
|
||||
elem.setAttribute(attr, val);
|
||||
// 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);
|
||||
};
|
||||
|
||||
var attrsToConvert = {
|
||||
'line': ['x1', 'x2', 'y1', 'y2'],
|
||||
'circle': ['cx', 'cy', 'r'],
|
||||
'ellipse': ['cx', 'cy', 'rx', 'ry'],
|
||||
'foreignObject': ['x', 'y', 'width', 'height'],
|
||||
'rect': ['x', 'y', 'width', 'height'],
|
||||
'image': ['x', 'y', 'width', 'height'],
|
||||
'use': ['x', 'y', 'width', 'height'],
|
||||
'text': ['x', 'y']
|
||||
'line': ['x1', 'x2', 'y1', 'y2'],
|
||||
'circle': ['cx', 'cy', 'r'],
|
||||
'ellipse': ['cx', 'cy', 'rx', 'ry'],
|
||||
'foreignObject': ['x', 'y', 'width', 'height'],
|
||||
'rect': ['x', 'y', 'width', 'height'],
|
||||
'image': ['x', 'y', 'width', 'height'],
|
||||
'use': ['x', 'y', 'width', 'height'],
|
||||
'text': ['x', 'y']
|
||||
};
|
||||
|
||||
// Function: svgedit.units.convertAttrs
|
||||
|
@ -188,25 +188,25 @@ var attrsToConvert = {
|
|||
// Parameters:
|
||||
// element - a DOM element whose attributes should be converted
|
||||
svgedit.units.convertAttrs = function (element) {
|
||||
var elName = element.tagName;
|
||||
var unit = elementContainer_.getBaseUnit();
|
||||
var attrs = attrsToConvert[elName];
|
||||
if (!attrs) { return; }
|
||||
var elName = element.tagName;
|
||||
var unit = elementContainer_.getBaseUnit();
|
||||
var attrs = attrsToConvert[elName];
|
||||
if (!attrs) { return; }
|
||||
|
||||
var len = attrs.length;
|
||||
var i;
|
||||
for (i = 0; i < len; i++) {
|
||||
var attr = attrs[i];
|
||||
var cur = element.getAttribute(attr);
|
||||
if (cur) {
|
||||
if (!isNaN(cur)) {
|
||||
element.setAttribute(attr, (cur / typeMap_[unit]) + unit);
|
||||
}
|
||||
// else {
|
||||
// Convert existing?
|
||||
// }
|
||||
}
|
||||
}
|
||||
var len = attrs.length;
|
||||
var i;
|
||||
for (i = 0; i < len; i++) {
|
||||
var attr = attrs[i];
|
||||
var cur = element.getAttribute(attr);
|
||||
if (cur) {
|
||||
if (!isNaN(cur)) {
|
||||
element.setAttribute(attr, (cur / typeMap_[unit]) + unit);
|
||||
}
|
||||
// else {
|
||||
// Convert existing?
|
||||
// }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Function: svgedit.units.convertToNum
|
||||
|
@ -217,27 +217,27 @@ svgedit.units.convertAttrs = function (element) {
|
|||
// attr - String with the name of the attribute associated with the value
|
||||
// val - String with the attribute value to convert
|
||||
svgedit.units.convertToNum = function (attr, val) {
|
||||
// Return a number if that's what it already is
|
||||
if (!isNaN(val)) { return val - 0; }
|
||||
var num;
|
||||
if (val.substr(-1) === '%') {
|
||||
// Deal with percentage, depends on attribute
|
||||
num = val.substr(0, val.length - 1) / 100;
|
||||
var width = elementContainer_.getWidth();
|
||||
var height = elementContainer_.getHeight();
|
||||
// Return a number if that's what it already is
|
||||
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;
|
||||
var width = elementContainer_.getWidth();
|
||||
var height = elementContainer_.getHeight();
|
||||
|
||||
if (wAttrs.indexOf(attr) >= 0) {
|
||||
return num * width;
|
||||
}
|
||||
if (hAttrs.indexOf(attr) >= 0) {
|
||||
return num * height;
|
||||
}
|
||||
return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2);
|
||||
}
|
||||
var unit = val.substr(-2);
|
||||
num = val.substr(0, val.length - 2);
|
||||
// Note that this multiplication turns the string into a number
|
||||
return num * typeMap_[unit];
|
||||
if (wAttrs.indexOf(attr) >= 0) {
|
||||
return num * width;
|
||||
}
|
||||
if (hAttrs.indexOf(attr) >= 0) {
|
||||
return num * height;
|
||||
}
|
||||
return num * Math.sqrt((width * width) + (height * height)) / Math.sqrt(2);
|
||||
}
|
||||
var unit = val.substr(-2);
|
||||
num = val.substr(0, val.length - 2);
|
||||
// Note that this multiplication turns the string into a number
|
||||
return num * typeMap_[unit];
|
||||
};
|
||||
|
||||
// Function: svgedit.units.isValidUnit
|
||||
|
@ -247,37 +247,37 @@ svgedit.units.convertToNum = function (attr, val) {
|
|||
// attr - String with the name of the attribute associated with the value
|
||||
// val - String with the attribute value to check
|
||||
svgedit.units.isValidUnit = function (attr, val, selectedElement) {
|
||||
var valid = false;
|
||||
if (unitAttrs.indexOf(attr) >= 0) {
|
||||
// True if it's just a number
|
||||
if (!isNaN(val)) {
|
||||
valid = true;
|
||||
} else {
|
||||
// Not a number, check if it has a valid unit
|
||||
val = val.toLowerCase();
|
||||
$.each(typeMap_, function (unit) {
|
||||
if (valid) { return; }
|
||||
var re = new RegExp('^-?[\\d\\.]+' + unit + '$');
|
||||
if (re.test(val)) { valid = true; }
|
||||
});
|
||||
}
|
||||
} else if (attr === 'id') {
|
||||
// if we're trying to change the id, make sure it's not already present in the doc
|
||||
// and the id value is valid.
|
||||
var valid = false;
|
||||
if (unitAttrs.indexOf(attr) >= 0) {
|
||||
// True if it's just a number
|
||||
if (!isNaN(val)) {
|
||||
valid = true;
|
||||
} else {
|
||||
// Not a number, check if it has a valid unit
|
||||
val = val.toLowerCase();
|
||||
$.each(typeMap_, function (unit) {
|
||||
if (valid) { return; }
|
||||
var re = new RegExp('^-?[\\d\\.]+' + unit + '$');
|
||||
if (re.test(val)) { valid = true; }
|
||||
});
|
||||
}
|
||||
} else if (attr === 'id') {
|
||||
// if we're trying to change the id, make sure it's not already present in the doc
|
||||
// and the id value is valid.
|
||||
|
||||
var result = false;
|
||||
// because getElem() can throw an exception in the case of an invalid id
|
||||
// (according to http://www.w3.org/TR/xml-id/ IDs must be a NCName)
|
||||
// we wrap it in an exception and only return true if the ID was valid and
|
||||
// not already present
|
||||
try {
|
||||
var elem = elementContainer_.getElement(val);
|
||||
result = (elem == null || elem === selectedElement);
|
||||
} catch (e) {}
|
||||
return result;
|
||||
}
|
||||
valid = true;
|
||||
var result = false;
|
||||
// because getElem() can throw an exception in the case of an invalid id
|
||||
// (according to http://www.w3.org/TR/xml-id/ IDs must be a NCName)
|
||||
// we wrap it in an exception and only return true if the ID was valid and
|
||||
// not already present
|
||||
try {
|
||||
var elem = elementContainer_.getElement(val);
|
||||
result = (elem == null || elem === selectedElement);
|
||||
} catch (e) {}
|
||||
return result;
|
||||
}
|
||||
valid = true;
|
||||
|
||||
return valid;
|
||||
return valid;
|
||||
};
|
||||
}());
|
||||
|
|
Loading…
Reference in New Issue