- Breaking change: Extension now formatted as export (and this is set to editor, including for callback)

- Breaking change: Locale now formatted as export
- Breaking change: Moved out remaining modular i18n (imagelib) to own folder
- Breaking change: Drop `executeAfterLoads` (and getJSPDF/getCanvg)
- Breaking change: `RGBColor` must accept `new`
- Breaking change: canvg - `stackBlurCanvasRGBA` must be set now by function (`setStackBlurCanvasRGBA`) rather than global; `canvg` now a named export
- Breaking change: Avoid passing `canvg`/`buildCanvgCallback` to extensions (have them import)
- Fix: i18nize imaglib more deeply
- Fix: Positioning of Document Properties dialog (Fixes #246)
- Fix (regression): PDF Export (Fixes #249)
- Fix (regression): Add polyfill for `ChildNode`/`ParentNode` (and use further)
- Fix (regression): Apply Babel universally to dependencies
- Fix (regression): Ordering of `uaPrefix` function in `svgEditor.js`
- Fix (regression): Embedded API
- Fix (embedded editor): Fix backspace key in Firefox so it doesn't navigate out of frame
- Fix: Alert if no exportWindow for PDF (e.g., if blocked)
- Refactoring( RGBColor) `RGBColor` as class, without rebuilding constants, optimize string replacement, move methods to prototype, use templates and object literals, use `Object.keys`
- Refactoring (canvg) Use classes more internally, use shorthand objects; array extras, return to lazy-loading
- Refactoring: Use Promises in place of `$.getScript`; always return Promises in case deciding to await resolving
- Refactoring: Avoid importing `RGBColor` into `svgutils.js` (jsPDF imports it itself)
- Refactoring: Arrow functions, destructuring, shorter property references
- Refactoring: Fix `lang` and `dir` for locales (though not in use currently anyways)
- Refactoring: Provide path config for canvg, jspdf
This commit is contained in:
Brett Zamir
2018-06-02 09:14:38 +08:00
parent a2df54881f
commit 9f65b1adb9
226 changed files with 26026 additions and 19715 deletions

View File

@@ -72,42 +72,41 @@ return false;
const supportsGoodTextCharPos_ = (function () {
const svgroot = document.createElementNS(NS.SVG, 'svg');
const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgroot);
document.documentElement.append(svgroot);
svgcontent.setAttribute('x', 5);
svgroot.appendChild(svgcontent);
svgroot.append(svgcontent);
const text = document.createElementNS(NS.SVG, 'text');
text.textContent = 'a';
svgcontent.appendChild(text);
svgcontent.append(text);
const pos = text.getStartPositionOfChar(0).x;
document.documentElement.removeChild(svgroot);
svgroot.remove();
return (pos === 0);
}());
const supportsPathBBox_ = (function () {
const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgcontent);
document.documentElement.append(svgcontent);
const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 C0,0 10,10 10,0');
svgcontent.appendChild(path);
svgcontent.append(path);
const bbox = path.getBBox();
document.documentElement.removeChild(svgcontent);
svgcontent.remove();
return (bbox.height > 4 && bbox.height < 5);
}());
// Support for correct bbox sizing on groups with horizontal/vertical lines
const supportsHVLineContainerBBox_ = (function () {
const svgcontent = document.createElementNS(NS.SVG, 'svg');
document.documentElement.appendChild(svgcontent);
document.documentElement.append(svgcontent);
const path = document.createElementNS(NS.SVG, 'path');
path.setAttribute('d', 'M0,0 10,0');
const path2 = document.createElementNS(NS.SVG, 'path');
path2.setAttribute('d', 'M5,0 15,0');
const g = document.createElementNS(NS.SVG, 'g');
g.appendChild(path);
g.appendChild(path2);
svgcontent.appendChild(g);
g.append(path, path2);
svgcontent.append(g);
const bbox = g.getBBox();
document.documentElement.removeChild(svgcontent);
svgcontent.remove();
// Webkit gives 0, FF gives 10, Opera (correctly) gives 15
return (bbox.width === 15);
}());

File diff suppressed because it is too large Load Diff

View File

@@ -1,237 +1,235 @@
const simpleColors = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
aqua: '00ffff',
aquamarine: '7fffd4',
azure: 'f0ffff',
beige: 'f5f5dc',
bisque: 'ffe4c4',
black: '000000',
blanchedalmond: 'ffebcd',
blue: '0000ff',
blueviolet: '8a2be2',
brown: 'a52a2a',
burlywood: 'deb887',
cadetblue: '5f9ea0',
chartreuse: '7fff00',
chocolate: 'd2691e',
coral: 'ff7f50',
cornflowerblue: '6495ed',
cornsilk: 'fff8dc',
crimson: 'dc143c',
cyan: '00ffff',
darkblue: '00008b',
darkcyan: '008b8b',
darkgoldenrod: 'b8860b',
darkgray: 'a9a9a9',
darkgreen: '006400',
darkkhaki: 'bdb76b',
darkmagenta: '8b008b',
darkolivegreen: '556b2f',
darkorange: 'ff8c00',
darkorchid: '9932cc',
darkred: '8b0000',
darksalmon: 'e9967a',
darkseagreen: '8fbc8f',
darkslateblue: '483d8b',
darkslategray: '2f4f4f',
darkturquoise: '00ced1',
darkviolet: '9400d3',
deeppink: 'ff1493',
deepskyblue: '00bfff',
dimgray: '696969',
dodgerblue: '1e90ff',
feldspar: 'd19275',
firebrick: 'b22222',
floralwhite: 'fffaf0',
forestgreen: '228b22',
fuchsia: 'ff00ff',
gainsboro: 'dcdcdc',
ghostwhite: 'f8f8ff',
gold: 'ffd700',
goldenrod: 'daa520',
gray: '808080',
green: '008000',
greenyellow: 'adff2f',
honeydew: 'f0fff0',
hotpink: 'ff69b4',
indianred: 'cd5c5c',
indigo: '4b0082',
ivory: 'fffff0',
khaki: 'f0e68c',
lavender: 'e6e6fa',
lavenderblush: 'fff0f5',
lawngreen: '7cfc00',
lemonchiffon: 'fffacd',
lightblue: 'add8e6',
lightcoral: 'f08080',
lightcyan: 'e0ffff',
lightgoldenrodyellow: 'fafad2',
lightgrey: 'd3d3d3',
lightgreen: '90ee90',
lightpink: 'ffb6c1',
lightsalmon: 'ffa07a',
lightseagreen: '20b2aa',
lightskyblue: '87cefa',
lightslateblue: '8470ff',
lightslategray: '778899',
lightsteelblue: 'b0c4de',
lightyellow: 'ffffe0',
lime: '00ff00',
limegreen: '32cd32',
linen: 'faf0e6',
magenta: 'ff00ff',
maroon: '800000',
mediumaquamarine: '66cdaa',
mediumblue: '0000cd',
mediumorchid: 'ba55d3',
mediumpurple: '9370d8',
mediumseagreen: '3cb371',
mediumslateblue: '7b68ee',
mediumspringgreen: '00fa9a',
mediumturquoise: '48d1cc',
mediumvioletred: 'c71585',
midnightblue: '191970',
mintcream: 'f5fffa',
mistyrose: 'ffe4e1',
moccasin: 'ffe4b5',
navajowhite: 'ffdead',
navy: '000080',
oldlace: 'fdf5e6',
olive: '808000',
olivedrab: '6b8e23',
orange: 'ffa500',
orangered: 'ff4500',
orchid: 'da70d6',
palegoldenrod: 'eee8aa',
palegreen: '98fb98',
paleturquoise: 'afeeee',
palevioletred: 'd87093',
papayawhip: 'ffefd5',
peachpuff: 'ffdab9',
peru: 'cd853f',
pink: 'ffc0cb',
plum: 'dda0dd',
powderblue: 'b0e0e6',
purple: '800080',
red: 'ff0000',
rosybrown: 'bc8f8f',
royalblue: '4169e1',
saddlebrown: '8b4513',
salmon: 'fa8072',
sandybrown: 'f4a460',
seagreen: '2e8b57',
seashell: 'fff5ee',
sienna: 'a0522d',
silver: 'c0c0c0',
skyblue: '87ceeb',
slateblue: '6a5acd',
slategray: '708090',
snow: 'fffafa',
springgreen: '00ff7f',
steelblue: '4682b4',
tan: 'd2b48c',
teal: '008080',
thistle: 'd8bfd8',
tomato: 'ff6347',
turquoise: '40e0d0',
violet: 'ee82ee',
violetred: 'd02090',
wheat: 'f5deb3',
white: 'ffffff',
whitesmoke: 'f5f5f5',
yellow: 'ffff00',
yellowgreen: '9acd32'
};
// array of color definition objects
const colorDefs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process (bits) {
return [
parseInt(bits[1], 10),
parseInt(bits[2], 10),
parseInt(bits[3], 10)
];
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'],
process (bits) {
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)
];
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'],
process (bits) {
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)
];
}
}
];
/**
* A class to parse color values
* @author Stoyan Stefanov <sstoo@gmail.com>
* @link https://www.phpied.com/rgb-color-parser-in-javascript/
* @license MIT
*/
export default function RGBColor (colorString) {
this.ok = false;
class RGBColor {
constructor (colorString) {
this.ok = false;
// strip any leading #
if (colorString.charAt(0) === '#') { // remove # if any
colorString = colorString.substr(1, 6);
}
// strip any leading #
if (colorString.charAt(0) === '#') { // remove # if any
colorString = colorString.substr(1, 6);
}
colorString = colorString.replace(/ /g, '');
colorString = colorString.toLowerCase();
colorString = colorString.replace(/ /g, '');
colorString = colorString.toLowerCase();
// before getting into regexps, try simple matches
// and overwrite the input
const simpleColors = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
aqua: '00ffff',
aquamarine: '7fffd4',
azure: 'f0ffff',
beige: 'f5f5dc',
bisque: 'ffe4c4',
black: '000000',
blanchedalmond: 'ffebcd',
blue: '0000ff',
blueviolet: '8a2be2',
brown: 'a52a2a',
burlywood: 'deb887',
cadetblue: '5f9ea0',
chartreuse: '7fff00',
chocolate: 'd2691e',
coral: 'ff7f50',
cornflowerblue: '6495ed',
cornsilk: 'fff8dc',
crimson: 'dc143c',
cyan: '00ffff',
darkblue: '00008b',
darkcyan: '008b8b',
darkgoldenrod: 'b8860b',
darkgray: 'a9a9a9',
darkgreen: '006400',
darkkhaki: 'bdb76b',
darkmagenta: '8b008b',
darkolivegreen: '556b2f',
darkorange: 'ff8c00',
darkorchid: '9932cc',
darkred: '8b0000',
darksalmon: 'e9967a',
darkseagreen: '8fbc8f',
darkslateblue: '483d8b',
darkslategray: '2f4f4f',
darkturquoise: '00ced1',
darkviolet: '9400d3',
deeppink: 'ff1493',
deepskyblue: '00bfff',
dimgray: '696969',
dodgerblue: '1e90ff',
feldspar: 'd19275',
firebrick: 'b22222',
floralwhite: 'fffaf0',
forestgreen: '228b22',
fuchsia: 'ff00ff',
gainsboro: 'dcdcdc',
ghostwhite: 'f8f8ff',
gold: 'ffd700',
goldenrod: 'daa520',
gray: '808080',
green: '008000',
greenyellow: 'adff2f',
honeydew: 'f0fff0',
hotpink: 'ff69b4',
indianred: 'cd5c5c',
indigo: '4b0082',
ivory: 'fffff0',
khaki: 'f0e68c',
lavender: 'e6e6fa',
lavenderblush: 'fff0f5',
lawngreen: '7cfc00',
lemonchiffon: 'fffacd',
lightblue: 'add8e6',
lightcoral: 'f08080',
lightcyan: 'e0ffff',
lightgoldenrodyellow: 'fafad2',
lightgrey: 'd3d3d3',
lightgreen: '90ee90',
lightpink: 'ffb6c1',
lightsalmon: 'ffa07a',
lightseagreen: '20b2aa',
lightskyblue: '87cefa',
lightslateblue: '8470ff',
lightslategray: '778899',
lightsteelblue: 'b0c4de',
lightyellow: 'ffffe0',
lime: '00ff00',
limegreen: '32cd32',
linen: 'faf0e6',
magenta: 'ff00ff',
maroon: '800000',
mediumaquamarine: '66cdaa',
mediumblue: '0000cd',
mediumorchid: 'ba55d3',
mediumpurple: '9370d8',
mediumseagreen: '3cb371',
mediumslateblue: '7b68ee',
mediumspringgreen: '00fa9a',
mediumturquoise: '48d1cc',
mediumvioletred: 'c71585',
midnightblue: '191970',
mintcream: 'f5fffa',
mistyrose: 'ffe4e1',
moccasin: 'ffe4b5',
navajowhite: 'ffdead',
navy: '000080',
oldlace: 'fdf5e6',
olive: '808000',
olivedrab: '6b8e23',
orange: 'ffa500',
orangered: 'ff4500',
orchid: 'da70d6',
palegoldenrod: 'eee8aa',
palegreen: '98fb98',
paleturquoise: 'afeeee',
palevioletred: 'd87093',
papayawhip: 'ffefd5',
peachpuff: 'ffdab9',
peru: 'cd853f',
pink: 'ffc0cb',
plum: 'dda0dd',
powderblue: 'b0e0e6',
purple: '800080',
red: 'ff0000',
rosybrown: 'bc8f8f',
royalblue: '4169e1',
saddlebrown: '8b4513',
salmon: 'fa8072',
sandybrown: 'f4a460',
seagreen: '2e8b57',
seashell: 'fff5ee',
sienna: 'a0522d',
silver: 'c0c0c0',
skyblue: '87ceeb',
slateblue: '6a5acd',
slategray: '708090',
snow: 'fffafa',
springgreen: '00ff7f',
steelblue: '4682b4',
tan: 'd2b48c',
teal: '008080',
thistle: 'd8bfd8',
tomato: 'ff6347',
turquoise: '40e0d0',
violet: 'ee82ee',
violetred: 'd02090',
wheat: 'f5deb3',
white: 'ffffff',
whitesmoke: 'f5f5f5',
yellow: 'ffff00',
yellowgreen: '9acd32'
};
for (const key in simpleColors) {
if (simpleColors.hasOwnProperty(key)) {
if (colorString === key) {
colorString = simpleColors[key];
// before getting into regexps, try simple matches
// and overwrite the input
if (colorString in simpleColors) {
colorString = simpleColors[colorString];
}
// end of simple type-in colors
// search through the definitions to find a match
for (let i = 0; i < colorDefs.length; i++) {
const {re} = colorDefs[i];
const processor = colorDefs[i].process;
const bits = re.exec(colorString);
if (bits) {
const [r, g, b] = processor(bits);
Object.assign(this, {r, g, b});
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
}
// emd of simple type-in colors
// array of color definition objects
const colorDefs = [
{
re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/,
example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'],
process (bits) {
return [
parseInt(bits[1], 10),
parseInt(bits[2], 10),
parseInt(bits[3], 10)
];
}
},
{
re: /^(\w{2})(\w{2})(\w{2})$/,
example: ['#00ff00', '336699'],
process (bits) {
return [
parseInt(bits[1], 16),
parseInt(bits[2], 16),
parseInt(bits[3], 16)
];
}
},
{
re: /^(\w{1})(\w{1})(\w{1})$/,
example: ['#fb0', 'f0f'],
process (bits) {
return [
parseInt(bits[1] + bits[1], 16),
parseInt(bits[2] + bits[2], 16),
parseInt(bits[3] + bits[3], 16)
];
}
}
];
// search through the definitions to find a match
for (let i = 0; i < colorDefs.length; i++) {
const {re} = colorDefs[i];
const processor = colorDefs[i].process;
const bits = re.exec(colorString);
if (bits) {
const channels = processor(bits);
this.r = channels[0];
this.g = channels[1];
this.b = channels[2];
this.ok = true;
}
}
// validate/cleanup values
this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r);
this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g);
this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b);
// some getters
this.toRGB = function () {
toRGB () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
};
this.toHex = function () {
}
toHex () {
let r = this.r.toString(16);
let g = this.g.toString(16);
let b = this.b.toString(16);
@@ -239,10 +237,10 @@ export default function RGBColor (colorString) {
if (g.length === 1) { g = '0' + g; }
if (b.length === 1) { b = '0' + b; }
return '#' + r + g + b;
};
}
// help
this.getHelpXML = function () {
getHelpXML () {
const examples = [];
// add regexps
for (let i = 0; i < colorDefs.length; i++) {
@@ -252,11 +250,7 @@ export default function RGBColor (colorString) {
}
}
// add type-in colors
for (const sc in simpleColors) {
if (simpleColors.hasOwnProperty(sc)) {
examples[examples.length] = sc;
}
}
examples.push(...Object.keys(simpleColors));
const xml = document.createElement('ul');
xml.setAttribute('id', 'rgbcolor-examples');
@@ -266,20 +260,18 @@ export default function RGBColor (colorString) {
const listColor = new RGBColor(examples[i]);
const exampleDiv = document.createElement('div');
exampleDiv.style.cssText =
'margin: 3px; ' +
'border: 1px solid black; ' +
'background:' + listColor.toHex() + '; ' +
'color:' + listColor.toHex()
`margin: 3px;
border: 1px solid black;
background: ${listColor.toHex()};
color: ${listColor.toHex()};`
;
exampleDiv.appendChild(document.createTextNode('test'));
const listItemValue = document.createTextNode(
' ' + examples[i] + ' -> ' + listColor.toRGB() + ' -> ' + listColor.toHex()
);
listItem.appendChild(exampleDiv);
listItem.appendChild(listItemValue);
xml.appendChild(listItem);
exampleDiv.append('test');
const listItemValue = ` ${examples[i]} -> ${listColor.toRGB()} -> ${listColor.toHex()}`;
listItem.append(exampleDiv, listItemValue);
xml.append(listItem);
} catch (e) {}
}
return xml;
};
}
}
export default RGBColor;

View File

@@ -80,7 +80,7 @@ export const remapElement = function (selected, changes, m) {
newgrad.setAttribute('y2', -(y2 - 1));
}
newgrad.id = editorContext_.getDrawing().getNextId();
findDefs().appendChild(newgrad);
findDefs().append(newgrad);
selected.setAttribute(type, 'url(#' + newgrad.id + ')');
}

View File

@@ -364,7 +364,7 @@ export class Drawing {
} else {
refGroup = this.all_layers[newpos].getGroup();
}
this.svgElem_.insertBefore(currentGroup, refGroup);
this.svgElem_.insertBefore(currentGroup, refGroup); // Ok to replace with `refGroup.before(currentGroup);`?
this.identifyLayers();
this.setCurrentLayer(this.getLayerName(newpos));
@@ -391,11 +391,11 @@ export class Drawing {
const child = currentGroup.firstChild;
if (child.localName === 'title') {
hrService.removeElement(child, child.nextSibling, currentGroup);
currentGroup.removeChild(child);
child.remove();
continue;
}
const oldNextSibling = child.nextSibling;
prevGroup.appendChild(child);
prevGroup.append(child);
hrService.moveElement(child, oldNextSibling, currentGroup);
}
@@ -562,7 +562,7 @@ export class Drawing {
for (let index = 0; index < children.length; index++) {
const ch = children[index];
if (ch.localName === 'title') { continue; }
group.appendChild(this.copyElem(ch));
group.append(this.copyElem(ch));
}
if (hrService) {
@@ -847,7 +847,7 @@ export const moveSelectedToLayer = function (layername) {
const oldNextSibling = elem.nextSibling;
// TODO: this is pretty brittle!
const oldLayer = elem.parentNode;
layer.appendChild(elem);
layer.append(elem);
batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer));
}

View File

