- Security fix: 'extPath', 'imgPath', 'extIconsPath', 'canvgPath', 'langPath', 'jGraduatePath', and 'jspdfPath' were not being prevented

- Breaking change: Rename "svgutils.js" to "utilities.js" (make in conformity with JSDoc module naming convention)
- Breaking change: Rename "svgedit.js" to "namespaces.js" (to make clear purpose and avoid confusing with editor)
- Breaking change: Rename "jquery-svg.js" to "jQuery.attr.js"
- Breaking change: Rename "jquery.contextMenu.js" to "jQuery.contextMenu.js"
- Breaking change: Rename "jquery.jpicker.js" to "jQuery.jPicker.js"
- Breaking change: Rename "JQuerySpinBtn.css" to "jQuery.SpinButton.css"
- Breaking change: Rename "JQuerySpinBtn.js" to "jQuery.SpinButton.js" (to have file name more closely reflect name)
- Breaking change: Rename "jquery.svgicons.js" to "jQuery.svgIcons.js"
- Breaking change: Rename "jquery.jgraduate.js" to "jQuery.jGraduate.js"
- Breaking change: Rename "pathseg.js" to "svgpathseg.js" (as it is a poyfill of SVGPathSeg)
- Breaking change: Rename `addSvgElementFromJson()` to `addSVGElementFromJson` for consistency
- Breaking change: Rename `changeSvgContent()` to `changeSVGContent()` for consistency
- Breaking change: Have `exportPDF` resolve with `output` and `outputType` rather than `dataurlstring` (as type may vary)
- Breaking change: Rename `extensions/mathjax/MathJax.js` to `extensions/mathjax/MathJax.min.js`
- Breaking change: Avoid recent change to have editor ready callbacks return Promises (we're not using and advantageous to keep sequential)
- Breaking change: Avoid recent addition of locale-side function in ext-imagelib for l10n
- Breaking change: Change name of ext-arrows.js from `Arrows` to `arrows` for sake of file path (not localized anyways).
- Breaking change: Change `addlangData` extension event to `addLangData` for consistency with method name
- Breaking change: Have `readLang`  return lang and data but do not call `setLang`
- Fix: Have general locales load first so extensions may use
- Fix: Provide `importLocale` to extensions `init` so it may delay adding of the extension until locale data loaded
- Fix: Ensure call to `rasterExport` without `imgType` properly sets MIME type to PNG
- Fix: Wrong name for moinsave
- Update: Update WebAppFind per new API changes
- Enhancement: Make `setStrings` public on editor for late setting (used
  by `ext-shapes.js`)
- Enhancement: Add `extensions_added` event
- Enhancement: Add `message` event (Relay messages including those which
  have been been received prior to extension load)
- Enhancement: Allow SVGEdit to work out of the box--avoid need for copying sample config file. Should also help with Github-based file servers
- Enhancement: Allow avoiding "name" in extension export (just extract out of file name)
- Enhancement: Add stack blur to canvg by default (and refactoring it)
- Enhancement: Return `Promise` for `embedImage` (as with some other loading methods)
- Enhancement: Supply `importLocale` to `langReady` to facilitate extension locale loading
- Enhancement: Recover if an extension fails to load (just log and otherwise ignore)
- Enhancement: More i18n of extensions (also fixed issue with some console warnings about missing locale strings); i18nize Hello World too
- Enhancement: Allowing importing of locales within `addLangData`
- npm: Update devDeps
- Docs: Migrate copies of all old wiki pages to docs/from-old-wiki folder; intended for a possible move to Markdown, so raw HTML (with formatting) was not preserved, though named links had their absolute URL links preserved
- Docs: Begin deleting `SvgCanvas.md` as ensuring jsdoc has replacements
- Docs: Add Edtior doc file for help to general users
- Docs: Clarify/simplify install instructions
- npm/Docs (JSDoc): Add script to check for overly generic types
- Docs (JSDoc): For config/prefs and extension creating, link to tutorials (moved tutorials to own directory to avoid recursion problems by jsdoc)
- Docs (JSDoc): Add modules (upper case for usual main entrance files or regular names)
- Docs (JSDoc): Fill out missing areas; indicate return of `undefined`; consistency with `@returns`
- Docs (JSDoc): Add our own layout template to support overflow
- Docs (JSDoc): Use cleverLinks and disallow unknown tags
- Docs (JSDoc): Insist on "pedantic" flag; put output directory in config
- Docs (JSDoc): Use more precise Integer/Float over number, the specific type of array/function/object
- Docs (JSDoc): Use `@throws`, `@enum`, `@event`/`@fires`/`@listens`
- Docs: Generally update/improve docs (fixes #92)
- Docs: Update links to `latest` path (Avoid needing to update such references upon each release)
- Docs: 80 chars max
- Refactoring: Drop code for extension as function (already requiring export to be an object)
- Refactoring: Object destructuring, `Object.entries`, Object shorthand, array extras, more camelCase variable names
- Refactoring: Add a `Command` base class
- Refactoring: Simplify svgicons `callback` ready detection
- Refactoring: Put `let` or `const` closer to scope
- Refactoring: Remove unneeded `delimiter` from regex escaping utility
- Refactoring: Clearer variable names
- Refactoring: Use (non-deprecated) Event constructors
- Testing: Use new Sinon
This commit is contained in:
Brett Zamir
2018-06-06 15:26:20 +08:00
parent 057f5a5dc2
commit a3f0b8e501
334 changed files with 60808 additions and 16650 deletions

View File

@@ -1,26 +1,29 @@
/* globals jQuery */
/**
* Package: svgedit.browser
* Browser detection
* @module browser
* @license MIT
*
* Licensed under the MIT License
*
* Copyright(c) 2010 Jeff Schiller
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Jeff Schiller, 2010 Alexis Deveria
*/
// Dependencies:
// 1) jQuery (for $.alert())
import './pathseg.js';
import {NS} from './svgedit.js';
import './svgpathseg.js';
import {NS} from './namespaces.js';
const $ = jQuery;
const supportsSvg_ = (function () {
const supportsSVG_ = (function () {
return !!document.createElementNS && !!document.createElementNS(NS.SVG, 'svg').createSVGRect;
}());
export const supportsSvg = () => supportsSvg_;
/**
* @function module:browser.supportsSvg
* @returns {boolean}
*/
export const supportsSvg = () => supportsSVG_;
const {userAgent} = navigator;
const svg = document.createElementNS(NS.SVG, 'svg');
@@ -155,29 +158,118 @@ return r1 instanceof SVGTransform && t1 instanceof SVGTransform &&
// Public API
/**
* @function module:browser.isOpera
* @returns {boolean}
*/
export const isOpera = () => isOpera_;
/**
* @function module:browser.isWebkit
* @returns {boolean}
*/
export const isWebkit = () => isWebkit_;
/**
* @function module:browser.isGecko
* @returns {boolean}
*/
export const isGecko = () => isGecko_;
/**
* @function module:browser.isIE
* @returns {boolean}
*/
export const isIE = () => isIE_;
/**
* @function module:browser.isChrome
* @returns {boolean}
*/
export const isChrome = () => isChrome_;
/**
* @function module:browser.isWindows
* @returns {boolean}
*/
export const isWindows = () => isWindows_;
/**
* @function module:browser.isMac
* @returns {boolean}
*/
export const isMac = () => isMac_;
/**
* @function module:browser.isTouch
* @returns {boolean}
*/
export const isTouch = () => isTouch_;
/**
* @function module:browser.supportsSelectors
* @returns {boolean}
*/
export const supportsSelectors = () => supportsSelectors_;
/**
* @function module:browser.supportsXpath
* @returns {boolean}
*/
export const supportsXpath = () => supportsXpath_;
/**
* @function module:browser.supportsPathReplaceItem
* @returns {boolean}
*/
export const supportsPathReplaceItem = () => supportsPathReplaceItem_;
/**
* @function module:browser.supportsPathInsertItemBefore
* @returns {boolean}
*/
export const supportsPathInsertItemBefore = () => supportsPathInsertItemBefore_;
/**
* @function module:browser.supportsPathBBox
* @returns {boolean}
*/
export const supportsPathBBox = () => supportsPathBBox_;
/**
* @function module:browser.supportsHVLineContainerBBox
* @returns {boolean}
*/
export const supportsHVLineContainerBBox = () => supportsHVLineContainerBBox_;
/**
* @function module:browser.supportsGoodTextCharPos
* @returns {boolean}
*/
export const supportsGoodTextCharPos = () => supportsGoodTextCharPos_;
/**
* @function module:browser.supportsEditableText
* @returns {boolean}
*/
export const supportsEditableText = () => supportsEditableText_;
/**
* @function module:browser.supportsGoodDecimals
* @returns {boolean}
*/
export const supportsGoodDecimals = () => supportsGoodDecimals_;
/**
* @function module:browser.supportsNonScalingStroke
* @returns {boolean}
*/
export const supportsNonScalingStroke = () => supportsNonScalingStroke_;
/**
* @function module:browser.supportsNativeTransformLists
* @returns {boolean}
*/
export const supportsNativeTransformLists = () => supportsNativeSVGTransformLists_;
// Using for unit testing
/**
* Set `supportsNativeSVGTransformLists_` to `false` (for unit testing)
* @function module:browser.disableSupportsNativeTransformLists
* @returns {undefined}
*/
export const disableSupportsNativeTransformLists = () => {
supportsNativeSVGTransformLists_ = false;
};

656
editor/canvg/StackBlur.js Normal file
View File

@@ -0,0 +1,656 @@
/**
* StackBlur - a fast almost Gaussian Blur For Canvas
In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account
mario@quasimondo.de
Or support me on flattr:
https://flattr.com/thing/72791/StackBlur-a-fast-almost-Gaussian-Blur-Effect-for-CanvasJavascript
* @module StackBlur
* @version 0.5
* @author Mario Klingemann
Contact: mario@quasimondo.com
Website: http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
Twitter: @quasimondo
* @copyright (c) 2010 Mario Klingemann
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
const mulTable = [
512, 512, 456, 512, 328, 456, 335, 512, 405, 328, 271, 456, 388, 335, 292, 512,
454, 405, 364, 328, 298, 271, 496, 456, 420, 388, 360, 335, 312, 292, 273, 512,
482, 454, 428, 405, 383, 364, 345, 328, 312, 298, 284, 271, 259, 496, 475, 456,
437, 420, 404, 388, 374, 360, 347, 335, 323, 312, 302, 292, 282, 273, 265, 512,
497, 482, 468, 454, 441, 428, 417, 405, 394, 383, 373, 364, 354, 345, 337, 328,
320, 312, 305, 298, 291, 284, 278, 271, 265, 259, 507, 496, 485, 475, 465, 456,
446, 437, 428, 420, 412, 404, 396, 388, 381, 374, 367, 360, 354, 347, 341, 335,
329, 323, 318, 312, 307, 302, 297, 292, 287, 282, 278, 273, 269, 265, 261, 512,
505, 497, 489, 482, 475, 468, 461, 454, 447, 441, 435, 428, 422, 417, 411, 405,
399, 394, 389, 383, 378, 373, 368, 364, 359, 354, 350, 345, 341, 337, 332, 328,
324, 320, 316, 312, 309, 305, 301, 298, 294, 291, 287, 284, 281, 278, 274, 271,
268, 265, 262, 259, 257, 507, 501, 496, 491, 485, 480, 475, 470, 465, 460, 456,
451, 446, 442, 437, 433, 428, 424, 420, 416, 412, 408, 404, 400, 396, 392, 388,
385, 381, 377, 374, 370, 367, 363, 360, 357, 354, 350, 347, 344, 341, 338, 335,
332, 329, 326, 323, 320, 318, 315, 312, 310, 307, 304, 302, 299, 297, 294, 292,
289, 287, 285, 282, 280, 278, 275, 273, 271, 269, 267, 265, 263, 261, 259];
const shgTable = [
9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17,
17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19,
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20,
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24];
/**
* @param {string|HTMLImageElement} img
* @param {string|HTMLCanvasElement} canvas
* @param {Float} radius
* @param {boolean} blurAlphaChannel
* @returns {undefined}
*/
function processImage (img, canvas, radius, blurAlphaChannel) {
if (typeof img === 'string') {
img = document.getElementById(img);
}
if (!img || !('naturalWidth' in img)) {
return;
}
const w = img.naturalWidth;
const h = img.naturalHeight;
if (typeof canvas === 'string') {
canvas = document.getElementById(canvas);
}
if (!canvas || !('getContext' in canvas)) {
return;
}
canvas.style.width = w + 'px';
canvas.style.height = h + 'px';
canvas.width = w;
canvas.height = h;
const context = canvas.getContext('2d');
context.clearRect(0, 0, w, h);
context.drawImage(img, 0, 0);
if (isNaN(radius) || radius < 1) { return; }
if (blurAlphaChannel) {
processCanvasRGBA(canvas, 0, 0, w, h, radius);
} else {
processCanvasRGB(canvas, 0, 0, w, h, radius);
}
}
/**
* @param {string|HTMLCanvasElement} canvas
* @param {Integer} topX
* @param {Integer} topY
* @param {Integer} width
* @param {Integer} height
* @throws {Error}
* @returns {ImageData} See {@link https://html.spec.whatwg.org/multipage/canvas.html#imagedata}
*/
function getImageDataFromCanvas (canvas, topX, topY, width, height) {
if (typeof canvas === 'string') {
canvas = document.getElementById(canvas);
}
if (!canvas || !('getContext' in canvas)) {
return;
}
const context = canvas.getContext('2d');
try {
return context.getImageData(topX, topY, width, height);
} catch (e) {
throw new Error('unable to access image data: ' + e);
}
}
/**
* @param {HTMLCanvasElement} canvas
* @param {Integer} topX
* @param {Integer} topY
* @param {Integer} width
* @param {Integer} height
* @param {Float} radius
* @returns {undefined}
*/
function processCanvasRGBA (canvas, topX, topY, width, height, radius) {
if (isNaN(radius) || radius < 1) { return; }
radius |= 0;
let imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);
imageData = processImageDataRGBA(imageData, topX, topY, width, height, radius);
canvas.getContext('2d').putImageData(imageData, topX, topY);
}
/**
* @param {ImageData} imageData
* @param {Integer} topX
* @param {Integer} topY
* @param {Integer} width
* @param {Integer} height
* @param {Float} radius
* @returns {ImageData}
*/
function processImageDataRGBA (imageData, topX, topY, width, height, radius) {
const pixels = imageData.data;
let x, y, i, p, yp, yi, yw, rSum, gSum, bSum, aSum,
rOutSum, gOutSum, bOutSum, aOutSum,
rInSum, gInSum, bInSum, aInSum,
pr, pg, pb, pa, rbs;
const div = radius + radius + 1;
// const w4 = width << 2;
const widthMinus1 = width - 1;
const heightMinus1 = height - 1;
const radiusPlus1 = radius + 1;
const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;
const stackStart = new BlurStack();
let stack = stackStart;
let stackEnd;
for (i = 1; i < div; i++) {
stack = stack.next = new BlurStack();
if (i === radiusPlus1) {
stackEnd = stack;
}
}
stack.next = stackStart;
let stackIn = null;
let stackOut = null;
yw = yi = 0;
const mulSum = mulTable[radius];
const shgSum = shgTable[radius];
for (y = 0; y < height; y++) {
rInSum = gInSum = bInSum = aInSum = rSum = gSum = bSum = aSum = 0;
rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);
rSum += sumFactor * pr;
gSum += sumFactor * pg;
bSum += sumFactor * pb;
aSum += sumFactor * pa;
stack = stackStart;
for (i = 0; i < radiusPlus1; i++) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
for (i = 1; i < radiusPlus1; i++) {
p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);
rSum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i);
gSum += (stack.g = (pg = pixels[p + 1])) * rbs;
bSum += (stack.b = (pb = pixels[p + 2])) * rbs;
aSum += (stack.a = (pa = pixels[p + 3])) * rbs;
rInSum += pr;
gInSum += pg;
bInSum += pb;
aInSum += pa;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for (x = 0; x < width; x++) {
pixels[yi + 3] = pa = (aSum * mulSum) >> shgSum;
if (pa !== 0) {
pa = 255 / pa;
pixels[yi] = ((rSum * mulSum) >> shgSum) * pa;
pixels[yi + 1] = ((gSum * mulSum) >> shgSum) * pa;
pixels[yi + 2] = ((bSum * mulSum) >> shgSum) * pa;
} else {
pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0;
}
rSum -= rOutSum;
gSum -= gOutSum;
bSum -= bOutSum;
aSum -= aOutSum;
rOutSum -= stackIn.r;
gOutSum -= stackIn.g;
bOutSum -= stackIn.b;
aOutSum -= stackIn.a;
p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2;
rInSum += (stackIn.r = pixels[p]);
gInSum += (stackIn.g = pixels[p + 1]);
bInSum += (stackIn.b = pixels[p + 2]);
aInSum += (stackIn.a = pixels[p + 3]);
rSum += rInSum;
gSum += gInSum;
bSum += bInSum;
aSum += aInSum;
stackIn = stackIn.next;
rOutSum += (pr = stackOut.r);
gOutSum += (pg = stackOut.g);
bOutSum += (pb = stackOut.b);
aOutSum += (pa = stackOut.a);
rInSum -= pr;
gInSum -= pg;
bInSum -= pb;
aInSum -= pa;
stackOut = stackOut.next;
yi += 4;
}
yw += width;
}
for (x = 0; x < width; x++) {
gInSum = bInSum = aInSum = rInSum = gSum = bSum = aSum = rSum = 0;
yi = x << 2;
rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
aOutSum = radiusPlus1 * (pa = pixels[yi + 3]);
rSum += sumFactor * pr;
gSum += sumFactor * pg;
bSum += sumFactor * pb;
aSum += sumFactor * pa;
stack = stackStart;
for (i = 0; i < radiusPlus1; i++) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack.a = pa;
stack = stack.next;
}
yp = width;
for (i = 1; i <= radius; i++) {
yi = (yp + x) << 2;
rSum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i);
gSum += (stack.g = (pg = pixels[yi + 1])) * rbs;
bSum += (stack.b = (pb = pixels[yi + 2])) * rbs;
aSum += (stack.a = (pa = pixels[yi + 3])) * rbs;
rInSum += pr;
gInSum += pg;
bInSum += pb;
aInSum += pa;
stack = stack.next;
if (i < heightMinus1) {
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for (y = 0; y < height; y++) {
p = yi << 2;
pixels[p + 3] = pa = (aSum * mulSum) >> shgSum;
if (pa > 0) {
pa = 255 / pa;
pixels[p] = ((rSum * mulSum) >> shgSum) * pa;
pixels[p + 1] = ((gSum * mulSum) >> shgSum) * pa;
pixels[p + 2] = ((bSum * mulSum) >> shgSum) * pa;
} else {
pixels[p] = pixels[p + 1] = pixels[p + 2] = 0;
}
rSum -= rOutSum;
gSum -= gOutSum;
bSum -= bOutSum;
aSum -= aOutSum;
rOutSum -= stackIn.r;
gOutSum -= stackIn.g;
bOutSum -= stackIn.b;
aOutSum -= stackIn.a;
p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2;
rSum += (rInSum += (stackIn.r = pixels[p]));
gSum += (gInSum += (stackIn.g = pixels[p + 1]));
bSum += (bInSum += (stackIn.b = pixels[p + 2]));
aSum += (aInSum += (stackIn.a = pixels[p + 3]));
stackIn = stackIn.next;
rOutSum += (pr = stackOut.r);
gOutSum += (pg = stackOut.g);
bOutSum += (pb = stackOut.b);
aOutSum += (pa = stackOut.a);
rInSum -= pr;
gInSum -= pg;
bInSum -= pb;
aInSum -= pa;
stackOut = stackOut.next;
yi += width;
}
}
return imageData;
}
/**
* @param {HTMLCanvasElement} canvas
* @param {Integer} topX
* @param {Integer} topY
* @param {Integer} width
* @param {Integer} height
* @param {Float} radius
* @returns {undefined}
*/
function processCanvasRGB (canvas, topX, topY, width, height, radius) {
if (isNaN(radius) || radius < 1) { return; }
radius |= 0;
let imageData = getImageDataFromCanvas(canvas, topX, topY, width, height);
imageData = processImageDataRGB(imageData, topX, topY, width, height, radius);
canvas.getContext('2d').putImageData(imageData, topX, topY);
}
/**
* @param {ImageData} imageData
* @param {Integer} topX
* @param {Integer} topY
* @param {Integer} width
* @param {Integer} height
* @param {Float} radius
* @returns {ImageData}
*/
function processImageDataRGB (imageData, topX, topY, width, height, radius) {
const pixels = imageData.data;
let x, y, i, p, yp, yi, yw, rSum, gSum, bSum,
rOutSum, gOutSum, bOutSum,
rInSum, gInSum, bInSum,
pr, pg, pb, rbs;
const div = radius + radius + 1;
// const w4 = width << 2;
const widthMinus1 = width - 1;
const heightMinus1 = height - 1;
const radiusPlus1 = radius + 1;
const sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2;
const stackStart = new BlurStack();
let stack = stackStart;
let stackEnd;
for (i = 1; i < div; i++) {
stack = stack.next = new BlurStack();
if (i === radiusPlus1) {
stackEnd = stack;
}
}
stack.next = stackStart;
let stackIn = null;
let stackOut = null;
yw = yi = 0;
const mulSum = mulTable[radius];
const shgSum = shgTable[radius];
for (y = 0; y < height; y++) {
rInSum = gInSum = bInSum = rSum = gSum = bSum = 0;
rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
rSum += sumFactor * pr;
gSum += sumFactor * pg;
bSum += sumFactor * pb;
stack = stackStart;
for (i = 0; i < radiusPlus1; i++) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack = stack.next;
}
for (i = 1; i < radiusPlus1; i++) {
p = yi + ((widthMinus1 < i ? widthMinus1 : i) << 2);
rSum += (stack.r = (pr = pixels[p])) * (rbs = radiusPlus1 - i);
gSum += (stack.g = (pg = pixels[p + 1])) * rbs;
bSum += (stack.b = (pb = pixels[p + 2])) * rbs;
rInSum += pr;
gInSum += pg;
bInSum += pb;
stack = stack.next;
}
stackIn = stackStart;
stackOut = stackEnd;
for (x = 0; x < width; x++) {
pixels[yi] = (rSum * mulSum) >> shgSum;
pixels[yi + 1] = (gSum * mulSum) >> shgSum;
pixels[yi + 2] = (bSum * mulSum) >> shgSum;
rSum -= rOutSum;
gSum -= gOutSum;
bSum -= bOutSum;
rOutSum -= stackIn.r;
gOutSum -= stackIn.g;
bOutSum -= stackIn.b;
p = (yw + ((p = x + radius + 1) < widthMinus1 ? p : widthMinus1)) << 2;
rInSum += (stackIn.r = pixels[p]);
gInSum += (stackIn.g = pixels[p + 1]);
bInSum += (stackIn.b = pixels[p + 2]);
rSum += rInSum;
gSum += gInSum;
bSum += bInSum;
stackIn = stackIn.next;
rOutSum += (pr = stackOut.r);
gOutSum += (pg = stackOut.g);
bOutSum += (pb = stackOut.b);
rInSum -= pr;
gInSum -= pg;
bInSum -= pb;
stackOut = stackOut.next;
yi += 4;
}
yw += width;
}
for (x = 0; x < width; x++) {
gInSum = bInSum = rInSum = gSum = bSum = rSum = 0;
yi = x << 2;
rOutSum = radiusPlus1 * (pr = pixels[yi]);
gOutSum = radiusPlus1 * (pg = pixels[yi + 1]);
bOutSum = radiusPlus1 * (pb = pixels[yi + 2]);
rSum += sumFactor * pr;
gSum += sumFactor * pg;
bSum += sumFactor * pb;
stack = stackStart;
for (i = 0; i < radiusPlus1; i++) {
stack.r = pr;
stack.g = pg;
stack.b = pb;
stack = stack.next;
}
yp = width;
for (i = 1; i <= radius; i++) {
yi = (yp + x) << 2;
rSum += (stack.r = (pr = pixels[yi])) * (rbs = radiusPlus1 - i);
gSum += (stack.g = (pg = pixels[yi + 1])) * rbs;
bSum += (stack.b = (pb = pixels[yi + 2])) * rbs;
rInSum += pr;
gInSum += pg;
bInSum += pb;
stack = stack.next;
if (i < heightMinus1) {
yp += width;
}
}
yi = x;
stackIn = stackStart;
stackOut = stackEnd;
for (y = 0; y < height; y++) {
p = yi << 2;
pixels[p] = (rSum * mulSum) >> shgSum;
pixels[p + 1] = (gSum * mulSum) >> shgSum;
pixels[p + 2] = (bSum * mulSum) >> shgSum;
rSum -= rOutSum;
gSum -= gOutSum;
bSum -= bOutSum;
rOutSum -= stackIn.r;
gOutSum -= stackIn.g;
bOutSum -= stackIn.b;
p = (x + (((p = y + radiusPlus1) < heightMinus1 ? p : heightMinus1) * width)) << 2;
rSum += (rInSum += (stackIn.r = pixels[p]));
gSum += (gInSum += (stackIn.g = pixels[p + 1]));
bSum += (bInSum += (stackIn.b = pixels[p + 2]));
stackIn = stackIn.next;
rOutSum += (pr = stackOut.r);
gOutSum += (pg = stackOut.g);
bOutSum += (pb = stackOut.b);
rInSum -= pr;
gInSum -= pg;
bInSum -= pb;
stackOut = stackOut.next;
yi += width;
}
}
return imageData;
}
/**
*
*/
export class BlurStack {
constructor () {
this.r = 0;
this.g = 0;
this.b = 0;
this.a = 0;
this.next = null;
}
}
export {
/**
* @class module:StackBlur.image
* @see module:StackBlur~processImage
*/
processImage as image,
/**
* @class module:StackBlur.canvasRGBA
* @see module:StackBlur~processCanvasRGBA
*/
processCanvasRGBA as canvasRGBA,
/**
* @class module:StackBlur.canvasRGB
* @see module:StackBlur~processCanvasRGB
*/
processCanvasRGB as canvasRGB,
/**
* @class module:StackBlur.imageDataRGBA
* @see module:StackBlur~processImageDataRGBA
*/
processImageDataRGBA as imageDataRGBA,
/**
* @class module:StackBlur.imageDataRGB
* @see module:StackBlur~processImageDataRGB
*/
processImageDataRGB as imageDataRGB
};