@@ -61,7 +61,7 @@ $('#save').click(saveSvg);
$('#exportPNG').click(exportPNG);
$('#exportPDF').click(exportPDF);
const iframe = $('<iframe src="svg-editor-es.html?extensions=ext-xdomain-messaging.js' +
const iframe = $('<iframe src="svg-editor.html?extensions=ext-xdomain-messaging.js' +
(location.href.includes('?')
? location.href.replace(/\?(.*)$/, '&$1')
: '') + // Append arguments to this file onto the iframe

View File

@@ -34,7 +34,6 @@ when handling returns: the callback notation is used instead.
const blah = new EmbeddedSVGEdit(window.frames.svgedit);
blah.clearSelection('woot', 'blah', 1337, [1, 2, 3, 4, 5, 'moo'], -42, {a: 'tree',b:6, c: 9})(function(){console.log('GET DATA',arguments)})
*/
let cbid = 0;
function getCallbackSetter (d) {
@@ -98,6 +97,7 @@ function getMessageListener (t) {
class EmbeddedSVGEdit {
constructor (frame, allowedOrigins) {
const t = this;
this.allowedOrigins = allowedOrigins || [];
// Initialize communication
this.frame = frame;
@@ -280,6 +280,16 @@ class EmbeddedSVGEdit {
// Older IE may need a polyfill for addEventListener, but so it would for SVG
window.addEventListener('message', getMessageListener(this), false);
window.addEventListener('keydown', (e) => {
const {key, keyCode, charCode, which} = e;
if (e.key === 'Backspace') {
e.preventDefault();
const keyboardEvent = new KeyboardEvent(e.type, {
key, keyCode, charCode, which
});
t.frame.contentDocument.dispatchEvent(keyboardEvent);
}
});
}
send (name, args, callback) {
@@ -310,7 +320,7 @@ class EmbeddedSVGEdit {
// callbacks). We might be able to address these shortcomings; see
// the todo elsewhere in this file.
const message = {id: cbid},
{svgCanvas} = t.frame.contentWindow;
{svgEditor: {canvas: svgCanvas}} = t.frame.contentWindow;
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) {

View File

@@ -7,285 +7,288 @@
* Copyright(c) 2010 Alexis Deveria
*
*/
import svgEditor from '../svg-editor.js';
svgEditor.addExtension('Arrows', function (S) {
const svgCanvas = svgEditor.canvas;
const $ = jQuery;
const // {svgcontent} = S,
addElem = S.addSvgElementFromJson,
{nonce} = S,
langList = {
en: [
{id: 'arrow_none', textContent: 'No arrow'}
],
fr: [
{id: 'arrow_none', textContent: 'Sans flèche'}
]
},
prefix = 'se_arrow_';
export default {
name: 'Arrows',
init (S) {
const svgEditor = this;
const svgCanvas = svgEditor.canvas;
const $ = jQuery;
const // {svgcontent} = S,
addElem = S.addSvgElementFromJson,
{nonce} = S,
langList = {
en: [
{id: 'arrow_none', textContent: 'No arrow'}
],
fr: [
{id: 'arrow_none', textContent: 'Sans flèche'}
]
},
prefix = 'se_arrow_';
let selElems, arrowprefix, randomizeIds = S.randomize_ids;
let selElems, arrowprefix, randomizeIds = S.randomize_ids;
function setArrowNonce (window, n) {
randomizeIds = true;
arrowprefix = prefix + n + '_';
pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk';
}
function unsetArrowNonce (window) {
randomizeIds = false;
arrowprefix = prefix;
pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk';
}
svgCanvas.bind('setnonce', setArrowNonce);
svgCanvas.bind('unsetnonce', unsetArrowNonce);
if (randomizeIds) {
arrowprefix = prefix + nonce + '_';
} else {
arrowprefix = prefix;
}
const pathdata = {
fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'},
bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'}
};
function getLinked (elem, attr) {
const str = elem.getAttribute(attr);
if (!str) { return null; }
const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) {
return null;
function setArrowNonce (window, n) {
randomizeIds = true;
arrowprefix = prefix + n + '_';
pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk';
}
return S.getElem(m[1]);
}
function showPanel (on) {
$('#arrow_panel').toggle(on);
if (on) {
function unsetArrowNonce (window) {
randomizeIds = false;
arrowprefix = prefix;
pathdata.fw.id = arrowprefix + 'fw';
pathdata.bk.id = arrowprefix + 'bk';
}
svgCanvas.bind('setnonce', setArrowNonce);
svgCanvas.bind('unsetnonce', unsetArrowNonce);
if (randomizeIds) {
arrowprefix = prefix + nonce + '_';
} else {
arrowprefix = prefix;
}
const pathdata = {
fw: {d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw'},
bk: {d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk'}
};
function getLinked (elem, attr) {
const str = elem.getAttribute(attr);
if (!str) { return null; }
const m = str.match(/\(#(.*)\)/);
if (!m || m.length !== 2) {
return null;
}
return S.getElem(m[1]);
}
function showPanel (on) {
$('#arrow_panel').toggle(on);
if (on) {
const el = selElems[0];
const end = el.getAttribute('marker-end');
const start = el.getAttribute('marker-start');
const mid = el.getAttribute('marker-mid');
let val;
if (end && start) {
val = 'both';
} else if (end) {
val = 'end';
} else if (start) {
val = 'start';
} else if (mid) {
val = 'mid';
if (mid.includes('bk')) {
val = 'mid_bk';
}
}
if (!start && !mid && !end) {
val = 'none';
}
$('#arrow_list').val(val);
}
}
function resetMarker () {
const el = selElems[0];
const end = el.getAttribute('marker-end');
const start = el.getAttribute('marker-start');
const mid = el.getAttribute('marker-mid');
let val;
if (end && start) {
val = 'both';
} else if (end) {
val = 'end';
} else if (start) {
val = 'start';
} else if (mid) {
val = 'mid';
if (mid.includes('bk')) {
val = 'mid_bk';
}
el.removeAttribute('marker-start');
el.removeAttribute('marker-mid');
el.removeAttribute('marker-end');
}
function addMarker (dir, type, id) {
// TODO: Make marker (or use?) per arrow type, since refX can be different
id = id || arrowprefix + dir;
const data = pathdata[dir];
if (type === 'mid') {
data.refx = 5;
}
if (!start && !mid && !end) {
val = 'none';
}
$('#arrow_list').val(val);
}
}
function resetMarker () {
const el = selElems[0];
el.removeAttribute('marker-start');
el.removeAttribute('marker-mid');
el.removeAttribute('marker-end');
}
function addMarker (dir, type, id) {
// TODO: Make marker (or use?) per arrow type, since refX can be different
id = id || arrowprefix + dir;
const data = pathdata[dir];
if (type === 'mid') {
data.refx = 5;
}
let marker = S.getElem(id);
if (!marker) {
marker = addElem({
element: 'marker',
attr: {
viewBox: '0 0 10 10',
id,
refY: 5,
markerUnits: 'strokeWidth',
markerWidth: 5,
markerHeight: 5,
orient: 'auto',
style: 'pointer-events:none' // Currently needed for Opera
}
});
const arrow = addElem({
element: 'path',
attr: {
d: data.d,
fill: '#000000'
}
});
marker.appendChild(arrow);
S.findDefs().appendChild(marker);
}
marker.setAttribute('refX', data.refx);
return marker;
}
function setArrow () {
resetMarker();
let type = this.value;
if (type === 'none') {
return;
}
// Set marker on element
let dir = 'fw';
if (type === 'mid_bk') {
type = 'mid';
dir = 'bk';
} else if (type === 'both') {
addMarker('bk', type);
svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')');
type = 'end';
dir = 'fw';
} else if (type === 'start') {
dir = 'bk';
}
addMarker(dir, type);
svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')');
S.call('changed', selElems);
}
function colorChanged (elem) {
const color = elem.getAttribute('stroke');
const mtypes = ['start', 'mid', 'end'];
const defs = S.findDefs();
$.each(mtypes, function (i, type) {
const marker = getLinked(elem, 'marker-' + type);
if (!marker) { return; }
const curColor = $(marker).children().attr('fill');
const curD = $(marker).children().attr('d');
if (curColor === color) { return; }
const allMarkers = $(defs).find('marker');
let newMarker = null;
// Different color, check if already made
allMarkers.each(function () {
const attrs = $(this).children().attr(['fill', 'd']);
if (attrs.fill === color && attrs.d === curD) {
// Found another marker with this color and this path
newMarker = this;
}
});
if (!newMarker) {
// Create a new marker with this color
const lastId = marker.id;
const dir = lastId.includes('_fw') ? 'fw' : 'bk';
newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
$(newMarker).children().attr('fill', color);
}
$(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
// Check if last marker can be removed
let remove = true;
$(S.svgcontent).find('line, polyline, path, polygon').each(function () {
const elem = this;
$.each(mtypes, function (j, mtype) {
if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
remove = false;
return remove;
let marker = S.getElem(id);
if (!marker) {
marker = addElem({
element: 'marker',
attr: {
viewBox: '0 0 10 10',
id,
refY: 5,
markerUnits: 'strokeWidth',
markerWidth: 5,
markerHeight: 5,
orient: 'auto',
style: 'pointer-events:none' // Currently needed for Opera
}
});
if (!remove) { return false; }
const arrow = addElem({
element: 'path',
attr: {
d: data.d,
fill: '#000000'
}
});
marker.append(arrow);
S.findDefs().append(marker);
}
marker.setAttribute('refX', data.refx);
return marker;
}
function setArrow () {
resetMarker();
let type = this.value;
if (type === 'none') {
return;
}
// Set marker on element
let dir = 'fw';
if (type === 'mid_bk') {
type = 'mid';
dir = 'bk';
} else if (type === 'both') {
addMarker('bk', type);
svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')');
type = 'end';
dir = 'fw';
} else if (type === 'start') {
dir = 'bk';
}
addMarker(dir, type);
svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')');
S.call('changed', selElems);
}
function colorChanged (elem) {
const color = elem.getAttribute('stroke');
const mtypes = ['start', 'mid', 'end'];
const defs = S.findDefs();
$.each(mtypes, function (i, type) {
const marker = getLinked(elem, 'marker-' + type);
if (!marker) { return; }
const curColor = $(marker).children().attr('fill');
const curD = $(marker).children().attr('d');
if (curColor === color) { return; }
const allMarkers = $(defs).find('marker');
let newMarker = null;
// Different color, check if already made
allMarkers.each(function () {
const attrs = $(this).children().attr(['fill', 'd']);
if (attrs.fill === color && attrs.d === curD) {
// Found another marker with this color and this path
newMarker = this;
}
});
if (!newMarker) {
// Create a new marker with this color
const lastId = marker.id;
const dir = lastId.includes('_fw') ? 'fw' : 'bk';
newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length);
$(newMarker).children().attr('fill', color);
}
$(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')');
// Check if last marker can be removed
let remove = true;
$(S.svgcontent).find('line, polyline, path, polygon').each(function () {
const elem = this;
$.each(mtypes, function (j, mtype) {
if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') {
remove = false;
return remove;
}
});
if (!remove) { return false; }
});
// Not found, so can safely remove
if (remove) {
$(marker).remove();
}
});
}
// Not found, so can safely remove
if (remove) {
$(marker).remove();
}
});
}
return {
name: 'Arrows',
context_tools: [{
type: 'select',
panel: 'arrow_panel',
title: 'Select arrow type',
id: 'arrow_list',
options: {
none: 'No arrow',
end: '----&gt;',
start: '&lt;----',
both: '&lt;---&gt;',
mid: '--&gt;--',
mid_bk: '--&lt;--'
return {
name: 'Arrows',
context_tools: [{
type: 'select',
panel: 'arrow_panel',
title: 'Select arrow type',
id: 'arrow_list',
options: {
none: 'No arrow',
end: '----&gt;',
start: '&lt;----',
both: '&lt;---&gt;',
mid: '--&gt;--',
mid_bk: '--&lt;--'
},
defval: 'none',
events: {
change: setArrow
}
}],
callback () {
$('#arrow_panel').hide();
// Set ID so it can be translated in locale file
$('#arrow_list option')[0].id = 'connector_no_arrow';
},
defval: 'none',
events: {
change: setArrow
}
}],
callback () {
$('#arrow_panel').hide();
// Set ID so it can be translated in locale file
$('#arrow_list option')[0].id = 'connector_no_arrow';
},
addLangData (lang) {
return {
data: langList[lang]
};
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
addLangData (lang) {
return {
data: langList[lang]
};
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
const markerElems = ['line', 'path', 'polyline', 'polygon'];
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && markerElems.includes(elem.tagName)) {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true);
const markerElems = ['line', 'path', 'polyline', 'polygon'];
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && markerElems.includes(elem.tagName)) {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
} else {
showPanel(false);
}
},
elementChanged (opts) {
const elem = opts.elems[0];
if (elem && (
elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end')
)) {
// const start = elem.getAttribute('marker-start');
// const mid = elem.getAttribute('marker-mid');
// const end = elem.getAttribute('marker-end');
// Has marker, so see if it should match color
colorChanged(elem);
}
}
},
elementChanged (opts) {
const elem = opts.elems[0];
if (elem && (
elem.getAttribute('marker-start') ||
elem.getAttribute('marker-mid') ||
elem.getAttribute('marker-end')
)) {
// const start = elem.getAttribute('marker-start');
// const mid = elem.getAttribute('marker-mid');
// const end = elem.getAttribute('marker-end');
// Has marker, so see if it should match color
colorChanged(elem);
}
}
};
});
};
}
};

View File

@@ -8,86 +8,89 @@
*
*/
import '../pathseg.js';
import svgEditor from '../svg-editor.js';
// This extension adds a simple button to the contextual panel for paths
// The button toggles whether the path is open or closed
svgEditor.addExtension('ClosePath', function () {
const $ = jQuery;
let selElems;
const updateButton = function (path) {
const seglist = path.pathSegList,
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
showbutton = closed ? '#tool_openpath' : '#tool_closepath',
hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
$(hidebutton).hide();
$(showbutton).show();
};
const showPanel = function (on) {
$('#closepath_panel').toggle(on);
if (on) {
const path = selElems[0];
if (path) { updateButton(path); }
}
};
const toggleClosed = function () {
const path = selElems[0];
if (path) {
export default {
name: 'ClosePath',
init () {
const $ = jQuery;
const svgEditor = this;
let selElems;
const updateButton = function (path) {
const seglist = path.pathSegList,
last = seglist.numberOfItems - 1;
// is closed
if (seglist.getItem(last).pathSegType === 1) {
seglist.removeItem(last);
} else {
seglist.appendItem(path.createSVGPathSegClosePath());
closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1,
showbutton = closed ? '#tool_openpath' : '#tool_closepath',
hidebutton = closed ? '#tool_closepath' : '#tool_openpath';
$(hidebutton).hide();
$(showbutton).show();
};
const showPanel = function (on) {
$('#closepath_panel').toggle(on);
if (on) {
const path = selElems[0];
if (path) { updateButton(path); }
}
updateButton(path);
}
};
};
const toggleClosed = function () {
const path = selElems[0];
if (path) {
const seglist = path.pathSegList,
last = seglist.numberOfItems - 1;
// is closed
if (seglist.getItem(last).pathSegType === 1) {
seglist.removeItem(last);
} else {
seglist.appendItem(path.createSVGPathSegClosePath());
}
updateButton(path);
}
};
return {
name: 'ClosePath',
svgicons: svgEditor.curConfig.extIconsPath + 'closepath_icons.svg',
buttons: [{
id: 'tool_openpath',
type: 'context',
panel: 'closepath_panel',
title: 'Open path',
events: {
click () {
toggleClosed();
return {
name: 'ClosePath',
svgicons: svgEditor.curConfig.extIconsPath + 'closepath_icons.svg',
buttons: [{
id: 'tool_openpath',
type: 'context',
panel: 'closepath_panel',
title: 'Open path',
events: {
click () {
toggleClosed();
}
}
}
},
{
id: 'tool_closepath',
type: 'context',
panel: 'closepath_panel',
title: 'Close path',
events: {
click () {
toggleClosed();
},
{
id: 'tool_closepath',
type: 'context',
panel: 'closepath_panel',
title: 'Close path',
events: {
click () {
toggleClosed();
}
}
}
}],
callback () {
$('#closepath_panel').hide();
},
selectedChanged (opts) {
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.tagName === 'path') {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true);
}],
callback () {
$('#closepath_panel').hide();
},
selectedChanged (opts) {
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.tagName === 'path') {
if (opts.selectedElement && !opts.multiselected) {
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
} else {
showPanel(false);
}
}
}
};
});
};
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -8,97 +8,99 @@
*
*/
import svgEditor from '../svg-editor.js';
export default {
name: 'eyedropper',
init (S) {
const svgEditor = this;
const $ = jQuery;
const {ChangeElementCommand} = S, // , svgcontent,
// svgdoc = S.svgroot.parentNode.ownerDocument,
svgCanvas = svgEditor.canvas,
addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
currentStyle = {
fillPaint: 'red', fillOpacity: 1.0,
strokePaint: 'black', strokeOpacity: 1.0,
strokeWidth: 5, strokeDashArray: null,
opacity: 1.0,
strokeLinecap: 'butt',
strokeLinejoin: 'miter'
};
svgEditor.addExtension('eyedropper', function (S) {
const $ = jQuery;
const {ChangeElementCommand} = S, // , svgcontent,
// svgdoc = S.svgroot.parentNode.ownerDocument,
svgCanvas = svgEditor.canvas,
addToHistory = function (cmd) { svgCanvas.undoMgr.addCommandToHistory(cmd); },
currentStyle = {
fillPaint: 'red', fillOpacity: 1.0,
strokePaint: 'black', strokeOpacity: 1.0,
strokeWidth: 5, strokeDashArray: null,
opacity: 1.0,
strokeLinecap: 'butt',
strokeLinejoin: 'miter'
};
function getStyle (opts) {
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
const mode = svgCanvas.getMode();
if (mode === 'eyedropper') { return; }
const tool = $('#tool_eyedropper');
// enable-eye-dropper if one element is selected
let elem = null;
if (!opts.multiselected && opts.elems[0] &&
!['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
) {
elem = opts.elems[0];
tool.removeClass('disabled');
// grab the current style
currentStyle.fillPaint = elem.getAttribute('fill') || 'black';
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0;
currentStyle.strokePaint = elem.getAttribute('stroke');
currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0;
currentStyle.strokeWidth = elem.getAttribute('stroke-width');
currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray');
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap');
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin');
currentStyle.opacity = elem.getAttribute('opacity') || 1.0;
// disable eye-dropper tool
} else {
tool.addClass('disabled');
}
}
return {
name: 'eyedropper',
svgicons: svgEditor.curConfig.extIconsPath + 'eyedropper-icon.xml',
buttons: [{
id: 'tool_eyedropper',
type: 'mode',
title: 'Eye Dropper Tool',
key: 'I',
events: {
click () {
svgCanvas.setMode('eyedropper');
}
}
}],
// if we have selected an element, grab its paint and enable the eye dropper button
selectedChanged: getStyle,
elementChanged: getStyle,
mouseDown (opts) {
function getStyle (opts) {
// if we are in eyedropper mode, we don't want to disable the eye-dropper tool
const mode = svgCanvas.getMode();
if (mode === 'eyedropper') {
const e = opts.event;
const {target} = e;
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
const changes = {};
if (mode === 'eyedropper') { return; }
const change = function (elem, attrname, newvalue) {
changes[attrname] = elem.getAttribute(attrname);
elem.setAttribute(attrname, newvalue);
};
if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); }
if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); }
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); }
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); }
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); }
if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); }
if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); }
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); }
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); }
addToHistory(new ChangeElementCommand(target, changes));
}
const tool = $('#tool_eyedropper');
// enable-eye-dropper if one element is selected
let elem = null;
if (!opts.multiselected && opts.elems[0] &&
!['svg', 'g', 'use'].includes(opts.elems[0].nodeName)
) {
elem = opts.elems[0];
tool.removeClass('disabled');
// grab the current style
currentStyle.fillPaint = elem.getAttribute('fill') || 'black';
currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0;
currentStyle.strokePaint = elem.getAttribute('stroke');
currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0;
currentStyle.strokeWidth = elem.getAttribute('stroke-width');
currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray');
currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap');
currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin');
currentStyle.opacity = elem.getAttribute('opacity') || 1.0;
// disable eye-dropper tool
} else {
tool.addClass('disabled');
}
}
};
});
return {
name: 'eyedropper',
svgicons: svgEditor.curConfig.extIconsPath + 'eyedropper-icon.xml',
buttons: [{
id: 'tool_eyedropper',
type: 'mode',
title: 'Eye Dropper Tool',
key: 'I',
events: {
click () {
svgCanvas.setMode('eyedropper');
}
}
}],
// if we have selected an element, grab its paint and enable the eye dropper button
selectedChanged: getStyle,
elementChanged: getStyle,
mouseDown (opts) {
const mode = svgCanvas.getMode();
if (mode === 'eyedropper') {
const e = opts.event;
const {target} = e;
if (!['svg', 'g', 'use'].includes(target.nodeName)) {
const changes = {};
const change = function (elem, attrname, newvalue) {
changes[attrname] = elem.getAttribute(attrname);
elem.setAttribute(attrname, newvalue);
};
if (currentStyle.fillPaint) { change(target, 'fill', currentStyle.fillPaint); }
if (currentStyle.fillOpacity) { change(target, 'fill-opacity', currentStyle.fillOpacity); }
if (currentStyle.strokePaint) { change(target, 'stroke', currentStyle.strokePaint); }
if (currentStyle.strokeOpacity) { change(target, 'stroke-opacity', currentStyle.strokeOpacity); }
if (currentStyle.strokeWidth) { change(target, 'stroke-width', currentStyle.strokeWidth); }
if (currentStyle.strokeDashArray) { change(target, 'stroke-dasharray', currentStyle.strokeDashArray); }
if (currentStyle.opacity) { change(target, 'opacity', currentStyle.opacity); }
if (currentStyle.strokeLinecap) { change(target, 'stroke-linecap', currentStyle.strokeLinecap); }
if (currentStyle.strokeLinejoin) { change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); }
addToHistory(new ChangeElementCommand(target, changes));
}
}
}
};
}
};

View File

@@ -9,256 +9,256 @@
*
*/
import svgEditor from '../svg-editor.js';
export default {
name: 'foreignObject',
init (S) {
const svgEditor = this;
const {text2xml, NS} = S;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const
// {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
svgdoc = S.svgroot.parentNode.ownerDocument;
svgEditor.addExtension('foreignObject', function (S) {
const {text2xml, NS} = S;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const
// {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
svgdoc = S.svgroot.parentNode.ownerDocument;
const properlySourceSizeTextArea = function () {
// TODO: remove magic numbers here and get values from CSS
const height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height);
};
const properlySourceSizeTextArea = function () {
// TODO: remove magic numbers here and get values from CSS
const height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height);
};
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
}
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#foreignObject_panel').toggle(on);
}
function toggleSourceButtons (on) {
$('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#foreign_save, #foreign_cancel').toggle(on);
}
let selElems,
started,
newFO,
editingforeign = false;
/**
* This function sets the content of element elt to the input XML.
* @param {String} xmlString - The XML text.
* @param elt - the parent element to append to
* @returns {Boolean} This function returns false if the set was unsuccessful, true otherwise.
*/
function setForeignString (xmlString) {
const elt = selElems[0];
try {
// convert string into XML document
const newDoc = text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
// run it through our sanitizer to remove anything we do not support
S.sanitizeSvg(newDoc.documentElement);
elt.parentNode.replaceChild(svgdoc.importNode(newDoc.documentElement.firstChild, true), elt);
S.call('changed', [elt]);
svgCanvas.clearSelection();
} catch (e) {
console.log(e);
return false;
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
}
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#foreignObject_panel').toggle(on);
}
return true;
}
function showForeignEditor () {
const elt = selElems[0];
if (!elt || editingforeign) { return; }
editingforeign = true;
toggleSourceButtons(true);
elt.removeAttribute('fill');
const str = S.svgToString(elt, 0);
$('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn();
properlySourceSizeTextArea();
$('#svg_source_textarea').focus();
}
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems);
}
return {
name: 'foreignObject',
svgicons: svgEditor.curConfig.extIconsPath + 'foreignobject-icons.xml',
buttons: [{
id: 'tool_foreign',
type: 'mode',
title: 'Foreign Object Tool',
events: {
click () {
svgCanvas.setMode('foreign');
}
}
}, {
id: 'edit_foreign',
type: 'context',
panel: 'foreignObject_panel',
title: 'Edit ForeignObject Content',
events: {
click () {
showForeignEditor();
}
}
}],
context_tools: [{
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's width",
id: 'foreign_width',
label: 'w',
size: 3,
events: {
change () {
setAttr('width', this.value);
}
}
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's height",
id: 'foreign_height',
label: 'h',
events: {
change () {
setAttr('height', this.value);
}
}
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's font size",
id: 'foreign_font_size',
label: 'font-size',
size: 2,
defval: 16,
events: {
change () {
setAttr('font-size', this.value);
}
}
function toggleSourceButtons (on) {
$('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#foreign_save, #foreign_cancel').toggle(on);
}
],
callback () {
$('#foreignObject_panel').hide();
let selElems,
started,
newFO,
editingforeign = false;
const endChanges = function () {
$('#svg_source_editor').hide();
editingforeign = false;
$('#svg_source_textarea').blur();
toggleSourceButtons(false);
};
/**
* This function sets the content of element elt to the input XML.
* @param {String} xmlString - The XML text.
* @param elt - the parent element to append to
* @returns {Boolean} This function returns false if the set was unsuccessful, true otherwise.
*/
function setForeignString (xmlString) {
const elt = selElems[0];
try {
// convert string into XML document
const newDoc = text2xml('<svg xmlns="' + NS.SVG + '" xmlns:xlink="' + NS.XLINK + '">' + xmlString + '</svg>');
// run it through our sanitizer to remove anything we do not support
S.sanitizeSvg(newDoc.documentElement);
elt.replaceWith(svgdoc.importNode(newDoc.documentElement.firstChild, true));
S.call('changed', [elt]);
svgCanvas.clearSelection();
} catch (e) {
console.log(e);
return false;
}
// TODO: Needs to be done after orig icon loads
setTimeout(function () {
// Create source save/cancel buttons
/* const save = */ $('#tool_source_save').clone()
.hide().attr('id', 'foreign_save').unbind()
.appendTo('#tool_source_back').click(function () {
if (!editingforeign) { return; }
return true;
}
if (!setForeignString($('#svg_source_textarea').val())) {
$.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) { return false; }
endChanges();
});
} else {
endChanges();
}
// setSelectMode();
});
function showForeignEditor () {
const elt = selElems[0];
if (!elt || editingforeign) { return; }
editingforeign = true;
toggleSourceButtons(true);
elt.removeAttribute('fill');
/* const cancel = */ $('#tool_source_cancel').clone()
.hide().attr('id', 'foreign_cancel').unbind()
.appendTo('#tool_source_back').click(function () {
endChanges();
});
}, 3000);
},
mouseDown (opts) {
// const e = opts.event;
const str = S.svgToString(elt, 0);
$('#svg_source_textarea').val(str);
$('#svg_source_editor').fadeIn();
properlySourceSizeTextArea();
$('#svg_source_textarea').focus();
}
if (svgCanvas.getMode() === 'foreign') {
started = true;
newFO = S.addSvgElementFromJson({
element: 'foreignObject',
attr: {
x: opts.start_x,
y: opts.start_y,
id: S.getNextId(),
'font-size': 16, // cur_text.font_size,
width: '48',
height: '20',
style: 'pointer-events:inherit'
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems);
}
return {
name: 'foreignObject',
svgicons: svgEditor.curConfig.extIconsPath + 'foreignobject-icons.xml',
buttons: [{
id: 'tool_foreign',
type: 'mode',
title: 'Foreign Object Tool',
events: {
click () {
svgCanvas.setMode('foreign');
}
});
const m = svgdoc.createElementNS(NS.MATH, 'math');
m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH);
m.setAttribute('display', 'inline');
const mi = svgdoc.createElementNS(NS.MATH, 'mi');
mi.setAttribute('mathvariant', 'normal');
mi.textContent = '\u03A6';
const mo = svgdoc.createElementNS(NS.MATH, 'mo');
mo.textContent = '\u222A';
const mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
mi2.textContent = '\u2133';
m.appendChild(mi);
m.appendChild(mo);
m.appendChild(mi2);
newFO.appendChild(m);
return {
started: true
};
}
},
mouseUp (opts) {
// const e = opts.event;
if (svgCanvas.getMode() === 'foreign' && started) {
const attrs = $(newFO).attr(['width', 'height']);
const keep = (attrs.width !== '0' || attrs.height !== '0');
svgCanvas.addToSelection([newFO], true);
}
}, {
id: 'edit_foreign',
type: 'context',
panel: 'foreignObject_panel',
title: 'Edit ForeignObject Content',
events: {
click () {
showForeignEditor();
}
}
}],
return {
keep,
element: newFO
};
context_tools: [{
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's width",
id: 'foreign_width',
label: 'w',
size: 3,
events: {
change () {
setAttr('width', this.value);
}
}
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's height",
id: 'foreign_height',
label: 'h',
events: {
change () {
setAttr('height', this.value);
}
}
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's font size",
id: 'foreign_font_size',
label: 'font-size',
size: 2,
defval: 16,
events: {
change () {
setAttr('font-size', this.value);
}
}
}
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.tagName === 'foreignObject') {
if (opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute('font-size'));
$('#foreign_width').val(elem.getAttribute('width'));
$('#foreign_height').val(elem.getAttribute('height'));
showPanel(true);
],
callback () {
$('#foreignObject_panel').hide();
const endChanges = function () {
$('#svg_source_editor').hide();
editingforeign = false;
$('#svg_source_textarea').blur();
toggleSourceButtons(false);
};
// TODO: Needs to be done after orig icon loads
setTimeout(function () {
// Create source save/cancel buttons
/* const save = */ $('#tool_source_save').clone()
.hide().attr('id', 'foreign_save').unbind()
.appendTo('#tool_source_back').click(function () {
if (!editingforeign) { return; }
if (!setForeignString($('#svg_source_textarea').val())) {
$.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) { return false; }
endChanges();
});
} else {
endChanges();
}
// setSelectMode();
});
/* const cancel = */ $('#tool_source_cancel').clone()
.hide().attr('id', 'foreign_cancel').unbind()
.appendTo('#tool_source_back').click(function () {
endChanges();
});
}, 3000);
},
mouseDown (opts) {
// const e = opts.event;
if (svgCanvas.getMode() === 'foreign') {
started = true;
newFO = S.addSvgElementFromJson({
element: 'foreignObject',
attr: {
x: opts.start_x,
y: opts.start_y,
id: S.getNextId(),
'font-size': 16, // cur_text.font_size,
width: '48',
height: '20',
style: 'pointer-events:inherit'
}
});
const m = svgdoc.createElementNS(NS.MATH, 'math');
m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH);
m.setAttribute('display', 'inline');
const mi = svgdoc.createElementNS(NS.MATH, 'mi');
mi.setAttribute('mathvariant', 'normal');
mi.textContent = '\u03A6';
const mo = svgdoc.createElementNS(NS.MATH, 'mo');
mo.textContent = '\u222A';
const mi2 = svgdoc.createElementNS(NS.MATH, 'mi');
mi2.textContent = '\u2133';
m.append(mi, mo, mi2);
newFO.append(m);
return {
started: true
};
}
},
mouseUp (opts) {
// const e = opts.event;
if (svgCanvas.getMode() === 'foreign' && started) {
const attrs = $(newFO).attr(['width', 'height']);
const keep = (attrs.width !== '0' || attrs.height !== '0');
svgCanvas.addToSelection([newFO], true);
return {
keep,
element: newFO
};
}
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.tagName === 'foreignObject') {
if (opts.selectedElement && !opts.multiselected) {
$('#foreign_font_size').val(elem.getAttribute('font-size'));
$('#foreign_width').val(elem.getAttribute('width'));
$('#foreign_height').val(elem.getAttribute('height'));
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
} else {
showPanel(false);
}
},
elementChanged (opts) {
// const elem = opts.elems[0];
}
},
elementChanged (opts) {
// const elem = opts.elems[0];
}
};
});
};
}
};

View File