View File

@@ -1,33 +1,64 @@
/* eslint-disable new-cap */
/*
// Todo: Compare with latest canvg (add any improvements of ours) and add full JSDocs (denoting links to standard APIs and which are custom): https://github.com/canvg/canvg
/**
* canvg.js - Javascript SVG parser and renderer on Canvas
* MIT Licensed
* Gabe Lerner (gabelerner@gmail.com)
* http://code.google.com/p/canvg/
* @module canvg
* @license MIT
* @author Gabe Lerner <gabelerner@gmail.com>
* @see https://github.com/canvg/canvg
*/
import RGBColor from './rgbcolor.js';
import {canvasRGBA} from './StackBlur.js';
let stackBlurCanvasRGBA;
export const setStackBlurCanvasRGBA = (value) => {
stackBlurCanvasRGBA = value;
let canvasRGBA_ = canvasRGBA;
/**
* @callback module:canvg.StackBlurCanvasRGBA
* @param {string} id
* @param {Float} x
* @param {Float} y
* @param {Float} width
* @param {Float} height
* @param {Float} blurRadius
*/
/**
* @callback module:canvg.ForceRedraw
* @returns {boolean}
*/
/**
* @function module:canvg.setStackBlurCanvasRGBA
* @param {module:canvg.StackBlurCanvasRGBA} cb Will be passed the canvas ID, x, y, width, height, blurRadius
*/
export const setStackBlurCanvasRGBA = (cb) => {
canvasRGBA_ = cb;
};
// canvg(target, s)
// empty parameters: replace all 'svg' elements on page with 'canvas' elements
// target: canvas element or the id of a canvas element
// s: svg string, url to svg file, or xml document
// opts: optional hash of options
// ignoreMouse: true => ignore mouse events
// ignoreAnimation: true => ignore animations
// ignoreDimensions: true => does not try to resize canvas
// ignoreClear: true => does not clear canvas
// offsetX: int => draws at a x offset
// offsetY: int => draws at a y offset
// scaleWidth: int => scales horizontally to width
// scaleHeight: int => scales vertically to height
// forceRedraw: function => will call the function on every frame, if it returns true, will redraw
// returns all the function after the first render is completed with dom
/**
* @typedef {PlainObject} module:canvg.CanvgOptions
* @property {boolean} opts.ignoreMouse true => ignore mouse events
* @property {boolean} opts.ignoreAnimation true => ignore animations
* @property {boolean} opts.ignoreDimensions true => does not try to resize canvas
* @property {boolean} opts.ignoreClear true => does not clear canvas
* @property {Integer} opts.offsetX int => draws at a x offset
* @property {Integer} opts.offsetY int => draws at a y offset
* @property {Integer} opts.scaleWidth int => scales horizontally to width
* @property {Integer} opts.scaleHeight int => scales vertically to height
* @property {module:canvg.ForceRedraw} opts.forceRedraw function => will call the function on every frame, if it returns true, will redraw
* @property {boolean} opts.log Adds log function
* @property {boolean} opts.useCORS Whether to set CORS `crossOrigin` for the image to `Anonymous`
*/
/**
* If called with no arguments, it will replace all `<svg>` elements on the page with `<canvas>` elements
* @function module:canvg.canvg
* @param {HTMLCanvasElement|string} target canvas element or the id of a canvas element
* @param {string|XMLDocument} s: svg string, url to svg file, or xml document
* @param {module:canvg.CanvgOptions} [opts] Optional hash of options
* @returns {Promise} All the function after the first render is completed with dom
*/
export const canvg = function (target, s, opts) {
// no parameters
if (target == null && s == null && opts == null) {
@@ -69,6 +100,11 @@ export const canvg = function (target, s, opts) {
return svg.load(ctx, s);
};
/**
* @param {module:canvg.CanvgOptions} opts
* @returns {object}
* @todo Flesh out exactly what object is returned here (after updating to latest and reincluding our changes here and those of StackBlur)
*/
function build (opts) {
const svg = {opts};
@@ -2644,16 +2680,17 @@ function build (opts) {
}
apply (ctx, x, y, width, height) {
if (typeof stackBlurCanvasRGBA === 'undefined') {
if (typeof canvasRGBA_ === 'undefined') {
svg.log('ERROR: `setStackBlurCanvasRGBA` must be run for blur to work');
return;
}
// Todo: This might not be a problem anymore with out `instanceof` fix
// StackBlur requires canvas be on document
ctx.canvas.id = svg.UniqueId();
ctx.canvas.style.display = 'none';
document.body.append(ctx.canvas);
stackBlurCanvasRGBA(ctx.canvas.id, x, y, width, height, this.blurRadius);
canvasRGBA_(ctx.canvas.id, x, y, width, height, this.blurRadius);
ctx.canvas.remove();
}
};

View File

@@ -1,3 +1,10 @@
/**
* For parsing color values
* @module RGBColor
* @author Stoyan Stefanov <sstoo@gmail.com>
* @see https://www.phpied.com/rgb-color-parser-in-javascript/
* @license MIT
*/
const simpleColors = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
@@ -183,11 +190,11 @@ const colorDefs = [
/**
* A class to parse color values
* @author Stoyan Stefanov <sstoo@gmail.com>
* @link https://www.phpied.com/rgb-color-parser-in-javascript/
* @license MIT
*/
class RGBColor {
export default class RGBColor {
/**
* @param {string} colorString
*/
constructor (colorString) {
this.ok = false;
@@ -225,10 +232,16 @@ class RGBColor {
}
// some getters
/**
* @returns {string}
*/
toRGB () {
return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')';
}
/**
* @returns {string}
*/
toHex () {
let r = this.r.toString(16);
let g = this.g.toString(16);
@@ -239,7 +252,10 @@ class RGBColor {
return '#' + r + g + b;
}
// help
/**
* help
* @returns {HTMLUListElement}
*/
getHelpXML () {
const examples = [];
// add regexps
@@ -274,4 +290,3 @@ color: ${listColor.toHex()};`
return xml;
}
}
export default RGBColor;

View File

@@ -1,10 +1,9 @@
/* globals jQuery */
/**
* Package: svgedit.contextmenu
*
* Licensed under the Apache License, Version 2
*
* Author: Adam Bender
* Adds context menu functionality
* @module contextmenu
* @license Apache-2.0
* @author Adam Bender
*/
// Dependencies:
// 1) jQuery (for dom injection of context menus)
@@ -13,9 +12,32 @@ const $ = jQuery;
let contextMenuExtensions = {};
/**
* Signature depends on what the user adds; in the case of our uses with
* SVGEditor, no parameters are passed nor anything expected for a return.
* @callback module:contextmenu.MenuItemAction
*/
/**
* @typedef {PlainObject} module:contextmenu.MenuItem
* @property {string} id
* @property {string} label
* @property {module:contextmenu.MenuItemAction} action
*/
/**
* @param {module:contextmenu.MenuItem} menuItem
* @returns {boolean}
*/
const menuItemIsValid = function (menuItem) {
return menuItem && menuItem.id && menuItem.label && menuItem.action && typeof menuItem.action === 'function';
};
/**
* @function module:contextmenu.add
* @param {module:contextmenu.MenuItem} menuItem
* @returns {undefined}
*/
export const add = function (menuItem) {
// menuItem: {id, label, shortcut, action}
if (!menuItemIsValid(menuItem)) {
@@ -31,12 +53,29 @@ export const add = function (menuItem) {
contextMenuExtensions[menuItem.id] = menuItem;
// TODO: Need to consider how to handle custom enable/disable behavior
};
/**
* @function module:contextmenu.hasCustomHandler
* @param {string} handlerKey
* @returns {boolean}
*/
export const hasCustomHandler = function (handlerKey) {
return Boolean(contextMenuExtensions[handlerKey]);
};
/**
* @function module:contextmenu.getCustomHandler
* @param {string} handlerKey
* @returns {module:contextmenu.MenuItemAction}
*/
export const getCustomHandler = function (handlerKey) {
return contextMenuExtensions[handlerKey].action;
};
/**
* @param {module:contextmenu.MenuItem} menuItem
* @returns {undefined}
*/
const injectExtendedContextMenuItemIntoDom = function (menuItem) {
if (!Object.keys(contextMenuExtensions).length) {
// all menuItems appear at the bottom of the menu in their own container.
@@ -49,9 +88,17 @@ const injectExtendedContextMenuItemIntoDom = function (menuItem) {
shortcut + '</span></a></li>');
};
/**
* @function module:contextmenu.injectExtendedContextMenuItemsIntoDom
* @returns {undefined}
*/
export const injectExtendedContextMenuItemsIntoDom = function () {
for (const menuItem in contextMenuExtensions) {
injectExtendedContextMenuItemIntoDom(contextMenuExtensions[menuItem]);
}
};
/**
* @function module:contextmenu.resetCustomMenus
* @returns {undefined}
*/
export const resetCustomMenus = function () { contextMenuExtensions = {}; };

View File

@@ -1,26 +1,56 @@
// Todo: Update to latest version and adapt (and needs jQuery update as well): https://github.com/swisnl/jQuery-contextMenu
// jQuery Context Menu Plugin
//
// Version 1.01
//
// Cory S.N. LaViska
// A Beautiful Site (https://abeautifulsite.net/)
// Modified by Alexis Deveria
//
// More info: https://abeautifulsite.net/2008/09/jquery-context-menu-plugin/
//
// Terms of Use
//
// This plugin is dual-licensed under the GNU General Public License
// and the MIT License and is copyright A Beautiful Site, LLC.
//
/**
* jQuery Context Menu Plugin
* Cory S.N. LaViska
* A Beautiful Site ({@link https://abeautifulsite.net/})
* Modified by Alexis Deveria
*
* More info: {@link https://abeautifulsite.net/2008/09/jquery-context-menu-plugin/}
*
* @module jQueryContextMenu
* @todo Update to latest version and adapt (and needs jQuery update as well): {@link https://github.com/swisnl/jQuery-contextMenu}
* @version 1.01
*
* @license
* Terms of Use
*
* This plugin is dual-licensed under the GNU General Public License
* and the MIT License and is copyright A Beautiful Site, LLC.
*
*/
import {isMac} from '../browser.js';
export default function ($) {
/**
* @callback module:jQueryContextMenu.jQueryContextMenuCallback
* @param {string} href The `href` value after the first character (for bypassing an initial `#`)
* @param {external:jQuery} srcElement The wrapped jQuery srcElement
* @param {{x: Float, y: Float, docX: Float, docY: Float}} coords
*/
/**
* @typedef {PlainObject} module:jQueryContextMenu.jQueryContextMenuConfig
* @property {string} menu
* @property {Float} inSpeed
* @property {Float} outSpeed
* @property {boolean} allowLeft
*/
/**
* Adds {@link external:jQuery.fn.contextMenu}, {@link external:jQuery.fn.disableContextMenuItems}, {@link external:jQuery.fn.enableContextMenuItems}, {@link external:jQuery.fn.disableContextMenu}, {@link external:jQuery.fn.enableContextMenu}, {@link external:jQuery.fn.destroyContextMenu}
* @function module:jQueryContextMenu.jQueryContextMenu
* @param {external:jQuery} $ The jQuery object to wrap (with `contextMenu`, `disableContextMenuItems`, `enableContextMenuItems`, `disableContextMenu`, `enableContextMenu`, `destroyContextMenu`)
* @returns {external:jQuery}
*/
function jQueryContextMenu ($) {
const win = $(window);
const doc = $(document);
$.extend($.fn, {
/**
* @memberof external:jQuery.fn
* @param {module:jQueryContextMenu.jQueryContextMenuConfig} o
* @param {module:jQueryContextMenu.jQueryContextMenuCallback} callback
* @returns {external:jQuery}
*/
contextMenu (o, callback) {
// Defaults
if (o.menu === undefined) return false;
@@ -107,7 +137,9 @@ export default function ($) {
doc.unbind('click').unbind('keypress');
$('.contextMenu').hide();
// Callback
if (callback) callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y});
if (callback) {
callback($(this).attr('href').substr(1), $(srcElement), {x: x - offset.left, y: y - offset.top, docX: x, docY: y});
}
return false;
});
@@ -137,7 +169,12 @@ export default function ($) {
return $(this);
},
// Disable context menu items on the fly
/**
* Disable context menu items on the fly
* @memberof external:jQuery.fn
* @param {undefined|string} o Comma-separated
* @returns {external:jQuery}
*/
disableContextMenuItems (o) {
if (o === undefined) {
// Disable all
@@ -155,7 +192,12 @@ export default function ($) {
return $(this);
},
// Enable context menu items on the fly
/**
* Enable context menu items on the fly
* @memberof external:jQuery.fn
* @param {undefined|string} o Comma-separated
* @returns {external:jQuery}
*/
enableContextMenuItems (o) {
if (o === undefined) {
// Enable all
@@ -173,7 +215,11 @@ export default function ($) {
return $(this);
},
// Disable context menu(s)
/**
* Disable context menu(s)
* @memberof external:jQuery.fn
* @returns {external:jQuery}
*/
disableContextMenu () {
$(this).each(function () {
$(this).addClass('disabled');
@@ -181,7 +227,11 @@ export default function ($) {
return $(this);
},
// Enable context menu(s)
/**
* Enable context menu(s)
* @memberof external:jQuery.fn
* @returns {external:jQuery}
*/
enableContextMenu () {
$(this).each(function () {
$(this).removeClass('disabled');
@@ -189,7 +239,11 @@ export default function ($) {
return $(this);
},
// Destroy context menu(s)
/**
* Destroy context menu(s)
* @memberof external:jQuery.fn
* @returns {external:jQuery}
*/
destroyContextMenu () {
// Destroy specified context menus
$(this).each(function () {
@@ -201,3 +255,5 @@ export default function ($) {
});
return $;
}
export default jQueryContextMenu;

View File

@@ -1,15 +1,14 @@
/* globals jQuery */
/**
* Coords.
*
* Licensed under the MIT License
*
* Manipulating coordinates
* @module coords
* @license MIT
*/
import './pathseg.js';
import './svgpathseg.js';
import {
snapToGrid, assignAttributes, getBBox, getRefElem, findDefs
} from './svgutils.js';
} from './utilities.js';
import {
transformPoint, transformListToTransform, matrixMultiply, transformBox
} from './math.js';
@@ -22,15 +21,26 @@ const pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a',
'H', 'h', 'V', 'v', 'S', 's', 'T', 't'];
/**
* @typedef editorContext
* @type {?object}
* @property {function} getGridSnapping
* @property {function} getDrawing
* @interface module:coords.EditorContext
*/
/**
* @function module:coords.EditorContext#getGridSnapping
* @returns {boolean}
*/
/**
* @function module:coords.EditorContext#getDrawing
* @returns {module:draw.Drawing}
*/
/**
* @function module:coords.EditorContext#getSVGRoot
* @returns {SVGSVGElement}
*/
let editorContext_ = null;
/**
* @param {editorContext} editorContext
* @function module:coords.init
* @param {module:coords.EditorContext} editorContext
*/
export const init = function (editorContext) {
editorContext_ = editorContext;
@@ -38,9 +48,8 @@ export const init = function (editorContext) {
/**
* Applies coordinate changes to an element based on the given matrix
* @param {Element} selected - DOM element to be changed
* @param {Object} changes - Object with changes to be remapped
* @param {SVGMatrix} m - Matrix object to use for remapping coordinates
* @function module:coords.remapElement
* @implements {module:path.EditorContext#remapElement}
*/
export const remapElement = function (selected, changes, m) {
const remap = function (x, y) { return transformPoint(x, y, m); },

View File

@@ -1,21 +1,20 @@
/* globals jQuery */
/**
* Package: svgedit.draw
*
* Licensed under the MIT License
*
* Copyright(c) 2011 Jeff Schiller
* Tools for drawing
* @module draw
* @license MIT
* @copyright 2011 Jeff Schiller
*/
import Layer from './layer.js';
import HistoryRecordingService from './historyrecording.js';
import {NS} from './svgedit.js';
import {NS} from './namespaces.js';
import {isOpera} from './browser.js';
import {
toXml, getElem,
copyElem as utilCopyElem
} from './svgutils.js';
} from './utilities.js';
import {
BatchCommand, RemoveElementCommand, MoveElementCommand, ChangeElementCommand
} from './history.js';
@@ -35,8 +34,8 @@ let disabledElems = [];
/**
* Get a HistoryRecordingService.
* @param {svgedit.history.HistoryRecordingService=} hrService - if exists, return it instead of creating a new service.
* @returns {svgedit.history.HistoryRecordingService}
* @param {module:history.HistoryRecordingService} [hrService] - if exists, return it instead of creating a new service.
* @returns {module:history.HistoryRecordingService}
*/
function historyRecordingService (hrService) {
return hrService || new HistoryRecordingService(canvas_.undoMgr);
@@ -44,7 +43,7 @@ function historyRecordingService (hrService) {
/**
* Find the layer name in a group element.
* @param group The group element to search in.
* @param {Element} group The group element to search in.
* @returns {string} The layer name or empty string.
*/
function findLayerNameInGroup (group) {
@@ -57,7 +56,7 @@ function findLayerNameInGroup (group) {
/**
* Given a set of names, return a new unique name.
* @param {Array.<string>} existingLayerNames - Existing layer names.
* @param {string[]} existingLayerNames - Existing layer names.
* @returns {string} - The new name.
*/
function getNewLayerName (existingLayerNames) {
@@ -69,12 +68,15 @@ function getNewLayerName (existingLayerNames) {
/**
* This class encapsulates the concept of a SVG-edit drawing
* @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object
* encapsulates. If the svgElem has a se:nonce attribute on it, then
* IDs will use the nonce as they are generated.
* @param {String} [optIdPrefix=svg_] - The ID prefix to use.
*/
export class Drawing {
/**
* @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object
* encapsulates. If the svgElem has a se:nonce attribute on it, then
* IDs will use the nonce as they are generated.
* @param {string} [optIdPrefix=svg_] - The ID prefix to use.
* @throws {Error} If not initialized with an SVG element
*/
constructor (svgElem, optIdPrefix) {
if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI ||
svgElem.tagName !== 'svg' || svgElem.namespaceURI !== NS.SVG) {
@@ -89,19 +91,19 @@ export class Drawing {
/**
* The latest object number used in this drawing.
* @type {number}
* @type {Integer}
*/
this.obj_num = 0;
/**
* The prefix to prepend to each element id in the drawing.
* @type {String}
* @type {string}
*/
this.idPrefix = optIdPrefix || 'svg_';
/**
* An array of released element ids to immediately reuse.
* @type {Array.<number>}
* @type {Integer[]}
*/
this.releasedNums = [];
@@ -109,7 +111,7 @@ export class Drawing {
* The z-ordered array of Layer objects. Each layer has a name
* and group element.
* The first layer is the one at the bottom of the rendering.
* @type {Array.<Layer>}
* @type {Layer[]}
*/
this.all_layers = [];
@@ -119,7 +121,7 @@ export class Drawing {
* Note: Layers are ordered, but referenced externally by name; so, we need both container
* types depending on which function is called (i.e. all_layers and layer_map).
*
* @type {Object.<string, Layer>}
* @type {PlainObject.<string, Layer>}
*/
this.layer_map = {};
@@ -165,14 +167,15 @@ export class Drawing {
}
/**
* @returns {!string|number} The previously set nonce
* @returns {!(string|Integer)} The previously set nonce
*/
getNonce () {
return this.nonce_;
}
/**
* @param {!string|number} n The nonce to set
* @param {!(string|Integer)} n The nonce to set
* @returns {undefined}
*/
setNonce (n) {
this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE);
@@ -182,6 +185,7 @@ export class Drawing {
/**
* Clears any previously set nonce
* @returns {undefined}
*/
clearNonce () {
// We deliberately leave any se:nonce attributes alone,
@@ -191,7 +195,7 @@ export class Drawing {
/**
* Returns the latest object id as a string.
* @return {String} The latest object Id.
* @returns {string} The latest object Id.
*/
getId () {
return this.nonce_
@@ -201,7 +205,7 @@ export class Drawing {
/**
* Returns the next object Id as a string.
* @return {String} The next object Id to use.
* @returns {string} The next object Id to use.
*/
getNextId () {
const oldObjNum = this.obj_num;
@@ -265,7 +269,7 @@ export class Drawing {
/**
* Returns the number of layers in the current drawing.
* @returns {integer} The number of layers in the current drawing.
* @returns {Integer} The number of layers in the current drawing.
*/
getNumLayers () {
return this.all_layers.length;
@@ -274,6 +278,7 @@ export class Drawing {
/**
* Check if layer with given name already exists
* @param {string} name - The layer name to check
* @returns {boolean}
*/
hasLayer (name) {
return this.layer_map[name] !== undefined;
@@ -281,7 +286,7 @@ export class Drawing {
/**
* Returns the name of the ith layer. If the index is out of range, an empty string is returned.
* @param {integer} i - The zero-based index of the layer you are querying.
* @param {Integer} i - The zero-based index of the layer you are querying.
* @returns {string} The name of the ith layer (or the empty string if none found)
*/
getLayerName (i) {
@@ -289,7 +294,7 @@ export class Drawing {
}
/**
* @returns {SVGGElement} The SVGGElement representing the current layer.
* @returns {SVGGElement|null} The SVGGElement representing the current layer.
*/
getCurrentLayer () {
return this.current_layer ? this.current_layer.getGroup() : null;
@@ -316,7 +321,7 @@ export class Drawing {
/**
* Set the current layer's name.
* @param {string} name - The new name.
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
* @param {module:history.HistoryRecordingService} hrService - History recording service
* @returns {string|null} The new name if changed; otherwise, null.
*/
setCurrentLayerName (name, hrService) {
@@ -334,8 +339,8 @@ export class Drawing {
/**
* Set the current layer's position.
* @param {number} newpos - The zero-based index of the new position of the layer. Range should be 0 to layers-1
* @returns {Object} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null.
* @param {Integer} newpos - The zero-based index of the new position of the layer. Range should be 0 to layers-1
* @returns {{title: SVGGElement, previousName: string}|null} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null.
*/
setCurrentLayerPosition (newpos) {
const layerCount = this.getNumLayers();
@@ -377,6 +382,10 @@ export class Drawing {
return null;
}
/**
* @param {module:history.HistoryRecordingService} hrService
* @returns {undefined}
*/
mergeLayer (hrService) {
const currentGroup = this.current_layer.getGroup();
const prevGroup = $(currentGroup).prev()[0];
@@ -413,6 +422,10 @@ export class Drawing {
hrService.endBatchCommand();
}
/**
* @param {module:history.HistoryRecordingService} hrService
* @returns {undefined}
*/
mergeAllLayers (hrService) {
// Set the current layer to the last layer.
this.current_layer = this.all_layers[this.all_layers.length - 1];
@@ -426,10 +439,10 @@ export class Drawing {
/**
* Sets the current layer. If the name is not a valid layer name, then this
* function returns false. Otherwise it returns true. This is not an
* function returns `false`. Otherwise it returns `true`. This is not an
* undo-able action.
* @param {string} name - The name of the layer you want to switch to.
* @returns {boolean} true if the current layer was switched, otherwise false
* @returns {boolean} `true` if the current layer was switched, otherwise `false`
*/
setCurrentLayer (name) {
const layer = this.layer_map[name];
@@ -447,6 +460,7 @@ export class Drawing {
/**
* Deletes the current layer from the drawing and then clears the selection.
* This function then calls the 'changed' handler. This is an undoable action.
* @todo Does this actually call the 'changed' handler?
* @returns {SVGGElement} The SVGGElement of the layer removed or null.
*/
deleteCurrentLayer () {
@@ -460,7 +474,8 @@ export class Drawing {
/**
* Updates layer system and sets the current layer to the
* top-most layer (last <g> child of this drawing).
* top-most layer (last `<g>` child of this drawing).
* @returns {undefined}
*/
identifyLayers () {
this.all_layers = [];
@@ -509,7 +524,7 @@ export class Drawing {
* Creates a new top-level layer in the drawing with the given name and
* makes it the current layer.
* @param {string} name - The given name. If the layer name exists, a new name will be generated.
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
* @param {module:history.HistoryRecordingService} hrService - History recording service
* @returns {SVGGElement} The SVGGElement of the new layer, which is
* also the current layer of this drawing.
*/
@@ -540,7 +555,7 @@ export class Drawing {
/**
* Creates a copy of the current layer with the given name and makes it the current layer.
* @param {string} name - The given name. If the layer name exists, a new name will be generated.
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
* @param {module:history.HistoryRecordingService} hrService - History recording service
* @returns {SVGGElement} The SVGGElement of the new layer, which is
* also the current layer of this drawing.
*/
@@ -585,42 +600,42 @@ export class Drawing {
/**
* Returns whether the layer is visible. If the layer name is not valid,
* then this function returns false.
* @param {string} layername - The name of the layer which you want to query.
* @returns {boolean} The visibility state of the layer, or false if the layer name was invalid.
* then this function returns `false`.
* @param {string} layerName - The name of the layer which you want to query.
* @returns {boolean} The visibility state of the layer, or `false` if the layer name was invalid.
*/
getLayerVisibility (layername) {
const layer = this.layer_map[layername];
getLayerVisibility (layerName) {
const layer = this.layer_map[layerName];
return layer ? layer.isVisible() : false;
}
/**
* Sets the visibility of the layer. If the layer name is not valid, this
* function returns false, otherwise it returns true. This is an
* undo-able action.
* @param {string} layername - The name of the layer to change the visibility
* function returns `null`, otherwise it returns the `SVGElement` representing
* the layer. This is an undo-able action.
* @param {string} layerName - The name of the layer to change the visibility
* @param {boolean} bVisible - Whether the layer should be visible
* @returns {?SVGGElement} The SVGGElement representing the layer if the
* layername was valid, otherwise null.
* `layerName` was valid, otherwise `null`.
*/
setLayerVisibility (layername, bVisible) {
setLayerVisibility (layerName, bVisible) {
if (typeof bVisible !== 'boolean') {
return null;
}
const layer = this.layer_map[layername];
const layer = this.layer_map[layerName];
if (!layer) { return null; }
layer.setVisible(bVisible);
return layer.getGroup();
}
/**
* Returns the opacity of the given layer. If the input name is not a layer, null is returned.
* @param {string} layername - name of the layer on which to get the opacity
* @returns {?number} The opacity value of the given layer. This will be a value between 0.0 and 1.0, or null
* if layername is not a valid layer
* Returns the opacity of the given layer. If the input name is not a layer, `null` is returned.
* @param {string} layerName - name of the layer on which to get the opacity
* @returns {?Float} The opacity value of the given layer. This will be a value between 0.0 and 1.0, or `null`
* if `layerName` is not a valid layer
*/
getLayerOpacity (layername) {
const layer = this.layer_map[layername];
getLayerOpacity (layerName) {
const layer = this.layer_map[layerName];
if (!layer) { return null; }
return layer.getOpacity();
}
@@ -629,14 +644,19 @@ export class Drawing {
* Sets the opacity of the given layer. If the input name is not a layer,
* nothing happens. If opacity is not a value between 0.0 and 1.0, then
* nothing happens.
* @param {string} layername - Name of the layer on which to set the opacity
* @param {number} opacity - A float value in the range 0.0-1.0
* NOTE: this function exists solely to apply a highlighting/de-emphasis
* effect to a layer. When it is possible for a user to affect the opacity
* of a layer, we will need to allow this function to produce an undo-able
* action.
* @param {string} layerName - Name of the layer on which to set the opacity
* @param {Float} opacity - A float value in the range 0.0-1.0
* @returns {undefined}
*/
setLayerOpacity (layername, opacity) {
setLayerOpacity (layerName, opacity) {
if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) {
return;
}
const layer = this.layer_map[layername];
const layer = this.layer_map[layerName];
if (layer) {
layer.setOpacity(opacity);
}
@@ -657,8 +677,10 @@ export class Drawing {
/**
* Called to ensure that drawings will or will not have randomized ids.
* The currentDrawing will have its nonce set if it doesn't already.
* @function module:draw.randomizeIds
* @param {boolean} enableRandomization - flag indicating if documents should have randomized ids
* @param {svgedit.draw.Drawing} currentDrawing
* @param {draw.Drawing} currentDrawing
* @returns {undefined}
*/
export const randomizeIds = function (enableRandomization, currentDrawing) {
randIds = enableRandomization === false
@@ -678,12 +700,77 @@ export const randomizeIds = function (enableRandomization, currentDrawing) {
* Group: Layers
*/
/**
* @see {@link https://api.jquery.com/jQuery.data/}
* @name external:jQuery.data
*/
/**
* @interface module:draw.DrawCanvasInit
* @property {module:path.pathActions} pathActions
* @property {external:jQuery.data} elData
* @property {module:history.UndoManager} undoMgr
*/
/**
* @function module:draw.DrawCanvasInit#getCurrentGroup
* @returns {Element}
*/
/**
* @function module:draw.DrawCanvasInit#setCurrentGroup
* @param {Element} cg
* @returns {undefined}
*/
/**
* @function module:draw.DrawCanvasInit#getSelectedElements
* @returns {Element[]} the array with selected DOM elements
*/
/**
* @function module:draw.DrawCanvasInit#getSVGContent
* @returns {SVGSVGElement}
*/
/**
* @function module:draw.DrawCanvasInit#getCurrentDrawing
* @returns {module:draw.Drawing}
*/
/**
* @function module:draw.DrawCanvasInit#clearSelection
* @param {boolean} [noCall] - When `true`, does not call the "selected" handler
* @returns {undefined}
*/
/**
* Run the callback function associated with the given event
* @function module:draw.DrawCanvasInit#call
* @param {"changed"|"contextset"} ev - String with the event name
* @param {module:svgcanvas.SvgCanvas#event:changed|module:svgcanvas.SvgCanvas#event:contextset} arg - Argument to pass through to the callback
* function. If the event is "changed", a (single-item) array of `Element`s is
* passed. If the event is "contextset", the arg is `null` or `Element`.
* @returns {undefined}
*/
/**
* @function module:draw.DrawCanvasInit#addCommandToHistory
* @param {Command} cmd
* @returns {undefined}
*/
/**
* @function module:draw.DrawCanvasInit#changeSVGContent
* @returns {undefined}
*/
let canvas_;
/**
* @function module:draw.init
* @param {module:draw.DrawCanvasInit} canvas
* @returns {undefined}
*/
export const init = function (canvas) {
canvas_ = canvas;
};
// Updates layer system
/**
* Updates layer system
* @function module:draw.identifyLayers
* @returns {undefined}
*/
export const identifyLayers = function () {
leaveContext();
canvas_.getCurrentDrawing().identifyLayers();
@@ -693,8 +780,11 @@ export const identifyLayers = function () {
* Creates a new top-level layer in the drawing with the given name, sets the current layer
* to it, and then clears the selection. This function then calls the 'changed' handler.
* This is an undoable action.
* @param name - The given name
* @param hrService
* @function module:draw.createLayer
* @param {string} name - The given name
* @param {module:history.HistoryRecordingService} hrService
* @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {undefined}
*/
export const createLayer = function (name, hrService) {
const newLayer = canvas_.getCurrentDrawing().createLayer(
@@ -709,8 +799,11 @@ export const createLayer = function (name, hrService) {
* Creates a new top-level layer in the drawing with the given name, copies all the current layer's contents
* to it, and then clears the selection. This function then calls the 'changed' handler.
* This is an undoable action.
* @function module:draw.cloneLayer
* @param {string} name - The given name. If the layer name exists, a new name will be generated.
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
* @param {module:history.HistoryRecordingService} hrService - History recording service
* @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {undefined}
*/
export const cloneLayer = function (name, hrService) {
// Clone the current layer and make the cloned layer the new current layer
@@ -724,6 +817,9 @@ export const cloneLayer = function (name, hrService) {
/**
* Deletes the current layer from the drawing and then clears the selection. This function
* then calls the 'changed' handler. This is an undoable action.
* @function module:draw.deleteCurrentLayer
* @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {boolean} `true` if an old layer group was found to delete
*/
export const deleteCurrentLayer = function () {
let currentLayer = canvas_.getCurrentDrawing().getCurrentLayer();
@@ -745,9 +841,9 @@ export const deleteCurrentLayer = function () {
/**
* Sets the current layer. If the name is not a valid layer name, then this function returns
* false. Otherwise it returns true. This is not an undo-able action.
* @param name - The name of the layer you want to switch to.
*
* @returns true if the current layer was switched, otherwise false
* @function module:draw.setCurrentLayer
* @param {string} name - The name of the layer you want to switch to.
* @returns {boolean} true if the current layer was switched, otherwise false
*/
export const setCurrentLayer = function (name) {
const result = canvas_.getCurrentDrawing().setCurrentLayer(toXml(name));
@@ -759,17 +855,18 @@ export const setCurrentLayer = function (name) {
/**
* Renames the current layer. If the layer name is not valid (i.e. unique), then this function
* does nothing and returns false, otherwise it returns true. This is an undo-able action.
*
* @param newname - the new name you want to give the current layer. This name must be unique
* among all layer names.
* @returns {Boolean} Whether the rename succeeded
* does nothing and returns `false`, otherwise it returns `true`. This is an undo-able action.
* @function module:draw.renameCurrentLayer
* @param {string} newName - the new name you want to give the current layer. This name must
* be unique among all layer names.
* @fires module:svgcanvas.SvgCanvas#event:changed
* @returns {boolean} Whether the rename succeeded
*/
export const renameCurrentLayer = function (newname) {
export const renameCurrentLayer = function (newName) {
const drawing = canvas_.getCurrentDrawing();
const layer = drawing.getCurrentLayer();
if (layer) {
const result = drawing.setCurrentLayerName(newname, historyRecordingService());
const result = drawing.setCurrentLayerName(newName, historyRecordingService());
if (result) {
canvas_.call('changed', [layer]);
return true;
@@ -782,14 +879,14 @@ export const renameCurrentLayer = function (newname) {
* Changes the position of the current layer to the new value. If the new index is not valid,
* this function does nothing and returns false, otherwise it returns true. This is an
* undo-able action.
* @param newpos - The zero-based index of the new position of the layer. This should be between
* @function module:draw.setCurrentLayerPosition
* @param {Integer} newPos - The zero-based index of the new position of the layer. This should be between
* 0 and (number of layers - 1)
*
* @returns {Boolean} true if the current layer position was changed, false otherwise.
* @returns {boolean} `true` if the current layer position was changed, `false` otherwise.
*/
export const setCurrentLayerPosition = function (newpos) {
export const setCurrentLayerPosition = function (newPos) {
const drawing = canvas_.getCurrentDrawing();
const result = drawing.setCurrentLayerPosition(newpos);
const result = drawing.setCurrentLayerPosition(newPos);
if (result) {
canvas_.addCommandToHistory(new MoveElementCommand(result.currentGroup, result.oldNextSibling, canvas_.getSVGContent()));
return true;
@@ -799,15 +896,16 @@ export const setCurrentLayerPosition = function (newpos) {
/**
* Sets the visibility of the layer. If the layer name is not valid, this function return
* false, otherwise it returns true. This is an undo-able action.
* @param layername - The name of the layer to change the visibility
* @param {Boolean} bVisible - Whether the layer should be visible
* @returns {Boolean} true if the layer's visibility was set, false otherwise
* `false`, otherwise it returns `true`. This is an undo-able action.
* @function module:draw.setLayerVisibility
* @param {string} layerName - The name of the layer to change the visibility
* @param {boolean} bVisible - Whether the layer should be visible
* @returns {boolean} true if the layer's visibility was set, false otherwise
*/
export const setLayerVisibility = function (layername, bVisible) {
export const setLayerVisibility = function (layerName, bVisible) {
const drawing = canvas_.getCurrentDrawing();
const prevVisibility = drawing.getLayerVisibility(layername);
const layer = drawing.setLayerVisibility(layername, bVisible);
const prevVisibility = drawing.getLayerVisibility(layerName);
const layer = drawing.setLayerVisibility(layerName, bVisible);
if (layer) {
const oldDisplay = prevVisibility ? 'inline' : 'none';
canvas_.addCommandToHistory(new ChangeElementCommand(layer, {display: oldDisplay}, 'Layer Visibility'));
@@ -824,16 +922,16 @@ export const setLayerVisibility = function (layername, bVisible) {
};
/**
* Moves the selected elements to layername. If the name is not a valid layer name, then false
* is returned. Otherwise it returns true. This is an undo-able action.
*
* @param layername - The name of the layer you want to which you want to move the selected elements
* @returns {Boolean} Whether the selected elements were moved to the layer.
* Moves the selected elements to layerName. If the name is not a valid layer name, then `false`
* is returned. Otherwise it returns `true`. This is an undo-able action.
* @function module:draw.moveSelectedToLayer
* @param {string} layerName - The name of the layer you want to which you want to move the selected elements
* @returns {boolean} Whether the selected elements were moved to the layer.
*/
export const moveSelectedToLayer = function (layername) {
export const moveSelectedToLayer = function (layerName) {
// find the layer
const drawing = canvas_.getCurrentDrawing();
const layer = drawing.getLayerByName(layername);
const layer = drawing.getLayerByName(layerName);
if (!layer) { return false; }
const batchCmd = new BatchCommand('Move Elements to Layer');
@@ -856,22 +954,37 @@ export const moveSelectedToLayer = function (layername) {
return true;
};
/**
* @function module:draw.mergeLayer
* @param {module:history.HistoryRecordingService} hrService
* @returns {undefined}
*/
export const mergeLayer = function (hrService) {
canvas_.getCurrentDrawing().mergeLayer(historyRecordingService(hrService));
canvas_.clearSelection();
leaveContext();
canvas_.changeSvgcontent();
canvas_.changeSVGContent();
};
/**
* @function module:draw.mergeAllLayers
* @param {module:history.HistoryRecordingService} hrService
* @returns {undefined}
*/
export const mergeAllLayers = function (hrService) {
canvas_.getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService));
canvas_.clearSelection();
leaveContext();
canvas_.changeSvgcontent();
canvas_.changeSVGContent();
};
// Return from a group context to the regular kind, make any previously
// disabled elements enabled again
/**
* Return from a group context to the regular kind, make any previously
* disabled elements enabled again
* @function module:draw.leaveContext
* @fires module:svgcanvas.SvgCanvas#event:contextset
* @returns {undefined}
*/
export const leaveContext = function () {
const len = disabledElems.length;
if (len) {
@@ -892,7 +1005,13 @@ export const leaveContext = function () {
canvas_.setCurrentGroup(null);
};
// Set the current context (for in-group editing)
/**
* Set the current context (for in-group editing)
* @function module:draw.setContext
* @param {Element} elem
* @fires module:svgcanvas.SvgCanvas#event:contextset
* @returns {undefined}
*/
export const setContext = function (elem) {
leaveContext();
if (typeof elem === 'string') {
@@ -916,4 +1035,9 @@ export const setContext = function (elem) {
canvas_.call('contextset', canvas_.getCurrentGroup());
};
/**
* @memberof module:draw
* @class Layer
* @see {@link module:layer.Layer}
*/
export {Layer};

View File

@@ -1,4 +1,8 @@
/* globals jQuery */
/**
* Attaches items to DOM for Embedded SVG support
* @module EmbeddedSVGEditDOM
*/
import EmbeddedSVGEdit from './embedapi.js';
const $ = jQuery;
@@ -41,9 +45,9 @@ function exportPDF () {
/**
// If you want to handle the PDF blob yourself, do as follows
svgCanvas.bind('exportedPDF', function (win, data) {
alert(data.dataurlstring);
alert(data.output);
});
svgCanvas.exportPDF(); // Accepts two args: optionalWindowName supplied back to bound exportPDF handler and optionalOutputType (defaults to dataurlstring)
svgCanvas.exportPDF(); // Accepts two args: optionalWindowName supplied back to bound exportPDF handler and optional outputType (defaults to dataurlstring)
return;
*/

View File

@@ -1,57 +1,48 @@
/*
Embedded SVG-edit API
General usage:
- Have an iframe somewhere pointing to a version of svg-edit > r1000
- Initialize the magic with:
const svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
- Pass functions in this format:
svgCanvas.setSvgString('string')
- Or if a callback is needed:
svgCanvas.setSvgString('string')(function(data, error){
if (error){
// There was an error
} else{
// Handle data
}
})
Everything is done with the same API as the real svg-edit,
and all documentation is unchanged.
However, this file depends on the postMessage API which
can only support JSON-serializable arguments and
return values, so, for example, arguments whose value is
'undefined', a function, a non-finite number, or a built-in
object like Date(), RegExp(), etc. will most likely not behave
as expected. In such a case one may need to host
the SVG editor on the same domain and reference the
JavaScript methods on the frame itself.
The only other difference is
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)})
/**
* Handles underlying communication between the embedding window and the editor frame
* @module EmbeddedSVGEdit
*/
let cbid = 0;
function getCallbackSetter (d) {
return function () {
const t = this, // New callback
args = [].slice.call(arguments),
cbid = t.send(d, args, function () {}); // The callback (currently it's nothing, but will be set later)
/**
* @callback module:EmbeddedSVGEdit.GenericCallback
* @param {...*} args Signature dependent on the function
* @returns {*} Return dependent on the function
*/
/**
* @callback module:EmbeddedSVGEdit.CallbackSetter
* @param {module:EmbeddedSVGEdit.GenericCallback} newCallback Callback to be stored (signature dependent on function)
* @returns {undefined}
*/
/**
* @callback module:EmbeddedSVGEdit.CallbackSetGetter
* @param {...*} args Signature dependent on the function
* @returns {module:EmbeddedSVGEdit.CallbackSetter}
*/
return function (newcallback) {
t.callbacks[cbid] = newcallback; // Set callback
/**
* @param {string} d
* @returns {module:EmbeddedSVGEdit.CallbackSetGetter}
*/
function getCallbackSetter (funcName) {
return function (...args) {
const t = this, // New callback
cbid = t.send(funcName, args, function () {}); // The callback (currently it's nothing, but will be set later)
return function (newCallback) {
t.callbacks[cbid] = newCallback; // Set callback
};
};
}
/*
/**
* Having this separate from messageListener allows us to
* avoid using JSON parsing (and its limitations) in the case
* of same domain control
* @param {module:EmbeddedSVGEdit.EmbeddedSVGEdit} t The `this` value
* @param {JSON} data
* @returns {undefined}
*/
function addCallback (t, data) {
const result = data.result || data.error,
@@ -65,6 +56,10 @@ function addCallback (t, data) {
}
}
/**
* @param {Event} e
* @returns {undefined}
*/
function messageListener (e) {
// We accept and post strings as opposed to objects for the sake of IE9 support; this
// will most likely be changed in the future
@@ -82,6 +77,15 @@ function messageListener (e) {
addCallback(this, data);
}
/**
* @callback module:EmbeddedSVGEdit.MessageListener
* @param {MessageEvent} e
* @returns {undefined}
*/
/**
* @param {module:EmbeddedSVGEdit.EmbeddedSVGEdit} t The `this` value
* @returns {module:EmbeddedSVGEdit.MessageListener} Event listener
*/
function getMessageListener (t) {
return function (e) {
messageListener.call(t, e);
@@ -89,13 +93,52 @@ function getMessageListener (t) {
}
/**
* @param {HTMLIFrameElement} frame
* @param {array} [allowedOrigins=[]] Array of origins from which incoming
* messages will be allowed when same origin is not used; defaults to none.
* If supplied, it should probably be the same as svgEditor's allowedOrigins
*/
* Embedded SVG-edit API
* General usage:
- Have an iframe somewhere pointing to a version of svg-edit > r1000
* @example
// Initialize the magic with:
const svgCanvas = new EmbeddedSVGEdit(window.frames.svgedit);
// Pass functions in this format:
svgCanvas.setSvgString('string');
// Or if a callback is needed:
svgCanvas.setSvgString('string')(function(data, error){
if (error){
// There was an error
} else{
// Handle data
}
});
// Everything is done with the same API as the real svg-edit,
// and all documentation is unchanged.
// However, this file depends on the postMessage API which
// can only support JSON-serializable arguments and
// return values, so, for example, arguments whose value is
// 'undefined', a function, a non-finite number, or a built-in
// object like Date(), RegExp(), etc. will most likely not behave
// as expected. In such a case one may need to host
// the SVG editor on the same domain and reference the
// JavaScript methods on the frame itself.
// The only other difference is
// 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)})
*
* @memberof module:EmbeddedSVGEdit
*/
class EmbeddedSVGEdit {
/**
* @param {HTMLIFrameElement} frame
* @param {string[]} [allowedOrigins=[]] Array of origins from which incoming
* messages will be allowed when same origin is not used; defaults to none.
* If supplied, it should probably be the same as svgEditor's allowedOrigins
*/
constructor (frame, allowedOrigins) {
const t = this;
this.allowedOrigins = allowedOrigins || [];
@@ -118,7 +161,7 @@ class EmbeddedSVGEdit {
// Run in svgedit itself
const functions = [
'addExtension',
'addSvgElementFromJson',
'addSVGElementFromJson',
'addToSelection',
'alignSelectedElements',
'assignAttributes',
@@ -292,6 +335,11 @@ class EmbeddedSVGEdit {
});
}
/**
* @param {string} name
* @param {ArgumentsArray} args Signature dependent on function
* @param {module:EmbeddedSVGEdit.GenericCallback} callback
*/
send (name, args, callback) {
const t = this;
cbid++;

View File

@@ -1,29 +1,22 @@
/* globals jQuery */
/*
/**
* ext-arrows.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Alexis Deveria
*
*/
export default {
name: 'Arrows',
init (S) {
name: 'arrows',
async init (S) {
const strings = await S.importLocale();
const svgEditor = this;
const svgCanvas = svgEditor.canvas;
const $ = jQuery;
const // {svgcontent} = S,
addElem = S.addSvgElementFromJson,
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;
@@ -226,34 +219,32 @@ export default {
});
}
return {
name: 'Arrows',
context_tools: [{
const contextTools = [
{
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
}
}],
}
];
return {
name: strings.name,
context_tools: strings.contextTools.map((contextTool, i) => {
return Object.assign(contextTools[i], contextTool);
}),
callback () {
$('#arrow_panel').hide();
// Set ID so it can be translated in locale file
$('#arrow_list option')[0].id = 'connector_no_arrow';
},
addLangData (lang) {
async addLangData ({lang, importLocale}) {
const strings = await importLocale();
return {
data: langList[lang]
data: strings.langList
};
},
selectedChanged (opts) {

View File

@@ -1,19 +1,20 @@
/* globals jQuery */
/*
/**
* ext-closepath.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Jeff Schiller
* @copyright 2010 Jeff Schiller
*
*/
import '../pathseg.js';
import '../svgpathseg.js';
// This extension adds a simple button to the contextual panel for paths
// The button toggles whether the path is open or closed
export default {
name: 'ClosePath',
init () {
name: 'closepath',
async init ({importLocale}) {
const strings = await importLocale();
const $ = jQuery;
const svgEditor = this;
let selElems;
@@ -47,14 +48,11 @@ export default {
}
};
return {
name: 'ClosePath',
svgicons: svgEditor.curConfig.extIconsPath + 'closepath_icons.svg',
buttons: [{
const buttons = [
{
id: 'tool_openpath',
type: 'context',
panel: 'closepath_panel',
title: 'Open path',
events: {
click () {
toggleClosed();
@@ -65,13 +63,20 @@ export default {
id: 'tool_closepath',
type: 'context',
panel: 'closepath_panel',
title: 'Close path',
events: {
click () {
toggleClosed();
}
}
}],
}
];
return {
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'closepath_icons.svg',
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
callback () {
$('#closepath_panel').hide();
},

View File

@@ -1,25 +1,26 @@
/* globals jQuery */
/*
/**
* ext-connector.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Alexis Deveria
*
*/
export default {
name: 'Connector',
init (S) {
name: 'connector',
async init (S) {
const $ = jQuery;
const svgEditor = this;
const svgCanvas = svgEditor.canvas;
const {svgroot, getNextId, getElem} = S,
addElem = S.addSvgElementFromJson,
const {svgroot, getNextId, getElem, importLocale} = S,
addElem = S.addSVGElementFromJson,
selManager = S.selectorManager,
connSel = '.se_connector',
// connect_str = '-SE_CONNECT-',
elData = $.data;
const strings = await importLocale();
let startX,
startY,
@@ -32,15 +33,6 @@ export default {
connections = [],
selElems = [];
const langList = {
en: [
{id: 'mode_connect', title: 'Connect two objects'}
],
fr: [
{id: 'mode_connect', title: 'Connecter deux objets'}
]
};
function getBBintersect (x, y, bb, offset) {
if (offset) {
offset -= 0;
@@ -155,7 +147,7 @@ export default {
/**
*
* @param {array} [elem=selElems] Array of elements
* @param {Element[]} [elem=selElems] Array of elements
*/
function findConnectors (elems = selElems) {
const connectors = $(svgcontent).find(connSel);
@@ -315,28 +307,31 @@ export default {
// // }
// });
return {
name: 'Connector',
svgicons: svgEditor.curConfig.imgPath + 'conn.svg',
buttons: [{
id: 'mode_connect',
type: 'mode',
icon: svgEditor.curConfig.imgPath + 'cut.png',
title: 'Connect two objects',
includeWith: {
button: '#tool_line',
isDefault: false,
position: 1
},
events: {
click () {
svgCanvas.setMode('connector');
}
const buttons = [{
id: 'mode_connect',
type: 'mode',
icon: svgEditor.curConfig.imgPath + 'cut.png',
includeWith: {
button: '#tool_line',
isDefault: false,
position: 1
},
events: {
click () {
svgCanvas.setMode('connector');
}
}],
addLangData (lang) {
}
}];
return {
name: strings.name,
svgicons: svgEditor.curConfig.imgPath + 'conn.svg',
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
async addLangData ({lang, importLocale}) {
return {
data: langList[lang]
data: strings.langList
};
},
mouseDown (opts) {

View File

@@ -1,16 +1,17 @@
/* globals jQuery */
/*
/**
* ext-eyedropper.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Jeff Schiller
* @copyright 2010 Jeff Schiller
*
*/
export default {
name: 'eyedropper',
init (S) {
async init (S) {
const strings = await S.importLocale();
const svgEditor = this;
const $ = jQuery;
const {ChangeElementCommand} = S, // , svgcontent,
@@ -55,20 +56,24 @@ export default {
}
}
return {
name: 'eyedropper',
svgicons: svgEditor.curConfig.extIconsPath + 'eyedropper-icon.xml',
buttons: [{
const buttons = [
{
id: 'tool_eyedropper',
type: 'mode',
title: 'Eye Dropper Tool',
key: 'I',
events: {
click () {
svgCanvas.setMode('eyedropper');
}
}
}],
}
];
return {
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'eyedropper-icon.xml',
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
// if we have selected an element, grab its paint and enable the eye dropper button
selectedChanged: getStyle,

View File

@@ -1,25 +1,25 @@
/* globals jQuery */
/*
/**
* ext-foreignobject.js
*
* Licensed under the Apache License, Version 2
* @license Apache-2.0
*
* Copyright(c) 2010 Jacques Distler
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Jacques Distler, 2010 Alexis Deveria
*
*/
export default {
name: 'foreignObject',
init (S) {
name: 'foreignobject',
async init (S) {
const svgEditor = this;
const {text2xml, NS} = S;
const {text2xml, NS, importLocale} = S;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const
// {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
// addElem = S.addSVGElementFromJson,
svgdoc = S.svgroot.parentNode.ownerDocument;
const strings = await importLocale();
const properlySourceSizeTextArea = function () {
// TODO: remove magic numbers here and get values from CSS
@@ -48,9 +48,9 @@ export default {
/**
* 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.
* @param {string} xmlString - The XML text
* @param {Element} 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];
@@ -89,36 +89,30 @@ export default {
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 buttons = [{
id: 'tool_foreign',
type: 'mode',
events: {
click () {
svgCanvas.setMode('foreign');
}
}, {
id: 'edit_foreign',
type: 'context',
panel: 'foreignObject_panel',
title: 'Edit ForeignObject Content',
events: {
click () {
showForeignEditor();
}
}
}, {
id: 'edit_foreign',
type: 'context',
panel: 'foreignObject_panel',
events: {
click () {
showForeignEditor();
}
}],
}
}];
context_tools: [{
const contextTools = [
{
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's width",
id: 'foreign_width',
label: 'w',
size: 3,
events: {
change () {
@@ -128,9 +122,7 @@ export default {
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's height",
id: 'foreign_height',
label: 'h',
events: {
change () {
setAttr('height', this.value);
@@ -139,9 +131,7 @@ export default {
}, {
type: 'input',
panel: 'foreignObject_panel',
title: "Change foreignObject's font size",
id: 'foreign_font_size',
label: 'font-size',
size: 2,
defval: 16,
events: {
@@ -150,8 +140,17 @@ export default {
}
}
}
];
],
return {
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'foreignobject-icons.xml',
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
context_tools: strings.contextTools.map((contextTool, i) => {
return Object.assign(contextTools[i], contextTool);
}),
callback () {
$('#foreignObject_panel').hide();
@@ -193,7 +192,7 @@ export default {
if (svgCanvas.getMode() === 'foreign') {
started = true;
newFO = S.addSvgElementFromJson({
newFO = S.addSVGElementFromJson({
element: 'foreignObject',
attr: {
x: opts.start_x,

View File

@@ -1,17 +1,17 @@
/* globals jQuery */
/*
/**
* ext-grid.js
*
* Licensed under the Apache License, Version 2
* @license Apache-2.0
*
* Copyright(c) 2010 Redou Mine
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Redou Mine, 2010 Alexis Deveria
*
*/
export default {
name: 'view_grid',
init ({NS, getTypeMap}) {
name: 'grid',
async init ({NS, getTypeMap, importLocale}) {
const strings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
@@ -131,8 +131,19 @@ export default {
$('#canvasGrid').toggle(showGrid);
$('#view_grid').toggleClass('push_button_pressed tool_button');
}
const buttons = [{
id: 'view_grid',
type: 'context',
panel: 'editor_panel',
events: {
click () {
svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate();
}
}
}];
return {
name: 'view_grid',
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'grid-icon.xml',
zoomChanged (zoom) {
@@ -143,18 +154,9 @@ export default {
gridUpdate();
}
},
buttons: [{
id: 'view_grid',
type: 'context',
panel: 'editor_panel',
title: 'Show/Hide Grid',
events: {
click () {
svgEditor.curConfig.showGrid = showGrid = !showGrid;
gridUpdate();
}
}
}]
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
})
};
}
};

View File

@@ -1,27 +1,28 @@
/* globals jQuery */
/*
/**
* ext-helloworld.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Alexis Deveria
*
*/
/*
This is a very basic SVG-Edit extension. It adds a "Hello World" button in
the left panel. Clicking on the button, and then the canvas will show the
user the point on the canvas that was clicked on.
/**
* This is a very basic SVG-Edit extension. It adds a "Hello World" button in
* the left ("mode") panel. Clicking on the button, and then the canvas
* will show the user the point on the canvas that was clicked on.
*/
export default {
name: 'Hello World',
init () {
name: 'helloworld',
async init ({importLocale}) {
// See `/editor/extensions/ext-locale/helloworld/`
const strings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
return {
name: 'Hello World',
name: strings.name,
// 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',
@@ -36,7 +37,7 @@ export default {
type: 'mode',
// Tooltip text
title: "Say 'Hello World'",
title: strings.buttons[0].title,
// Events
events: {
@@ -70,8 +71,14 @@ export default {
const x = opts.mouse_x / zoom;
const y = opts.mouse_y / zoom;
const text = 'Hello World!\n\nYou clicked here: ' +
x + ', ' + y;
// We do our own formatting
let {text} = strings;
[
['x', x],
['y', y]
].forEach(([prop, val]) => {
text = text.replace('{' + prop + '}', val);
});
// Show the text using the custom alert function
$.alert(text);

View File

@@ -1,19 +1,17 @@
/* globals jQuery */
/*
/**
* ext-imagelib.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Alexis Deveria
*
*/
import {importSetGlobalDefault} from '../external/dynamic-import-polyfill/importModule.js';
export default {
name: 'imagelib',
init ({decode64}) {
async init ({decode64, importLocale}) {
const imagelibStrings = await importLocale();
const svgEditor = this;
let imagelibStrings;
const $ = jQuery;
const {uiStrings, canvas: svgCanvas} = svgEditor;
@@ -23,7 +21,7 @@ export default {
}
function importImage (url) {
const newImage = svgCanvas.addSvgElementFromJson({
const newImage = svgCanvas.addSVGElementFromJson({
element: 'image',
attr: {
x: 0,
@@ -340,10 +338,19 @@ export default {
.appendTo(libOpts)
.text(name)
.on('click touchend', function () {
frame.attr('src', url({
path: svgEditor.curConfig.extIconsPath,
modularVersion
})).show();
frame.attr(
'src',
// Todo: Adopt some standard formatting library like `fluent.js` instead
url.replace(
'{path}',
svgEditor.curConfig.extIconsPath
).replace(
'{modularVersion}',
modularVersion
? (imagelibStrings.moduleEnding || '-es')
: ''
)
).show();
header.text(name);
libOpts.hide();
back.show();
@@ -354,30 +361,20 @@ export default {
}
}
const buttons = [{
id: 'tool_imagelib',
type: 'app_menu', // _flyout
position: 4,
events: {
mouseup: showBrowser
}
}];
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');
}
},
buttons: imagelibStrings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
callback () {
$('<style>').text(
'#imgbrowse_holder {' +

View File

@@ -0,0 +1,19 @@
export default {
name: 'Arrows',
langList: [
{id: 'arrow_none', textContent: 'No arrow'}
],
contextTools: [
{
title: 'Select arrow type',
options: {
none: 'No arrow',
end: '----&gt;',
start: '&lt;----',
both: '&lt;---&gt;',
mid: '--&gt;--',
mid_bk: '--&lt;--'
}
}
]
};

View File

@@ -0,0 +1,19 @@
export default {
name: 'Arrows',
langList: [
{id: 'arrow_none', textContent: 'Sans flèche'}
],
contextTools: [
{
title: 'Select arrow type',
options: {
none: 'No arrow',
end: '----&gt;',
start: '&lt;----',
both: '&lt;---&gt;',
mid: '--&gt;--',
mid_bk: '--&lt;--'
}
}
]
};

View File

@@ -0,0 +1,11 @@
export default {
name: 'ClosePath',
buttons: [
{
title: 'Open path'
},
{
title: 'Close path'
}
]
};

View File

@@ -0,0 +1,11 @@
export default {
name: 'Connector',
langList: [
{id: 'mode_connect', title: 'Connect two objects'}
],
buttons: [
{
title: 'Connect two objects'
}
]
};

View File

@@ -0,0 +1,11 @@
export default {
name: 'Connector',
langList: [
{id: 'mode_connect', title: 'Connecter deux objets'}
],
buttons: [
{
title: 'Connect two objects'
}
]
};

View File

@@ -0,0 +1,9 @@
export default {
name: 'eyedropper',
buttons: [
{
title: 'Eye Dropper Tool',
key: 'I'
}
]
};

View File

@@ -0,0 +1,25 @@
export default {
name: 'foreignObject',
buttons: [
{
title: 'Foreign Object Tool'
},
{
title: 'Edit ForeignObject Content'
}
],
contextTools: [
{
title: "Change foreignObject's width",
label: 'w'
},
{
title: "Change foreignObject's height",
label: 'h'
},
{
title: "Change foreignObject's font size",
label: 'font-size'
}
]
};

View File

@@ -0,0 +1,8 @@
export default {
name: 'View Grid',
buttons: [
{
title: 'Show/Hide Grid'
}
]
};

View File

@@ -0,0 +1,9 @@
export default {
name: 'Hello World',
text: 'Hello World!\n\nYou clicked here: {x}, {y}',
buttons: [
{
title: "Say 'Hello World'"
}
]
};

View File

@@ -4,12 +4,15 @@ export default {
import_single: 'Import single',
import_multi: 'Import multiple',
open: 'Open as new document',
buttons: [
{
title: 'Image library'
}
],
imgLibs: [
{
name: 'Demo library (local)',
url ({path, modularVersion}) {
return path + 'imagelib/index' + (modularVersion ? '-es' : '') + '.html';
},
url: '{path}imagelib/index{modularVersion}.html',
description: 'Demonstration library for SVG-edit on this server'
},
{

View File

@@ -4,12 +4,15 @@ export default {
import_single: 'import_single',
import_multi: 'import_multi',
open: 'open',
buttons: [
{
title: 'Image library'
}
],
imgLibs: [
{
name: 'Demo library (local)',
url ({path, modularVersion}) {
return path + 'imagelib/index' + (modularVersion ? '-es' : '') + '.html';
},
url: '{path}imagelib/index{modularVersion}.html',
description: 'Demonstration library for SVG-edit on this server'
},
{

View File

@@ -0,0 +1,46 @@
export default {
name: 'Markers',
langList: [
{id: 'nomarker', title: 'No Marker'},
{id: 'leftarrow', title: 'Left Arrow'},
{id: 'rightarrow', title: 'Right Arrow'},
{id: 'textmarker', title: 'Text Marker'},
{id: 'forwardslash', title: 'Forward Slash'},
{id: 'reverseslash', title: 'Reverse Slash'},
{id: 'verticalslash', title: 'Vertical Slash'},
{id: 'box', title: 'Box'},
{id: 'star', title: 'Star'},
{id: 'xmark', title: 'X'},
{id: 'triangle', title: 'Triangle'},
{id: 'mcircle', title: 'Circle'},
{id: 'leftarrow_o', title: 'Open Left Arrow'},
{id: 'rightarrow_o', title: 'Open Right Arrow'},
{id: 'box_o', title: 'Open Box'},
{id: 'star_o', title: 'Open Star'},
{id: 'triangle_o', title: 'Open Triangle'},
{id: 'mcircle_o', title: 'Open Circle'}
],
contextTools: [
{
title: 'Start marker',
label: 's'
},
{
title: 'Select start marker type'
},
{
title: 'Middle marker',
label: 'm'
},
{
title: 'Select mid marker type'
},
{
title: 'End marker',
label: 'e'
},
{
title: 'Select end marker type'
}
]
};

View File

@@ -0,0 +1,8 @@
export default {
name: 'MathJax',
buttons: [
{
title: 'Add Mathematics'
}
]
};

View File

@@ -0,0 +1,8 @@
export default {
name: 'Extension Panning',
buttons: [
{
title: 'Panning'
}
]
};

View File

@@ -0,0 +1,14 @@
export default {
name: 'polygon',
buttons: [
{
title: 'Polygon Tool'
}
],
contextTools: [
{
title: 'Number of Sides',
label: 'sides'
}
]
};

View File

@@ -0,0 +1,3 @@
export default {
saved: 'Saved! Return to Item View!'
};

View File

@@ -0,0 +1,3 @@
export default {
uploading: 'Uploading...'
};

View File

@@ -0,0 +1,24 @@
export default {
loading: 'Loading...',
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'
},
buttons: [
{
title: 'Shape library'
}
]
};

View File

@@ -0,0 +1,24 @@
export default {
loading: 'Loading...',
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'
},
buttons: [
{
title: "Bibliothèque d'images"
}
]
};

View File

@@ -0,0 +1,22 @@
export default {
name: 'star',
buttons: [
{
title: 'Star Tool'
}
],
contextTools: [
{
title: 'Number of Sides',
label: 'points'
},
{
title: 'Pointiness',
label: 'Pointiness'
},
{
title: 'Twists the star',
label: 'Radial Shift'
}
]
};

View File

@@ -0,0 +1,8 @@
export default {
name: 'WebAppFind',
buttons: [
{
title: 'Save Image back to Disk'
}
]
};

View File

@@ -1,11 +1,10 @@
/* globals jQuery */
/*
/**
* ext-markers.js
*
* Licensed under the Apache License, Version 2
* @license Apache-2.0
*
* Copyright(c) 2010 Will Schleter
* based on ext-arrows.js by Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Will Schleter based on ext-arrows.js by Copyright(c) 2010 Alexis Deveria
*
* This extension provides for the addition of markers to the either end
* or the middle of a line, polyline, path, polygon.
@@ -24,21 +23,21 @@
* an application specific attribute - se_type - is added to each marker element
* to store the type of marker
*
* TODO:
* @todo
* remove some of the restrictions above
* add option for keeping text aligned to horizontal
* add support for dimension extension lines
*
*/
*/
export default {
name: 'Markers',
init (S) {
name: 'markers',
async init (S) {
const strings = await S.importLocale();
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const // {svgcontent} = S,
addElem = S.addSvgElementFromJson;
addElem = S.addSVGElementFromJson;
const mtypes = ['start', 'mid', 'end'];
const markerPrefix = 'se_marker_';
const idPrefix = 'mkr_';
@@ -75,41 +74,15 @@ export default {
{element: 'circle', attr: {r: 30, cx: 50, cy: 50}}
};
const langList = {
en: [
{id: 'start_marker_list', title: 'Select start marker type'},
{id: 'mid_marker_list', title: 'Select mid marker type'},
{id: 'end_marker_list', title: 'Select end marker type'},
{id: 'nomarker', title: 'No Marker'},
{id: 'leftarrow', title: 'Left Arrow'},
{id: 'rightarrow', title: 'Right Arrow'},
{id: 'textmarker', title: 'Text Marker'},
{id: 'forwardslash', title: 'Forward Slash'},
{id: 'reverseslash', title: 'Reverse Slash'},
{id: 'verticalslash', title: 'Vertical Slash'},
{id: 'box', title: 'Box'},
{id: 'star', title: 'Star'},
{id: 'xmark', title: 'X'},
{id: 'triangle', title: 'Triangle'},
{id: 'mcircle', title: 'Circle'},
{id: 'leftarrow_o', title: 'Open Left Arrow'},
{id: 'rightarrow_o', title: 'Open Right Arrow'},
{id: 'box_o', title: 'Open Box'},
{id: 'star_o', title: 'Open Star'},
{id: 'triangle_o', title: 'Open Triangle'},
{id: 'mcircle_o', title: 'Open Circle'}
]
};
// duplicate shapes to support unfilled (open) marker types with an _o suffix
$.each(['leftarrow', 'rightarrow', 'box', 'star', 'mcircle', 'triangle'], function (i, v) {
markerTypes[v + '_o'] = markerTypes[v];
});
/**
* @param elem - A graphic element will have an attribute like marker-start
* @param attr - marker-start, marker-mid, or marker-end
* @returns The marker element that is linked to the graphic element
* @param {Element} elem - A graphic element will have an attribute like marker-start
* @param {"marker-start"|"marker-mid"|"marker-end"} attr
* @returns {Element} The marker element that is linked to the graphic element
*/
function getLinked (elem, attr) {
const str = elem.getAttribute(attr);
@@ -421,14 +394,12 @@ export default {
}
}
function getTitle (lang = 'en', id) {
const list = langList[lang];
for (const i in list) {
if (list.hasOwnProperty(i) && list[i].id === id) {
return list[i].title;
}
}
return id;
function getTitle (id) {
const {langList} = strings;
const item = langList.find((item) => {
return item.id === id;
});
return item ? item.title : id;
}
// build the toolbar button array from the marker definitions
@@ -462,7 +433,7 @@ export default {
const listname = pos + '_marker_list';
let def = true;
$.each(markerTypes, function (id, v) {
const title = getTitle(lang, String(id));
const title = getTitle(String(id));
buttons.push({
id: idPrefix + pos + '_' + id,
svgicon: id,
@@ -479,16 +450,55 @@ export default {
return buttons;
}
let currentLang;
const ret = {
name: 'Markers',
const contextTools = [
{
type: 'input',
panel: 'marker_panel',
id: 'start_marker',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
id: 'start_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
id: 'mid_marker',
defval: '',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
id: 'mid_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
id: 'end_marker',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
id: 'end_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}
];
return {
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'markers-icons.xml',
callback () {
$('#marker_panel').addClass('toolset').hide();
},
addLangData (lang) {
currentLang = lang;
return { data: langList[lang] };
async addLangData ({importLocale, lang}) {
return { data: strings.langList };
},
selectedChanged (opts) {
// Use this to update the current selected elements
@@ -524,69 +534,9 @@ export default {
updateReferences(elem);
}
// changing_flag = false; // Not apparently in use
}
};
// Todo: Check if the lang will be available in time
Object.defineProperties(ret, {
buttons: {
get () {
return buildButtonList(currentLang);
}
},
context_tools: {
get () {
return [
{
type: 'input',
panel: 'marker_panel',
title: 'Start marker',
id: 'start_marker',
label: 's',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle(currentLang, 'start_marker_list'),
id: 'start_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'Middle marker',
id: 'mid_marker',
label: 'm',
defval: '',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle(currentLang, 'mid_marker_list'),
id: 'mid_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}, {
type: 'input',
panel: 'marker_panel',
title: 'End marker',
id: 'end_marker',
label: 'e',
size: 3,
events: { change: setMarker }
}, {
type: 'button-select',
panel: 'marker_panel',
title: getTitle(currentLang, 'end_marker_list'),
id: 'end_marker_list',
colnum: 3,
events: { change: setArrowFromButton }
}
];
}
}
});
return ret;
buttons: buildButtonList(),
context_tools: contextTools
};
}
};

View File

@@ -1,10 +1,10 @@
/* globals jQuery, MathJax */
/*
/**
* ext-mathjax.js
*
* Licensed under the Apache License
* @license Apache
*
* Copyright(c) 2013 Jo Segaert
* @copyright 2013 Jo Segaert
*
*/
// Todo: Wait for Mathjax 3.0 to get ES Module/avoid global
@@ -12,7 +12,8 @@ import {importScript} from '../external/dynamic-import-polyfill/importModule.js'
export default {
name: 'mathjax',
init () {
async init ({importLocale}) {
const strings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
@@ -45,7 +46,7 @@ export default {
// 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',
mathjaxSrcSecure = 'mathjax/MathJax.min.js?config=TeX-AMS-MML_SVG.js',
{uiStrings} = svgEditor;
let
math,
@@ -72,15 +73,15 @@ export default {
/*
* 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
* 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>
* 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.
* 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>.
* to your formula's `<svg>` and copy the lot. So we have to replace each
* `<use>` tag by its `<path>`.
*/
MathJax.Hub.queue.Push(
function () {
@@ -116,99 +117,102 @@ export default {
);
}
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">' +
'$${}$$' +
const buttons = [{
id: 'tool_mathjax',
type: 'mode',
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>' +
'<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();
'<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'
// 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 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];
console.log(math);
mathjaxLoaded = true;
console.log('MathJax Loaded');
});
}).catch(() => {
console.log('Failed loadeing MathJax.');
$.alert('Failed loading MathJax. You will not be able to change the mathematics.');
// 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'
}
// Set the mode.
svgCanvas.setMode('mathjax');
// 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];
console.log(math);
mathjaxLoaded = true;
console.log('MathJax Loaded');
});
}).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');
}
}],
}
}];
return {
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'mathjax-icons.xml',
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
mouseDown () {
if (svgCanvas.getMode() === 'mathjax') {

View File

@@ -1,10 +1,10 @@
/* globals jQuery */
/*
/**
* ext-overview_window.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2013 James Sacksteder
* @copyright 2013 James Sacksteder
*
*/
export default {

View File

@@ -1,34 +1,35 @@
/*
/**
* ext-panning.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2013 Luis Aguirre
* @copyright 2013 Luis Aguirre
*
*/
/*
This is a very basic SVG-Edit extension to let tablet/mobile devices pan without problem
*/
export default {
name: 'ext-panning',
init () {
name: 'panning',
async init ({importLocale}) {
const strings = await importLocale();
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');
}
const buttons = [{
id: 'ext-panning',
type: 'mode',
events: {
click () {
svgCanvas.setMode('ext-panning');
}
}],
}
}];
return {
name: strings.name,
svgicons: svgEditor.curConfig.extIconsPath + 'ext-panning.xml',
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
mouseDown () {
if (svgCanvas.getMode() === 'ext-panning') {
svgEditor.setPanning(true);

View File

@@ -4,7 +4,7 @@
export default {
name: 'php_savefile',
callback () {
init () {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;

View File

@@ -1,21 +1,21 @@
/* globals jQuery */
/*
/**
* ext-polygon.js
*
*
* Copyright(c) 2010 CloudCanvas, Inc.
* All rights reserved
* @copyright 2010 CloudCanvas, Inc. All rights reserved
*
*/
export default {
name: 'polygon',
init (S) {
async init (S) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
const // {svgcontent} = S,
// addElem = S.addSvgElementFromJson,
const {importLocale} = S, // {svgcontent}
// addElem = S.addSVGElementFromJson,
editingitex = false;
const strings = await importLocale();
let selElems,
// svgdoc = S.svgroot.parentNode.ownerDocument,
// newFOG, newFOGParent, newDef, newImageName, newMaskID, modeChangeG,
@@ -71,7 +71,7 @@ export default {
* 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.
* @returns {boolean} This function returns false if the set was unsuccessful, true otherwise.
*/
/*
function setItexString(tex) {
@@ -110,36 +110,38 @@ export default {
return true;
}
*/
const buttons = [{
id: 'tool_polygon',
type: 'mode',
position: 11,
events: {
click () {
svgCanvas.setMode('polygon');
showPanel(true);
}
}
}];
const contextTools = [{
type: 'input',
panel: 'polygon_panel',
id: 'polySides',
size: 3,
defval: 5,
events: {
change () {
setAttr('sides', this.value);
}
}
}];
return {
name: 'polygon',
name: strings.name,
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);
}
}
}],
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
context_tools: strings.contextTools.map((contextTool, i) => {
return Object.assign(contextTools[i], contextTool);
}),
callback () {
$('#polygon_panel').hide();
@@ -185,7 +187,7 @@ export default {
if (svgCanvas.getMode() === 'polygon') {
started = true;
newFO = S.addSvgElementFromJson({
newFO = S.addSVGElementFromJson({
element: 'polygon',
attr: {
cx: opts.start_x,

View File

@@ -1,20 +1,19 @@
/* globals jQuery */
/*
/**
* ext-server_moinsave.js
*
* Licensed under the MIT License
*
* Copyright(c) 2010 Alexis Deveria
* 2011 MoinMoin:ReimarBauer
* adopted for moinmoins item storage. it sends in one post png and svg data
* (I agree to dual license my work to additional GPLv2 or later)
* @license MIT
*
* @copyright 2010 Alexis Deveria, 2011 MoinMoin:ReimarBauer
* adopted for moinmoins item storage. It sends in one post png and svg data
* (I agree to dual license my work to additional GPLv2 or later)
*/
import {canvg} from '../canvg/canvg.js';
export default {
name: 'server_opensave',
callback ({encode64}) {
name: 'server_moinsave',
async init ({encode64, importLocale}) {
const strings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
@@ -49,7 +48,7 @@ export default {
.append('<input type="hidden" name="contenttype" value="application/x-svgdraw">')
.appendTo('body')
.submit().remove();
alert('Saved! Return to Item View!');
alert(strings.saved);
top.window.location = '/' + name;
}
});

View File

@@ -1,17 +1,18 @@
/* globals jQuery */
/*
/**
* ext-server_opensave.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Alexis Deveria
*
*/
import {canvg} from '../canvg/canvg.js';
export default {
name: 'server_opensave',
callback ({decode64, encode64}) {
async init ({decode64, encode64, importLocale}) {
const strings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
@@ -63,7 +64,7 @@ export default {
},
exportPDF (win, data) {
const filename = getFileNameFromTitle(),
datauri = data.dataurlstring;
datauri = data.output;
if (clientDownloadSupport(filename, '.pdf', datauri)) {
return;
}
@@ -186,7 +187,7 @@ export default {
form.submit();
rebuildInput(form);
$.process_cancel('Uploading...', function () {
$.process_cancel(strings.uploading, function () {
cancelled = true;
$('#dialog_box').hide();
});

View File

@@ -1,16 +1,16 @@
/* globals jQuery */
/*
/**
* ext-shapes.js
*
* Licensed under the MIT License
* @license MIT
*
* Copyright(c) 2010 Christian Tzurcanu
* Copyright(c) 2010 Alexis Deveria
* @copyright 2010 Christian Tzurcanu, 2010 Alexis Deveria
*
*/
export default {
name: 'shapes',
init () {
async init ({importLocale}) {
const strings = await importLocale();
const svgEditor = this;
const $ = jQuery;
const canv = svgEditor.canvas;
@@ -18,22 +18,7 @@ export default {
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'
};
const {categories} = strings;
const library = {
basic: {
@@ -89,7 +74,10 @@ export default {
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>',
'<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');
const width = 24;
@@ -119,7 +107,7 @@ export default {
const lib = library[catId];
if (!lib) {
$('#shape_buttons').html('Loading...');
$('#shape_buttons').html(strings.loading);
$.getJSON(svgEditor.curConfig.extIconsPath + 'shapelib/' + catId + '.json', function (result) {
curLib = library[catId] = {
data: result.data,
@@ -135,20 +123,22 @@ export default {
if (!lib.buttons.length) { makeButtons(catId, lib); }
loadIcons();
}
const buttons = [{
id: 'tool_shapelib',
type: 'mode_flyout', // _flyout
position: 6,
events: {
click () {
canv.setMode(modeId);
}
}
}];
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);
}
}
}],
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
callback () {
$('<style>').text(
'#shape_buttons {' +
@@ -236,6 +226,12 @@ export default {
'margin-top': -(h / 2 - 15),
'margin-left': 3
});
// Now add shape categories from locale
const cats = {};
for (const o in categories) {
cats['#shape_cats [data-cat="' + o + '"]'] = categories[o];
}
this.setStrings('content', cats);
},
mouseDown (opts) {
const mode = canv.getMode();
@@ -250,7 +246,7 @@ export default {
startClientPos.x = opts.event.clientX;
startClientPos.y = opts.event.clientY;
curShape = canv.addSvgElementFromJson({
curShape = canv.addSVGElementFromJson({
element: 'path',
curStyles: true,
attr: {

View File

@@ -1,20 +1,20 @@
/* globals jQuery */
/*
/**
* ext-star.js
*
*
* Copyright(c) 2010 CloudCanvas, Inc.
* All rights reserved
* @copyright 2010 CloudCanvas, Inc. All rights reserved
*
*/
export default {
name: 'star',
init (S) {
async init (S) {
const svgEditor = this;
const $ = jQuery;
const svgCanvas = svgEditor.canvas;
let // {svgcontent} = S,
const {importLocale} = S; // {svgcontent},
let
selElems,
// editingitex = false,
// svgdoc = S.svgroot.parentNode.ownerDocument,
@@ -24,7 +24,7 @@ export default {
// newFOG, newFOGParent, newDef, newImageName, newMaskID,
// undoCommand = 'Not image',
// modeChangeG, ccZoom, wEl, hEl, wOffset, hOffset, ccRgbEl, brushW, brushH;
const strings = await importLocale();
function showPanel (on) {
let fcRules = $('#fc_rules');
if (!fcRules.length) {
@@ -54,58 +54,56 @@ export default {
return 1 / Math.cos(n);
}
*/
const buttons = [{
id: 'tool_star',
type: 'mode',
position: 12,
events: {
click () {
showPanel(true);
svgCanvas.setMode('star');
}
}
}];
const contextTools = [{
type: 'input',
panel: 'star_panel',
id: 'starNumPoints',
size: 3,
defval: 5,
events: {
change () {
setAttr('point', this.value);
}
}
}, {
type: 'input',
panel: 'star_panel',
id: 'starRadiusMulitplier',
size: 3,
defval: 2.5
}, {
type: 'input',
panel: 'star_panel',
id: 'radialShift',
size: 3,
defval: 0,
events: {
change () {
setAttr('radialshift', this.value);
}
}
}];
return {
name: 'star',
name: strings.name,
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);
}
}
}],
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
}),
context_tools: strings.contextTools.map((contextTool, i) => {
return Object.assign(contextTools[i], contextTool);
}),
callback () {
$('#star_panel').hide();
// const endChanges = function(){};
@@ -120,7 +118,7 @@ export default {
if (svgCanvas.getMode() === 'star') {
started = true;
newFO = S.addSvgElementFromJson({
newFO = S.addSVGElementFromJson({
element: 'polygon',
attr: {
cx: opts.start_x,

View File

@@ -1,36 +1,26 @@
/* globals jQuery */
/*
/**
* ext-storage.js
*
* Licensed under the MIT License
* This extension allows automatic saving of the SVG canvas contents upon
* page unload (which can later be automatically retrieved upon future
* editor loads).
*
* Copyright(c) 2010 Brett Zamir
* The functionality was originally part of the SVG Editor, but moved to a
* separate extension to make the setting behavior optional, and adapted
* to inform the user of its setting of local data.
* Dependencies:
*
*/
/**
* This extension allows automatic saving of the SVG canvas contents upon
* page unload (which can later be automatically retrieved upon future
* editor loads).
*
* The functionality was originally part of the SVG Editor, but moved to a
* separate extension to make the setting behavior optional, and adapted
* to inform the user of its setting of local data.
* 1. jQuery BBQ (for deparam)
* @license MIT
*
* @copyright 2010 Brett Zamir
* @todo Revisit on whether to use $.pref over directly setting curConfig in all
* extensions for a more public API (not only for extPath and imagePath,
* but other currently used config in the extensions)
* @todo We might provide control of storage settings through the UI besides the
* initial (or URL-forced) dialog. *
*/
/*
Dependencies:
1. jQuery BBQ (for deparam)
*/
/*
TODOS
1. Revisit on whether to use $.pref over directly setting curConfig in all
extensions for a more public API (not only for extPath and imagePath,
but other currently used config in the extensions)
2. We might provide control of storage settings through the UI besides the
initial (or URL-forced) dialog.
*/
import {importSetGlobalDefault} from '../external/dynamic-import-polyfill/importModule.js';
export default {
name: 'storage',
init () {
@@ -151,23 +141,10 @@ export default {
let loaded = false;
return {
name: 'storage',
async langReady ({lang}) {
async langReady ({importLocale}) {
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 confirmSetStorage = await importLocale();
const {
message, storagePrefsAndContent, storagePrefsOnly,
storagePrefs, storageNoPrefsOrContent, storageNoPrefs,

View File

@@ -1,71 +1,104 @@
/*
Depends on Firefox add-on and executables from https://github.com/brettz9/webappfind
Todos:
1. See WebAppFind Readme for SVG-related todos
/**
* Depends on Firefox add-on and executables from {@link https://github.com/brettz9/webappfind}
* @author Brett Zamir
* @license MIT
* @todo See WebAppFind Readme for SVG-related todos
*/
export default {
name: 'WebAppFind',
init () {
name: 'webappfind',
async init ({importLocale}) {
const strings = await importLocale();
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',
const saveMessage = 'save',
readMessage = '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)
let pathID;
this.canvas.bind(
'message',
/**
* @param {external:Window} win
* @param {module:svgcanvas.SvgCanvas#event:message} data
* @listens module:svgcanvas.SvgCanvas#event:message
* @throws {Error} Unexpected event type
* @returns {undefined}
*/
(win, {data, origin}) => {
// console.log('data, origin', data, origin);
let type, content;
try {
({type, pathID, content} = data.webappfind); // May throw if data is not an object
if (origin !== location.origin || // We are only interested in a message sent as though within this URL by our browser add-on
excludedMessages.includes(type) // Avoid our post below (other messages might be possible in the future which may also need to be excluded if your subsequent code makes assumptions on the type of message this is)
) {
return;
}
} catch (err) {
return;
}
switch (type) {
case 'view':
// Populate the contents
svgEditor.loadFromString(content);
/* if ($('#tool_save_file')) {
$('#tool_save_file').disabled = false;
} */
break;
case 'save-end':
alert(`save complete for pathID ${pathID}!`);
break;
default:
throw new Error('Unexpected WebAppFind event type');
}
}
);
/*
window.postMessage({
webappfind: {
type: readMessage
}
}, window.location.origin === 'null'
// Avoid "null" string error for `file:` protocol (even though
// file protocol not currently supported by Firefox)
? '*'
: window.location.origin
);
*/
const buttons = [{
id: 'webappfind_save', //
type: 'app_menu',
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({
webappfind: {
type: saveMessage,
pathID,
content: svgEditor.canvas.getSvgString()
}
}, window.location.origin === 'null'
// Avoid "null" string error for `file:` protocol (even
// though file protocol not currently supported by add-on)
? '*'
: window.location.origin
);
}
}
}];
return {
name: 'WebAppFind',
name: strings.name,
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);
}
}
}]
buttons: strings.buttons.map((button, i) => {
return Object.assign(buttons[i], button);
})
};
}
};

View File

@@ -19,7 +19,7 @@ export default {
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
// See svgedit-config-es.js for an example of how to configure
const {allowedOrigins} = svgEditor.curConfig;
if (!allowedOrigins.includes('*') && !allowedOrigins.includes(e.origin)) {
return;

View File

@@ -1,6 +1,10 @@
// MIT License
// From: https://github.com/uupaa/dynamic-import-polyfill/blob/master/importModule.js
/**
* @module importModule
*/
function toAbsoluteURL (url) {
const a = document.createElement('a');
a.setAttribute('href', url); // <a href="hoge.html">
@@ -16,9 +20,26 @@ function addScriptAtts (script, atts) {
}
// Additions by Brett
/**
* @typedef {PlainObject} module:importModule.ImportConfig
* @property {string} global The variable name to set on `window` (when not using the modular version)
* @property {boolean} [returnDefault=false]
*/
/**
* @function module:importModule.importSetGlobalDefault
* @param {string} url
* @param {module:importModule.ImportConfig} config
* @returns {*} The return depends on the export of the targeted module.
*/
export async function importSetGlobalDefault (url, config) {
return importSetGlobal(url, {...config, returnDefault: true});
}
/**
* @function module:importModule.importSetGlobal
* @param {string} url
* @param {module:importModule.ImportConfig} config
* @returns {ArbitraryModule|*} The return depends on the export of the targeted module.
*/
export async function importSetGlobal (url, {global, returnDefault}) {
// Todo: Replace calls to this function with `import()` when supported
const modularVersion = !('svgEditor' in window) ||

View File

@@ -1,12 +1,11 @@
/**
* Package: svedit.history
*
* Licensed under the MIT License
*
* Copyright(c) 2010 Jeff Schiller
* For command history tracking and undo functionality
* @module history
* @license MIT
* @copyright 2010 Jeff Schiller
*/
import {getHref, setHref, getRotationAngle} from './svgutils.js';
import {getHref, setHref, getRotationAngle} from './utilities.js';
import {removeElementFromListMap} from './svgtransformlist.js';
/**
@@ -21,39 +20,93 @@ export const HistoryEventTypes = {
// const removedElements = {};
/**
* Base class for commands
*/
class Command {
/**
* @returns {string}
*/
getText () {
return this.text;
}
}
// Todo: Figure out why the interface members aren't showing
// up (with or without modules applied), despite our apparently following
// http://usejsdoc.org/tags-interface.html#virtual-comments
/**
* An interface that all command objects must implement.
* @typedef {Object} svgedit.history.HistoryCommand
* void apply(svgedit.history.HistoryEventHandler);
* void unapply(svgedit.history.HistoryEventHandler);
* Element[] elements();
* String getText();
* @interface module:history.HistoryCommand
*/
/**
* Applies
*
* static String type();
* }
* @function module:history.HistoryCommand#apply
* @param {module:history.HistoryEventHandler}
* @fires module:history~Command#event:history
* @returns {undefined|true}
*/
/**
*
* Unapplies
* @function module:history.HistoryCommand#unapply
* @param {module:history.HistoryEventHandler}
* @fires module:history~Command#event:history
* @returns {undefined|true}
*/
/**
* Returns the elements
* @function module:history.HistoryCommand#elements
* @returns {Element[]}
*/
/**
* Gets the text
* @function module:history.HistoryCommand#getText
* @returns {string}
*/
/**
* Gives the type
* @function module:history.HistoryCommand.type
* @returns {string}
*/
/**
* Gives the type
* @function module:history.HistoryCommand#type
* @returns {string}
*/
/**
* @event module:history~Command#event:history
* @type {module:history.HistoryCommand}
*/
/**
* An interface for objects that will handle history events.
* @interface module:history.HistoryEventHandler
*/
/**
*
* @function module:history.HistoryEventHandler#handleHistoryEvent
* @param {string} eventType One of the HistoryEvent types
* @param {module:history~Command#event:history} command
* @listens module:history~Command#event:history
* @returns {undefined}
*
* Interface: svgedit.history.HistoryEventHandler
* An interface for objects that will handle history events.
*
* interface svgedit.history.HistoryEventHandler {
* void handleHistoryEvent(eventType, command);
* }
*
* eventType is a string conforming to one of the HistoryEvent types.
* command is an object fulfilling the HistoryCommand interface.
*/
/**
* @class svgedit.history.MoveElementCommand
* @implements svgedit.history.HistoryCommand
* History command for an element that had its DOM position changed
* @implements {module:history.HistoryCommand}
* @param {Element} elem - The DOM element that was moved
* @param {Element} oldNextSibling - The element's next sibling before it was moved
* @param {Element} oldParent - The element's parent before it was moved
* @param {string} [text] - An optional string visible to user related to this change
*/
export class MoveElementCommand {
export class MoveElementCommand extends Command {
constructor (elem, oldNextSibling, oldParent, text) {
super();
this.elem = elem;
this.text = text ? ('Move ' + elem.tagName + ' to ' + text) : ('Move ' + elem.tagName);
this.oldNextSibling = oldNextSibling;
@@ -61,16 +114,15 @@ export class MoveElementCommand {
this.newNextSibling = elem.nextSibling;
this.newParent = elem.parentNode;
}
getText () {
return this.text;
}
type () {
return 'svgedit.history.MoveElementCommand';
}
/**
* Re-positions the element
* @param {{handleHistoryEvent: function}} handler
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
apply (handler) {
// TODO(codedread): Refactor this common event code into a base HistoryCommand class.
@@ -87,7 +139,9 @@ export class MoveElementCommand {
/**
* Positions the element back to its original location
* @param {{handleHistoryEvent: function}} handler
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
unapply (handler) {
if (handler) {
@@ -102,7 +156,7 @@ export class MoveElementCommand {
}
/**
* @returns {Array} Array with element associated with this command
* @returns {Element[]} Array with element associated with this command
*/
elements () {
return [this.elem];
@@ -111,14 +165,15 @@ export class MoveElementCommand {
MoveElementCommand.type = MoveElementCommand.prototype.type;
/**
* @implements svgedit.history.HistoryCommand
* History command for an element that was added to the DOM
* @implements {module:history.HistoryCommand}
*
* @param elem - The newly added DOM element
* @param text - An optional string visible to user related to this change
* @param {Element} elem - The newly added DOM element
* @param {string} text - An optional string visible to user related to this change
*/
export class InsertElementCommand {
export class InsertElementCommand extends Command {
constructor (elem, text) {
super();
this.elem = elem;
this.text = text || ('Create ' + elem.tagName);
this.parent = elem.parentNode;
@@ -129,11 +184,12 @@ export class InsertElementCommand {
return 'svgedit.history.InsertElementCommand';
}
getText () {
return this.text;
}
// Re-Inserts the new element
/**
* Re-inserts the new element
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
apply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this);
@@ -146,7 +202,12 @@ export class InsertElementCommand {
}
}
// Removes the element
/**
* Removes the element
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
unapply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this);
@@ -161,7 +222,7 @@ export class InsertElementCommand {
}
/**
* @returns {Array} Array with element associated with this command
* @returns {Element[]} Array with element associated with this command
*/
elements () {
return [this.elem];
@@ -170,15 +231,16 @@ export class InsertElementCommand {
InsertElementCommand.type = InsertElementCommand.prototype.type;
/**
* @implements svgedit.history.HistoryCommand
* History command for an element removed from the DOM
* @param elem - The removed DOM element
* @param oldNextSibling - The DOM element's nextSibling when it was in the DOM
* @param oldParent - The DOM element's parent
* @param {String} [text] - An optional string visible to user related to this change
* @implements {module:history.HistoryCommand}
* @param {Element} elem - The removed DOM element
* @param {Node} oldNextSibling - The DOM element's nextSibling when it was in the DOM
* @param {Element} oldParent - The DOM element's parent
* @param {string} [text] - An optional string visible to user related to this change
*/
export class RemoveElementCommand {
export class RemoveElementCommand extends Command {
constructor (elem, oldNextSibling, oldParent, text) {
super();
this.elem = elem;
this.text = text || ('Delete ' + elem.tagName);
this.nextSibling = oldNextSibling;
@@ -191,11 +253,12 @@ export class RemoveElementCommand {
return 'svgedit.history.RemoveElementCommand';
}
getText () {
return this.text;
}
// Re-removes the new element
/**
* Re-removes the new element
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
apply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this);
@@ -210,7 +273,12 @@ export class RemoveElementCommand {
}
}
// Re-adds the new element
/**
* Re-adds the new element
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
unapply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this);
@@ -230,7 +298,7 @@ export class RemoveElementCommand {
}
/**
* @returns {Array} Array with element associated with this command
* @returns {Element[]} Array with element associated with this command
*/
elements () {
return [this.elem];
@@ -239,15 +307,23 @@ export class RemoveElementCommand {
RemoveElementCommand.type = RemoveElementCommand.prototype.type;
/**
* @implements svgedit.history.HistoryCommand
* @typedef {"#text"|"#href"|string} module:history.CommandAttributeName
*/
/**
* @typedef {PlainObject.<module:history.CommandAttributeName, string>} module:history.CommandAttributes
*/
/**
* History command to make a change to an element.
* Usually an attribute change, but can also be textcontent.
* @param elem - The DOM element that was changed
* @param attrs - An object with the attributes to be changed and the values they had *before* the change
* @param {String} text - An optional string visible to user related to this change
* @implements {module:history.HistoryCommand}
* @param {Element} elem - The DOM element that was changed
* @param {module:history.CommandAttributes} attrs - Attributes to be changed with the values they had *before* the change
* @param {string} text - An optional string visible to user related to this change
*/
export class ChangeElementCommand {
export class ChangeElementCommand extends Command {
constructor (elem, attrs, text) {
super();
this.elem = elem;
this.text = text ? ('Change ' + elem.tagName + ' ' + text) : ('Change ' + elem.tagName);
this.newValues = {};
@@ -266,11 +342,12 @@ export class ChangeElementCommand {
return 'svgedit.history.ChangeElementCommand';
}
getText () {
return this.text;
}
// Performs the stored change action
/**
* Performs the stored change action
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {true}
*/
apply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this);
@@ -319,7 +396,12 @@ export class ChangeElementCommand {
return true;
}
// Reverses the stored change action
/**
* Reverses the stored change action
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {true}
*/
unapply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this);
@@ -369,7 +451,7 @@ export class ChangeElementCommand {
}
/**
* @returns {Array} Array with element associated with this command
* @returns {Element[]} Array with element associated with this command
*/
elements () {
return [this.elem];
@@ -382,12 +464,15 @@ ChangeElementCommand.type = ChangeElementCommand.prototype.type;
// and they both affect the same element, then collapse the two commands into one
/**
* @implements svgedit.history.HistoryCommand
* History command that can contain/execute multiple other commands
* @param {String} [text] - An optional string visible to user related to this change
* @implements {module:history.HistoryCommand}
*/
export class BatchCommand {
export class BatchCommand extends Command {
/**
* @param {string} [text] - An optional string visible to user related to this change
*/
constructor (text) {
super();
this.text = text || 'Batch Command';
this.stack = [];
}
@@ -396,11 +481,12 @@ export class BatchCommand {
return 'svgedit.history.BatchCommand';
}
getText () {
return this.text;
}
// Runs "apply" on all subcommands
/**
* Runs "apply" on all subcommands
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
apply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this);
@@ -416,7 +502,12 @@ export class BatchCommand {
}
}
// Runs "unapply" on all subcommands
/**
* Runs "unapply" on all subcommands
* @param {module:history.HistoryEventHandler} handler
* @fires module:history~Command#event:history
* @returns {undefined}
*/
unapply (handler) {
if (handler) {
handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this);
@@ -431,7 +522,10 @@ export class BatchCommand {
}
}
// Iterate through all our subcommands and returns all the elements we are changing
/**
* Iterate through all our subcommands
* @returns {Element[]} All the elements we are changing
*/
elements () {
const elems = [];
let cmd = this.stack.length;
@@ -447,14 +541,14 @@ export class BatchCommand {
/**
* Adds a given command to the history stack
* @param cmd - The undo command object to add
* @param {Command} cmd - The undo command object to add
*/
addSubCommand (cmd) {
this.stack.push(cmd);
}
/**
* @returns {Boolean} Indicates whether or not the batch command is empty
* @returns {boolean} Indicates whether or not the batch command is empty
*/
isEmpty () {
return !this.stack.length;
@@ -463,10 +557,12 @@ export class BatchCommand {
BatchCommand.type = BatchCommand.prototype.type;
/**
* @param historyEventHandler - an object that conforms to the HistoryEventHandler interface
* (see above)
*
*/
export class UndoManager {
/**
* @param {module:history.HistoryEventHandler} historyEventHandler
*/
constructor (historyEventHandler) {
this.handler_ = historyEventHandler || null;
this.undoStackPointer = 0;
@@ -478,41 +574,47 @@ export class UndoManager {
this.undoableChangeStack = [];
}
// Resets the undo stack, effectively clearing the undo/redo history
/**
* Resets the undo stack, effectively clearing the undo/redo history
* @returns {undefined}
*/
resetUndoStack () {
this.undoStack = [];
this.undoStackPointer = 0;
}
/**
* @returns {Number} Integer with the current size of the undo history stack
* @returns {Integer} Current size of the undo history stack
*/
getUndoStackSize () {
return this.undoStackPointer;
}
/**
* @returns {Number} Integer with the current size of the redo history stack
* @returns {Integer} Current size of the redo history stack
*/
getRedoStackSize () {
return this.undoStack.length - this.undoStackPointer;
}
/**
* @returns {String} String associated with the next undo command
* @returns {string} String associated with the next undo command
*/
getNextUndoCommandText () {
return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer - 1].getText() : '';
}
/**
* @returns {String} String associated with the next redo command
* @returns {string} String associated with the next redo command
*/
getNextRedoCommandText () {
return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : '';
}
// Performs an undo step
/**
* Performs an undo step
* @returns {undefined}
*/
undo () {
if (this.undoStackPointer > 0) {
const cmd = this.undoStack[--this.undoStackPointer];
@@ -520,7 +622,10 @@ export class UndoManager {
}
}
// Performs a redo step
/**
* Performs a redo step
* @returns {undefined}
*/
redo () {
if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) {
const cmd = this.undoStack[this.undoStackPointer++];
@@ -530,7 +635,8 @@ export class UndoManager {
/**
* Adds a command object to the undo history stack
* @param cmd - The command object to add
* @param {Command} cmd - The command object to add
* @returns {undefined}
*/
addCommandToHistory (cmd) {
// FIXME: we MUST compress consecutive text changes to the same element
@@ -549,12 +655,13 @@ export class UndoManager {
/**
* This function tells the canvas to remember the old values of the
* attrName attribute for each element sent in. The elements and values
* are stored on a stack, so the next call to finishUndoableChange() will
* `attrName` attribute for each element sent in. The elements and values
* are stored on a stack, so the next call to `finishUndoableChange()` will
* pop the elements and old values off the stack, gets the current values
* from the DOM and uses all of these to construct the undo-able command.
* @param attrName - The name of the attribute being changed
* @param elems - Array of DOM elements being changed
* @param {string} attrName - The name of the attribute being changed
* @param {Element[]} elems - Array of DOM elements being changed
* @returns {undefined}
*/
beginUndoableChange (attrName, elems) {
const p = ++this.undoChangeStackPointer;
@@ -574,10 +681,10 @@ export class UndoManager {
}
/**
* This function returns a BatchCommand object which summarizes the
* change since beginUndoableChange was called. The command can then
* This function returns a `BatchCommand` object which summarizes the
* change since `beginUndoableChange` was called. The command can then
* be added to the command history
* @returns Batch command object with resulting changes
* @returns {BatchCommand} Batch command object with resulting changes
*/
finishUndoableChange () {
const p = this.undoChangeStackPointer--;

View File

@@ -1,9 +1,8 @@
/**
* Package: svgedit.history
*
* Licensed under the MIT License
*
* Copyright(c) 2016 Flint O'Brien
* HistoryRecordingService component of history
* @module history
* @license MIT
* @copyright 2016 Flint O'Brien
*/
import {
@@ -23,33 +22,32 @@ import {
* HistoryRecordingService.NO_HISTORY is a singleton that can be passed in to functions
* that record history. This helps when the caller requires that no history be recorded.
*
* Usage:
* The following will record history: insert, batch, insert.
* ```
* hrService = new svgedit.history.HistoryRecordingService(this.undoMgr);
* @example
* hrService = new history.HistoryRecordingService(this.undoMgr);
* hrService.insertElement(elem, text); // add simple command to history.
* hrService.startBatchCommand('create two elements');
* hrService.changeElement(elem, attrs, text); // add to batchCommand
* hrService.changeElement(elem, attrs2, text); // add to batchCommand
* hrService.endBatchCommand(); // add batch command with two change commands to history.
* hrService.insertElement(elem, text); // add simple command to history.
* ```
*
* Note that all functions return this, so commands can be chained, like so:
*
* ```
* @example
* // Note that all functions return this, so commands can be chained, like so:
* hrService
* .startBatchCommand('create two elements')
* .insertElement(elem, text)
* .changeElement(elem, attrs, text)
* .endBatchCommand();
* ```
*
* @param {svgedit.history.UndoManager} undoManager - The undo manager.
* A value of null is valid for cases where no history recording is required.
* See singleton: HistoryRecordingService.NO_HISTORY
* @memberof module:history
*/
class HistoryRecordingService {
/**
* @param {history.UndoManager|null} undoManager - The undo manager.
* A value of `null` is valid for cases where no history recording is required.
* See singleton: {@link module:history.HistoryRecordingService.HistoryRecordingService.NO_HISTORY}
*/
constructor (undoManager) {
this.undoManager_ = undoManager;
this.currentBatchCommand_ = null;
@@ -61,7 +59,7 @@ class HistoryRecordingService {
* Requires a corresponding call to endBatchCommand. Start and end commands can be nested.
*
* @param {string} text - Optional string describing the batch command.
* @returns {svgedit.history.HistoryRecordingService}
* @returns {module:history.HistoryRecordingService}
*/
startBatchCommand (text) {
if (!this.undoManager_) { return this; }
@@ -72,7 +70,7 @@ class HistoryRecordingService {
/**
* End a batch command and add it to the history or a parent batch command.
* @returns {svgedit.history.HistoryRecordingService}
* @returns {module:history.HistoryRecordingService}
*/
endBatchCommand () {
if (!this.undoManager_) { return this; }
@@ -92,7 +90,7 @@ class HistoryRecordingService {
* @param {Element} oldNextSibling - The element's next sibling before it was moved
* @param {Element} oldParent - The element's parent before it was moved
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
* @returns {module:history.HistoryRecordingService}
*/
moveElement (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
@@ -104,7 +102,7 @@ class HistoryRecordingService {
* Add an InsertElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was added
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
* @returns {module:history.HistoryRecordingService}
*/
insertElement (elem, text) {
if (!this.undoManager_) { return this; }
@@ -118,7 +116,7 @@ class HistoryRecordingService {
* @param {Element} oldNextSibling - The element's next sibling before it was removed
* @param {Element} oldParent - The element's parent before it was removed
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
* @returns {module:history.HistoryRecordingService}
*/
removeElement (elem, oldNextSibling, oldParent, text) {
if (!this.undoManager_) { return this; }
@@ -129,9 +127,9 @@ class HistoryRecordingService {
/**
* Add a ChangeElementCommand to the history or current batch command
* @param {Element} elem - The DOM element that was changed
* @param {Object} attrs - An object with the attributes to be changed and the values they had *before* the change
* @param {module:history.CommandAttributes} attrs - An object with the attributes to be changed and the values they had *before* the change
* @param {string} [text] - An optional string visible to user related to this change
* @returns {svgedit.history.HistoryRecordingService}
* @returns {module:history.HistoryRecordingService}
*/
changeElement (elem, attrs, text) {
if (!this.undoManager_) { return this; }
@@ -141,9 +139,9 @@ class HistoryRecordingService {
/**
* Private function to add a command to the history or current batch command.
* @param cmd
* @returns {svgedit.history.HistoryRecordingService}
* @private
* @param {Command} cmd
* @returns {module:history.HistoryRecordingService}
*/
addCommand_ (cmd) {
if (!this.undoManager_) { return this; }
@@ -155,7 +153,8 @@ class HistoryRecordingService {
}
}
/**
* @property {HistoryRecordingService} NO_HISTORY - Singleton that can be passed to functions that record history, but the caller requires that no history be recorded.
* @memberof module:history.HistoryRecordingService
* @property {module:history.HistoryRecordingService} NO_HISTORY - Singleton that can be passed to functions that record history, but the caller requires that no history be recorded.
*/
HistoryRecordingService.NO_HISTORY = new HistoryRecordingService();
export default HistoryRecordingService;

View File

@@ -1,23 +1,35 @@
/**
* jQuery module to work with SVG.
*
* Licensed under the MIT License
*
* jQuery module to work with SVG attributes
* @module jQueryAttr
* @license MIT
*/
// This fixes $(...).attr() to work as expected with SVG elements.
// Does not currently use *AttributeNS() since we rarely need that.
// See https://api.jquery.com/attr/ for basic documentation of .attr()
// Additional functionality:
// - When getting attributes, a string that's a number is returned as type number.
// - If an array is supplied as the first parameter, multiple values are returned
// as an object with values for each given attribute
/**
* This fixes `$(...).attr()` to work as expected with SVG elements.
* Does not currently use `*AttributeNS()` since we rarely need that.
* Adds {@link external:jQuery.fn.attr}.
* See {@link https://api.jquery.com/attr/} for basic documentation of `.attr()`
*
* Additional functionality:
* - When getting attributes, a string that's a number is returned as type number.
* - If an array is supplied as the first parameter, multiple values are returned
* as an object with values for each given attribute
* @function module:jQueryAttr.jQueryAttr
* @param {external:jQuery} $ The jQuery object to which to add the plug-in
* @returns {external:jQuery}
*/
export default function ($) {
const proxied = $.fn.attr,
svgns = 'http://www.w3.org/2000/svg';
/**
* @typedef {PlainObject.<string, string|Float>} module:jQueryAttr.Attributes
*/
/**
* @function external:jQuery.fn.attr
* @param {string|string[]|PlainObject.<string, string>} key
* @param {string} value
* @returns {external:jQuery|module:jQueryAttr.Attributes}
*/
$.fn.attr = function (key, value) {
const len = this.length;
if (!len) { return proxied.apply(this, arguments); }
@@ -46,8 +58,8 @@ export default function ($) {
}
if (typeof key === 'object') {
// Setting attributes from object
for (const v in key) {
elem.setAttribute(v, key[v]);
for (const [name, val] of Object.entries(key)) {
elem.setAttribute(name, val);
}
// Getting attribute
} else {

View File

@@ -3,51 +3,32 @@
*
* jQuery Plugin for a gradient picker
*
* Copyright (c) 2010 Jeff Schiller
* http://blog.codedread.com/
* Copyright (c) 2010 Alexis Deveria
* http://a.deveria.com/
* @module jGraduate
* @copyright 2010 Jeff Schiller {@link http://blog.codedread.com/}, 2010 Alexis Deveria {@link http://a.deveria.com/}
*
* Apache 2 License
jGraduate(options, okCallback, cancelCallback)
where options is an object literal:
{
window: { title: 'Pick the start color and opacity for the gradient' },
images: { clientPath: 'images/' },
paint: a Paint object,
newstop: String of value "same", "inverse", "black" or "white"
OR object with one or both values {color: #Hex color, opac: number 0-1}
}
- the Paint object is:
Paint {
type: String, // one of "none", "solidColor", "linearGradient", "radialGradient"
alpha: Number representing opacity (0-100),
solidColor: String representing #RRGGBB hex of color,
linearGradient: object of interface SVGLinearGradientElement,
radialGradient: object of interface SVGRadialGradientElement,
}
$.jGraduate.Paint() -> constructs a 'none' color
$.jGraduate.Paint({copy: o}) -> creates a copy of the paint o
$.jGraduate.Paint({hex: '#rrggbb'}) -> creates a solid color paint with hex = "#rrggbb"
$.jGraduate.Paint({linearGradient: o, a: 50}) -> creates a linear gradient paint with opacity=0.5
$.jGraduate.Paint({radialGradient: o, a: 7}) -> creates a radial gradient paint with opacity=0.07
$.jGraduate.Paint({hex: '#rrggbb', linearGradient: o}) -> throws an exception?
- picker accepts the following object as input:
{
okCallback: function to call when Ok is pressed
cancelCallback: function to call when Cancel is pressed
paint: object describing the paint to display initially, if not set, then default to opaque white
}
- okCallback receives a Paint object
* @license Apache-2.0
* @example
* // The Paint object is described below.
* $.jGraduate.Paint() // constructs a 'none' color
* @example $.jGraduate.Paint({copy: o}) // creates a copy of the paint o
* @example $.jGraduate.Paint({hex: '#rrggbb'}) // creates a solid color paint with hex = "#rrggbb"
* @example $.jGraduate.Paint({linearGradient: o, a: 50}) // creates a linear gradient paint with opacity=0.5
* @example $.jGraduate.Paint({radialGradient: o, a: 7}) // creates a radial gradient paint with opacity=0.07
* @example $.jGraduate.Paint({hex: '#rrggbb', linearGradient: o}) // throws an exception?
*
*/
/**
* The jQuery namespace.
* @external jQuery
*/
/**
* The jQuery plugin namespace.
* @namespace {PlainObject} fn
* @memberof external:jQuery
* @see {@link http://learn.jquery.com/plugins/|jQuery Plugins}
*/
const ns = {
svg: 'http://www.w3.org/2000/svg',
xlink: 'http://www.w3.org/1999/xlink'
@@ -60,24 +41,68 @@ if (!window.console) {
};
}
/**
* Adds {@link external:jQuery.jGraduate.Paint}, {@link external:jQuery.fn.jGraduateDefaults}, {@link external:jQuery.fn.jGraduate}
* @function module:jGraduate.jGraduate
* @param {external:jQuery} $ The jQuery instance to wrap
* @returns {external:jQuery}
*/
export default function ($) {
if (!$.loadingStylesheets) {
$.loadingStylesheets = [];
}
const stylesheet = 'jgraduate/css/jgraduate.css';
const stylesheet = 'jgraduate/css/jGraduate.css';
if (!$.loadingStylesheets.includes(stylesheet)) {
$.loadingStylesheets.push(stylesheet);
}
$.jGraduate = {
Paint: function (opt) {
/**
* @typedef {PlainObject} module:jGraduate.jGraduatePaintOptions
* @param {Float} [alpha]
* @param {module:jGraduate~Paint} [copy] Copy paint object
* @param {SVGLinearGradientElement} [linearGradient]
* @param {SVGRadialGradientElement} [radialGradient]
* @param {string} [solidColor]
*/
/**
* @memberof module:jGraduate~
*/
class Paint {
/**
* @param {module:jGraduate.jGraduatePaintOptions} [opt]
*/
constructor (opt) {
const options = opt || {};
this.alpha = isNaN(options.alpha) ? 100 : options.alpha;
// copy paint object
if (options.copy) {
/**
* @name module:jGraduate~Paint#type
* @type {"none"|"solidColor"|"linearGradient"|"radialGradient"}
*/
this.type = options.copy.type;
/**
* Represents opacity (0-100)
* @name module:jGraduate~Paint#alpha
* @type {Float}
*/
this.alpha = options.copy.alpha;
/**
* Represents #RRGGBB hex of color
* @name module:jGraduate~Paint#solidColor
* @type {string}
*/
this.solidColor = null;
/**
* @name module:jGraduate~Paint#linearGradient
* @type {SVGLinearGradientElement}
*/
this.linearGradient = null;
/**
* @name module:jGraduate~Paint#radialGradient
* @type {SVGRadialGradientElement}
*/
this.radialGradient = null;
switch (this.type) {
@@ -117,16 +142,56 @@ export default function ($) {
this.radialGradient = null;
}
}
}
/**
* @namespace {PlainObject} jGraduate
* @memberof external:jQuery
*/
$.jGraduate = /** @lends external:jQuery.jGraduate */ {
/**
* @class external:jQuery.jGraduate.Paint
* @see module:jGraduate~Paint
*/
Paint
};
$.fn.jGraduateDefaults = {
// JSDoc doesn't show this as belonging to our `module:jGraduate.Options` type,
// so we use `@see`
/**
* @namespace {module:jGraduate.Options} jGraduateDefaults
* @memberof external:jQuery.fn
*/
$.fn.jGraduateDefaults = /** @lends external:jQuery.fn.jGraduateDefaults */ {
/**
* Creates an object with a 'none' color
* @type {external:jQuery.jGraduate.Paint}
* @see module:jGraduate.Options
*/
paint: new $.jGraduate.Paint(),
/**
* @namespace
*/
window: {
/**
* @type {string}
* @see module:jGraduate.Options
*/
pickerTitle: 'Drag markers to pick a paint'
},
/**
* @namespace
*/
images: {
/**
* @type {string}
* @see module:jGraduate.Options
*/
clientPath: 'images/'
},
/**
* @type {string}
* @see module:jGraduate.Options
*/
newstop: 'inverse' // same, inverse, black, white
};
@@ -156,11 +221,42 @@ export default function ($) {
return elem;
}
$.fn.jGraduate = function (options) {
const $arguments = arguments;
/**
* @typedef {PlainObject} module:jGraduate.ColorOpac Object may have one or both values
* @property {string} [color] #Hex color
* @property {Float} [opac] 0-1
*/
/**
* @typedef {PlainObject} module:jGraduate.Options
* @property {module:jGraduate~Paint} [paint] A Paint object object describing the paint to display initially; defaults to a new instance without options (defaults to opaque white)
* @property {external:Window} [window]
* @property {string} [window.pickerTitle='Drag markers to pick a paint']
* @property {PlainObject} [images]
* @property {string} [images.clientPath='images/']
* @property {"same"|"inverse"|"black"|"white"|module:jGraduate.ColorOpac} [newstop="inverse"]
*/
/**
* @callback external:jQuery.fn.jGraduate.OkCallback
* @param {external:jQuery.jGraduate.Paint} paint
* @returns {undefined}
*/
/**
* @callback external:jQuery.fn.jGraduate.CancelCallback
* @returns {undefined}
*/
/**
* @function external:jQuery.fn.jGraduate
* @param {module:jGraduate.Options} [options]
* @param {external:jQuery.fn.jGraduate.OkCallback} [okCallback] Called with a Paint object when Ok is pressed
* @param {external:jQuery.fn.jGraduate.CancelCallback} [cancelCallback] Called with no arguments when Cancel is pressed
* @returns {external:jQuery}
*/
$.fn.jGraduate = function (options, okCallback, cancelCallback) {
return this.each(function () {
const $this = $(this),
$settings = $.extend(true, {}, $.fn.jGraduateDefaults, options),
$settings = $.extend(true, {}, $.fn.jGraduateDefaults, options || {}),
id = $this.attr('id'),
idref = '#' + $this.attr('id') + ' ';
@@ -192,8 +288,8 @@ export default function ($) {
$.extend(true, $this, { // public properties, methods, and callbacks
// make a copy of the incoming paint
paint: new $.jGraduate.Paint({copy: $settings.paint}),
okCallback: (typeof $arguments[1] === 'function' && $arguments[1]) || null,
cancelCallback: (typeof $arguments[2] === 'function' && $arguments[2]) || null
okCallback: typeof okCallback === 'function' ? okCallback : null,
cancelCallback: typeof cancelCallback === 'function' ? cancelCallback : null
});
let // pos = $this.position(),
@@ -201,7 +297,7 @@ export default function ($) {
const $win = $(window);
if ($this.paint.type === 'none') {
$this.paint = $.jGraduate.Paint({solidColor: 'ffffff'});
$this.paint = new $.jGraduate.Paint({solidColor: 'ffffff'});
}
$this.addClass('jGraduate_Picker');

View File

@@ -1,35 +1,68 @@
/*
/**
* jPicker (Adapted from version 1.1.6)
*
* jQuery Plugin for Photoshop style color picker
*
* Copyright (c) 2010 Christopher T. Tillman
* Digital Magic Productions, Inc. (http://www.digitalmagicpro.com/)
* MIT style license, FREE to use, alter, copy, sell, and especially ENHANCE
* @module jPicker
* @copyright (c) 2010 Christopher T. Tillman
* Digital Magic Productions, Inc. ({@link http://www.digitalmagicpro.com/})
* FREE to use, alter, copy, sell, and especially ENHANCE
* @license MIT
*
* Painstakingly ported from John Dyers' excellent work on his own color picker based on the Prototype framework.
*
* John Dyers' website: (http://johndyer.name)
* Color Picker page: (http://johndyer.name/post/2007/09/PhotoShop-like-JavaScript-Color-Picker.aspx)
*
* John Dyers' website: {@link http://johndyer.name}
* Color Picker page: {@link http://johndyer.name/photoshop-like-javascript-color-picker/}
*/
/**
* @external Math
*/
/**
* @memberof external:Math
* @param {Float} value
* @param {Float} precision
* @returns {Float}
*/
Math.precision = function (value, precision) {
if (precision === undefined) precision = 0;
return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision);
};
/**
* @function module:jPicker.jPicker
* @param {external:jQuery} $ The jQuery object to wrap (with {@link external:jQuery.loadingStylesheets}, {@link external:jQuery.fn.$.fn.jPicker}, {@link external:jQuery.fn.$.fn.jPicker.defaults})
* @returns {external:jQuery}
*/
const jPicker = function ($) {
if (!$.loadingStylesheets) {
/**
* @name loadingStylesheets
* @type {string[]}
* @memberof external:jQuery
*/
$.loadingStylesheets = [];
}
const stylesheet = 'jgraduate/css/jPicker.css';
if (!$.loadingStylesheets.includes(stylesheet)) {
$.loadingStylesheets.push(stylesheet);
}
/**
* @typedef {PlainObject} module:jPicker.SliderOptions
* @property {external:jQuery|PlainObject} arrow
* @property {string} arrow.image Not in use?
* @property {Float} arrow.width
* @property {Float} arrow.height
* @property {PlainObject} map
* @property {Float} map.width
* @property {Float} map.height
*/
/**
* Encapsulate slider functionality for the ColorMap and ColorBar -
* could be useful to use a jQuery UI draggable for this with certain extensions
* @param {external:jQuery} bar
* @param {module:jPicker.SliderOptions} options
*/
function Slider (bar, options) {
const $this = this;
@@ -506,261 +539,309 @@ const jPicker = function ($) {
color.bind(colorChanged);
}
$.jPicker = {
List: [], // array holding references to each active instance of the control
// color object - we will be able to assign by any color space type or retrieve any color space info
// we want this public so we can optionally assign new color objects to initial values using inputs other than a string hex value (also supported)
Color: class {
constructor (init) {
const $this = this;
function fireChangeEvents (context) {
for (let i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context);
}
function val (name, value, context) {
// Kind of ugly
const set = Boolean(value);
if (set && value.ahex === '') value.ahex = '00000000';
if (!set) {
if (name === undefined || name == null || name === '') name = 'all';
if (r == null) return null;
switch (name.toLowerCase()) {
case 'ahex': return ColorMethods.rgbaToHex({ r, g, b, a });
case 'hex': return val('ahex').substring(0, 6);
case 'all': return { r, g, b, a, h, s, v, hex: val.call($this, 'hex'), ahex: val.call($this, 'ahex') };
default:
let ret = {};
for (let i = 0; i < name.length; i++) {
switch (name.charAt(i)) {
case 'r':
if (name.length === 1) ret = r;
else ret.r = r;
break;
case 'g':
if (name.length === 1) ret = g;
else ret.g = g;
break;
case 'b':
if (name.length === 1) ret = b;
else ret.b = b;
break;
case 'a':
if (name.length === 1) ret = a;
else ret.a = a;
break;
case 'h':
if (name.length === 1) ret = h;
else ret.h = h;
break;
case 's':
if (name.length === 1) ret = s;
else ret.s = s;
break;
case 'v':
if (name.length === 1) ret = v;
else ret.v = v;
break;
}
}
return !name.length ? val.call($this, 'all') : ret;
}
}
if (context != null && context === $this) return;
if (name == null) name = '';
/**
* @typedef {PlainObject} module:jPicker.JPickerInit
* @property {Integer} a
* @property {Integer} b
* @property {Integer} g
* @property {Integer} h
* @property {Integer} r
* @property {Integer} s
* @property {Integer} v
* @property {string} hex
* @property {string} ahex
*/
let changed = false;
if (value == null) {
if (r != null) {
r = null;
changed = true;
}
if (g != null) {
g = null;
changed = true;
}
if (b != null) {
b = null;
changed = true;
}
if (a != null) {
a = null;
changed = true;
}
if (h != null) {
h = null;
changed = true;
}
if (s != null) {
s = null;
changed = true;
}
if (v != null) {
v = null;
changed = true;
}
changed && fireChangeEvents.call($this, context || $this);
return;
}
/**
* @namespace {PlainObject} jPicker
* @memberof external:jQuery
*/
$.jPicker = /** @lends external:jQuery.jPicker */ {
/**
* Array holding references to each active instance of the jPicker control
* @type {external:jQuery.fn.$.fn.jPicker[]}
*/
List: [],
/**
* Color object - we will be able to assign by any color space type or
* retrieve any color space info.
* We want this public so we can optionally assign new color objects to
* initial values using inputs other than a string hex value (also supported)
* Note: JSDoc didn't document when expressed here as an ES6 Class.
* @namespace
* @class
* @memberof external:jQuery.jPicker
* @param {module:jPicker.JPickerInit} init
*/
Color: function (init) {
const $this = this;
function fireChangeEvents (context) {
for (let i = 0; i < changeEvents.length; i++) changeEvents[i].call($this, $this, context);
}
function val (name, value, context) {
// Kind of ugly
const set = Boolean(value);
if (set && value.ahex === '') value.ahex = '00000000';
if (!set) {
if (name === undefined || name == null || name === '') name = 'all';
if (r == null) return null;
switch (name.toLowerCase()) {
case 'ahex':
case 'hex':
const ret = ColorMethods.hexToRgba((value && (value.ahex || value.hex)) || value || 'none');
val.call($this, 'rgba', { r: ret.r, g: ret.g, b: ret.b, a: name === 'ahex' ? ret.a : a != null ? a : 255 }, context);
break;
case 'ahex': return ColorMethods.rgbaToHex({ r, g, b, a });
case 'hex': return val('ahex').substring(0, 6);
case 'all': return { r, g, b, a, h, s, v, hex: val.call($this, 'hex'), ahex: val.call($this, 'ahex') };
default:
if (value && (value.ahex != null || value.hex != null)) {
val.call($this, 'ahex', value.ahex || value.hex || '00000000', context);
return;
}
const newV = {};
let rgb = false, hsv = false;
if (value.r !== undefined && !name.includes('r')) name += 'r';
if (value.g !== undefined && !name.includes('g')) name += 'g';
if (value.b !== undefined && !name.includes('b')) name += 'b';
if (value.a !== undefined && !name.includes('a')) name += 'a';
if (value.h !== undefined && !name.includes('h')) name += 'h';
if (value.s !== undefined && !name.includes('s')) name += 's';
if (value.v !== undefined && !name.includes('v')) name += 'v';
let ret = {};
for (let i = 0; i < name.length; i++) {
switch (name.charAt(i)) {
case 'r':
if (hsv) continue;
rgb = true;
newV.r = (value && value.r && value.r | 0) || (value && value | 0) || 0;
if (newV.r < 0) newV.r = 0;
else if (newV.r > 255) newV.r = 255;
if (r !== newV.r) {
({r} = newV);
changed = true;
}
if (name.length === 1) ret = r;
else ret.r = r;
break;
case 'g':
if (hsv) continue;
rgb = true;
newV.g = (value && value.g && value.g | 0) || (value && value | 0) || 0;
if (newV.g < 0) newV.g = 0;
else if (newV.g > 255) newV.g = 255;
if (g !== newV.g) {
({g} = newV);
changed = true;
}
if (name.length === 1) ret = g;
else ret.g = g;
break;
case 'b':
if (hsv) continue;
rgb = true;
newV.b = (value && value.b && value.b | 0) || (value && value | 0) || 0;
if (newV.b < 0) newV.b = 0;
else if (newV.b > 255) newV.b = 255;
if (b !== newV.b) {
({b} = newV);
changed = true;
}
if (name.length === 1) ret = b;
else ret.b = b;
break;
case 'a':
newV.a = value && value.a != null ? value.a | 0 : value != null ? value | 0 : 255;
if (newV.a < 0) newV.a = 0;
else if (newV.a > 255) newV.a = 255;
if (a !== newV.a) {
({a} = newV);
changed = true;
}
if (name.length === 1) ret = a;
else ret.a = a;
break;
case 'h':
if (rgb) continue;
hsv = true;
newV.h = (value && value.h && value.h | 0) || (value && value | 0) || 0;
if (newV.h < 0) newV.h = 0;
else if (newV.h > 360) newV.h = 360;
if (h !== newV.h) {
({h} = newV);
changed = true;
}
if (name.length === 1) ret = h;
else ret.h = h;
break;
case 's':
if (rgb) continue;
hsv = true;
newV.s = value && value.s != null ? value.s | 0 : value != null ? value | 0 : 100;
if (newV.s < 0) newV.s = 0;
else if (newV.s > 100) newV.s = 100;
if (s !== newV.s) {
({s} = newV);
changed = true;
}
if (name.length === 1) ret = s;
else ret.s = s;
break;
case 'v':
if (rgb) continue;
hsv = true;
newV.v = value && value.v != null ? value.v | 0 : value != null ? value | 0 : 100;
if (newV.v < 0) newV.v = 0;
else if (newV.v > 100) newV.v = 100;
if (v !== newV.v) {
({v} = newV);
changed = true;
}
if (name.length === 1) ret = v;
else ret.v = v;
break;
}
}
if (changed) {
if (rgb) {
r = r || 0;
g = g || 0;
b = b || 0;
const ret = ColorMethods.rgbToHsv({ r, g, b });
({h, s, v} = ret);
} else if (hsv) {
h = h || 0;
s = s != null ? s : 100;
v = v != null ? v : 100;
const ret = ColorMethods.hsvToRgb({ h, s, v });
({r, g, b} = ret);
}
a = a != null ? a : 255;
fireChangeEvents.call($this, context || $this);
}
break;
return !name.length ? val.call($this, 'all') : ret;
}
}
function bind (callback) {
if (typeof callback === 'function') changeEvents.push(callback);
}
function unbind (callback) {
if (typeof callback !== 'function') return;
let i;
while ((i = changeEvents.includes(callback))) {
changeEvents.splice(i, 1);
}
}
function destroy () {
changeEvents = null;
}
let r, g, b, a, h, s, v, changeEvents = [];
if (context != null && context === $this) return;
if (name == null) name = '';
$.extend(true, $this, {
// public properties and methods
val,
bind,
unbind,
destroy
});
if (init) {
if (init.ahex != null) {
val('ahex', init);
} else if (init.hex != null) {
val(
(init.a != null ? 'a' : '') + 'hex',
init.a != null
? {ahex: init.hex + ColorMethods.intToHex(init.a)}
: init
);
} else if (init.r != null && init.g != null && init.b != null) {
val('rgb' + (init.a != null ? 'a' : ''), init);
} else if (init.h != null && init.s != null && init.v != null) {
val('hsv' + (init.a != null ? 'a' : ''), init);
let changed = false;
if (value == null) {
if (r != null) {
r = null;
changed = true;
}
if (g != null) {
g = null;
changed = true;
}
if (b != null) {
b = null;
changed = true;
}
if (a != null) {
a = null;
changed = true;
}
if (h != null) {
h = null;
changed = true;
}
if (s != null) {
s = null;
changed = true;
}
if (v != null) {
v = null;
changed = true;
}
changed && fireChangeEvents.call($this, context || $this);
return;
}
switch (name.toLowerCase()) {
case 'ahex':
case 'hex':
const ret = ColorMethods.hexToRgba((value && (value.ahex || value.hex)) || value || 'none');
val.call($this, 'rgba', { r: ret.r, g: ret.g, b: ret.b, a: name === 'ahex' ? ret.a : a != null ? a : 255 }, context);
break;
default:
if (value && (value.ahex != null || value.hex != null)) {
val.call($this, 'ahex', value.ahex || value.hex || '00000000', context);
return;
}
const newV = {};
let rgb = false, hsv = false;
if (value.r !== undefined && !name.includes('r')) name += 'r';
if (value.g !== undefined && !name.includes('g')) name += 'g';
if (value.b !== undefined && !name.includes('b')) name += 'b';
if (value.a !== undefined && !name.includes('a')) name += 'a';
if (value.h !== undefined && !name.includes('h')) name += 'h';
if (value.s !== undefined && !name.includes('s')) name += 's';
if (value.v !== undefined && !name.includes('v')) name += 'v';
for (let i = 0; i < name.length; i++) {
switch (name.charAt(i)) {
case 'r':
if (hsv) continue;
rgb = true;
newV.r = (value && value.r && value.r | 0) || (value && value | 0) || 0;
if (newV.r < 0) newV.r = 0;
else if (newV.r > 255) newV.r = 255;
if (r !== newV.r) {
({r} = newV);
changed = true;
}
break;
case 'g':
if (hsv) continue;
rgb = true;
newV.g = (value && value.g && value.g | 0) || (value && value | 0) || 0;
if (newV.g < 0) newV.g = 0;
else if (newV.g > 255) newV.g = 255;
if (g !== newV.g) {
({g} = newV);
changed = true;
}
break;
case 'b':
if (hsv) continue;
rgb = true;
newV.b = (value && value.b && value.b | 0) || (value && value | 0) || 0;
if (newV.b < 0) newV.b = 0;
else if (newV.b > 255) newV.b = 255;
if (b !== newV.b) {
({b} = newV);
changed = true;
}
break;
case 'a':
newV.a = value && value.a != null ? value.a | 0 : value != null ? value | 0 : 255;
if (newV.a < 0) newV.a = 0;
else if (newV.a > 255) newV.a = 255;
if (a !== newV.a) {
({a} = newV);
changed = true;
}
break;
case 'h':
if (rgb) continue;
hsv = true;
newV.h = (value && value.h && value.h | 0) || (value && value | 0) || 0;
if (newV.h < 0) newV.h = 0;
else if (newV.h > 360) newV.h = 360;
if (h !== newV.h) {
({h} = newV);
changed = true;
}
break;
case 's':
if (rgb) continue;
hsv = true;
newV.s = value && value.s != null ? value.s | 0 : value != null ? value | 0 : 100;
if (newV.s < 0) newV.s = 0;
else if (newV.s > 100) newV.s = 100;
if (s !== newV.s) {
({s} = newV);
changed = true;
}
break;
case 'v':
if (rgb) continue;
hsv = true;
newV.v = value && value.v != null ? value.v | 0 : value != null ? value | 0 : 100;
if (newV.v < 0) newV.v = 0;
else if (newV.v > 100) newV.v = 100;
if (v !== newV.v) {
({v} = newV);
changed = true;
}
break;
}
}
if (changed) {
if (rgb) {
r = r || 0;
g = g || 0;
b = b || 0;
const ret = ColorMethods.rgbToHsv({ r, g, b });
({h, s, v} = ret);
} else if (hsv) {
h = h || 0;
s = s != null ? s : 100;
v = v != null ? v : 100;
const ret = ColorMethods.hsvToRgb({ h, s, v });
({r, g, b} = ret);
}
a = a != null ? a : 255;
fireChangeEvents.call($this, context || $this);
}
break;
}
}
function bind (callback) {
if (typeof callback === 'function') changeEvents.push(callback);
}
function unbind (callback) {
if (typeof callback !== 'function') return;
let i;
while ((i = changeEvents.includes(callback))) {
changeEvents.splice(i, 1);
}
}
function destroy () {
changeEvents = null;
}
let r, g, b, a, h, s, v, changeEvents = [];
$.extend(true, $this, {
// public properties and methods
val,
bind,
unbind,
destroy
});
if (init) {
if (init.ahex != null) {
val('ahex', init);
} else if (init.hex != null) {
val(
(init.a != null ? 'a' : '') + 'hex',
init.a != null
? {ahex: init.hex + ColorMethods.intToHex(init.a)}
: init
);
} else if (init.r != null && init.g != null && init.b != null) {
val('rgb' + (init.a != null ? 'a' : ''), init);
} else if (init.h != null && init.s != null && init.v != null) {
val('hsv' + (init.a != null ? 'a' : ''), init);
}
}
},
// color conversion methods - make public to give use to external scripts
/**
* color conversion methods - make public to give use to external scripts
* @namespace
*/
ColorMethods: {
/**
* @typedef {PlainObject} module:jPicker.RGBA
* @property {Integer} r
* @property {Integer} g
* @property {Integer} b
* @property {Integer} a
*/
/**
* @typedef {PlainObject} module:jPicker.RGB
* @property {Integer} r
* @property {Integer} g
* @property {Integer} b
*/
/**
* @param {string} hex
* @returns {module:jPicker.RGBA}
*/
hexToRgba (hex) {
if (hex === '' || hex === 'none') return { r: null, g: null, b: null, a: null };
hex = this.validateHex(hex);
@@ -782,25 +863,53 @@ const jPicker = function ($) {
}
if (hex.length > 0) b = hex.substring(0, hex.length);
}
return { r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a) };
return {
r: this.hexToInt(r), g: this.hexToInt(g), b: this.hexToInt(b), a: this.hexToInt(a)
};
},
/**
* @param {string} hex
* @returns {string}
*/
validateHex (hex) {
// if (typeof hex === 'object') return '';
hex = hex.toLowerCase().replace(/[^a-f0-9]/g, '');
if (hex.length > 8) hex = hex.substring(0, 8);
return hex;
},
/**
* @param {module:jPicker.RGBA} rgba
* @returns {string}
*/
rgbaToHex (rgba) {
return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a);
},
/**
* @param {Integer} dec
* @returns {string}
*/
intToHex (dec) {
let result = (dec | 0).toString(16);
if (result.length === 1) result = ('0' + result);
return result.toLowerCase();
},
/**
* @param {string} hex
* @returns {Integer}
*/
hexToInt (hex) {
return parseInt(hex, 16);
},
/**
* @typedef {PlainObject} module:jPicker.HSV
* @property {Integer} h
* @property {Integer} s
* @property {Integer} v
*/
/**
* @param {module:jPicker.RGB} rgb
* @returns {module:jPicker.HSV}
*/
rgbToHsv (rgb) {
const r = rgb.r / 255, g = rgb.g / 255, b = rgb.b / 255, hsv = { h: 0, s: 0, v: 0 };
let min = 0, max = 0;
@@ -830,6 +939,10 @@ const jPicker = function ($) {
hsv.v = (hsv.v * 100) | 0;
return hsv;
},
/**
* @param {module:jPicker.HSV} hsv
* @returns {module:jPicker.RGB}
*/
hsvToRgb (hsv) {
const rgb = {r: 0, g: 0, b: 0, a: 100};
let {h, s, v} = hsv;
@@ -887,6 +1000,19 @@ const jPicker = function ($) {
}
};
const {Color, List, ColorMethods} = $.jPicker; // local copies for YUI compressor
/**
* @function external:jQuery.fn.jPicker
* @see {@link external:jQuery.fn.$.fn.jPicker}
*/
/**
* While it would seem this should specify the name `jPicker` for JSDoc, that doesn't
* get us treated as a function as well as a namespace (even with `@function name`),
* so we use an approach to add a redundant `$.fn.` in the name.
* @namespace
* @memberof external:jQuery.fn
* @param {external:jQuery.fn.jPickerOptions} options
* @returns {external:jQuery}
*/
$.fn.jPicker = function (options) {
const $arguments = arguments;
return this.each(function () {
@@ -914,6 +1040,11 @@ const jPicker = function ($) {
}
const isLessThanIE7 = parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; // needed to run the AlphaImageLoader function for IE6
// set color mode and update visuals for the new color mode
/**
*
* @param {"h"|"s"|"v"|"r"|"g"|"b"|"a"} colorMode [description]
* @throws {Error} Invalid mode
*/
function setColorMode (colorMode) {
const {active} = color, // local copies for YUI compressor
// {clientPath} = images,
@@ -1702,35 +1833,111 @@ const jPicker = function ($) {
});
};
/**
* @typedef {PlainObject} external:jQuery.fn.jPickerOptionsIconInfo
* @property {string} file Color Map/Color Bar/Color Picker arrow icon
* @property {Float} width
* @property {Float} height
*/
/**
* @typedef {PlainObject} external:jQuery.fn.jPickerOptionsImagesDimensionsArrow
* @property {Float} width
* @property {Float} height
* @property {external:jQuery.fn.jPickerOptionsIconInfo} arrow
*/
/**
* @typedef {PlainObject} external:jQuery.fn.jPickerOptionsRadioTextboxLocale
* @property {string} radio
* @property {string} textbox
*/
/**
* @typedef {PlainObject} external:jQuery.fn.jPickerOptions
* @property {PlainObject} window
* @property {string|null} window.title Any title for the jPicker window itself - displays
* "Drag Markers To Pick A Color" if left null
* @property {PlainObject} window.effects
* @property {"slide"|"show"|"fade"} window.effects.type Effect used to show/hide an expandable picker
* @property {PlainObject} window.effects.speed
* @property {"fast"|"slow"|Float} window.effects.speed.show Duration of "show" effect. Time in milliseconds.
* @property {"fast"|"slow"|Float} window.effects.speed.hide Duration of "hide" effect. Time in milliseconds
* @property {PlainObject} window.position
* @property {"left"|"center"|"right"|"screenCenter"|Float} window.position.x Relative px value
* @property {"top"|"bottom"|"center"|Float} window.position.y Relative px value
* @property {boolean} window.expandable Defaults to large static picker - set to `true` to make an expandable
* picker (small icon with popup) - set automatically when binded to input element
* @property {boolean} window.liveUpdate Set `false` if you want the user to have to click "OK" before the
* binded input box updates values (always `true` for expandable picker)
* @property {boolean} window.alphaSupport Set to `true` to enable alpha picking
* @property {Float} window.alphaPrecision Set decimal precision for alpha percentage display - hex codes do
* not map directly to percentage integers - range 0-2
* @property {boolean} window.updateInputColor Set to `false` to prevent binded input colors from changing
* @property {PlainObject} color
* @property {"h"|"s"|"v"|"r"|"g"|"b"|"a"} color.mode Symbols stand for "h" (hue), "s" (saturation), "v" (value), "r" (red), "g" (green), "b" (blue), "a" (alpha)
* @property {Color|string} color.active Strings are HEX values (e.g. #ffc000) WITH OR WITHOUT the "#" prefix
* @property {Color[]|string[]} color.quickList The quick pick color list
* Strings are HEX values (e.g. #ffc000) WITH OR WITHOUT the "#" prefix
* @property {PlainObject} images
* @property {string} images.clientPath Path to image files
* @property {external:jQuery.fn.jPickerOptionsImagesDimensionsArrow} images.colorMap
* @property {external:jQuery.fn.jPickerOptionsImagesDimensionsArrow} images.colorBar
* @property {external:jQuery.fn.jPickerOptionsIconInfo} images.picker
* @property {PlainObject} localization alter these to change the text presented by the picker (e.g. different language)
* @property {PlainObject} localization.text
* @property {string} localization.text.title
* @property {string} localization.text.newColor
* @property {string} localization.text.currentColor
* @property {string} localization.text.ok
* @property {string} localization.text.cancel
* @property {PlainObject} localization.tooltips
* @property {PlainObject} localization.tooltips.colors
* @property {string} localization.tooltips.colors.newColor
* @property {string} localization.tooltips.colors.currentColor
* @property {PlainObject} localization.tooltips.buttons
* @property {string} localization.tooltips.buttons.ok
* @property {string} localization.tooltips.buttons.cancel
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.hue
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.saturation
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.value
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.red
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.green
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.blue
* @property {external:jQuery.fn.jPickerOptionsRadioTextboxLocale} localization.tooltips.alpha
* @property {PlainObject} localization.tooltips.hex
* @property {string} localization.tooltips.hex.textbox
* @property {string} localization.tooltips.hex.alpha
*/
/**
* jPicker defaults - you can change anything in this section (such as the
* clientPath to your images) without fear of breaking the program
* @namespace {external:jQuery.fn.jPickerOptions} defaults
* @memberof external:jQuery.fn.$.fn.jPicker
* @borrows external:jQuery.fn.jPickerOptions as external:jQuery.fn.jPicker.defaults
* @see Source for all of the values
*/
$.fn.jPicker.defaults = {
window: {
title: null, /* any title for the jPicker window itself - displays "Drag Markers To Pick A Color" if left null */
title: null,
effects: {
type: 'slide', /* effect used to show/hide an expandable picker. Acceptable values "slide", "show", "fade" */
type: 'slide',
speed: {
show: 'slow', /* duration of "show" effect. Acceptable values are "fast", "slow", or time in ms */
hide: 'fast' /* duration of "hide" effect. Acceptable values are "fast", "slow", or time in ms */
show: 'slow',
hide: 'fast'
}
},
position: {
x: 'screenCenter', /* acceptable values "left", "center", "right", "screenCenter", or relative px value */
y: 'top' /* acceptable values "top", "bottom", "center", or relative px value */
x: 'screenCenter',
y: 'top'
},
expandable: false, /* default to large static picker - set to true to make an expandable picker (small icon with popup) - set automatically when binded to input element */
liveUpdate: true, /* set false if you want the user to have to click "OK" before the binded input box updates values (always "true" for expandable picker) */
alphaSupport: false, /* set to true to enable alpha picking */
alphaPrecision: 0, /* set decimal precision for alpha percentage display - hex codes do not map directly to percentage integers - range 0-2 */
updateInputColor: true /* set to false to prevent binded input colors from changing */
expandable: false,
liveUpdate: true,
alphaSupport: false,
alphaPrecision: 0,
updateInputColor: true
},
color: {
mode: 'h', /* acceptabled values "h" (hue), "s" (saturation), "v" (value), "r" (red), "g" (green), "b" (blue), "a" (alpha) */
active: new Color({ahex: '#ffcc00ff'}), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) WITH OR WITHOUT the "#" prefix */
// the quick pick color list
mode: 'h',
active: new Color({ahex: '#ffcc00ff'}),
quickList: [
new Color({ h: 360, s: 33, v: 100 }), /* acceptable values are any declared $.jPicker.Color object or string HEX value (e.g. #ffc000) WITH OR WITHOUT the "#" prefix */
new Color({ h: 360, s: 33, v: 100 }),
new Color({ h: 360, s: 66, v: 100 }),
new Color({ h: 360, s: 100, v: 100 }),
new Color({ h: 360, s: 100, v: 75 }),
@@ -1805,12 +2012,12 @@ const jPicker = function ($) {
]
},
images: {
clientPath: '/jPicker/images/', /* Path to image files */
clientPath: '/jPicker/images/',
colorMap: {
width: 256,
height: 256,
arrow: {
file: 'mappoint.gif', /* ColorMap arrow icon */
file: 'mappoint.gif',
width: 15,
height: 15
}
@@ -1819,18 +2026,17 @@ const jPicker = function ($) {
width: 20,
height: 256,
arrow: {
file: 'rangearrows.gif', /* ColorBar arrow icon */
file: 'rangearrows.gif',
width: 20,
height: 7
}
},
picker: {
file: 'picker.gif', /* Color Picker icon */
file: 'picker.gif',
width: 25,
height: 24
}
},
// alter these to change the text presented by the picker (e.g. different language) */
localization: {
text: {
title: 'Drag Markers To Pick A Color',

View File

@@ -1,13 +1,14 @@
/* globals jQuery */
/**
* Licensed under the MIT License
* Provides tools for the layer concept
* @module layer
* @license MIT
*
* Copyright(c) 2011 Jeff Schiller
* Copyright(c) 2016 Flint O'Brien
* @copyright 2011 Jeff Schiller, 2016 Flint O'Brien
*/
import {NS} from './svgedit.js';
import {toXml, walkTree} from './svgutils.js';
import {NS} from './namespaces.js';
import {toXml, walkTree} from './utilities.js';
const $ = jQuery;
@@ -15,20 +16,22 @@ const $ = jQuery;
* This class encapsulates the concept of a layer in the drawing. It can be constructed with
* an existing group element or, with three parameters, will create a new layer group element.
*
* Usage:
* new Layer'name', group) // Use the existing group for this layer.
* new Layer('name', group, svgElem) // Create a new group and add it to the DOM after group.
* new Layer('name', null, svgElem) // Create a new group and add it to the DOM as the last layer.
*
* @param {string} name - Layer name
* @param {SVGGElement|null} group - An existing SVG group element or null.
* If group and no svgElem, use group for this layer.
* If group and svgElem, create a new group element and insert it in the DOM after group.
* If no group and svgElem, create a new group element and insert it in the DOM as the last layer.
* @param {SVGGElement=} svgElem - The SVG DOM element. If defined, use this to add
* a new layer to the document.
* @example
* new Layer('name', group); // Use the existing group for this layer.
* new Layer('name', group, svgElem); // Create a new group and add it to the DOM after group.
* new Layer('name', null, svgElem); // Create a new group and add it to the DOM as the last layer.
* @memberof module:layer
*/
class Layer {
/**
* @param {string} name - Layer name
* @param {SVGGElement|null} group - An existing SVG group element or null.
* If group and no svgElem, use group for this layer.
* If group and svgElem, create a new group element and insert it in the DOM after group.
* If no group and svgElem, create a new group element and insert it in the DOM as the last layer.
* @param {SVGGElement=} svgElem - The SVG DOM element. If defined, use this to add
* a new layer to the document.
*/
constructor (name, group, svgElem) {
this.name_ = name;
this.group_ = svgElem ? null : group;
@@ -73,6 +76,7 @@ class Layer {
/**
* Active this layer so it takes pointer events.
* @returns {undefined}
*/
activate () {
this.group_.setAttribute('style', 'pointer-events:all');
@@ -80,6 +84,7 @@ class Layer {
/**
* Deactive this layer so it does NOT take pointer events.
* @returns {undefined}
*/
deactivate () {
this.group_.setAttribute('style', 'pointer-events:none');
@@ -88,6 +93,7 @@ class Layer {
/**
* Set this layer visible or hidden based on 'visible' parameter.
* @param {boolean} visible - If true, make visible; otherwise, hide it.
* @returns {undefined}
*/
setVisible (visible) {
const expected = visible === undefined || visible ? 'inline' : 'none';
@@ -107,7 +113,7 @@ class Layer {
/**
* Get layer opacity.
* @returns {number} Opacity value.
* @returns {Float} Opacity value.
*/
getOpacity () {
const opacity = this.group_.getAttribute('opacity');
@@ -120,7 +126,8 @@ class Layer {
/**
* Sets the opacity of this layer. If opacity is not a value between 0.0 and 1.0,
* nothing happens.
* @param {number} opacity - A float value in the range 0.0-1.0
* @param {Float} opacity - A float value in the range 0.0-1.0
* @returns {undefined}
*/
setOpacity (opacity) {
if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) {
@@ -131,6 +138,7 @@ class Layer {
/**
* Append children to this layer.
* @param {SVGGElement} children - The children to append to this layer.
* @returns {undefined}
*/
appendChildren (children) {
for (let i = 0; i < children.length; ++i) {
@@ -138,6 +146,9 @@ class Layer {
}
}
/**
* @returns {SVGTitleElement|null}
*/
getTitleElement () {
const len = this.group_.childNodes.length;
for (let i = 0; i < len; ++i) {
@@ -152,7 +163,7 @@ class Layer {
/**
* Set the name of this layer.
* @param {string} name - The new name.
* @param {svgedit.history.HistoryRecordingService} hrService - History recording service
* @param {module:history.HistoryRecordingService} hrService - History recording service
* @returns {string|null} The new name if changed; otherwise, null.
*/
setName (name, hrService) {
@@ -195,10 +206,10 @@ Layer.CLASS_NAME = 'layer';
Layer.CLASS_REGEX = new RegExp('(\\s|^)' + Layer.CLASS_NAME + '(\\s|$)');
/**
* Add class Layer.CLASS_NAME to the element (usually class='layer').
* Add class `Layer.CLASS_NAME` to the element (usually `class='layer'`).
*
* Parameters:
* @param {SVGGElement} elem - The SVG element to update
* @returns {undefined}
*/
function addLayerClass (elem) {
const classes = elem.getAttribute('class');

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -108,7 +108,6 @@ export default {
mode_circle: 'Circle',
mode_fhellipse: 'Free-Hand Ellipse',
mode_path: 'Path Tool',
mode_shapelib: 'Shape library',
mode_text: 'Text Tool',
mode_image: 'Image Tool',
mode_zoom: 'Zoom Tool [Ctrl+Up/Down]',
@@ -118,7 +117,6 @@ export default {
redo: 'Redo [Y]',
tool_source: 'Edit Source [U]',
wireframe_mode: 'Wireframe Mode [F]',
toggle_grid: 'Show/Hide Grid',
clone: 'Duplicate Element [D]',
del: 'Delete Element [Delete/Backspace]',
group_elements: 'Group Elements [G]',
@@ -188,22 +186,6 @@ export default {
snapping_stepsize: 'Snapping Step-Size:',
grid_color: 'Grid color:'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'Dialog balloons',
electronics: 'Electronics',
math: 'Mathematical',
music: 'Music',
misc: 'Miscellaneous',
raphael_1: 'raphaeljs.com set 1',
raphael_2: 'raphaeljs.com set 2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -105,7 +105,6 @@ export default {
mode_circle: '‫دایره‬',
mode_fhellipse: '‫بیضی با قابلیت تغییر پویا‬',
mode_path: '‫ابزار مسیر ',
mode_shapelib: 'Shape library',
mode_text: '‫ابزار متن ',
mode_image: '‫ابزار تصویر ',
mode_zoom: '‫ابزار بزرگ نمایی ',
@@ -115,7 +114,6 @@ export default {
redo: '‫ازنو ',
tool_source: '‫ویرایش منبع ',
wireframe_mode: '‫حالت نمایش لبه ها ',
toggle_grid: 'Show/Hide Grid',
clone: 'Clone Element(s)',
del: 'Delete Element(s)',
group_elements: '‫قرار دادن عناصر در گروه ',
@@ -185,22 +183,6 @@ export default {
snapping_stepsize: 'Snapping Step-Size:',
grid_color: 'Grid color'
},
shape_cats: {
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'
},
notification: {
invalidAttrValGiven: '‫مقدار داده شده نامعتبر است‬',
noContentToFitTo: '‫محتوایی برای هم اندازه شدن وجود ندارد‬',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: "Bibliothèque d'images",
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: "Pas d'ancrage :",
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: "Il n'y a pas de contenu auquel ajuster",

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: "Op 'e nij",
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: "Non c'è contenuto cui adeguarsi",

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -187,22 +184,6 @@ export default {
snapping_onoff: 'snapping_onoff',
snapping_stepsize: 'snapping_stepsize'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

View File

@@ -100,7 +100,6 @@ export default {
mode_select: 'mode_select',
mode_fhpath: 'mode_fhpath',
mode_line: 'mode_line',
mode_connect: 'mode_connect',
mode_rect: 'mode_rect',
mode_square: 'mode_square',
mode_fhrect: 'mode_fhrect',
@@ -108,7 +107,6 @@ export default {
mode_circle: 'mode_circle',
mode_fhellipse: 'mode_fhellipse',
mode_path: 'mode_path',
mode_shapelib: 'mode_shapelib',
mode_text: 'mode_text',
mode_image: 'mode_image',
mode_zoom: 'mode_zoom',
@@ -118,7 +116,6 @@ export default {
redo: 'redo',
tool_source: 'tool_source',
wireframe_mode: 'wireframe_mode',
toggle_grid: 'toggle_grid',
clone: 'clone',
del: 'del',
group_elements: 'group_elements',
@@ -188,22 +185,6 @@ export default {
snapping_stepsize: 'snapping_stepsize',
grid_color: 'grid_color'
},
shape_cats: {
basic: 'basic',
object: 'object',
symbol: 'symbol',
arrow: 'arrow',
flowchart: 'flowchart',
animal: 'animal',
game: 'game',
dialog_balloon: 'dialog_balloon',
electronics: 'electronics',
math: 'math',
music: 'music',
misc: 'misc',
raphael_1: 'raphael_1',
raphael_2: 'raphael_2'
},
notification: {
invalidAttrValGiven: 'Invalid value given',
noContentToFitTo: 'No content to fit to',

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