@@ -9,150 +9,152 @@
*
*/
import svgEditor from '../svg-editor.js';
export default {
name: 'view_grid',
init ({NS, getTypeMap}) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
{assignAttributes} = svgCanvas,
hcanvas = document.createElement('canvas'),
canvBG = $('#canvasBackground'),
units = getTypeMap(), // Assumes prior `init()` call on `units.js` module
intervals = [0.01, 0.1, 1, 10, 100, 1000];
let showGrid = svgEditor.curConfig.showGrid || false;
svgEditor.addExtension('view_grid', function ({NS, getTypeMap}) {
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const svgdoc = document.getElementById('svgcanvas').ownerDocument,
{assignAttributes} = svgCanvas,
hcanvas = document.createElement('canvas'),
canvBG = $('#canvasBackground'),
units = getTypeMap(), // Assumes prior `init()` call on `units.js` module
intervals = [0.01, 0.1, 1, 10, 100, 1000];
let showGrid = svgEditor.curConfig.showGrid || false;
$(hcanvas).hide().appendTo('body');
$(hcanvas).hide().appendTo('body');
const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
assignAttributes(canvasGrid, {
id: 'canvasGrid',
width: '100%',
height: '100%',
x: 0,
y: 0,
overflow: 'visible',
display: 'none'
});
canvBG.append(canvasGrid);
const canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg');
assignAttributes(canvasGrid, {
id: 'canvasGrid',
width: '100%',
height: '100%',
x: 0,
y: 0,
overflow: 'visible',
display: 'none'
});
canvBG.append(canvasGrid);
// grid-pattern
const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
assignAttributes(gridPattern, {
id: 'gridpattern',
patternUnits: 'userSpaceOnUse',
x: 0, // -(value.strokeWidth / 2), // position for strokewidth
y: 0, // -(value.strokeWidth / 2), // position for strokewidth
width: 100,
height: 100
});
// grid-pattern
const gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern');
assignAttributes(gridPattern, {
id: 'gridpattern',
patternUnits: 'userSpaceOnUse',
x: 0, // -(value.strokeWidth / 2), // position for strokewidth
y: 0, // -(value.strokeWidth / 2), // position for strokewidth
width: 100,
height: 100
});
const gridimg = svgdoc.createElementNS(NS.SVG, 'image');
assignAttributes(gridimg, {
x: 0,
y: 0,
width: 100,
height: 100
});
gridPattern.append(gridimg);
$('#svgroot defs').append(gridPattern);
const gridimg = svgdoc.createElementNS(NS.SVG, 'image');
assignAttributes(gridimg, {
x: 0,
y: 0,
width: 100,
height: 100
});
gridPattern.appendChild(gridimg);
$('#svgroot defs').append(gridPattern);
// grid-box
const gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
assignAttributes(gridBox, {
width: '100%',
height: '100%',
x: 0,
y: 0,
'stroke-width': 0,
stroke: 'none',
fill: 'url(#gridpattern)',
style: 'pointer-events: none; display:visible;'
});
$('#canvasGrid').append(gridBox);
// grid-box
const gridBox = svgdoc.createElementNS(NS.SVG, 'rect');
assignAttributes(gridBox, {
width: '100%',
height: '100%',
x: 0,
y: 0,
'stroke-width': 0,
stroke: 'none',
fill: 'url(#gridpattern)',
style: 'pointer-events: none; display:visible;'
});
$('#canvasGrid').append(gridBox);
function updateGrid (zoom) {
// TODO: Try this with <line> elements, then compare performance difference
const unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
const uMulti = unit * zoom;
// Calculate the main number interval
const rawM = 100 / uMulti;
let multi = 1;
for (let i = 0; i < intervals.length; i++) {
const num = intervals[i];
multi = num;
if (rawM <= num) {
break;
}
}
const bigInt = multi * uMulti;
// Set the canvas size to the width of the container
hcanvas.width = bigInt;
hcanvas.height = bigInt;
const ctx = hcanvas.getContext('2d');
const curD = 0.5;
const part = bigInt / 10;
ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.curConfig.gridColor;
for (let i = 1; i < 10; i++) {
const subD = Math.round(part * i) + 0.5;
// const lineNum = (i % 2)?12:10;
const lineNum = 0;
ctx.moveTo(subD, bigInt);
ctx.lineTo(subD, lineNum);
ctx.moveTo(bigInt, subD);
ctx.lineTo(lineNum, subD);
}
ctx.stroke();
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.moveTo(curD, bigInt);
ctx.lineTo(curD, 0);
ctx.moveTo(bigInt, curD);
ctx.lineTo(0, curD);
ctx.stroke();
const datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', bigInt);
gridimg.parentNode.setAttribute('height', bigInt);
svgCanvas.setHref(gridimg, datauri);
}
function gridUpdate () {
if (showGrid) {
updateGrid(svgCanvas.getZoom());
}
$('#canvasGrid').toggle(showGrid);
$('#view_grid').toggleClass('push_button_pressed tool_button');
}
return {
name: 'view_grid',
svgicons: svgEditor.curConfig.extIconsPath + 'grid-icon.xml',
zoomChanged (zoom) {
if (showGrid) { updateGrid(zoom); }
},
callback () {
if (showGrid) {
gridUpdate();
}
},
buttons: [{
id: 'view_grid',
type: 'context',
panel: 'editor_panel',
title: 'Show/Hide Grid',
events: {
click () {
svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate();
function updateGrid (zoom) {
// TODO: Try this with <line> elements, then compare performance difference
const unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px
const uMulti = unit * zoom;
// Calculate the main number interval
const rawM = 100 / uMulti;
let multi = 1;
for (let i = 0; i < intervals.length; i++) {
const num = intervals[i];
multi = num;
if (rawM <= num) {
break;
}
}
}]
};
});
const bigInt = multi * uMulti;
// Set the canvas size to the width of the container
hcanvas.width = bigInt;
hcanvas.height = bigInt;
const ctx = hcanvas.getContext('2d');
const curD = 0.5;
const part = bigInt / 10;
ctx.globalAlpha = 0.2;
ctx.strokeStyle = svgEditor.curConfig.gridColor;
for (let i = 1; i < 10; i++) {
const subD = Math.round(part * i) + 0.5;
// const lineNum = (i % 2)?12:10;
const lineNum = 0;
ctx.moveTo(subD, bigInt);
ctx.lineTo(subD, lineNum);
ctx.moveTo(bigInt, subD);
ctx.lineTo(lineNum, subD);
}
ctx.stroke();
ctx.beginPath();
ctx.globalAlpha = 0.5;
ctx.moveTo(curD, bigInt);
ctx.lineTo(curD, 0);
ctx.moveTo(bigInt, curD);
ctx.lineTo(0, curD);
ctx.stroke();
const datauri = hcanvas.toDataURL('image/png');
gridimg.setAttribute('width', bigInt);
gridimg.setAttribute('height', bigInt);
gridimg.parentNode.setAttribute('width', bigInt);
gridimg.parentNode.setAttribute('height', bigInt);
svgCanvas.setHref(gridimg, datauri);
}
function gridUpdate () {
if (showGrid) {
updateGrid(svgCanvas.getZoom());
}
$('#canvasGrid').toggle(showGrid);
$('#view_grid').toggleClass('push_button_pressed tool_button');
}
return {
name: 'view_grid',
svgicons: svgEditor.curConfig.extIconsPath + 'grid-icon.xml',
zoomChanged (zoom) {
if (showGrid) { updateGrid(zoom); }
},
callback () {
if (showGrid) {
gridUpdate();
}
},
buttons: [{
id: 'view_grid',
type: 'context',
panel: 'editor_panel',
title: 'Show/Hide Grid',
events: {
click () {
svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate();
}
}
}]
};
}
};

View File

@@ -13,66 +13,70 @@
the left panel. Clicking on the button, and then the canvas will show the
user the point on the canvas that was clicked on.
*/
import svgEditor from '../svg-editor.js';
svgEditor.addExtension('Hello World', function () {
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
return {
name: 'Hello World',
// For more notes on how to make an icon file, see the source of
// the helloworld-icon.xml
svgicons: svgEditor.curConfig.extIconsPath + 'helloworld-icon.xml',
// Multiple buttons can be added in this array
buttons: [{
// Must match the icon ID in helloworld-icon.xml
id: 'hello_world',
export default {
name: 'Hello World',
init () {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
return {
name: 'Hello World',
// For more notes on how to make an icon file, see the source of
// the helloworld-icon.xml
svgicons: svgEditor.curConfig.extIconsPath + 'helloworld-icon.xml',
// This indicates that the button will be added to the "mode"
// button panel on the left side
type: 'mode',
// Multiple buttons can be added in this array
buttons: [{
// Must match the icon ID in helloworld-icon.xml
id: 'hello_world',
// Tooltip text
title: "Say 'Hello World'",
// This indicates that the button will be added to the "mode"
// button panel on the left side
type: 'mode',
// Events
events: {
click () {
// The action taken when the button is clicked on.
// For "mode" buttons, any other button will
// automatically be de-pressed.
svgCanvas.setMode('hello_world');
// Tooltip text
title: "Say 'Hello World'",
// Events
events: {
click () {
// The action taken when the button is clicked on.
// For "mode" buttons, any other button will
// automatically be de-pressed.
svgCanvas.setMode('hello_world');
}
}
}],
// This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels)
mouseDown () {
// Check the mode on mousedown
if (svgCanvas.getMode() === 'hello_world') {
// The returned object must include "started" with
// a value of true in order for mouseUp to be triggered
return {started: true};
}
},
// This is triggered from anywhere, but "started" must have been set
// to true (see above). Note that "opts" is an object with event info
mouseUp (opts) {
// Check the mode on mouseup
if (svgCanvas.getMode() === 'hello_world') {
const zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const text = 'Hello World!\n\nYou clicked here: ' +
x + ', ' + y;
// Show the text using the custom alert function
$.alert(text);
}
}
}],
// This is triggered when the main mouse button is pressed down
// on the editor canvas (not the tool panels)
mouseDown () {
// Check the mode on mousedown
if (svgCanvas.getMode() === 'hello_world') {
// The returned object must include "started" with
// a value of true in order for mouseUp to be triggered
return {started: true};
}
},
// This is triggered from anywhere, but "started" must have been set
// to true (see above). Note that "opts" is an object with event info
mouseUp (opts) {
// Check the mode on mouseup
if (svgCanvas.getMode() === 'hello_world') {
const zoom = svgCanvas.getZoom();
// Get the actual coordinate by dividing by the zoom value
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const text = 'Hello World!\n\nYou clicked here: ' +
x + ', ' + y;
// Show the text using the custom alert function
$.alert(text);
}
}
};
});
};
}
};

View File

@@ -7,462 +7,454 @@
* Copyright(c) 2010 Alexis Deveria
*
*/
import svgEditor from '../svg-editor.js';
import {importSetGlobalDefault} from '../external/dynamic-import-polyfill/importModule.js';
svgEditor.addExtension('imagelib', function ({decode64}) {
const $ = jQuery;
const {uiStrings, canvas: svgCanvas} = svgEditor;
export default {
name: 'imagelib',
init ({decode64}) {
const svgEditor = this;
let imagelibStrings;
$.extend(uiStrings, {
imagelib: {
select_lib: 'Select an image library',
show_list: 'Show library list',
import_single: 'Import single',
import_multi: 'Import multiple',
open: 'Open as new document'
const $ = jQuery;
const {uiStrings, canvas: svgCanvas} = svgEditor;
function closeBrowser () {
$('#imgbrowse_holder').hide();
}
});
const modularVersion = !('svgEditor' in window) ||
!window.svgEditor ||
window.svgEditor.modules !== false;
const imgLibs = [
{
name: 'Demo library (local)',
url: svgEditor.curConfig.extIconsPath +
'imagelib/index' + (modularVersion ? '-es' : '') + '.html',
description: 'Demonstration library for SVG-edit on this server'
},
{
name: 'IAN Symbol Libraries',
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
description: 'Free library of illustrations'
},
{
name: 'Openclipart',
url: 'https://openclipart.org/svgedit',
description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.'
function importImage (url) {
const newImage = svgCanvas.addSvgElementFromJson({
element: 'image',
attr: {
x: 0,
y: 0,
width: 0,
height: 0,
id: svgCanvas.getNextId(),
style: 'pointer-events:inherit'
}
});
svgCanvas.clearSelection();
svgCanvas.addToSelection([newImage]);
svgCanvas.setImageURL(url);
}
];
function closeBrowser () {
$('#imgbrowse_holder').hide();
}
const pending = {};
function importImage (url) {
const newImage = svgCanvas.addSvgElementFromJson({
element: 'image',
attr: {
x: 0,
y: 0,
width: 0,
height: 0,
id: svgCanvas.getNextId(),
style: 'pointer-events:inherit'
}
});
svgCanvas.clearSelection();
svgCanvas.addToSelection([newImage]);
svgCanvas.setImageURL(url);
}
let mode = 's';
let multiArr = [];
let transferStopped = false;
let preview, submit;
const pending = {};
window.addEventListener('message', function (evt) {
// Receive `postMessage` data
let response = evt.data;
let mode = 's';
let multiArr = [];
let transferStopped = false;
let preview, submit;
window.addEventListener('message', function (evt) {
// Receive `postMessage` data
let response = evt.data;
if (!response || typeof response !== 'string') {
// Do nothing
return;
}
try {
// Todo: This block can be removed (and the above check changed to
// insist on an object) if embedAPI moves away from a string to
// an object (if IE9 support not needed)
response = JSON.parse(response);
if (response.namespace !== 'imagelib') {
if (!response || typeof response !== 'string') {
// Do nothing
return;
}
} catch (e) {
return;
}
const hasName = 'name' in response;
const hasHref = 'href' in response;
if (!hasName && transferStopped) {
transferStopped = false;
return;
}
let id;
if (hasHref) {
id = response.href;
response = response.data;
}
// Hide possible transfer dialog box
$('#dialog_box').hide();
let entry, curMeta, svgStr, imgStr;
const type = hasName
? 'meta'
: response.charAt(0);
switch (type) {
case 'meta': {
// Metadata
transferStopped = false;
curMeta = response;
pending[curMeta.id] = curMeta;
const name = (curMeta.name || 'file');
const message = uiStrings.notification.retrieving.replace('%s', name);
if (mode !== 'm') {
$.process_cancel(message, function () {
transferStopped = true;
// Should a message be sent back to the frame?
$('#dialog_box').hide();
});
} else {
entry = $('<div>' + message + '</div>').data('id', curMeta.id);
preview.append(entry);
curMeta.entry = entry;
try {
// Todo: This block can be removed (and the above check changed to
// insist on an object) if embedAPI moves away from a string to
// an object (if IE9 support not needed)
response = JSON.parse(response);
if (response.namespace !== 'imagelib') {
return;
}
} catch (e) {
return;
}
return;
}
case '<':
svgStr = true;
break;
case 'd': {
if (response.startsWith('data:image/svg+xml')) {
const pre = 'data:image/svg+xml;base64,';
const src = response.substring(pre.length);
response = decode64(src);
const hasName = 'name' in response;
const hasHref = 'href' in response;
if (!hasName && transferStopped) {
transferStopped = false;
return;
}
let id;
if (hasHref) {
id = response.href;
response = response.data;
}
// Hide possible transfer dialog box
$('#dialog_box').hide();
let entry, curMeta, svgStr, imgStr;
const type = hasName
? 'meta'
: response.charAt(0);
switch (type) {
case 'meta': {
// Metadata
transferStopped = false;
curMeta = response;
pending[curMeta.id] = curMeta;
const name = (curMeta.name || 'file');
const message = uiStrings.notification.retrieving.replace('%s', name);
if (mode !== 'm') {
$.process_cancel(message, function () {
transferStopped = true;
// Should a message be sent back to the frame?
$('#dialog_box').hide();
});
} else {
entry = $('<div>' + message + '</div>').data('id', curMeta.id);
preview.append(entry);
curMeta.entry = entry;
}
return;
}
case '<':
svgStr = true;
break;
} else if (response.startsWith('data:image/')) {
imgStr = true;
case 'd': {
if (response.startsWith('data:image/svg+xml')) {
const pre = 'data:image/svg+xml;base64,';
const src = response.substring(pre.length);
response = decode64(src);
svgStr = true;
break;
} else if (response.startsWith('data:image/')) {
imgStr = true;
break;
}
}
// Else fall through
default:
// TODO: See if there's a way to base64 encode the binary data stream
// const str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
// Assume it's raw image data
// importImage(str);
// Don't give warning as postMessage may have been used by something else
if (mode !== 'm') {
closeBrowser();
} else {
pending[id].entry.remove();
}
// $.alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') {
// closeBrowser();
// } else {
// pending[id].entry.remove();
// }
// });
return;
}
switch (mode) {
case 's':
// Import one
if (svgStr) {
svgCanvas.importSvgString(response);
} else if (imgStr) {
importImage(response);
}
closeBrowser();
break;
case 'm':
// Import multiple
multiArr.push([(svgStr ? 'svg' : 'img'), response]);
curMeta = pending[id];
let title;
if (svgStr) {
if (curMeta && curMeta.name) {
title = curMeta.name;
} else {
// Try to find a title
const xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
}
if (curMeta) {
preview.children().each(function () {
if ($(this).data('id') === id) {
if (curMeta.preview_url) {
$(this).html('<img src="' + curMeta.preview_url + '">' + title);
} else {
$(this).text(title);
}
submit.removeAttr('disabled');
}
});
} else {
preview.append('<div>' + title + '</div>');
submit.removeAttr('disabled');
}
} else {
if (curMeta && curMeta.preview_url) {
title = curMeta.name || '';
}
if (curMeta && curMeta.preview_url) {
entry = '<img src="' + curMeta.preview_url + '">' + title;
} else {
entry = '<img src="' + response + '">';
}
if (curMeta) {
preview.children().each(function () {
if ($(this).data('id') === id) {
$(this).html(entry);
submit.removeAttr('disabled');
}
});
} else {
preview.append($('<div>').append(entry));
submit.removeAttr('disabled');
}
}
break;
case 'o':
// Open
if (!svgStr) { break; }
svgEditor.openPrep(function (ok) {
if (!ok) { return; }
svgCanvas.clear();
svgCanvas.setSvgString(response);
// updateCanvas();
});
closeBrowser();
break;
}
}
// Else fall through
default:
// TODO: See if there's a way to base64 encode the binary data stream
// const str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
}, true);
// Assume it's raw image data
// importImage(str);
// Don't give warning as postMessage may have been used by something else
if (mode !== 'm') {
closeBrowser();
} else {
pending[id].entry.remove();
}
// $.alert('Unexpected data was returned: ' + response, function() {
// if (mode !== 'm') {
// closeBrowser();
// } else {
// pending[id].entry.remove();
// }
// });
return;
}
switch (mode) {
case 's':
// Import one
if (svgStr) {
svgCanvas.importSvgString(response);
} else if (imgStr) {
importImage(response);
}
closeBrowser();
break;
case 'm':
// Import multiple
multiArr.push([(svgStr ? 'svg' : 'img'), response]);
curMeta = pending[id];
let title;
if (svgStr) {
if (curMeta && curMeta.name) {
title = curMeta.name;
} else {
// Try to find a title
const xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
}
if (curMeta) {
preview.children().each(function () {
if ($(this).data('id') === id) {
if (curMeta.preview_url) {
$(this).html('<img src="' + curMeta.preview_url + '">' + title);
} else {
$(this).text(title);
}
submit.removeAttr('disabled');
}
});
} else {
preview.append('<div>' + title + '</div>');
submit.removeAttr('disabled');
}
} else {
if (curMeta && curMeta.preview_url) {
title = curMeta.name || '';
}
if (curMeta && curMeta.preview_url) {
entry = '<img src="' + curMeta.preview_url + '">' + title;
} else {
entry = '<img src="' + response + '">';
}
if (curMeta) {
preview.children().each(function () {
if ($(this).data('id') === id) {
$(this).html(entry);
submit.removeAttr('disabled');
}
});
} else {
preview.append($('<div>').append(entry));
submit.removeAttr('disabled');
}
}
break;
case 'o':
// Open
if (!svgStr) { break; }
svgEditor.openPrep(function (ok) {
if (!ok) { return; }
svgCanvas.clear();
svgCanvas.setSvgString(response);
// updateCanvas();
});
closeBrowser();
break;
}
}, true);
function toggleMulti (show) {
$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
if (!preview) {
preview = $('<div id=imglib_preview>').css({
position: 'absolute',
top: 45,
right: 10,
width: 180,
bottom: 45,
background: '#fff',
overflow: 'auto'
}).insertAfter('#lib_framewrap');
submit = $('<button disabled>Import selected</button>')
.appendTo('#imgbrowse')
.on('click touchend', function () {
$.each(multiArr, function (i) {
const type = this[0];
const data = this[1];
if (type === 'svg') {
svgCanvas.importSvgString(data);
} else {
importImage(data);
}
svgCanvas.moveSelectedElements(i * 20, i * 20, false);
});
preview.empty();
multiArr = [];
$('#imgbrowse_holder').hide();
}).css({
function toggleMulti (show) {
$('#lib_framewrap, #imglib_opts').css({right: (show ? 200 : 10)});
if (!preview) {
preview = $('<div id=imglib_preview>').css({
position: 'absolute',
bottom: 10,
right: -10
});
}
top: 45,
right: 10,
width: 180,
bottom: 45,
background: '#fff',
overflow: 'auto'
}).insertAfter('#lib_framewrap');
preview.toggle(show);
submit.toggle(show);
}
function showBrowser () {
let browser = $('#imgbrowse');
if (!browser.length) {
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
'</div></div>').insertAfter('#svg_docprops');
browser = $('#imgbrowse');
const allLibs = uiStrings.imagelib.select_lib;
const libOpts = $('<ul id=imglib_opts>').appendTo(browser);
const frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
const header = $('<h1>').prependTo(browser).text(allLibs).css({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
});
const cancel = $('<button>' + uiStrings.common.cancel + '</button>')
.appendTo(browser)
.on('click touchend', function () {
$('#imgbrowse_holder').hide();
}).css({
position: 'absolute',
top: 5,
right: -10
});
const leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
const back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>')
.appendTo(leftBlock)
.on('click touchend', function () {
frame.attr('src', 'about:blank').hide();
libOpts.show();
header.text(allLibs);
back.hide();
}).css({
'margin-right': 5
}).hide();
/* const type = */ $('<select><option value=s>' +
uiStrings.imagelib.import_single + '</option><option value=m>' +
uiStrings.imagelib.import_multi + '</option><option value=o>' +
uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function () {
mode = $(this).val();
switch (mode) {
case 's':
case 'o':
toggleMulti(false);
break;
case 'm':
// Import multiple
toggleMulti(true);
break;
}
}).css({
'margin-top': 10
});
cancel.prepend($.getSvgIcon('cancel', true));
back.prepend($.getSvgIcon('tool_imagelib', true));
$.each(imgLibs, function (i, {name, url, description}) {
$('<li>')
.appendTo(libOpts)
.text(name)
submit = $('<button disabled>Import selected</button>')
.appendTo('#imgbrowse')
.on('click touchend', function () {
frame.attr('src', url).show();
header.text(name);
libOpts.hide();
back.show();
}).append(`<span>${description}</span>`);
});
} else {
$('#imgbrowse_holder').show();
}
}
return {
svgicons: svgEditor.curConfig.extIconsPath + 'ext-imagelib.xml',
buttons: [{
id: 'tool_imagelib',
type: 'app_menu', // _flyout
position: 4,
title: 'Image library',
events: {
mouseup: showBrowser
$.each(multiArr, function (i) {
const type = this[0];
const data = this[1];
if (type === 'svg') {
svgCanvas.importSvgString(data);
} else {
importImage(data);
}
svgCanvas.moveSelectedElements(i * 20, i * 20, false);
});
preview.empty();
multiArr = [];
$('#imgbrowse_holder').hide();
}).css({
position: 'absolute',
bottom: 10,
right: -10
});
}
}],
callback () {
$('<style>').text(
'#imgbrowse_holder {' +
'position: absolute;' +
'top: 0;' +
'left: 0;' +
'width: 100%;' +
'height: 100%;' +
'background-color: rgba(0, 0, 0, .5);' +
'z-index: 5;' +
'}' +
'#imgbrowse {' +
'position: absolute;' +
'top: 25px;' +
'left: 25px;' +
'right: 25px;' +
'bottom: 25px;' +
'min-width: 300px;' +
'min-height: 200px;' +
'background: #B0B0B0;' +
'border: 1px outset #777;' +
'}' +
'#imgbrowse h1 {' +
'font-size: 20px;' +
'margin: .4em;' +
'text-align: center;' +
'}' +
'#lib_framewrap,' +
'#imgbrowse > ul {' +
'position: absolute;' +
'top: 45px;' +
'left: 10px;' +
'right: 10px;' +
'bottom: 10px;' +
'background: white;' +
'margin: 0;' +
'padding: 0;' +
'}' +
'#imgbrowse > ul {' +
'overflow: auto;' +
'}' +
'#imgbrowse > div {' +
'border: 1px solid #666;' +
'}' +
'#imglib_preview > div {' +
'padding: 5px;' +
'font-size: 12px;' +
'}' +
'#imglib_preview img {' +
'display: block;' +
'margin: 0 auto;' +
'max-height: 100px;' +
'}' +
'#imgbrowse li {' +
'list-style: none;' +
'padding: .5em;' +
'background: #E8E8E8;' +
'border-bottom: 1px solid #B0B0B0;' +
'line-height: 1.2em;' +
'font-style: sans-serif;' +
'}' +
'#imgbrowse li > span {' +
'color: #666;' +
'font-size: 15px;' +
'display: block;' +
'}' +
'#imgbrowse li:hover {' +
'background: #FFC;' +
'cursor: pointer;' +
'}' +
'#imgbrowse iframe {' +
'width: 100%;' +
'height: 100%;' +
'border: 0;' +
'}'
).appendTo('head');
preview.toggle(show);
submit.toggle(show);
}
};
});
function showBrowser () {
let browser = $('#imgbrowse');
if (!browser.length) {
$('<div id=imgbrowse_holder><div id=imgbrowse class=toolbar_button>' +
'</div></div>').insertAfter('#svg_docprops');
browser = $('#imgbrowse');
const allLibs = imagelibStrings.select_lib;
const libOpts = $('<ul id=imglib_opts>').appendTo(browser);
const frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
const header = $('<h1>').prependTo(browser).text(allLibs).css({
position: 'absolute',
top: 0,
left: 0,
width: '100%'
});
const cancel = $('<button>' + uiStrings.common.cancel + '</button>')
.appendTo(browser)
.on('click touchend', function () {
$('#imgbrowse_holder').hide();
}).css({
position: 'absolute',
top: 5,
right: -10
});
const leftBlock = $('<span>').css({position: 'absolute', top: 5, left: 10}).appendTo(browser);
const back = $('<button hidden>' + imagelibStrings.show_list + '</button>')
.appendTo(leftBlock)
.on('click touchend', function () {
frame.attr('src', 'about:blank').hide();
libOpts.show();
header.text(allLibs);
back.hide();
}).css({
'margin-right': 5
}).hide();
/* const type = */ $('<select><option value=s>' +
imagelibStrings.import_single + '</option><option value=m>' +
imagelibStrings.import_multi + '</option><option value=o>' +
imagelibStrings.open + '</option></select>').appendTo(leftBlock).change(function () {
mode = $(this).val();
switch (mode) {
case 's':
case 'o':
toggleMulti(false);
break;
case 'm':
// Import multiple
toggleMulti(true);
break;
}
}).css({
'margin-top': 10
});
cancel.prepend($.getSvgIcon('cancel', true));
back.prepend($.getSvgIcon('tool_imagelib', true));
const modularVersion = !('svgEditor' in window) ||
!window.svgEditor ||
window.svgEditor.modules !== false;
$.each(imagelibStrings.imgLibs, function (i, {name, url, description}) {
$('<li>')
.appendTo(libOpts)
.text(name)
.on('click touchend', function () {
frame.attr('src', url({
path: svgEditor.curConfig.extIconsPath,
modularVersion
})).show();
header.text(name);
libOpts.hide();
back.show();
}).append(`<span>${description}</span>`);
});
} else {
$('#imgbrowse_holder').show();
}
}
return {
svgicons: svgEditor.curConfig.extIconsPath + 'ext-imagelib.xml',
buttons: [{
id: 'tool_imagelib',
type: 'app_menu', // _flyout
position: 4,
title: 'Image library',
events: {
mouseup: showBrowser
}
}],
async langReady ({lang}) {
async function tryImport (lang) {
const url = `${svgEditor.curConfig.extPath}ext-locale/imagelib/${lang}.js`;
imagelibStrings = await importSetGlobalDefault(url, {
global: 'svgEditorExtensionLocale_imagelib_' + lang
});
}
try {
await tryImport(lang);
} catch (err) {
await tryImport('en');
}
},
callback () {
$('<style>').text(
'#imgbrowse_holder {' +
'position: absolute;' +
'top: 0;' +
'left: 0;' +
'width: 100%;' +
'height: 100%;' +
'background-color: rgba(0, 0, 0, .5);' +
'z-index: 5;' +
'}' +
'#imgbrowse {' +
'position: absolute;' +
'top: 25px;' +
'left: 25px;' +
'right: 25px;' +
'bottom: 25px;' +
'min-width: 300px;' +
'min-height: 200px;' +
'background: #B0B0B0;' +
'border: 1px outset #777;' +
'}' +
'#imgbrowse h1 {' +
'font-size: 20px;' +
'margin: .4em;' +
'text-align: center;' +
'}' +
'#lib_framewrap,' +
'#imgbrowse > ul {' +
'position: absolute;' +
'top: 45px;' +
'left: 10px;' +
'right: 10px;' +
'bottom: 10px;' +
'background: white;' +
'margin: 0;' +
'padding: 0;' +
'}' +
'#imgbrowse > ul {' +
'overflow: auto;' +
'}' +
'#imgbrowse > div {' +
'border: 1px solid #666;' +
'}' +
'#imglib_preview > div {' +
'padding: 5px;' +
'font-size: 12px;' +
'}' +
'#imglib_preview img {' +
'display: block;' +
'margin: 0 auto;' +
'max-height: 100px;' +
'}' +
'#imgbrowse li {' +
'list-style: none;' +
'padding: .5em;' +
'background: #E8E8E8;' +
'border-bottom: 1px solid #B0B0B0;' +
'line-height: 1.2em;' +
'font-style: sans-serif;' +
'}' +
'#imgbrowse li > span {' +
'color: #666;' +
'font-size: 15px;' +
'display: block;' +
'}' +
'#imgbrowse li:hover {' +
'background: #FFC;' +
'cursor: pointer;' +
'}' +
'#imgbrowse iframe {' +
'width: 100%;' +
'height: 100%;' +
'border: 0;' +
'}'
).appendTo('head');
}
};
}
};

View File

@@ -0,0 +1,26 @@
export default {
select_lib: 'Select an image library',
show_list: 'Show library list',
import_single: 'Import single',
import_multi: 'Import multiple',
open: 'Open as new document',
imgLibs: [
{
name: 'Demo library (local)',
url ({path, modularVersion}) {
return path + 'imagelib/index' + (modularVersion ? '-es' : '') + '.html';
},
description: 'Demonstration library for SVG-edit on this server'
},
{
name: 'IAN Symbol Libraries',
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
description: 'Free library of illustrations'
},
{
name: 'Openclipart',
url: 'https://openclipart.org/svgedit',
description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.'
}
]
};

View File

@@ -0,0 +1,26 @@
export default {
select_lib: "Choisir une bibliothèque d'images",
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open',
imgLibs: [
{
name: 'Demo library (local)',
url ({path, modularVersion}) {
return path + 'imagelib/index' + (modularVersion ? '-es' : '') + '.html';
},
description: 'Demonstration library for SVG-edit on this server'
},
{
name: 'IAN Symbol Libraries',
url: 'https://ian.umces.edu/symbols/catalog/svgedit/album_chooser.php',
description: 'Free library of illustrations'
},
{
name: 'Openclipart',
url: 'https://openclipart.org/svgedit',
description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.'
}
]
};

View File

@@ -1,44 +0,0 @@
export default {
en: {
message: 'By default and where supported, SVG-Edit can store your editor ' +
'preferences and SVG content locally on your machine so you do not ' +
'need to add these back each time you load SVG-Edit. If, for privacy ' +
'reasons, you do not wish to store this information on your machine, ' +
'you can change away from the default option below.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
},
de: {
message: 'Standardmäßig kann SVG-Edit Ihre Editor-Einstellungen ' +
'und die SVG-Inhalte lokal auf Ihrem Gerät abspeichern. So brauchen Sie ' +
'nicht jedes Mal die SVG neu laden. Falls Sie aus Datenschutzgründen ' +
'dies nicht wollen, ' +
'können Sie die Standardeinstellung im Folgenden ändern.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
},
fr: {
message: "Par défaut et si supporté, SVG-Edit peut stocker les préférences de l'éditeur " +
"et le contenu SVG localement sur votre machine de sorte que vous n'ayez pas besoin de les " +
'rajouter chaque fois que vous chargez SVG-Edit. Si, pour des raisons de confidentialité, ' +
'vous ne souhaitez pas stocker ces données sur votre machine, vous pouvez changer ce ' +
'comportement ci-dessous.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: "Si vous choisissez de désactiver le stockage en mémorisant le choix, l'URL va changer afin que la question ne vous soit plus reposée."
}
};

View File

@@ -0,0 +1,14 @@
export default {
message: 'Standardmäßig kann SVG-Edit Ihre Editor-Einstellungen ' +
'und die SVG-Inhalte lokal auf Ihrem Gerät abspeichern. So brauchen Sie ' +
'nicht jedes Mal die SVG neu laden. Falls Sie aus Datenschutzgründen ' +
'dies nicht wollen, ' +
'können Sie die Standardeinstellung im Folgenden ändern.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
};

View File

@@ -0,0 +1,14 @@
export default {
message: 'By default and where supported, SVG-Edit can store your editor ' +
'preferences and SVG content locally on your machine so you do not ' +
'need to add these back each time you load SVG-Edit. If, for privacy ' +
'reasons, you do not wish to store this information on your machine, ' +
'you can change away from the default option below.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: 'If you choose to opt out of storage while remembering this choice, the URL will change so as to avoid asking again.'
};

View File

@@ -0,0 +1,14 @@
export default {
message: "Par défaut et si supporté, SVG-Edit peut stocker les préférences de l'éditeur " +
"et le contenu SVG localement sur votre machine de sorte que vous n'ayez pas besoin de les " +
'rajouter chaque fois que vous chargez SVG-Edit. Si, pour des raisons de confidentialité, ' +
'vous ne souhaitez pas stocker ces données sur votre machine, vous pouvez changer ce ' +
'comportement ci-dessous.',
storagePrefsAndContent: 'Store preferences and SVG content locally',
storagePrefsOnly: 'Only store preferences locally',
storagePrefs: 'Store preferences locally',
storageNoPrefsOrContent: 'Do not store my preferences or SVG content locally',
storageNoPrefs: 'Do not store my preferences locally',
rememberLabel: 'Remember this choice?',
rememberTooltip: "Si vous choisissez de désactiver le stockage en mémorisant le choix, l'URL va changer afin que la question ne vous soit plus reposée."
};

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,4 +1,3 @@
import svgEditor from '../svg-editor.js';
/*
* ext-panning.js
*
@@ -9,38 +8,42 @@ import svgEditor from '../svg-editor.js';
*/
/*
This is a very basic SVG-Edit extension to let tablet/mobile devices panning without problem
This is a very basic SVG-Edit extension to let tablet/mobile devices pan without problem
*/
svgEditor.addExtension('ext-panning', function () {
const svgCanvas = svgEditor.canvas;
return {
name: 'Extension Panning',
svgicons: svgEditor.curConfig.extIconsPath + 'ext-panning.xml',
buttons: [{
id: 'ext-panning',
type: 'mode',
title: 'Panning',
events: {
click () {
svgCanvas.setMode('ext-panning');
export default {
name: 'ext-panning',
init () {
const svgEditor = this;
const svgCanvas = svgEditor.canvas;
return {
name: 'Extension Panning',
svgicons: svgEditor.curConfig.extIconsPath + 'ext-panning.xml',
buttons: [{
id: 'ext-panning',
type: 'mode',
title: 'Panning',
events: {
click () {
svgCanvas.setMode('ext-panning');
}
}
}],
mouseDown () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true);
return {started: true};
}
},
mouseUp () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false);
return {
keep: false,
element: null
};
}
}
}],
mouseDown () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true);
return {started: true};
}
},
mouseUp () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(false);
return {
keep: false,
element: null
};
}
}
};
});
};
}
};

View File

@@ -1,9 +1,11 @@
/* globals jQuery */
// TODO: Might add support for "exportImage" custom
// handler as in "ext-server_opensave.js" (and in savefile.php)
import svgEditor from '../svg-editor.js';
svgEditor.addExtension('php_savefile', {
export default {
name: 'php_savefile',
callback () {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
function getFileNameFromTitle () {
@@ -20,4 +22,4 @@ svgEditor.addExtension('php_savefile', {
}
});
}
});
};

View File

@@ -7,276 +7,278 @@
* All rights reserved
*
*/
import svgEditor from '../svg-editor.js';
svgEditor.addExtension('polygon', function (S) {
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const // {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
editingitex = false;
let selElems,
// svgdoc = S.svgroot.parentNode.ownerDocument,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
// edg = 0,
// undoCommand = 'Not image';
started, newFO;
export default {
name: 'polygon',
init (S) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const // {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
editingitex = false;
let selElems,
// svgdoc = S.svgroot.parentNode.ownerDocument,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
// edg = 0,
// undoCommand = 'Not image';
started, newFO;
// const ccZoom;
// const wEl, hEl;
// const wOffset, hOffset;
// const ccRBG;
// const ccOpacity;
// const brushW, brushH;
// const ccZoom;
// const wEl, hEl;
// const wOffset, hOffset;
// const ccRBG;
// const ccOpacity;
// const brushW, brushH;
// const ccDebug = document.getElementById('debugpanel');
// const ccDebug = document.getElementById('debugpanel');
/* const properlySourceSizeTextArea = function(){
// TODO: remove magic numbers here and get values from CSS
const height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height);
}; */
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
/* const properlySourceSizeTextArea = function(){
// TODO: remove magic numbers here and get values from CSS
const height = $('#svg_source_container').height() - 80;
$('#svg_source_textarea').css('height', height);
}; */
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
}
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#polygon_panel').toggle(on);
}
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#polygon_panel').toggle(on);
}
/*
function toggleSourceButtons(on){
$('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#polygon_save, #polygon_cancel').toggle(on);
}
*/
/*
function toggleSourceButtons(on){
$('#tool_source_save, #tool_source_cancel').toggle(!on);
$('#polygon_save, #polygon_cancel').toggle(on);
}
*/
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems);
}
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems);
}
function cot (n) {
return 1 / Math.tan(n);
}
function cot (n) {
return 1 / Math.tan(n);
}
function sec (n) {
return 1 / Math.cos(n);
}
function sec (n) {
return 1 / Math.cos(n);
}
/**
* Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3
* This function sets the content of of the currently-selected foreignObject element,
* based on the itex contained in string.
* @param {string} tex The itex text.
* @returns This function returns false if the set was unsuccessful, true otherwise.
*/
/*
function setItexString(tex) {
const mathns = 'http://www.w3.org/1998/Math/MathML',
xmlnsns = 'http://www.w3.org/2000/xmlns/',
ajaxEndpoint = '../../itex';
const elt = selElems[0];
try {
const math = svgdoc.createElementNS(mathns, 'math');
math.setAttributeNS(xmlnsns, 'xmlns', mathns);
math.setAttribute('display', 'inline');
const semantics = document.createElementNS(mathns, 'semantics');
const annotation = document.createElementNS(mathns, 'annotation');
annotation.setAttribute('encoding', 'application/x-tex');
annotation.textContent = tex;
const mrow = document.createElementNS(mathns, 'mrow');
semantics.appendChild(mrow);
semantics.appendChild(annotation);
math.appendChild(semantics);
// make an AJAX request to the server, to get the MathML
$.post(ajaxEndpoint, {tex, display: 'inline'}, function(data){
const children = data.documentElement.childNodes;
while (children.length > 0) {
mrow.appendChild(svgdoc.adoptNode(children[0], true));
}
S.sanitizeSvg(math);
/**
* Obtained from http://code.google.com/p/passenger-top/source/browse/instiki/public/svg-edit/editor/extensions/ext-itex.js?r=3
* This function sets the content of of the currently-selected foreignObject element,
* based on the itex contained in string.
* @param {string} tex The itex text.
* @returns This function returns false if the set was unsuccessful, true otherwise.
*/
/*
function setItexString(tex) {
const mathns = 'http://www.w3.org/1998/Math/MathML',
xmlnsns = 'http://www.w3.org/2000/xmlns/',
ajaxEndpoint = '../../itex';
const elt = selElems[0];
try {
const math = svgdoc.createElementNS(mathns, 'math');
math.setAttributeNS(xmlnsns, 'xmlns', mathns);
math.setAttribute('display', 'inline');
const semantics = document.createElementNS(mathns, 'semantics');
const annotation = document.createElementNS(mathns, 'annotation');
annotation.setAttribute('encoding', 'application/x-tex');
annotation.textContent = tex;
const mrow = document.createElementNS(mathns, 'mrow');
semantics.append(mrow, annotation);
math.append(semantics);
// make an AJAX request to the server, to get the MathML
$.post(ajaxEndpoint, {tex, display: 'inline'}, function(data){
const children = data.documentElement.childNodes;
while (children.length > 0) {
mrow.append(svgdoc.adoptNode(children[0], true));
}
S.sanitizeSvg(math);
S.call('changed', [elt]);
});
elt.firstChild.replaceWith(math);
S.call('changed', [elt]);
});
elt.replaceChild(math, elt.firstChild);
S.call('changed', [elt]);
svgCanvas.clearSelection();
} catch(e) {
console.log(e);
return false;
svgCanvas.clearSelection();
} catch(e) {
console.log(e);
return false;
}
return true;
}
return true;
}
*/
return {
name: 'polygon',
svgicons: svgEditor.curConfig.extIconsPath + 'polygon-icons.svg',
buttons: [{
id: 'tool_polygon',
type: 'mode',
title: 'Polygon Tool',
position: 11,
events: {
click () {
svgCanvas.setMode('polygon');
showPanel(true);
}
}
}],
context_tools: [{
type: 'input',
panel: 'polygon_panel',
title: 'Number of Sides',
id: 'polySides',
label: 'sides',
size: 3,
defval: 5,
events: {
change () {
setAttr('sides', this.value);
}
}
}],
callback () {
$('#polygon_panel').hide();
const endChanges = function () {
};
// TODO: Needs to be done after orig icon loads
setTimeout(function () {
// Create source save/cancel buttons
/* const save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () {
if (!editingitex) {
return;
}
// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
/*
if (!setItexString($('#svg_source_textarea').val())) {
$.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) {
return false;
}
endChanges();
});
} else { */
endChanges();
// }
// setSelectMode();
});
/* const cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () {
endChanges();
});
}, 3000);
},
mouseDown (opts) {
// const e = opts.event;
const rgb = svgCanvas.getColor('fill');
// const ccRgbEl = rgb.substring(1, rgb.length);
const sRgb = svgCanvas.getColor('stroke');
// ccSRgbEl = sRgb.substring(1, rgb.length);
const sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'polygon') {
started = true;
newFO = S.addSvgElementFromJson({
element: 'polygon',
attr: {
cx: opts.start_x,
cy: opts.start_y,
id: S.getNextId(),
shape: 'regularPoly',
sides: document.getElementById('polySides').value,
orient: 'x',
edge: 0,
fill: rgb,
strokecolor: sRgb,
strokeWidth: sWidth
}
});
return {
started: true
};
}
},
mouseMove (opts) {
if (!started) {
return;
}
if (svgCanvas.getMode() === 'polygon') {
// const e = opts.event;
const c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
let x = opts.mouse_x;
let y = opts.mouse_y;
const {cx, cy, fill, strokecolor, strokeWidth, sides} = c, // {orient} = c,
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
newFO.setAttributeNS(null, 'edge', edg);
const inradius = (edg / 2) * cot(Math.PI / sides);
const circumradius = inradius * sec(Math.PI / sides);
let points = '';
for (let s = 0; sides >= s; s++) {
const angle = 2.0 * Math.PI * s / sides;
x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy;
points += x + ',' + y + ' ';
}
// const poly = newFO.createElementNS(NS.SVG, 'polygon');
newFO.setAttributeNS(null, 'points', points);
newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
// newFO.setAttributeNS(null, 'transform', 'rotate(-90)');
// const shape = newFO.getAttributeNS(null, 'shape');
// newFO.appendChild(poly);
// DrawPoly(cx, cy, sides, edg, orient);
return {
started: true
};
}
},
mouseUp (opts) {
if (svgCanvas.getMode() === 'polygon') {
const attrs = $(newFO).attr('edge');
const keep = (attrs.edge !== '0');
// svgCanvas.addToSelection([newFO], true);
return {
keep,
element: newFO
};
}
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
if (opts.selectedElement && !opts.multiselected) {
$('#polySides').val(elem.getAttribute('sides'));
*/
return {
name: 'polygon',
svgicons: svgEditor.curConfig.extIconsPath + 'polygon-icons.svg',
buttons: [{
id: 'tool_polygon',
type: 'mode',
title: 'Polygon Tool',
position: 11,
events: {
click () {
svgCanvas.setMode('polygon');
showPanel(true);
}
}
}],
context_tools: [{
type: 'input',
panel: 'polygon_panel',
title: 'Number of Sides',
id: 'polySides',
label: 'sides',
size: 3,
defval: 5,
events: {
change () {
setAttr('sides', this.value);
}
}
}],
callback () {
$('#polygon_panel').hide();
const endChanges = function () {
};
// TODO: Needs to be done after orig icon loads
setTimeout(function () {
// Create source save/cancel buttons
/* const save = */ $('#tool_source_save').clone().hide().attr('id', 'polygon_save').unbind().appendTo('#tool_source_back').click(function () {
if (!editingitex) {
return;
}
// Todo: Uncomment the setItexString() function above and handle ajaxEndpoint?
/*
if (!setItexString($('#svg_source_textarea').val())) {
$.confirm('Errors found. Revert to original?', function (ok) {
if (!ok) {
return false;
}
endChanges();
});
} else { */
endChanges();
// }
// setSelectMode();
});
/* const cancel = */ $('#tool_source_cancel').clone().hide().attr('id', 'polygon_cancel').unbind().appendTo('#tool_source_back').click(function () {
endChanges();
});
}, 3000);
},
mouseDown (opts) {
// const e = opts.event;
const rgb = svgCanvas.getColor('fill');
// const ccRgbEl = rgb.substring(1, rgb.length);
const sRgb = svgCanvas.getColor('stroke');
// ccSRgbEl = sRgb.substring(1, rgb.length);
const sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'polygon') {
started = true;
newFO = S.addSvgElementFromJson({
element: 'polygon',
attr: {
cx: opts.start_x,
cy: opts.start_y,
id: S.getNextId(),
shape: 'regularPoly',
sides: document.getElementById('polySides').value,
orient: 'x',
edge: 0,
fill: rgb,
strokecolor: sRgb,
strokeWidth: sWidth
}
});
return {
started: true
};
}
},
mouseMove (opts) {
if (!started) {
return;
}
if (svgCanvas.getMode() === 'polygon') {
// const e = opts.event;
const c = $(newFO).attr(['cx', 'cy', 'sides', 'orient', 'fill', 'strokecolor', 'strokeWidth']);
let x = opts.mouse_x;
let y = opts.mouse_y;
const {cx, cy, fill, strokecolor, strokeWidth, sides} = c, // {orient} = c,
edg = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5;
newFO.setAttributeNS(null, 'edge', edg);
const inradius = (edg / 2) * cot(Math.PI / sides);
const circumradius = inradius * sec(Math.PI / sides);
let points = '';
for (let s = 0; sides >= s; s++) {
const angle = 2.0 * Math.PI * s / sides;
x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy;
points += x + ',' + y + ' ';
}
// const poly = newFO.createElementNS(NS.SVG, 'polygon');
newFO.setAttributeNS(null, 'points', points);
newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
// newFO.setAttributeNS(null, 'transform', 'rotate(-90)');
// const shape = newFO.getAttributeNS(null, 'shape');
// newFO.append(poly);
// DrawPoly(cx, cy, sides, edg, orient);
return {
started: true
};
}
},
mouseUp (opts) {
if (svgCanvas.getMode() === 'polygon') {
const attrs = $(newFO).attr('edge');
const keep = (attrs.edge !== '0');
// svgCanvas.addToSelection([newFO], true);
return {
keep,
element: newFO
};
}
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'regularPoly') {
if (opts.selectedElement && !opts.multiselected) {
$('#polySides').val(elem.getAttribute('sides'));
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
} else {
showPanel(false);
}
},
elementChanged (opts) {
// const elem = opts.elems[0];
}
},
elementChanged (opts) {
// const elem = opts.elems[0];
}
};
});
};
}
};

View File

@@ -10,10 +10,12 @@
* (I agree to dual license my work to additional GPLv2 or later)
*
*/
import svgEditor from '../svg-editor.js';
import {canvg} from '../canvg/canvg.js';
svgEditor.addExtension('server_opensave', {
callback ({canvg, encode64, buildCanvgCallback}) {
export default {
name: 'server_opensave',
callback ({encode64}) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const saveSvgAction = '/+modify';
@@ -22,7 +24,7 @@ svgEditor.addExtension('server_opensave', {
/* const target = */ $('<iframe name="output_frame" src="#"/>').hide().appendTo('body');
svgEditor.setCustomHandlers({
save (win, data) {
async save (win, data) {
const svg = '<?xml version="1.0"?>\n' + data;
const qstr = $.param.querystring();
const name = qstr.substr(9).split('/+get/')[1];
@@ -33,26 +35,23 @@ svgEditor.addExtension('server_opensave', {
const c = $('#export_canvas')[0];
c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH;
buildCanvgCallback(function () {
canvg(c, svg, {renderCallback () {
const datauri = c.toDataURL('image/png');
// const {uiStrings} = svgEditor;
const pngData = encode64(datauri); // Brett: This encoding seems unnecessary
/* const form = */ $('<form>').attr({
method: 'post',
action: saveSvgAction + '/' + name,
target: 'output_frame'
}).append('<input type="hidden" name="png_data" value="' + pngData + '">')
.append('<input type="hidden" name="filepath" value="' + svgData + '">')
.append('<input type="hidden" name="filename" value="' + 'drawing.svg">')
.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
.appendTo('body')
.submit().remove();
}});
})();
await canvg(c, svg);
const datauri = c.toDataURL('image/png');
// const {uiStrings} = svgEditor;
const pngData = encode64(datauri); // Brett: This encoding seems unnecessary
/* const form = */ $('<form>').attr({
method: 'post',
action: saveSvgAction + '/' + name,
target: 'output_frame'
}).append('<input type="hidden" name="png_data" value="' + pngData + '">')
.append('<input type="hidden" name="filepath" value="' + svgData + '">')
.append('<input type="hidden" name="filename" value="' + 'drawing.svg">')
.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
.appendTo('body')
.submit().remove();
alert('Saved! Return to Item View!');
top.window.location = '/' + name;
}
});
}
});
};

View File

@@ -7,10 +7,12 @@
* Copyright(c) 2010 Alexis Deveria
*
*/
import svgEditor from '../svg-editor.js';
import {canvg} from '../canvg/canvg.js';
svgEditor.addExtension('server_opensave', {
callback ({canvg, decode64, encode64, buildCanvgCallback}) {
export default {
name: 'server_opensave',
callback ({decode64, encode64}) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
function getFileNameFromTitle () {
@@ -76,7 +78,7 @@ svgEditor.addExtension('server_opensave', {
.submit().remove();
},
// Todo: Integrate this extension with a new built-in exportWindowType, "download"
exportImage (win, data) {
async exportImage (win, data) {
const {issues, mimeType, quality} = data;
if (!$('#export_canvas').length) {
@@ -86,40 +88,37 @@ svgEditor.addExtension('server_opensave', {
c.width = svgCanvas.contentW;
c.height = svgCanvas.contentH;
buildCanvgCallback(function () {
canvg(c, data.svg, {renderCallback () {
const datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType);
// {uiStrings} = svgEditor;
await canvg(c, data.svg);
const datauri = quality ? c.toDataURL(mimeType, quality) : c.toDataURL(mimeType);
// {uiStrings} = svgEditor;
// Check if there are issues
let pre, note = '';
if (issues.length) {
pre = '\n \u2022 ';
note += ('\n\n' + pre + issues.join(pre));
}
// Check if there are issues
let pre, note = '';
if (issues.length) {
pre = '\n \u2022 ';
note += ('\n\n' + pre + issues.join(pre));
}
if (note.length) {
alert(note);
}
if (note.length) {
alert(note);
}
const filename = getFileNameFromTitle();
const suffix = '.' + data.type.toLowerCase();
const filename = getFileNameFromTitle();
const suffix = '.' + data.type.toLowerCase();
if (clientDownloadSupport(filename, suffix, datauri)) {
return;
}
if (clientDownloadSupport(filename, suffix, datauri)) {
return;
}
$('<form>').attr({
method: 'post',
action: saveImgAction,
target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="' + mimeType + '">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
.appendTo('body')
.submit().remove();
}});
})();
$('<form>').attr({
method: 'post',
action: saveImgAction,
target: 'output_frame'
}).append('<input type="hidden" name="output_img" value="' + datauri + '">')
.append('<input type="hidden" name="mime" value="' + mimeType + '">')
.append('<input type="hidden" name="filename" value="' + xhtmlEscape(filename) + '">')
.appendTo('body')
.submit().remove();
}
});
@@ -222,4 +221,4 @@ svgEditor.addExtension('server_opensave', {
$('#tool_import').show().prepend(importSvgForm);
$('#tool_image').prepend(importImgForm);
}
});
};

View File

@@ -8,351 +8,354 @@
* Copyright(c) 2010 Alexis Deveria
*
*/
import svgEditor from '../svg-editor.js';
svgEditor.addExtension('shapes', function () {
const $ = jQuery;
const canv = svgEditor.canvas;
const svgroot = canv.getRootElem();
let lastBBox = {};
export default {
name: 'shapes',
init () {
const svgEditor = this;
const $ = jQuery;
const canv = svgEditor.canvas;
const svgroot = canv.getRootElem();
let lastBBox = {};
// This populates the category list
const categories = {
basic: 'Basic',
object: 'Objects',
symbol: 'Symbols',
arrow: 'Arrows',
flowchart: 'Flowchart',
animal: 'Animals',
game: 'Cards & Chess',
dialog_balloon: 'Dialog balloons',
electronics: 'Electronics',
math: 'Mathematical',
music: 'Music',
misc: 'Miscellaneous',
raphael_1: 'raphaeljs.com set 1',
raphael_2: 'raphaeljs.com set 2'
};
// This populates the category list
const categories = {
basic: 'Basic',
object: 'Objects',
symbol: 'Symbols',
arrow: 'Arrows',
flowchart: 'Flowchart',
animal: 'Animals',
game: 'Cards & Chess',
dialog_balloon: 'Dialog balloons',
electronics: 'Electronics',
math: 'Mathematical',
music: 'Music',
misc: 'Miscellaneous',
raphael_1: 'raphaeljs.com set 1',
raphael_2: 'raphaeljs.com set 2'
};
const library = {
basic: {
data: {
heart: 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
frame: 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z',
donut: 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z',
triangle: 'm1,280.375l149,-260.75l149,260.75z',
right_triangle: 'm1,299l0,-298l298,298z',
diamond: 'm1,150l149,-149l149,149l-149,149l-149,-149z',
pentagon: 'm1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z',
hexagon: 'm1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z',
septagon1: 'm0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z',
heptagon: 'm1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z',
decagon: 'm1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z',
dodecagon: 'm1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z',
star_points_5: 'm1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z',
trapezoid: 'm1,299l55.875,-298l186.25001,0l55.87498,298z',
arrow_up: 'm1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z',
vertical_scrool: 'm37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875',
smiley: 'm68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z',
left_braket: 'm174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066',
uml_actor: 'm40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z',
dialog_balloon_1: 'm0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z',
cloud: 'm182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z',
cylinder: 'm299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z',
arrow_u_turn: 'm1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z',
arrow_left_up: 'm0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z',
maximize: 'm1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z',
cross: 'm0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z',
plaque: 'm-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z',
page: 'm249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234'
const library = {
basic: {
data: {
heart: 'm150,73c61,-175 300,0 0,225c-300,-225 -61,-400 0,-225z',
frame: 'm0,0l300,0l0,300l-300,0zm35,-265l0,230l230,0l0,-230z',
donut: 'm1,150l0,0c0,-82.29042 66.70958,-149 149,-149l0,0c39.51724,0 77.41599,15.69816 105.35889,43.64108c27.94293,27.94293 43.64111,65.84165 43.64111,105.35892l0,0c0,82.29041 -66.70958,149 -149,149l0,0c-82.29041,0 -149,-66.70959 -149,-149zm74.5,0l0,0c0,41.1452 33.35481,74.5 74.5,74.5c41.14522,0 74.5,-33.3548 74.5,-74.5c0,-41.1452 -33.3548,-74.5 -74.5,-74.5l0,0c-41.14519,0 -74.5,33.35481 -74.5,74.5z',
triangle: 'm1,280.375l149,-260.75l149,260.75z',
right_triangle: 'm1,299l0,-298l298,298z',
diamond: 'm1,150l149,-149l149,149l-149,149l-149,-149z',
pentagon: 'm1.00035,116.97758l148.99963,-108.4053l148.99998,108.4053l-56.91267,175.4042l-184.1741,0l-56.91284,-175.4042z',
hexagon: 'm1,149.99944l63.85715,-127.71428l170.28572,0l63.85713,127.71428l-63.85713,127.71428l-170.28572,0l-63.85715,-127.71428z',
septagon1: 'm0.99917,191.06511l29.51249,-127.7108l119.48833,-56.83673l119.48836,56.83673l29.51303,127.7108l-82.69087,102.41679l-132.62103,0l-82.69031,-102.41679z',
heptagon: 'm1,88.28171l87.28172,-87.28171l123.43653,0l87.28172,87.28171l0,123.43654l-87.28172,87.28172l-123.43653,0l-87.28172,-87.28172l0,-123.43654z',
decagon: 'm1,150.00093l28.45646,-88.40318l74.49956,-54.63682l92.08794,0l74.50002,54.63682l28.45599,88.40318l-28.45599,88.40318l-74.50002,54.63681l-92.08794,0l-74.49956,-54.63681l-28.45646,-88.40318z',
dodecagon: 'm1,110.07421l39.92579,-69.14842l69.14842,-39.92579l79.85159,0l69.14842,39.92579l39.92578,69.14842l0,79.85159l-39.92578,69.14842l-69.14842,39.92578l-79.85159,0l-69.14842,-39.92578l-39.92579,-69.14842l0,-79.85159z',
star_points_5: 'm1,116.58409l113.82668,0l35.17332,-108.13487l35.17334,108.13487l113.82666,0l-92.08755,66.83026l35.17514,108.13487l-92.08759,-66.83208l-92.08757,66.83208l35.17515,-108.13487l-92.08758,-66.83026z',
trapezoid: 'm1,299l55.875,-298l186.25001,0l55.87498,298z',
arrow_up: 'm1.49805,149.64304l148.50121,-148.00241l148.50121,148.00241l-74.25061,0l0,148.71457l-148.5012,0l0,-148.71457z',
vertical_scrool: 'm37.375,261.625l0,-242.9375l0,0c0,-10.32083 8.36669,-18.6875 18.6875,-18.6875l224.25,0c10.32083,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36667,18.6875 -18.6875,18.6875l-18.6875,0l0,242.9375c0,10.32083 -8.36668,18.6875 -18.6875,18.6875l-224.25,0l0,0c-10.32083,0 -18.6875,-8.36667 -18.6875,-18.6875c0,-10.32083 8.36667,-18.6875 18.6875,-18.6875zm37.375,-261.625l0,0c10.32081,0 18.6875,8.36667 18.6875,18.6875c0,10.32081 -8.36669,18.6875 -18.6875,18.6875c-5.1604,0 -9.34375,-4.18335 -9.34375,-9.34375c0,-5.16041 4.18335,-9.34375 9.34375,-9.34375l18.6875,0m186.875,18.6875l-205.5625,0m-37.375,224.25l0,0c5.1604,0 9.34375,4.18335 9.34375,9.34375c0,5.1604 -4.18335,9.34375 -9.34375,9.34375l18.6875,0m-18.6875,18.6875l0,0c10.32081,0 18.6875,-8.36667 18.6875,-18.6875l0,-18.6875',
smiley: 'm68.49886,214.78838q81.06408,55.67332 161.93891,0m-144.36983,-109.9558c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57948,6.97517 15.57948,15.57949c0,8.60431 -6.97517,15.57947 -15.57948,15.57947c-8.60431,0 -15.57948,-6.97516 -15.57948,-15.57947m95.83109,0c0,-8.60432 6.97517,-15.57949 15.57948,-15.57949c8.60431,0 15.57947,6.97517 15.57947,15.57949c0,8.60431 -6.97516,15.57947 -15.57947,15.57947c-8.60429,0 -15.57948,-6.97516 -15.57948,-15.57947m-181.89903,44.73038l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296zm0,0l0,0c0,-82.60133 66.96162,-149.56296 149.56296,-149.56296c82.60135,0 149.56296,66.96162 149.56296,149.56296c0,82.60135 -66.96161,149.56296 -149.56296,149.56296c-82.60133,0 -149.56296,-66.96161 -149.56296,-149.56296z',
left_braket: 'm174.24565,298.5c-13.39009,0 -24.24489,-1.80908 -24.24489,-4.04065l0,-140.4187c0,-2.23158 -10.85481,-4.04065 -24.2449,-4.04065l0,0c13.39009,0 24.2449,-1.80907 24.2449,-4.04065l0,-140.4187l0,0c0,-2.23159 10.8548,-4.04066 24.24489,-4.04066',
uml_actor: 'm40.5,100l219,0m-108.99991,94.00006l107,105m-107.00009,-106.00006l-100,106m99.5,-231l0,125m33.24219,-158.75781c0,18.35916 -14.88303,33.24219 -33.24219,33.24219c-18.35916,0 -33.2422,-14.88303 -33.2422,-33.24219c0.00002,-18.35915 14.88304,-33.24219 33.2422,-33.24219c18.35916,0 33.24219,14.88304 33.24219,33.24219z',
dialog_balloon_1: 'm0.99786,35.96579l0,0c0,-19.31077 15.28761,-34.96524 34.14583,-34.96524l15.52084,0l0,0l74.50001,0l139.68748,0c9.05606,0 17.74118,3.68382 24.14478,10.24108c6.40356,6.55726 10.00107,15.45081 10.00107,24.72416l0,87.41311l0,0l0,52.44785l0,0c0,19.31078 -15.2876,34.96524 -34.14584,34.96524l-139.68748,0l-97.32507,88.90848l22.82506,-88.90848l-15.52084,0c-18.85822,0 -34.14583,-15.65446 -34.14583,-34.96524l0,0l0,-52.44785l0,0z',
cloud: 'm182.05086,34.31005c-0.64743,0.02048 -1.27309,0.07504 -1.92319,0.13979c-10.40161,1.03605 -19.58215,7.63722 -24.24597,17.4734l-2.47269,7.44367c0.53346,-2.57959 1.35258,-5.08134 2.47269,-7.44367c-8.31731,-8.61741 -19.99149,-12.59487 -31.52664,-10.72866c-11.53516,1.8662 -21.55294,9.3505 -27.02773,20.19925c-15.45544,-9.51897 -34.72095,-8.94245 -49.62526,1.50272c-14.90431,10.44516 -22.84828,28.93916 -20.43393,47.59753l1.57977,7.58346c-0.71388,-2.48442 -1.24701,-5.01186 -1.57977,-7.58346l-0.2404,0.69894c-12.95573,1.4119 -23.58103,11.46413 -26.34088,24.91708c-2.75985,13.45294 2.9789,27.25658 14.21789,34.21291l17.54914,4.26352c-6.1277,0.50439 -12.24542,-0.9808 -17.54914,-4.26352c-8.66903,9.71078 -10.6639,24.08736 -4.94535,35.96027c5.71854,11.87289 17.93128,18.70935 30.53069,17.15887l7.65843,-2.02692c-2.46413,1.0314 -5.02329,1.70264 -7.65843,2.02692c7.15259,13.16728 19.01251,22.77237 32.93468,26.5945c13.92217,3.82214 28.70987,1.56322 41.03957,-6.25546c10.05858,15.86252 27.91113,24.19412 45.81322,21.38742c17.90208,-2.8067 32.66954,-16.26563 37.91438,-34.52742l1.82016,-10.20447c-0.27254,3.46677 -0.86394,6.87508 -1.82016,10.20447c12.31329,8.07489 27.80199,8.52994 40.52443,1.18819c12.72244,-7.34175 20.6609,-21.34155 20.77736,-36.58929l-4.56108,-22.7823l-17.96776,-15.41455c13.89359,8.70317 22.6528,21.96329 22.52884,38.19685c16.5202,0.17313 30.55292,-13.98268 36.84976,-30.22897c6.29684,-16.24631 3.91486,-34.76801 -6.2504,-48.68089c4.21637,-10.35873 3.96622,-22.14172 -0.68683,-32.29084c-4.65308,-10.14912 -13.23602,-17.69244 -23.55914,-20.65356c-2.31018,-13.45141 -11.83276,-24.27162 -24.41768,-27.81765c-12.58492,-3.54603 -25.98557,0.82654 -34.41142,11.25287l-5.11707,8.63186c1.30753,-3.12148 3.01521,-6.03101 5.11707,-8.63186c-5.93959,-8.19432 -15.2556,-12.8181 -24.96718,-12.51096z',
cylinder: 'm299.0007,83.77844c0,18.28676 -66.70958,33.11111 -149.00002,33.11111m149.00002,-33.11111l0,0c0,18.28676 -66.70958,33.11111 -149.00002,33.11111c-82.29041,0 -148.99997,-14.82432 -148.99997,-33.11111m0,0l0,0c0,-18.28674 66.70956,-33.1111 148.99997,-33.1111c82.29044,0 149.00002,14.82436 149.00002,33.1111l0,132.44449c0,18.28674 -66.70958,33.11105 -149.00002,33.11105c-82.29041,0 -148.99997,-14.82431 -148.99997,-33.11105z',
arrow_u_turn: 'm1.00059,299.00055l0,-167.62497l0,0c0,-72.00411 58.37087,-130.37499 130.375,-130.37499l0,0l0,0c34.57759,0 67.73898,13.7359 92.18906,38.18595c24.45006,24.45005 38.18593,57.61144 38.18593,92.18904l0,18.625l37.24997,0l-74.49995,74.50002l-74.50002,-74.50002l37.25,0l0,-18.625c0,-30.8589 -25.0161,-55.87498 -55.87498,-55.87498l0,0l0,0c-30.85892,0 -55.875,25.01608 -55.875,55.87498l0,167.62497z',
arrow_left_up: 'm0.99865,224.5l74.50004,-74.5l0,37.25l111.74991,0l0,-111.75l-37.25,0l74.5,-74.5l74.5,74.5l-37.25,0l0,186.25l-186.24989,0l0,37.25l-74.50005,-74.5z',
maximize: 'm1.00037,150.34581l55.30305,-55.30267l0,27.65093l22.17356,0l0,-44.21833l44.21825,0l0,-22.17357l-27.65095,0l55.30267,-55.30292l55.3035,55.30292l-27.65175,0l0,22.17357l44.21835,0l0,44.21833l22.17357,0l0,-27.65093l55.30345,55.30267l-55.30345,55.3035l0,-27.65175l-22.17357,0l0,44.21834l-44.21835,0l0,22.17355l27.65175,0l-55.3035,55.30348l-55.30267,-55.30348l27.65095,0l0,-22.17355l-44.21825,0l0,-44.21834l-22.17356,0l0,27.65175l-55.30305,-55.3035z',
cross: 'm0.99844,99.71339l98.71494,0l0,-98.71495l101.26279,0l0,98.71495l98.71495,0l0,101.2628l-98.71495,0l0,98.71494l-101.26279,0l0,-98.71494l-98.71494,0z',
plaque: 'm-0.00197,49.94376l0,0c27.5829,0 49.94327,-22.36036 49.94327,-49.94327l199.76709,0l0,0c0,27.5829 22.36037,49.94327 49.94325,49.94327l0,199.7671l0,0c-27.58289,0 -49.94325,22.36034 -49.94325,49.94325l-199.76709,0c0,-27.58292 -22.36037,-49.94325 -49.94327,-49.94325z',
page: 'm249.3298,298.99744l9.9335,-39.73413l39.73413,-9.93355l-49.66763,49.66768l-248.33237,0l0,-298.00001l298.00001,0l0,248.33234'
},
buttons: []
},
buttons: []
}
};
const modeId = 'shapelib';
const startClientPos = {};
let currentD, curShapeId, curShape, startX, startY;
let curLib = library.basic;
function loadIcons () {
$('#shape_buttons').empty().append(curLib.buttons);
}
};
const modeId = 'shapelib';
const startClientPos = {};
function makeButtons (cat, shapes) {
const size = curLib.size || 300;
const fill = curLib.fill || false;
const off = size * 0.05;
const vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
const stroke = fill ? 0 : (size / 30);
const shapeIcon = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>',
'text/xml');
let currentD, curShapeId, curShape, startX, startY;
let curLib = library.basic;
const width = 24;
const height = 24;
shapeIcon.documentElement.setAttribute('width', width);
shapeIcon.documentElement.setAttribute('height', height);
const svgElem = $(document.importNode(shapeIcon.documentElement, true));
function loadIcons () {
$('#shape_buttons').empty().append(curLib.buttons);
}
const {data} = shapes;
function makeButtons (cat, shapes) {
const size = curLib.size || 300;
const fill = curLib.fill || false;
const off = size * 0.05;
const vb = [-off, -off, size + off * 2, size + off * 2].join(' ');
const stroke = fill ? 0 : (size / 30);
const shapeIcon = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><svg viewBox="' + vb + '"><path fill="' + (fill ? '#333' : 'none') + '" stroke="#000" stroke-width="' + stroke + '" /></svg></svg>',
'text/xml');
curLib.buttons = [];
for (const id in data) {
const pathD = data[id];
const icon = svgElem.clone();
icon.find('path').attr('d', pathD);
const width = 24;
const height = 24;
shapeIcon.documentElement.setAttribute('width', width);
shapeIcon.documentElement.setAttribute('height', height);
const svgElem = $(document.importNode(shapeIcon.documentElement, true));
const {data} = shapes;
curLib.buttons = [];
for (const id in data) {
const pathD = data[id];
const icon = svgElem.clone();
icon.find('path').attr('d', pathD);
const iconBtn = icon.wrap('<div class="tool_button">').parent().attr({
id: modeId + '_' + id,
title: id
});
// Store for later use
curLib.buttons.push(iconBtn[0]);
const iconBtn = icon.wrap('<div class="tool_button">').parent().attr({
id: modeId + '_' + id,
title: id
});
// Store for later use
curLib.buttons.push(iconBtn[0]);
}
}
}
function loadLibrary (catId) {
const lib = library[catId];
function loadLibrary (catId) {
const lib = library[catId];
if (!lib) {
$('#shape_buttons').html('Loading...');
$.getJSON(svgEditor.curConfig.extIconsPath + 'shapelib/' + catId + '.json', function (result) {
curLib = library[catId] = {
data: result.data,
size: result.size,
fill: result.fill
};
makeButtons(catId, result);
loadIcons();
});
return;
if (!lib) {
$('#shape_buttons').html('Loading...');
$.getJSON(svgEditor.curConfig.extIconsPath + 'shapelib/' + catId + '.json', function (result) {
curLib = library[catId] = {
data: result.data,
size: result.size,
fill: result.fill
};
makeButtons(catId, result);
loadIcons();
});
return;
}
curLib = lib;
if (!lib.buttons.length) { makeButtons(catId, lib); }
loadIcons();
}
curLib = lib;
if (!lib.buttons.length) { makeButtons(catId, lib); }
loadIcons();
}
return {
svgicons: svgEditor.curConfig.extIconsPath + 'ext-shapes.xml',
buttons: [{
id: 'tool_shapelib',
type: 'mode_flyout', // _flyout
position: 6,
title: 'Shape library',
events: {
click () {
return {
svgicons: svgEditor.curConfig.extIconsPath + 'ext-shapes.xml',
buttons: [{
id: 'tool_shapelib',
type: 'mode_flyout', // _flyout
position: 6,
title: 'Shape library',
events: {
click () {
canv.setMode(modeId);
}
}
}],
callback () {
$('<style>').text(
'#shape_buttons {' +
'overflow: auto;' +
'width: 180px;' +
'max-height: 300px;' +
'display: table-cell;' +
'vertical-align: middle;' +
'}' +
'#shape_cats {' +
'min-width: 110px;' +
'display: table-cell;' +
'vertical-align: middle;' +
'height: 300px;' +
'}' +
'#shape_cats > div {' +
'line-height: 1em;' +
'padding: .5em;' +
'border:1px solid #B0B0B0;' +
'background: #E8E8E8;' +
'margin-bottom: -1px;' +
'}' +
'#shape_cats div:hover {' +
'background: #FFFFCC;' +
'}' +
'#shape_cats div.current {' +
'font-weight: bold;' +
'}').appendTo('head');
const btnDiv = $('<div id="shape_buttons">');
$('#tools_shapelib > *').wrapAll(btnDiv);
const shower = $('#tools_shapelib_show');
loadLibrary('basic');
// Do mouseup on parent element rather than each button
$('#shape_buttons').mouseup(function (evt) {
const btn = $(evt.target).closest('div.tool_button');
if (!btn.length) { return; }
const copy = btn.children().clone();
shower.children(':not(.flyout_arrow_horiz)').remove();
shower
.append(copy)
.attr('data-curopt', '#' + btn[0].id) // This sets the current mode
.mouseup();
canv.setMode(modeId);
curShapeId = btn[0].id.substr((modeId + '_').length);
currentD = curLib.data[curShapeId];
$('.tools_flyout').fadeOut();
});
const shapeCats = $('<div id="shape_cats">');
let catStr = '';
$.each(categories, function (id, label) {
catStr += '<div data-cat=' + id + '>' + label + '</div>';
});
shapeCats.html(catStr).children().bind('mouseup', function () {
const catlink = $(this);
catlink.siblings().removeClass('current');
catlink.addClass('current');
loadLibrary(catlink.attr('data-cat'));
// Get stuff
return false;
});
shapeCats.children().eq(0).addClass('current');
$('#tools_shapelib').append(shapeCats);
shower.mouseup(function () {
canv.setMode(currentD ? modeId : 'select');
});
$('#tool_shapelib').remove();
const h = $('#tools_shapelib').height();
$('#tools_shapelib').css({
'margin-top': -(h / 2 - 15),
'margin-left': 3
});
},
mouseDown (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
startX = opts.start_x;
const x = startX;
startY = opts.start_y;
const y = startY;
const curStyle = canv.getStyle();
startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY;
curShape = canv.addSvgElementFromJson({
element: 'path',
curStyles: true,
attr: {
d: currentD,
id: canv.getNextId(),
opacity: curStyle.opacity / 2,
style: 'pointer-events:none'
}
});
// Make sure shape uses absolute values
if (/[a-z]/.test(currentD)) {
currentD = curLib.data[curShapeId] = canv.pathActions.convertPath(curShape);
curShape.setAttribute('d', currentD);
canv.pathActions.fixEnd(curShape);
}
}
}],
callback () {
$('<style>').text(
'#shape_buttons {' +
'overflow: auto;' +
'width: 180px;' +
'max-height: 300px;' +
'display: table-cell;' +
'vertical-align: middle;' +
'}' +
'#shape_cats {' +
'min-width: 110px;' +
'display: table-cell;' +
'vertical-align: middle;' +
'height: 300px;' +
'}' +
'#shape_cats > div {' +
'line-height: 1em;' +
'padding: .5em;' +
'border:1px solid #B0B0B0;' +
'background: #E8E8E8;' +
'margin-bottom: -1px;' +
'}' +
'#shape_cats div:hover {' +
'background: #FFFFCC;' +
'}' +
'#shape_cats div.current {' +
'font-weight: bold;' +
'}').appendTo('head');
curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
const btnDiv = $('<div id="shape_buttons">');
$('#tools_shapelib > *').wrapAll(btnDiv);
canv.recalculateDimensions(curShape);
const shower = $('#tools_shapelib_show');
/* const tlist = */ canv.getTransformList(curShape);
loadLibrary('basic');
lastBBox = curShape.getBBox();
// Do mouseup on parent element rather than each button
$('#shape_buttons').mouseup(function (evt) {
const btn = $(evt.target).closest('div.tool_button');
return {
started: true
};
},
mouseMove (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
if (!btn.length) { return; }
const zoom = canv.getZoom();
const evt = opts.event;
const copy = btn.children().clone();
shower.children(':not(.flyout_arrow_horiz)').remove();
shower
.append(copy)
.attr('data-curopt', '#' + btn[0].id) // This sets the current mode
.mouseup();
canv.setMode(modeId);
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
curShapeId = btn[0].id.substr((modeId + '_').length);
currentD = curLib.data[curShapeId];
const tlist = canv.getTransformList(curShape),
box = curShape.getBBox(),
left = box.x, top = box.y;
// {width, height} = box,
// const dx = (x - startX), dy = (y - startY);
$('.tools_flyout').fadeOut();
});
const newbox = {
x: Math.min(startX, x),
y: Math.min(startY, y),
width: Math.abs(x - startX),
height: Math.abs(y - startY)
};
const shapeCats = $('<div id="shape_cats">');
/*
// This is currently serving no purpose, so commenting out
let sy = height ? (height + dy) / height : 1,
sx = width ? (width + dx) / width : 1;
*/
let catStr = '';
$.each(categories, function (id, label) {
catStr += '<div data-cat=' + id + '>' + label + '</div>';
});
let sx = (newbox.width / lastBBox.width) || 1;
let sy = (newbox.height / lastBBox.height) || 1;
shapeCats.html(catStr).children().bind('mouseup', function () {
const catlink = $(this);
catlink.siblings().removeClass('current');
catlink.addClass('current');
loadLibrary(catlink.attr('data-cat'));
// Get stuff
return false;
});
shapeCats.children().eq(0).addClass('current');
$('#tools_shapelib').append(shapeCats);
shower.mouseup(function () {
canv.setMode(currentD ? modeId : 'select');
});
$('#tool_shapelib').remove();
const h = $('#tools_shapelib').height();
$('#tools_shapelib').css({
'margin-top': -(h / 2 - 15),
'margin-left': 3
});
},
mouseDown (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
startX = opts.start_x;
const x = startX;
startY = opts.start_y;
const y = startY;
const curStyle = canv.getStyle();
startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY;
curShape = canv.addSvgElementFromJson({
element: 'path',
curStyles: true,
attr: {
d: currentD,
id: canv.getNextId(),
opacity: curStyle.opacity / 2,
style: 'pointer-events:none'
// Not perfect, but mostly works...
let tx = 0;
if (x < startX) {
tx = lastBBox.width;
}
let ty = 0;
if (y < startY) {
ty = lastBBox.height;
}
});
// Make sure shape uses absolute values
if (/[a-z]/.test(currentD)) {
currentD = curLib.data[curShapeId] = canv.pathActions.convertPath(curShape);
curShape.setAttribute('d', currentD);
canv.pathActions.fixEnd(curShape);
// update the transform list with translate,scale,translate
const translateOrigin = svgroot.createSVGTransform(),
scale = svgroot.createSVGTransform(),
translateBack = svgroot.createSVGTransform();
translateOrigin.setTranslate(-(left + tx), -(top + ty));
if (!evt.shiftKey) {
const max = Math.min(Math.abs(sx), Math.abs(sy));
sx = max * (sx < 0 ? -1 : 1);
sy = max * (sy < 0 ? -1 : 1);
}
scale.setScale(sx, sy);
translateBack.setTranslate(left + tx, top + ty);
tlist.appendItem(translateBack);
tlist.appendItem(scale);
tlist.appendItem(translateOrigin);
canv.recalculateDimensions(curShape);
lastBBox = curShape.getBBox();
},
mouseUp (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
const keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y);
return {
keep: keepObject,
element: curShape,
started: false
};
}
curShape.setAttribute('transform', 'translate(' + x + ',' + y + ') scale(0.005) translate(' + -x + ',' + -y + ')');
canv.recalculateDimensions(curShape);
/* const tlist = */ canv.getTransformList(curShape);
lastBBox = curShape.getBBox();
return {
started: true
};
},
mouseMove (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
const zoom = canv.getZoom();
const evt = opts.event;
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const tlist = canv.getTransformList(curShape),
box = curShape.getBBox(),
left = box.x, top = box.y;
// {width, height} = box,
// const dx = (x - startX), dy = (y - startY);
const newbox = {
x: Math.min(startX, x),
y: Math.min(startY, y),
width: Math.abs(x - startX),
height: Math.abs(y - startY)
};
/*
// This is currently serving no purpose, so commenting out
let sy = height ? (height + dy) / height : 1,
sx = width ? (width + dx) / width : 1;
*/
let sx = (newbox.width / lastBBox.width) || 1;
let sy = (newbox.height / lastBBox.height) || 1;
// Not perfect, but mostly works...
let tx = 0;
if (x < startX) {
tx = lastBBox.width;
}
let ty = 0;
if (y < startY) {
ty = lastBBox.height;
}
// update the transform list with translate,scale,translate
const translateOrigin = svgroot.createSVGTransform(),
scale = svgroot.createSVGTransform(),
translateBack = svgroot.createSVGTransform();
translateOrigin.setTranslate(-(left + tx), -(top + ty));
if (!evt.shiftKey) {
const max = Math.min(Math.abs(sx), Math.abs(sy));
sx = max * (sx < 0 ? -1 : 1);
sy = max * (sy < 0 ? -1 : 1);
}
scale.setScale(sx, sy);
translateBack.setTranslate(left + tx, top + ty);
tlist.appendItem(translateBack);
tlist.appendItem(scale);
tlist.appendItem(translateOrigin);
canv.recalculateDimensions(curShape);
lastBBox = curShape.getBBox();
},
mouseUp (opts) {
const mode = canv.getMode();
if (mode !== modeId) { return; }
const keepObject = (opts.event.clientX !== startClientPos.x && opts.event.clientY !== startClientPos.y);
return {
keep: keepObject,
element: curShape,
started: false
};
}
};
});
};
}
};

View File

@@ -7,227 +7,230 @@
* All rights reserved
*
*/
import svgEditor from '../svg-editor.js';
svgEditor.addExtension('star', function (S) {
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
export default {
name: 'star',
init (S) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
let // {svgcontent} = S,
selElems,
// editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument,
started,
newFO;
// edg = 0,
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
// undoCommand = 'Not image',
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
let // {svgcontent} = S,
selElems,
// editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument,
started,
newFO;
// edg = 0,
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
// undoCommand = 'Not image',
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
fcRules = $('<style id="fc_rules"></style>').appendTo('head');
}
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#star_panel').toggle(on);
}
fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }');
$('#star_panel').toggle(on);
}
/*
function toggleSourceButtons(on){
$('#star_save, #star_cancel').toggle(on);
}
*/
/*
function toggleSourceButtons(on){
$('#star_save, #star_cancel').toggle(on);
}
*/
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems);
}
function setAttr (attr, val) {
svgCanvas.changeSelectedAttribute(attr, val);
S.call('changed', selElems);
}
/*
function cot(n){
return 1 / Math.tan(n);
}
/*
function cot(n){
return 1 / Math.tan(n);
}
function sec(n){
return 1 / Math.cos(n);
}
*/
function sec(n){
return 1 / Math.cos(n);
}
*/
return {
name: 'star',
svgicons: svgEditor.curConfig.extIconsPath + 'star-icons.svg',
buttons: [{
id: 'tool_star',
type: 'mode',
title: 'Star Tool',
position: 12,
events: {
click () {
showPanel(true);
svgCanvas.setMode('star');
}
}
}],
context_tools: [{
type: 'input',
panel: 'star_panel',
title: 'Number of Sides',
id: 'starNumPoints',
label: 'points',
size: 3,
defval: 5,
events: {
change () {
setAttr('point', this.value);
}
}
}, {
type: 'input',
panel: 'star_panel',
title: 'Pointiness',
id: 'starRadiusMulitplier',
label: 'Pointiness',
size: 3,
defval: 2.5
}, {
type: 'input',
panel: 'star_panel',
title: 'Twists the star',
id: 'radialShift',
label: 'Radial Shift',
size: 3,
defval: 0,
events: {
change () {
setAttr('radialshift', this.value);
}
}
}],
callback () {
$('#star_panel').hide();
// const endChanges = function(){};
},
mouseDown (opts) {
const rgb = svgCanvas.getColor('fill');
// const ccRgbEl = rgb.substring(1, rgb.length);
const sRgb = svgCanvas.getColor('stroke');
// const ccSRgbEl = sRgb.substring(1, rgb.length);
const sWidth = svgCanvas.getStrokeWidth();
if (svgCanvas.getMode() === 'star') {
started = true;
newFO = S.addSvgElementFromJson({
element: 'polygon',
attr: {
cx: opts.start_x,
cy: opts.start_y,
id: S.getNextId(),
shape: 'star',
point: document.getElementById('starNumPoints').value,
r: 0,
radialshift: document.getElementById('radialShift').value,
r2: 0,
orient: 'point',
fill: rgb,
strokecolor: sRgb,
strokeWidth: sWidth
return {
name: 'star',
svgicons: svgEditor.curConfig.extIconsPath + 'star-icons.svg',
buttons: [{
id: 'tool_star',
type: 'mode',
title: 'Star Tool',
position: 12,
events: {
click () {
showPanel(true);
svgCanvas.setMode('star');
}
});
return {
started: true
};
}
},
mouseMove (opts) {
if (!started) {
return;
}
if (svgCanvas.getMode() === 'star') {
const c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
}
}],
let x = opts.mouse_x;
let y = opts.mouse_y;
const {cx, cy, fill, strokecolor, strokeWidth, radialshift, point, orient} = c,
circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5,
inradius = circumradius / document.getElementById('starRadiusMulitplier').value;
newFO.setAttributeNS(null, 'r', circumradius);
newFO.setAttributeNS(null, 'r2', inradius);
let polyPoints = '';
for (let s = 0; point >= s; s++) {
let angle = 2.0 * Math.PI * (s / point);
if (orient === 'point') {
angle -= (Math.PI / 2);
} else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2);
context_tools: [{
type: 'input',
panel: 'star_panel',
title: 'Number of Sides',
id: 'starNumPoints',
label: 'points',
size: 3,
defval: 5,
events: {
change () {
setAttr('point', this.value);
}
}
}, {
type: 'input',
panel: 'star_panel',
title: 'Pointiness',
id: 'starRadiusMulitplier',
label: 'Pointiness',
size: 3,
defval: 2.5
}, {
type: 'input',
panel: 'star_panel',
title: 'Twists the star',
id: 'radialShift',
label: 'Radial Shift',
size: 3,
defval: 0,
events: {
change () {
setAttr('radialshift', this.value);
}
}
}],
callback () {
$('#star_panel').hide();
// const endChanges = function(){};
},
mouseDown (opts) {
const rgb = svgCanvas.getColor('fill');
// const ccRgbEl = rgb.substring(1, rgb.length);
const sRgb = svgCanvas.getColor('stroke');
// const ccSRgbEl = sRgb.substring(1, rgb.length);
const sWidth = svgCanvas.getStrokeWidth();
x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy;
if (svgCanvas.getMode() === 'star') {
started = true;
polyPoints += x + ',' + y + ' ';
newFO = S.addSvgElementFromJson({
element: 'polygon',
attr: {
cx: opts.start_x,
cy: opts.start_y,
id: S.getNextId(),
shape: 'star',
point: document.getElementById('starNumPoints').value,
r: 0,
radialshift: document.getElementById('radialShift').value,
r2: 0,
orient: 'point',
fill: rgb,
strokecolor: sRgb,
strokeWidth: sWidth
}
});
return {
started: true
};
}
},
mouseMove (opts) {
if (!started) {
return;
}
if (svgCanvas.getMode() === 'star') {
const c = $(newFO).attr(['cx', 'cy', 'point', 'orient', 'fill', 'strokecolor', 'strokeWidth', 'radialshift']);
if (inradius != null) {
angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point);
let x = opts.mouse_x;
let y = opts.mouse_y;
const {cx, cy, fill, strokecolor, strokeWidth, radialshift, point, orient} = c,
circumradius = (Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy))) / 1.5,
inradius = circumradius / document.getElementById('starRadiusMulitplier').value;
newFO.setAttributeNS(null, 'r', circumradius);
newFO.setAttributeNS(null, 'r2', inradius);
let polyPoints = '';
for (let s = 0; point >= s; s++) {
let angle = 2.0 * Math.PI * (s / point);
if (orient === 'point') {
angle -= (Math.PI / 2);
} else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2);
}
angle += radialshift;
x = (inradius * Math.cos(angle)) + cx;
y = (inradius * Math.sin(angle)) + cy;
x = (circumradius * Math.cos(angle)) + cx;
y = (circumradius * Math.sin(angle)) + cy;
polyPoints += x + ',' + y + ' ';
if (inradius != null) {
angle = (2.0 * Math.PI * (s / point)) + (Math.PI / point);
if (orient === 'point') {
angle -= (Math.PI / 2);
} else if (orient === 'edge') {
angle = (angle + (Math.PI / point)) - (Math.PI / 2);
}
angle += radialshift;
x = (inradius * Math.cos(angle)) + cx;
y = (inradius * Math.sin(angle)) + cy;
polyPoints += x + ',' + y + ' ';
}
}
newFO.setAttributeNS(null, 'points', polyPoints);
newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
/* const shape = */ newFO.getAttributeNS(null, 'shape');
return {
started: true
};
}
newFO.setAttributeNS(null, 'points', polyPoints);
newFO.setAttributeNS(null, 'fill', fill);
newFO.setAttributeNS(null, 'stroke', strokecolor);
newFO.setAttributeNS(null, 'stroke-width', strokeWidth);
/* const shape = */ newFO.getAttributeNS(null, 'shape');
},
mouseUp () {
if (svgCanvas.getMode() === 'star') {
const attrs = $(newFO).attr(['r']);
// svgCanvas.addToSelection([newFO], true);
return {
keep: (attrs.r !== '0'),
element: newFO
};
}
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
return {
started: true
};
}
},
mouseUp () {
if (svgCanvas.getMode() === 'star') {
const attrs = $(newFO).attr(['r']);
// svgCanvas.addToSelection([newFO], true);
return {
keep: (attrs.r !== '0'),
element: newFO
};
}
},
selectedChanged (opts) {
// Use this to update the current selected elements
selElems = opts.elems;
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'star') {
if (opts.selectedElement && !opts.multiselected) {
// $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
$('#starNumPoints').val(elem.getAttribute('point'));
$('#radialShift').val(elem.getAttribute('radialshift'));
showPanel(true);
let i = selElems.length;
while (i--) {
const elem = selElems[i];
if (elem && elem.getAttributeNS(null, 'shape') === 'star') {
if (opts.selectedElement && !opts.multiselected) {
// $('#starRadiusMulitplier').val(elem.getAttribute('r2'));
$('#starNumPoints').val(elem.getAttribute('point'));
$('#radialShift').val(elem.getAttribute('radialshift'));
showPanel(true);
} else {
showPanel(false);
}
} else {
showPanel(false);
}
} else {
showPanel(false);
}
},
elementChanged (opts) {
// const elem = opts.elems[0];
}
},
elementChanged (opts) {
// const elem = opts.elems[0];
}
};
});
};
}
};

View File

@@ -29,254 +29,269 @@ TODOS
2. We might provide control of storage settings through the UI besides the
initial (or URL-forced) dialog.
*/
// Todo: We might use dynamic `import()` later instead, based on detected locale
import confirmSetStorage from './ext-locale/storage.js';
import svgEditor from '../svg-editor.js';
import {importSetGlobalDefault} from '../external/dynamic-import-polyfill/importModule.js';
svgEditor.addExtension('storage', function () {
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
export default {
name: 'storage',
init () {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
// We could empty any already-set data for users when they decline storage,
// but it would be a risk for users who wanted to store but accidentally
// said "no"; instead, we'll let those who already set it, delete it themselves;
// to change, set the "emptyStorageOnDecline" config setting to true
// in svgedit-config-iife.js/svgedit-config-es.js.
const {
emptyStorageOnDecline,
// When the code in svg-editor.js prevents local storage on load per
// user request, we also prevent storing on unload here so as to
// avoid third-party sites making XSRF requests or providing links
// which would cause the user's local storage not to load and then
// upon page unload (such as the user closing the window), the storage
// would thereby be set with an empty value, erasing any of the
// user's prior work. To change this behavior so that no use of storage
// or adding of new storage takes place regardless of settings, set
// the "noStorageOnLoad" config setting to true in svgedit-config-iife.js.
noStorageOnLoad,
forceStorage
} = svgEditor.curConfig;
const {storage} = svgEditor;
// We could empty any already-set data for users when they decline storage,
// but it would be a risk for users who wanted to store but accidentally
// said "no"; instead, we'll let those who already set it, delete it themselves;
// to change, set the "emptyStorageOnDecline" config setting to true
// in svgedit-config-iife.js/svgedit-config-es.js.
const {
emptyStorageOnDecline,
// When the code in svg-editor.js prevents local storage on load per
// user request, we also prevent storing on unload here so as to
// avoid third-party sites making XSRF requests or providing links
// which would cause the user's local storage not to load and then
// upon page unload (such as the user closing the window), the storage
// would thereby be set with an empty value, erasing any of the
// user's prior work. To change this behavior so that no use of storage
// or adding of new storage takes place regardless of settings, set
// the "noStorageOnLoad" config setting to true in svgedit-config-iife.js.
noStorageOnLoad,
forceStorage
} = svgEditor.curConfig;
const {storage} = svgEditor;
function replaceStoragePrompt (val) {
val = val ? 'storagePrompt=' + val : '';
const loc = top.location; // Allow this to work with the embedded editor as well
if (loc.href.includes('storagePrompt=')) {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
});
} else {
loc.href += (loc.href.includes('?') ? '&' : '?') + val;
}
}
function setSVGContentStorage (val) {
if (storage) {
const name = 'svgedit-' + svgEditor.curConfig.canvasName;
if (!val) {
storage.removeItem(name);
function replaceStoragePrompt (val) {
val = val ? 'storagePrompt=' + val : '';
const loc = top.location; // Allow this to work with the embedded editor as well
if (loc.href.includes('storagePrompt=')) {
loc.href = loc.href.replace(/([&?])storagePrompt=[^&]*(&?)/, function (n0, n1, amp) {
return (val ? n1 : '') + val + (!val && amp ? n1 : (amp || ''));
});
} else {
storage.setItem(name, val);
loc.href += (loc.href.includes('?') ? '&' : '?') + val;
}
}
}
function expireCookie (cookie) {
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
}
function removeStoragePrefCookie () {
expireCookie('store');
}
function emptyStorage () {
setSVGContentStorage('');
for (let name in svgEditor.curPrefs) {
if (svgEditor.curPrefs.hasOwnProperty(name)) {
name = 'svg-edit-' + name;
if (storage) {
function setSVGContentStorage (val) {
if (storage) {
const name = 'svgedit-' + svgEditor.curConfig.canvasName;
if (!val) {
storage.removeItem(name);
}
expireCookie(name);
}
}
}
// emptyStorage();
/**
* Listen for unloading: If and only if opted in by the user, set the content
* document and preferences into storage:
* 1. Prevent save warnings (since we're automatically saving unsaved
* content into storage)
* 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)
* 3. Use localStorage (where available) or cookies to set preferences.
*/
function setupBeforeUnloadListener () {
window.addEventListener('beforeunload', function (e) {
// Don't save anything unless the user opted in to storage
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
return;
}
if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
setSVGContentStorage(svgCanvas.getSvgString());
}
svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
// svgEditor.showSaveWarning = false;
const {curPrefs} = svgEditor;
for (let key in curPrefs) {
if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
let val = curPrefs[key];
const store = (val !== undefined);
key = 'svg-edit-' + key;
if (!store) {
continue;
}
if (storage) {
storage.setItem(key, val);
} else if (window.widget) {
window.widget.setPreferenceForKey(val, key);
} else {
val = encodeURIComponent(val);
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
}
}
}
}, false);
}
let loaded = false;
return {
name: 'storage',
langReady (data) {
// const {uiStrings: {confirmSetStorage}} = data, // No need to store as dialog should only run once
const {lang} = data;
const {storagePrompt} = $.deparam.querystring(true);
const {
message, storagePrefsAndContent, storagePrefsOnly,
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,
rememberLabel, rememberTooltip
} = confirmSetStorage[lang];
// No need to run this one-time dialog again just because the user
// changes the language
if (loaded) {
return;
}
loaded = true;
// Note that the following can load even if "noStorageOnLoad" is
// set to false; to avoid any chance of storage, avoid this
// extension! (and to avoid using any prior storage, set the
// config option "noStorageOnLoad" to true).
if (!forceStorage && (
// If the URL has been explicitly set to always prompt the
// user (e.g., so one can be pointed to a URL where one
// can alter one's settings, say to prevent future storage)...
storagePrompt === true ||
(
// ...or...if the URL at least doesn't explicitly prevent a
// storage prompt (as we use for users who
// don't want to set cookies at all but who don't want
// continual prompts about it)...
storagePrompt !== false &&
// ...and this user hasn't previously indicated a desire for storage
!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)
)
// ...then show the storage prompt.
)) {
const options = [];
if (storage) {
options.unshift(
{value: 'prefsAndContent', text: storagePrefsAndContent},
{value: 'prefsOnly', text: storagePrefsOnly},
{value: 'noPrefsOrContent', text: storageNoPrefsOrContent}
);
} else {
options.unshift(
{value: 'prefsOnly', text: storagePrefs},
{value: 'noPrefsOrContent', text: storageNoPrefs}
);
storage.setItem(name, val);
}
// Hack to temporarily provide a wide and high enough dialog
const oldContainerWidth = $('#dialog_container')[0].style.width,
oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
oldContentHeight = $('#dialog_content')[0].style.height,
oldContainerHeight = $('#dialog_container')[0].style.height;
$('#dialog_content')[0].style.height = '120px';
$('#dialog_container')[0].style.height = '170px';
$('#dialog_container')[0].style.width = '800px';
$('#dialog_container')[0].style.marginLeft = '-400px';
// Open select-with-checkbox dialog
// From svg-editor.js
$.select(
message,
options,
function (pref, checked) {
if (pref && pref !== 'noPrefsOrContent') {
// Regardless of whether the user opted
// to remember the choice (and move to a URL which won't
// ask them again), we have to assume the user
// doesn't even want to remember their not wanting
// storage, so we don't set the cookie or continue on with
// setting storage on beforeunload
document.cookie = 'store=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly'
// If the URL was configured to always insist on a prompt, if
// the user does indicate a wish to store their info, we
// don't want ask them again upon page refresh so move
// them instead to a URL which does not always prompt
if (storagePrompt === true && checked) {
replaceStoragePrompt();
return;
}
} else { // The user does not wish storage (or cancelled, which we treat equivalently)
removeStoragePrefCookie();
if (pref && // If the user explicitly expresses wish for no storage
emptyStorageOnDecline
) {
emptyStorage();
}
if (pref && checked) {
// Open a URL which won't set storage and won't prompt user about storage
replaceStoragePrompt('false');
return;
}
}
// Reset width/height of dialog (e.g., for use by Export)
$('#dialog_container')[0].style.width = oldContainerWidth;
$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;
$('#dialog_content')[0].style.height = oldContentHeight;
$('#dialog_container')[0].style.height = oldContainerHeight;
// It should be enough to (conditionally) add to storage on
// beforeunload, but if we wished to update immediately,
// we might wish to try setting:
// svgEditor.setConfig({noStorageOnLoad: true});
// and then call:
// svgEditor.loadContentAndPrefs();
// We don't check for noStorageOnLoad here because
// the prompt gives the user the option to store data
setupBeforeUnloadListener();
svgEditor.storagePromptClosed = true;
},
null,
null,
{
label: rememberLabel,
checked: false,
tooltip: rememberTooltip
}
);
} else if (!noStorageOnLoad || forceStorage) {
setupBeforeUnloadListener();
}
}
};
});
function expireCookie (cookie) {
document.cookie = encodeURIComponent(cookie) + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
}
function removeStoragePrefCookie () {
expireCookie('store');
}
function emptyStorage () {
setSVGContentStorage('');
for (let name in svgEditor.curPrefs) {
if (svgEditor.curPrefs.hasOwnProperty(name)) {
name = 'svg-edit-' + name;
if (storage) {
storage.removeItem(name);
}
expireCookie(name);
}
}
}
// emptyStorage();
/**
* Listen for unloading: If and only if opted in by the user, set the content
* document and preferences into storage:
* 1. Prevent save warnings (since we're automatically saving unsaved
* content into storage)
* 2. Use localStorage to set SVG contents (potentially too large to allow in cookies)
* 3. Use localStorage (where available) or cookies to set preferences.
*/
function setupBeforeUnloadListener () {
window.addEventListener('beforeunload', function (e) {
// Don't save anything unless the user opted in to storage
if (!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)) {
return;
}
if (document.cookie.match(/(?:^|;\s*)store=prefsAndContent/)) {
setSVGContentStorage(svgCanvas.getSvgString());
}
svgEditor.setConfig({no_save_warning: true}); // No need for explicit saving at all once storage is on
// svgEditor.showSaveWarning = false;
const {curPrefs} = svgEditor;
for (let key in curPrefs) {
if (curPrefs.hasOwnProperty(key)) { // It's our own config, so we don't need to iterate up the prototype chain
let val = curPrefs[key];
const store = (val !== undefined);
key = 'svg-edit-' + key;
if (!store) {
continue;
}
if (storage) {
storage.setItem(key, val);
} else if (window.widget) {
window.widget.setPreferenceForKey(val, key);
} else {
val = encodeURIComponent(val);
document.cookie = encodeURIComponent(key) + '=' + val + '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
}
}
}
}, false);
}
let loaded = false;
return {
name: 'storage',
async langReady ({lang}) {
const {storagePrompt} = $.deparam.querystring(true);
let confirmSetStorage;
async function tryImport (lang) {
const url = `${svgEditor.curConfig.extPath}ext-locale/storage/${lang}.js`;
confirmSetStorage = await importSetGlobalDefault(url, {
global: 'svgEditorExtensionLocale_storage_' + lang
});
}
try {
await tryImport(lang);
} catch (err) {
await tryImport('en');
}
const {
message, storagePrefsAndContent, storagePrefsOnly,
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,
rememberLabel, rememberTooltip
} = confirmSetStorage;
// No need to run this one-time dialog again just because the user
// changes the language
if (loaded) {
return;
}
loaded = true;
// Note that the following can load even if "noStorageOnLoad" is
// set to false; to avoid any chance of storage, avoid this
// extension! (and to avoid using any prior storage, set the
// config option "noStorageOnLoad" to true).
if (!forceStorage && (
// If the URL has been explicitly set to always prompt the
// user (e.g., so one can be pointed to a URL where one
// can alter one's settings, say to prevent future storage)...
storagePrompt === true ||
(
// ...or...if the URL at least doesn't explicitly prevent a
// storage prompt (as we use for users who
// don't want to set cookies at all but who don't want
// continual prompts about it)...
storagePrompt !== false &&
// ...and this user hasn't previously indicated a desire for storage
!document.cookie.match(/(?:^|;\s*)store=(?:prefsAndContent|prefsOnly)/)
)
// ...then show the storage prompt.
)) {
const options = [];
if (storage) {
options.unshift(
{value: 'prefsAndContent', text: storagePrefsAndContent},
{value: 'prefsOnly', text: storagePrefsOnly},
{value: 'noPrefsOrContent', text: storageNoPrefsOrContent}
);
} else {
options.unshift(
{value: 'prefsOnly', text: storagePrefs},
{value: 'noPrefsOrContent', text: storageNoPrefs}
);
}
// Hack to temporarily provide a wide and high enough dialog
const oldContainerWidth = $('#dialog_container')[0].style.width,
oldContainerMarginLeft = $('#dialog_container')[0].style.marginLeft,
oldContentHeight = $('#dialog_content')[0].style.height,
oldContainerHeight = $('#dialog_container')[0].style.height;
$('#dialog_content')[0].style.height = '120px';
$('#dialog_container')[0].style.height = '170px';
$('#dialog_container')[0].style.width = '800px';
$('#dialog_container')[0].style.marginLeft = '-400px';
// Open select-with-checkbox dialog
// From svg-editor.js
$.select(
message,
options,
function (pref, checked) {
if (pref && pref !== 'noPrefsOrContent') {
// Regardless of whether the user opted
// to remember the choice (and move to a URL which won't
// ask them again), we have to assume the user
// doesn't even want to remember their not wanting
// storage, so we don't set the cookie or continue on with
// setting storage on beforeunload
document.cookie = 'store=' + encodeURIComponent(pref) + '; expires=Fri, 31 Dec 9999 23:59:59 GMT'; // 'prefsAndContent' | 'prefsOnly'
// If the URL was configured to always insist on a prompt, if
// the user does indicate a wish to store their info, we
// don't want ask them again upon page refresh so move
// them instead to a URL which does not always prompt
if (storagePrompt === true && checked) {
replaceStoragePrompt();
return;
}
} else { // The user does not wish storage (or cancelled, which we treat equivalently)
removeStoragePrefCookie();
if (pref && // If the user explicitly expresses wish for no storage
emptyStorageOnDecline
) {
emptyStorage();
}
if (pref && checked) {
// Open a URL which won't set storage and won't prompt user about storage
replaceStoragePrompt('false');
return;
}
}
// Reset width/height of dialog (e.g., for use by Export)
$('#dialog_container')[0].style.width = oldContainerWidth;
$('#dialog_container')[0].style.marginLeft = oldContainerMarginLeft;
$('#dialog_content')[0].style.height = oldContentHeight;
$('#dialog_container')[0].style.height = oldContainerHeight;
// It should be enough to (conditionally) add to storage on
// beforeunload, but if we wished to update immediately,
// we might wish to try setting:
// svgEditor.setConfig({noStorageOnLoad: true});
// and then call:
// svgEditor.loadContentAndPrefs();
// We don't check for noStorageOnLoad here because
// the prompt gives the user the option to store data
setupBeforeUnloadListener();
svgEditor.storagePromptClosed = true;
},
null,
null,
{
label: rememberLabel,
checked: false,
tooltip: rememberTooltip
}
);
} else if (!noStorageOnLoad || forceStorage) {
setupBeforeUnloadListener();
}
}
};
}
};

View File

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

View File

@@ -1,41 +1,44 @@
import svgEditor from '../svg-editor.js';
/**
* Should not be needed for same domain control (just call via child frame),
* but an API common for cross-domain and same domain use can be found
* in embedapi.js with a demo at embedapi.html
*/
svgEditor.addExtension('xdomain-messaging', function () {
const svgCanvas = svgEditor.canvas;
try {
window.addEventListener('message', function (e) {
// We accept and post strings for the sake of IE9 support
if (typeof e.data !== 'string' || e.data.charAt() === '|') {
return;
}
const data = JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') {
return;
}
// The default is not to allow any origins, including even the same domain or if run on a file:// URL
// See config-sample.js for an example of how to configure
const {allowedOrigins} = svgEditor.curConfig;
if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {
return;
}
const cbid = data.id;
const {name, args} = data;
const message = {
namespace: 'svg-edit',
id: cbid
};
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) {
message.error = err.message;
}
e.source.postMessage(JSON.stringify(message), '*');
}, false);
} catch (err) {
console.log('Error with xdomain message listener: ' + err);
export default {
name: 'xdomain-messaging',
init () {
const svgEditor = this;
const svgCanvas = svgEditor.canvas;
try {
window.addEventListener('message', function (e) {
// We accept and post strings for the sake of IE9 support
if (typeof e.data !== 'string' || e.data.charAt() === '|') {
return;
}
const data = JSON.parse(e.data);
if (!data || typeof data !== 'object' || data.namespace !== 'svgCanvas') {
return;
}
// The default is not to allow any origins, including even the same domain or if run on a file:// URL
// See config-sample.js for an example of how to configure
const {allowedOrigins} = svgEditor.curConfig;
if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {
return;
}
const cbid = data.id;
const {name, args} = data;
const message = {
namespace: 'svg-edit',
id: cbid
};
try {
message.result = svgCanvas[name].apply(svgCanvas, args);
} catch (err) {
message.error = err.message;
}
e.source.postMessage(JSON.stringify(message), '*');
}, false);
} catch (err) {
console.log('Error with xdomain message listener: ' + err);
}
}
});
};

View File

@@ -0,0 +1,101 @@
// From https://github.com/inexorabletash/polyfill/blob/master/dom.js
function mixin (o, ps) {
if (!o) return;
Object.keys(ps).forEach((p) => {
if ((p in o) || (p in o.prototype)) { return; }
try {
Object.defineProperty(
o.prototype,
p,
Object.getOwnPropertyDescriptor(ps, p)
);
} catch (ex) {
// Throws in IE8; just copy it
o[p] = ps[p];
}
});
}
function convertNodesIntoANode (nodes) {
nodes = nodes.map((node) => {
return !(node instanceof Node) ? document.createTextNode(node) : node;
});
if (nodes.length === 1) {
return nodes[0];
}
const node = document.createDocumentFragment();
nodes.forEach((n) => {
node.appendChild(n);
});
return node;
}
const ParentNode = {
prepend (...nodes) {
nodes = convertNodesIntoANode(nodes);
this.insertBefore(nodes, this.firstChild);
},
append (...nodes) {
nodes = convertNodesIntoANode(nodes);
this.appendChild(nodes);
}
};
mixin(Document || HTMLDocument, ParentNode); // HTMLDocument for IE8
mixin(DocumentFragment, ParentNode);
mixin(Element, ParentNode);
// Mixin ChildNode
// https://dom.spec.whatwg.org/#interface-childnode
const ChildNode = {
before (...nodes) {
const parent = this.parentNode;
if (!parent) return;
let viablePreviousSibling = this.previousSibling;
while (nodes.includes(viablePreviousSibling)) {
viablePreviousSibling = viablePreviousSibling.previousSibling;
}
const node = convertNodesIntoANode(nodes);
parent.insertBefore(
node,
viablePreviousSibling
? viablePreviousSibling.nextSibling
: parent.firstChild
);
},
after (...nodes) {
const parent = this.parentNode;
if (!parent) return;
let viableNextSibling = this.nextSibling;
while (nodes.includes(viableNextSibling)) {
viableNextSibling = viableNextSibling.nextSibling;
}
const node = convertNodesIntoANode(nodes);
parent.insertBefore(node, viableNextSibling);
},
replaceWith (...nodes) {
const parent = this.parentNode;
if (!parent) return;
let viableNextSibling = this.nextSibling;
while (nodes.includes(viableNextSibling)) {
viableNextSibling = viableNextSibling.nextSibling;
}
const node = convertNodesIntoANode(nodes);
if (this.parentNode === parent) {
parent.replaceChild(node, this);
} else {
parent.insertBefore(node, viableNextSibling);
}
},
remove () {
if (!this.parentNode) { return; }
this.parentNode.removeChild(this);
}
};
mixin(DocumentType, ChildNode);
mixin(Element, ChildNode);
mixin(CharacterData, ChildNode);

View File

@@ -1,23 +1,52 @@
// MIT License
// From: https://github.com/uupaa/dynamic-import-polyfill/blob/master/importModule.js
function toAbsoluteURL(url) {
const a = document.createElement("a");
a.setAttribute("href", url); // <a href="hoge.html">
function toAbsoluteURL (url) {
const a = document.createElement('a');
a.setAttribute('href', url); // <a href="hoge.html">
return a.cloneNode(false).href; // -> "http://example.com/hoge.html"
}
// My own addition
export function importScript(url) {
function addScriptAtts (script, atts) {
['id', 'class', 'type'].forEach((prop) => {
if (prop in atts) {
script[prop] = atts[prop];
}
});
}
// Additions by Brett
export async function importSetGlobalDefault (url, config) {
return importSetGlobal(url, {...config, returnDefault: true});
}
export async function importSetGlobal (url, {global, returnDefault}) {
// Todo: Replace calls to this function with `import()` when supported
const modularVersion = !('svgEditor' in window) ||
!window.svgEditor ||
window.svgEditor.modules !== false;
if (modularVersion) {
return importModule(url, undefined, {returnDefault});
}
await importScript(url);
return window[global];
}
// Addition by Brett
export function importScript (url, atts = {}) {
if (Array.isArray(url)) {
return Promise.all(url.map((u) => {
return importScript(u, atts);
}));
}
return new Promise((resolve, reject) => {
const script = document.createElement("script");
const script = document.createElement('script');
const destructor = () => {
script.onerror = null;
script.onload = null;
script.remove();
script.src = "";
script.src = '';
};
script.defer = "defer";
script.defer = 'defer';
addScriptAtts(script, atts);
script.onerror = () => {
reject(new Error(`Failed to import: ${url}`));
destructor();
@@ -28,24 +57,30 @@ export function importScript(url) {
};
script.src = url;
document.head.appendChild(script);
document.head.append(script);
});
}
export function importModule(url) {
export function importModule (url, atts = {}, {returnDefault = false} = {}) {
if (Array.isArray(url)) {
return Promise.all(url.map((u) => {
return importModule(u, atts);
}));
}
return new Promise((resolve, reject) => {
const vector = "$importModule$" + Math.random().toString(32).slice(2);
const script = document.createElement("script");
const vector = '$importModule$' + Math.random().toString(32).slice(2);
const script = document.createElement('script');
const destructor = () => {
delete window[vector];
script.onerror = null;
script.onload = null;
script.remove();
URL.revokeObjectURL(script.src);
script.src = "";
script.src = '';
};
script.defer = "defer";
script.type = "module";
addScriptAtts(script, atts);
script.defer = 'defer';
script.type = 'module';
script.onerror = () => {
reject(new Error(`Failed to import: ${url}`));
destructor();
@@ -55,11 +90,11 @@ export function importModule(url) {
destructor();
};
const absURL = toAbsoluteURL(url);
const loader = `import * as m from "${absURL}"; window.${vector} = m;`; // export Module
const blob = new Blob([loader], { type: "text/javascript" });
const loader = `import * as m from '${absURL.replace(/'/g, "\\'")}'; window.${vector} = ${returnDefault ? 'm.default || ' : ''}m;`; // export Module
const blob = new Blob([loader], { type: 'text/javascript' });
script.src = URL.createObjectURL(blob);
document.head.appendChild(script);
document.head.append(script);
});
}

View File

@@ -222,7 +222,7 @@ export class RemoveElementCommand {
console.log('Error: reference element was lost');
}
}
this.parent.insertBefore(this.elem, this.nextSibling);
this.parent.insertBefore(this.elem, this.nextSibling); // Don't use `before` or `prepend` as `this.nextSibling` may be `null`
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this);

View File

@@ -150,7 +150,9 @@ export default function ($) {
function mkElem (name, attrs, newparent) {
const elem = document.createElementNS(ns.svg, name);
setAttrs(elem, attrs);
if (newparent) newparent.appendChild(elem);
if (newparent) {
newparent.append(elem);
}
return elem;
}
@@ -521,7 +523,7 @@ export default function ($) {
opac = stopElem.getAttribute('stop-opacity');
n = stopElem.getAttribute('offset');
} else {
curGradient.appendChild(stop);
curGradient.append(stop);
}
if (opac === null) opac = 1;
@@ -619,7 +621,7 @@ export default function ($) {
if (curStop) curStop.setAttribute('stroke', '#000');
item.setAttribute('stroke', 'blue');
curStop = item;
curStop.parentNode.appendChild(curStop);
curStop.parentNode.append(curStop);
// stops = $('stop');
// opac_select.val(curStop.attr('fill-opacity') || 1);
// root.append(delStop);
@@ -720,7 +722,7 @@ export default function ($) {
});
$(stopMakerSVG).mouseover(function () {
stopMakerSVG.appendChild(delStop);
stopMakerSVG.append(delStop);
});
stopGroup = mkElem('g', {}, stopMakerSVG);
@@ -805,7 +807,7 @@ export default function ($) {
// if there are not at least two stops, then
if (numstops < 2) {
while (numstops < 2) {
curGradient.appendChild(document.createElementNS(ns.svg, 'stop'));
curGradient.append(document.createElementNS(ns.svg, 'stop'));
++numstops;
}
stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop');
@@ -883,7 +885,7 @@ export default function ($) {
// if there are not at least two stops, then
if (numstops < 2) {
while (numstops < 2) {
curGradient.appendChild(document.createElementNS(ns.svg, 'stop'));
curGradient.append(document.createElementNS(ns.svg, 'stop'));
++numstops;
}
stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop');
@@ -1161,7 +1163,7 @@ export default function ($) {
$this.show();
// jPicker will try to show after a 0ms timeout, so need to fire this after that
setTimeout(function () {
setTimeout(() => {
tab.addClass('jGraduate_tab_current').click();
}, 10);
});

View File

@@ -50,7 +50,7 @@ const removeAttributes = function (node, attributes) {
}
});
toRemove.forEach(function (a) {
toRemove.forEach((a) => {
node.removeAttribute(a.name);
});
};
@@ -204,7 +204,7 @@ const svgElementToPdf = function (element, pdf, options) {
default:
if (remove) {
console.log("can't translate to pdf:", node);
node.parentNode.removeChild(node);
node.remove();
}
}
});

View File

@@ -39,11 +39,11 @@ class Layer {
this.group_ = svgdoc.createElementNS(NS.SVG, 'g');
const layerTitle = svgdoc.createElementNS(NS.SVG, 'title');
layerTitle.textContent = name;
this.group_.appendChild(layerTitle);
this.group_.append(layerTitle);
if (group) {
$(group).after(this.group_);
} else {
svgElem.appendChild(this.group_);
svgElem.append(this.group_);
}
}
@@ -134,7 +134,7 @@ class Layer {
*/
appendChildren (children) {
for (let i = 0; i < children.length; ++i) {
this.group_.appendChild(children[i]);
this.group_.append(children[i]);
}
}

View File

@@ -1,4 +1,4 @@
This directory holds JSON files that translate the UI strings in SVG-edit.
This directory holds JavaScript files that translate the UI strings in SVG-edit.
Initial translations were done by Narendra Sisodiya putting the English
strings through the Google Translation API. Humans will need to take these
automated translations and ensure they make sense.

View File

@@ -1,5 +1,4 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
export default {
lang: 'af',
dir: 'ltr',
common: {
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ar',
dir: 'rtl',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'az',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'be',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'bg',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ca',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'cs',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'cy',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'da',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'de',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'el',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'en',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphaeljs.com set 1',
raphael_2: 'raphaeljs.com set 2'
},
imagelib: {
select_lib: 'Select an image library',
show_list: 'Show library list',
import_single: 'Import single',
import_multi: 'Import multiple',
open: 'Open as new document'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -241,4 +233,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'es',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'et',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
export default {
lang: 'fa',
dir: 'ltr',
dir: 'rtl',
common: {
ok: '‫تأیید‬',
cancel: '‫لغو‬',
@@ -202,13 +201,6 @@ svgEditor.readLang({
raphael_1: 'raphaeljs.com set 1',
raphael_2: 'raphaeljs.com set 2'
},
imagelib: {
select_lib: 'Select an image library',
show_list: 'Show library list',
import_single: 'Import single',
import_multi: 'Import multiple',
open: 'Open as new document'
},
notification: {
invalidAttrValGiven: '‫مقدار داده شده نامعتبر است‬',
noContentToFitTo: '‫محتوایی برای هم اندازه شدن وجود ندارد‬',
@@ -233,4 +225,4 @@ svgEditor.readLang({
URLloadFail: 'Unable to load from URL',
retrieving: 'Retrieving "%s"...'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'fi',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'fr',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: "Choisir une bibliothèque d'images",
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: "Il n'y a pas de contenu auquel ajuster",
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'fy',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ga',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'gl',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'he',
dir: 'rtl',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'hi',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'hr',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'hu',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'hy',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'id',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'is',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'it',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: "Non c'è contenuto cui adeguarsi",
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ja',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ko',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'lt',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'lv',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'mk',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ms',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'mt',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'nl',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'no',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,8 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
author: 'author',
export default {
lang: 'pl',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -206,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -241,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'pt-BR',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -204,13 +203,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -239,4 +231,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'pt-PT',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ro',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -204,13 +203,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -239,4 +231,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'ru',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'sk',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'sl',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -204,13 +203,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -239,4 +231,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'sq',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'sr',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'sv',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'sw',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'test',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'th',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'tl',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'tr',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'uk',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'vi',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'yi',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'zh-CN',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'zh-HK',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -1,7 +1,6 @@
import svgEditor from '../svg-editor.js';
svgEditor.readLang({
lang: 'lang',
dir: 'dir',
export default {
lang: 'zh-TW',
dir: 'ltr',
common: {
ok: 'OK',
cancel: 'Cancel',
@@ -205,13 +204,6 @@ svgEditor.readLang({
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
imagelib: {
select_lib: 'select_lib',
show_list: 'show_list',
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',
@@ -240,4 +232,4 @@ svgEditor.readLang({
exportNoDashArray: 'Strokes will appear filled',
exportNoText: 'Text may not appear as expected'
}
});
};

View File

@@ -9,14 +9,15 @@
*
*/
import {importSetGlobalDefault} from '../external/dynamic-import-polyfill/importModule.js';
const $ = jQuery;
let langParam;
function setStrings (type, obj, ids) {
// Root element to look for element from
const parent = $('#svg_editor').parent();
for (let sel in obj) {
const val = obj[sel];
Object.entries(obj).forEach(([sel, val]) => {
if (!val) { console.log(sel); }
if (ids) { sel = '#' + sel; }
@@ -41,7 +42,7 @@ function setStrings (type, obj, ids) {
} else {
console.log('Missing: ' + sel);
}
}
});
}
let editor_;
@@ -122,7 +123,6 @@ export const readLang = function (langData) {
tool_docprops: tools.docprops,
tool_export: tools.export_img,
tool_import: tools.import_doc,
tool_imagelib: tools.imagelib,
tool_open: tools.open_doc,
tool_save: tools.save_doc,
@@ -143,7 +143,7 @@ export const readLang = function (langData) {
}
// TODO: Find way to make this run after shapelib ext has loaded
setTimeout(function () {
setTimeout(() => {
setStrings('content', cats);
}, 2000);
@@ -268,7 +268,7 @@ export const readLang = function (langData) {
editor_.setLang(langParam, langData);
};
export const putLocale = function (givenParam, goodLangs, conf) {
export const putLocale = async function (givenParam, goodLangs, conf) {
if (givenParam) {
langParam = givenParam;
} else {
@@ -295,19 +295,12 @@ export const putLocale = function (givenParam, goodLangs, conf) {
// if (langParam.startsWith('en')) {return;}
}
// $.getScript(url, function (d) {
// Fails locally in Chrome 5+
// if (!d) {
const s = document.createElement('script');
const modularVersion = !('svgEditor' in window) ||
!window.svgEditor ||
window.svgEditor.modules !== false;
const url = conf.langPath + 'lang.' + langParam + '.js';
if (modularVersion) {
s.type = 'module'; // Make this the default when widely supported
}
s.src = url;
document.querySelector('head').appendChild(s);
// }
// });
return readLang(
// Todo: Replace this with `return import(url);` when
// `import()` widely supported
await importSetGlobalDefault(url, {
global: 'svgEditorLang_' + langParam.replace(/-/g, '_')
})
);
};

Some files were not shown because too many files have changed in this diff Show More