diff --git a/.eslintignore b/.eslintignore index 220ed876..88fc3369 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,7 +5,6 @@ docs/jsdoc svgedit-config-es.js svgedit-config-iife.js -svgedit-config-sample-iife.js svgedit-custom.css # Vendor/minified files diff --git a/.gitignore b/.gitignore index b1ecc5fe..3c2b54e9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,6 @@ node_modules build/ -# For examples, see -# svgedit-config-sample-es.js -# svgedit-config-sample-iife.js -svgedit-config-es.js -svgedit-config-iife.js - svgedit-custom.css docs/jsdoc diff --git a/CHANGES.md b/CHANGES.md index f4117ca2..eef73a8f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,37 @@ # ? +- 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: In interests of modularity/removing globals, remove `window.svgCanvas` and `svgCanvas.ready` as used by older extensions; use `svgEditor.canvas` and `svgEditor.ready` instead @@ -13,14 +45,19 @@ (`setStackBlurCanvasRGBA`) rather than global; `canvg` now a named export - Breaking change: Avoid passing `canvg`/`buildCanvgCallback` to extensions (have them import) +- Breaking change: Have `readLang` return lang and data but do not call + `setLang` - npm: Add `prepublishOnly` script to ensure building/testing before publish -- npm: Update devDep Rollup, Sinon +- npm: Update devDeps including Rollup, Sinon - Fix: Remove redundant (and incorrect) length set. (#256 ; fixes #255) - Fix: Detection of whether to keep ellipse (rx and ry when just created are now returning 0 instead of null); also with rectangle/square; fixes #262 - Fix: Avoid erring during resize on encountering MathML (which have no `style`) +- 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: i18nize imaglib more deeply - Fix: Positioning of Document Properties dialog (Fixes #246) - Fix (regression): PDF Export (Fixes #249) @@ -31,15 +68,37 @@ - Fix (embedded editor): Fix backspace key in Firefox so it doesn't navigate out of frame - Fix: Alert if no `exportWindow` for PDF (e.g., if blocked) +- Fix: Ensure call to `rasterExport` without `imgType` properly sets MIME + type to PNG +- Fix: Wrong name for moinsave - Fix (Embedded API): Cross-domain may fail to even access `origin` or `contentDocument` - Fix (Embedded API): Avoid adding URL to iframe src if there are no arguments - Fix (Cross-domain usage): Recover from exceptions with `localStorage` - Fix regression (Imagelib): Fix path for non-module version +- 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: Sort SVG attributes alphabetically (#252 @Neil Fraser) - Enhancement: Allow callback argument and return promise for canvas methods: `rasterExport` and `exportPDF` - Enhancement: Add `pointsAdded` canvas event (Fixes #141) +- 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 +- Enhancement: Allowing importing of locales within `addLangData` - i18n: Clarify locale messages (where still available as English) to reflect fact that Chrome only has "Save as" via context menu/right-click, not via file menu (toward #192) @@ -59,19 +118,55 @@ - Refactoring: Fix `lang` and `dir` for locales (though not in use currently anyways) - Refactoring: Provide path config for canvg, jspdf +- 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 - Refactoring (minor): variadic args through ellipsis - Refactoring (minor): `getIssues` to return codes and strings, lbs - Refactoring (minor): Use single quotes in PHP - Docs (Code comments): Coding standards within -- Docs: Move jsdoc output to public directory so may be visible on releases - (while still having in a `.gitignore`) -- Docs (JSDoc): Add items; fix table layout -- Docs: Exclusions from jsdoc - Docs: Transfer some changes from ExtensionDocs on wiki (need to fully reconcile) - Docs: Reference JSDocs in README - Docs (ReleaseInstructions): Update +- 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 were carried over + with absolute URLs +- 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 +- 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 +- npm/Docs (JSDoc): Add script to check for overly generic types +- Docs (JSDoc): Move jsdoc output to public directory so may be visible + on releases (while still having in a `.gitignore`) +- Docs (JSDoc): Exclusions +- Docs (JSDoc): Add items; fix table layout +- 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): Use Markdown plugin over HTML +- 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` - Linting (ESLint): Avoid linting jsdoc folder +- Testing: Use new Sinon # 3.0.0-alpha.4 @@ -333,7 +428,7 @@ git log 4bb15e0..253b4bf - Potentially breaking API changes: * Disallowed "extPath", "imgPath", "langPath", and "jGraduatePath" setting via URL and prevent cross-domain/cross-folder extensions being set by URL (security enhancement) * Deprecated "pngsave" option called by setCustomHandlers() in favor of "exportImage" (to accommodate export of other image types). Second argument will now supply, in addition to "issues" and "svg", the properties "type" (currently 'PNG', 'JPEG', 'BMP', 'WEBP'), "mimeType", and "quality" (for 'JPEG' and 'WEBP' types). - * Default extensions will now always load (along with those supplied in the URL unless the latter is prohibited by configuration), so if you do not wish your old code to load all of the default extensions, you will need to add &noDefaultExtensions=true to the URL (or add equivalent configuration in config.js). ext-overview_window.js can now be excluded though it is still a default. + * Default extensions will now always load (along with those supplied in the URL unless the latter is prohibited by configuration), so if you do not wish your old code to load all of the default extensions, you will need to add `&noDefaultExtensions=true` to the URL (or add equivalent configuration in config.js). ext-overview_window.js can now be excluded though it is still a default. * Preferences and configuration options must be within the list supplied within svg-editor.js (should include those of all documented extensions). * Embedded messaging will no longer work by default for privacy/data integrity reasons. One must include the "ext-xdomain-messaging.js" extension and supply an array configuration item, "allowedOrigins" with potential values including: "\*" (to allow all domains--strongly discouraged!), "null" as a string to allow file:// access, window.location.origin (to allow same domain access), or specific trusted origins. The embedded editor works without the extension if the main editor is on the same domain, but if cross-domain control is needed, the "allowedOrigins" array must be supplied by a call to svgEditor.setConfig({allowedOrigins: [origin1, origin2, etc.]}) in the new config.js file. @@ -357,7 +452,7 @@ git log 4bb15e0..253b4bf - Open Local Files (Firefox 3.6+ only) - Import SVG into Drawing (Firefox 3.6+ only) - Ability to create extensions/plugins -- Main menu and overal interface improvements +- Main menu and overall interface improvements - Create and select elements outside the canvas - Base support for the svg:use element - Add/Edit Sub-paths diff --git a/Makefile b/Makefile index ad18f3f0..3a50532d 100644 --- a/Makefile +++ b/Makefile @@ -8,15 +8,15 @@ ZIP=zip # All files that will be compiled by the Closure compiler. JS_FILES=\ - svgedit.js \ - jquery-svg.js \ - contextmenu/jquery.contextMenu.js \ - pathseg.js \ + namespaces.js \ + jQuery.attr.js \ + contextmenu/jQuery.contextMenu.js \ + svgpathseg.js \ browser.js \ svgtransformlist.js \ math.js \ units.js \ - svgutils.js \ + utilities.js \ sanitize.js \ history.js \ historyrecording.js \ @@ -93,7 +93,7 @@ chrome: cd build ; $(ZIP) -r $(PACKAGE)-crx.zip svgedit_app ; rm -rf svgedit_app; cd .. jgraduate: - java -jar $(CLOSURE) --js editor/jgraduate/jquery.jgraduate.js --js_output_file editor/jgraduate/jquery.jgraduate.min.js + java -jar $(CLOSURE) --js editor/jgraduate/jquery.jGraduate.js --js_output_file editor/jgraduate/jquery.jgraduate.min.js clean: rm -rf config rm -rf build/$(PACKAGE) diff --git a/README.md b/README.md index 02ba1bd8..b561a7fb 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,80 @@ # ![alt text](https://svg-edit.github.io/svgedit/images/logo48x48.svg "svg-edit logo of a pencil") SVG-edit -SVG-edit is a fast, web-based, javascript-driven SVG drawing editor that works in any modern browser. +SVG-edit is a fast, web-based, JavaScript-driven SVG drawing editor that +works in any modern browser. ## Demo -### [Try SVG-edit here](https://svg-edit.github.io/svgedit/releases/svg-edit-2.8.1/svg-editor.html) +### [Try SVG-edit here](https://svg-edit.github.io/svgedit/releases/latest/editor/svg-editor.html) -(Also available as a [download](https://github.com/SVG-Edit/svgedit/releases/download/svg-edit-2.8.1/svg-edit-2.8.1.zip) in [releases](https://github.com/SVG-Edit/svgedit/releases)). +(Also available as a download in [releases](https://github.com/SVG-Edit/svgedit/releases)). -You may also try the [pre-release](https://svg-edit.github.io/svgedit/releases/svg-edit-3.0.0-alpha.4/editor/svg-editor.html) (or the [ES6-Module](https://svg-edit.github.io/svgedit/releases/svg-edit-3.0.0-alpha.4/editor/svg-editor.html) version, assuming a modern browser). +You may also try the [pre-release](https://svg-edit.github.io/svgedit/releases/latest/editor/svg-editor.html) (or its [ES6-Module](https://svg-edit.github.io/svgedit/releases/latest/editor/svg-editor.html) version, assuming a modern browser). ## Installation -Note that steps 1-2 below are only necessary if you wish to integrate -SVG-edit into your own npm package; otherwise, you can skip those steps -and instead of looking within `node_modules/svgedit`, look within your -copy of the svgedit Git repo. +### Quick install -1. Set up an npm package of your own: `npm init` (complete the fields). -1. Install SVG-edit into your package: `npm i svgedit` -1. Copy `svgedit-config-sample-es.js` (in the SVG-edit project root; - see `node_modules/svgedit`) to `svgedit-config-es.js`. - 1. This will enable `svg-editor-es.html` to work, an HTML file directly - using ES6 modules. Note that this file only works on modern browsers. - The config file now imports the SVG edit code, minimizing the scripts - that need to be referenced in the HTML file. -1. To also build a rolled-up, Babelified, non-ES Modules (IIFE) - JavaScript file which will allow `svg-editor.html` to work, a file - which does not rely on ES6 Modules support, follow these steps: - 1. Run `npm install` within the `node_modules/svgedit` directory to - install the build tools for SVG-edit. - 1. Run `npm run build-config` within the `node_modules/svgedit` directory. -1. If you wish to make changes to the HTML, modify `svg-editor-es.html` and - then run `npm run build-html` to have the changes properly copied to - `svg-editor.html`. +1. Clone or copy the repository contents (at least the `editor` directory). +1. If you need programmatic customization, see its section below. +1. Otherwise, just add an iframe to your site, adding any extensions or + configuration (see `docs/tutorials/ConfigOptions.md` + ([ConfigOptions]{@tutorial ConfigOptions})) within the URL: +```html + +``` + +### Integrating SVG-edit into your own npm package + +These steps are only needed if you wish to set up your own npm package +incorporating SVGEdit. + +1. Create your npm package: `npm init` (complete the fields). +1. Install SVG-edit into your package: + `npm i svgedit`. +1. Look within `node_modules/svgedit/`, e.g., `node_modules/svgedit/editor/svg-editor.html` + for the files your package needs and use accordingly. +1. `npm publish` + +## Programmatic customization + +1. If you are not concerned about supporting ES6 Modules (see the + "ES6 Modules file" section), you can add your config directly to + `svgedit-config-iife.js` within the SVG-Edit project root. + 1. Note: Do not remove the `import svgEditor...` code which is responsible for + importing the SVG edit code. Versions prior to 3.0 did not require this, + but the advantage is that your HTML does not need to be polluted with + extra script references. +1. Modify or utilize any options. See `docs/tutorials/ConfigOptions.md` + ([ConfigOptions]{@tutorial ConfigOptions}). + +## ES6 Modules file + +1. `svg-editor-es.html` is an HTML file directly using ES6 modules. + It is only supported in the latest browsers. It is probably mostly + useful for debugging, as it requires more network requests. + If you would like to work with this file, you should make configuration + changes in `svgedit-config-es.js` (in the SVG-Edit project root). +1. If you are working with the ES6 Modules config but also wish to work with + the normal `svg-editor.html` version (so your code can work in older + browsers or get the presumable performance benefits of this file which + references JavaScript rolled up into a single file), you can follow these + steps after any config changes you make, so that your changes can also be + automatically made available to both versions. + 1. JavaScript: + 1. Run `npm install` within the `node_modules/svgedit` directory to + install the build tools for SVG-edit. + 1. Run `npm run build-config` within the `node_modules/svgedit` directory. + 1. This will rebuild `svgedit-config-iife.js` (applying Babel to allow + it to work on older browsers and applying Rollup to build all + JavaScript into one file). The file will then contain non-ES6 module + JavaScript that can work in older browsers. Note that it bundles all + of SVGEdit, so it is to be expected that this file will be much larger + in size than the original ES6 config file. + 1. HTML: + 1. If you wish to make changes to both HTML files, it is recommended that you + work and test on `svg-editor-es.html` and then run `npm run build-html` + to have the changes properly copied to `svg-editor.html`. ## Recent news * 2018-05-26 Published 3.0.0-alpha.2 with ES6 Modules support @@ -54,18 +95,19 @@ copy of the svgedit Git repo. ## Supported browsers -The following browsers had been tested for 2.6 or earlier and will probably continue to work with 2.8. - * Firefox 1.5+ - * Opera 9.50+ - * Safari 4+ - * Chrome 1+ - * IE 9+ and Edge +The following browsers had been tested for 2.6 or earlier and will probably continue to work with 3.0. + +- Firefox 1.5+ +- Opera 9.50+ +- Safari 4+ +- Chrome 1+ +- IE 9+ and Edge ## Further reading and more information - * See [docs](docs/) for more documentation. See the [JSDocs for our latest release](https://svg-edit.github.io/svgedit/releases/svg-edit-3.0.0-alpha.4/docs/jsdoc/index.html). + * See [docs](docs/) for more documentation. See the [JSDocs for our latest release](https://svg-edit.github.io/svgedit/releases/latest/docs/jsdoc/index.html). * [Acknowledgements](docs/Acknowledgements.md) lists open source projects used in svg-edit. * See [AUTHORS](AUTHORS) file for authors. - * [Stackoverflow](https://stackoverflow.com/tags/svg-edit) group. + * [StackOverflow](https://stackoverflow.com/tags/svg-edit) group. * Join the [svg-edit mailing list](https://groups.google.com/forum/#!forum/svg-edit). * Join us on `#svg-edit` on `freenode.net` (or use the [web client](https://webchat.freenode.net/?channels=svg-edit)). diff --git a/dist/canvg.js b/dist/canvg.js index a0214367..df3688fe 100644 --- a/dist/canvg.js +++ b/dist/canvg.js @@ -151,6 +151,13 @@ var canvg = (function (exports) { } }; + /** + * For parsing color values + * @module RGBColor + * @author Stoyan Stefanov + * @see https://www.phpied.com/rgb-color-parser-in-javascript/ + * @license MIT + */ var simpleColors = { aliceblue: 'f0f8ff', antiquewhite: 'faebd7', @@ -320,12 +327,12 @@ var canvg = (function (exports) { /** * A class to parse color values - * @author Stoyan Stefanov - * @link https://www.phpied.com/rgb-color-parser-in-javascript/ - * @license MIT */ var RGBColor = function () { + /** + * @param {string} colorString + */ function RGBColor(colorString) { classCallCheck(this, RGBColor); @@ -372,6 +379,9 @@ var canvg = (function (exports) { } // some getters + /** + * @returns {string} + */ createClass(RGBColor, [{ @@ -379,6 +389,11 @@ var canvg = (function (exports) { value: function toRGB() { return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; } + + /** + * @returns {string} + */ + }, { key: 'toHex', value: function toHex() { @@ -397,7 +412,10 @@ var canvg = (function (exports) { return '#' + r + g + b; } - // help + /** + * help + * @returns {HTMLUListElement} + */ }, { key: 'getHelpXML', @@ -434,28 +452,414 @@ var canvg = (function (exports) { return RGBColor; }(); - /* eslint-disable new-cap */ + /** + * StackBlur - a fast almost Gaussian Blur For Canvas - var stackBlurCanvasRGBA = void 0; - var setStackBlurCanvasRGBA = function setStackBlurCanvasRGBA(value) { - stackBlurCanvasRGBA = value; + 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. + */ + + var 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]; + + var 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|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; + } + + var 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; + + var 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) { + var pixels = imageData.data; + + var x = void 0, + y = void 0, + i = void 0, + p = void 0, + yp = void 0, + yi = void 0, + yw = void 0, + rSum = void 0, + gSum = void 0, + bSum = void 0, + aSum = void 0, + rOutSum = void 0, + gOutSum = void 0, + bOutSum = void 0, + aOutSum = void 0, + rInSum = void 0, + gInSum = void 0, + bInSum = void 0, + aInSum = void 0, + pr = void 0, + pg = void 0, + pb = void 0, + pa = void 0, + rbs = void 0; + + var div = radius + radius + 1; + // const w4 = width << 2; + var widthMinus1 = width - 1; + var heightMinus1 = height - 1; + var radiusPlus1 = radius + 1; + var sumFactor = radiusPlus1 * (radiusPlus1 + 1) / 2; + + var stackStart = new BlurStack(); + var stack = stackStart; + var stackEnd = void 0; + for (i = 1; i < div; i++) { + stack = stack.next = new BlurStack(); + if (i === radiusPlus1) { + stackEnd = stack; + } + } + stack.next = stackStart; + var stackIn = null; + var stackOut = null; + + yw = yi = 0; + + var mulSum = mulTable[radius]; + var 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; + } + + /** + * + */ + var BlurStack = function BlurStack() { + classCallCheck(this, BlurStack); + + this.r = 0; + this.g = 0; + this.b = 0; + this.a = 0; + this.next = null; }; - // 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 + /* eslint-disable new-cap */ + + var canvasRGBA_ = processCanvasRGBA; + + /** + * @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 + */ + var setStackBlurCanvasRGBA = function setStackBlurCanvasRGBA(cb) { + canvasRGBA_ = cb; + }; + + /** + * @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 `` elements on the page with `` 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 + */ var canvg = function canvg(target, s, opts) { // no parameters if (target == null && s == null && opts == null) { @@ -497,6 +901,11 @@ var canvg = (function (exports) { 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) { var svg = { opts: opts }; @@ -3635,16 +4044,17 @@ var canvg = (function (exports) { createClass(_class46, [{ key: 'apply', value: function 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(); } }]); diff --git a/dist/extensions/ext-arrows.js b/dist/extensions/ext-arrows.js index 5d1a5662..3cb727ef 100644 --- a/dist/extensions/ext-arrows.js +++ b/dist/extensions/ext-arrows.js @@ -1,302 +1,367 @@ var svgEditorExtension_arrows = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + /* globals jQuery */ - /* + /** * ext-arrows.js * - * Licensed under the MIT License + * @license MIT * - * Copyright(c) 2010 Alexis Deveria + * @copyright 2010 Alexis Deveria * */ var extArrows = { - name: 'Arrows', - init: function init(S) { - var svgEditor = this; - var svgCanvas = svgEditor.canvas; - var $ = jQuery; - // {svgcontent} = S, - var addElem = S.addSvgElementFromJson, - nonce = S.nonce, - langList = { - en: [{ id: 'arrow_none', textContent: 'No arrow' }], - fr: [{ id: 'arrow_none', textContent: 'Sans flèche' }] - }, - prefix = 'se_arrow_'; + name: 'arrows', + init: function () { + var _ref = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(S) { + var strings, svgEditor, svgCanvas, $, addElem, nonce, prefix, selElems, arrowprefix, randomizeIds, setArrowNonce, unsetArrowNonce, pathdata, getLinked, showPanel, resetMarker, addMarker, setArrow, colorChanged, contextTools; + return regeneratorRuntime.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + colorChanged = function colorChanged(elem) { + var color = elem.getAttribute('stroke'); + var mtypes = ['start', 'mid', 'end']; + var defs = S.findDefs(); + + $.each(mtypes, function (i, type) { + var marker = getLinked(elem, 'marker-' + type); + if (!marker) { + return; + } + + var curColor = $(marker).children().attr('fill'); + var curD = $(marker).children().attr('d'); + if (curColor === color) { + return; + } + + var allMarkers = $(defs).find('marker'); + var newMarker = null; + // Different color, check if already made + allMarkers.each(function () { + var attrs = $(this).children().attr(['fill', 'd']); + if (attrs.fill === color && attrs.d === curD) { + // Found another marker with this color and this path + newMarker = this; + } + }); + + if (!newMarker) { + // Create a new marker with this color + var lastId = marker.id; + var dir = lastId.includes('_fw') ? 'fw' : 'bk'; + + newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length); + + $(newMarker).children().attr('fill', color); + } + + $(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')'); + + // Check if last marker can be removed + var remove = true; + $(S.svgcontent).find('line, polyline, path, polygon').each(function () { + var elem = this; + $.each(mtypes, function (j, mtype) { + if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { + remove = false; + return remove; + } + }); + if (!remove) { + return false; + } + }); + + // Not found, so can safely remove + if (remove) { + $(marker).remove(); + } + }); + }; + + setArrow = function setArrow() { + resetMarker(); + + var type = this.value; + if (type === 'none') { + return; + } + + // Set marker on element + var dir = 'fw'; + if (type === 'mid_bk') { + type = 'mid'; + dir = 'bk'; + } else if (type === 'both') { + addMarker('bk', type); + svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); + type = 'end'; + dir = 'fw'; + } else if (type === 'start') { + dir = 'bk'; + } + + addMarker(dir, type); + svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')'); + S.call('changed', selElems); + }; + + addMarker = function addMarker(dir, type, id) { + // TODO: Make marker (or use?) per arrow type, since refX can be different + id = id || arrowprefix + dir; + + var data = pathdata[dir]; + + if (type === 'mid') { + data.refx = 5; + } + + var marker = S.getElem(id); + if (!marker) { + marker = addElem({ + element: 'marker', + attr: { + viewBox: '0 0 10 10', + id: id, + refY: 5, + markerUnits: 'strokeWidth', + markerWidth: 5, + markerHeight: 5, + orient: 'auto', + style: 'pointer-events:none' // Currently needed for Opera + } + }); + var arrow = addElem({ + element: 'path', + attr: { + d: data.d, + fill: '#000000' + } + }); + marker.append(arrow); + S.findDefs().append(marker); + } + + marker.setAttribute('refX', data.refx); + + return marker; + }; + + resetMarker = function resetMarker() { + var el = selElems[0]; + el.removeAttribute('marker-start'); + el.removeAttribute('marker-mid'); + el.removeAttribute('marker-end'); + }; + + showPanel = function showPanel(on) { + $('#arrow_panel').toggle(on); + if (on) { + var el = selElems[0]; + var end = el.getAttribute('marker-end'); + var start = el.getAttribute('marker-start'); + var mid = el.getAttribute('marker-mid'); + var val = void 0; + if (end && start) { + val = 'both'; + } else if (end) { + val = 'end'; + } else if (start) { + val = 'start'; + } else if (mid) { + val = 'mid'; + if (mid.includes('bk')) { + val = 'mid_bk'; + } + } + + if (!start && !mid && !end) { + val = 'none'; + } + + $('#arrow_list').val(val); + } + }; + + getLinked = function getLinked(elem, attr) { + var str = elem.getAttribute(attr); + if (!str) { + return null; + } + var m = str.match(/\(#(.*)\)/); + if (!m || m.length !== 2) { + return null; + } + return S.getElem(m[1]); + }; + + unsetArrowNonce = function unsetArrowNonce(window) { + randomizeIds = false; + arrowprefix = prefix; + pathdata.fw.id = arrowprefix + 'fw'; + pathdata.bk.id = arrowprefix + 'bk'; + }; + + setArrowNonce = function setArrowNonce(window, n) { + randomizeIds = true; + arrowprefix = prefix + n + '_'; + pathdata.fw.id = arrowprefix + 'fw'; + pathdata.bk.id = arrowprefix + 'bk'; + }; + + _context2.next = 10; + return S.importLocale(); + + case 10: + strings = _context2.sent; + svgEditor = this; + svgCanvas = svgEditor.canvas; + $ = jQuery; + // {svgcontent} = S, + addElem = S.addSVGElementFromJson, nonce = S.nonce, prefix = 'se_arrow_'; + selElems = void 0, arrowprefix = void 0, randomizeIds = S.randomize_ids; - var selElems = void 0, - arrowprefix = void 0, - randomizeIds = S.randomize_ids; + svgCanvas.bind('setnonce', setArrowNonce); + svgCanvas.bind('unsetnonce', unsetArrowNonce); - function setArrowNonce(window, n) { - randomizeIds = true; - arrowprefix = prefix + n + '_'; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } + if (randomizeIds) { + arrowprefix = prefix + nonce + '_'; + } else { + arrowprefix = prefix; + } - function unsetArrowNonce(window) { - randomizeIds = false; - arrowprefix = prefix; - pathdata.fw.id = arrowprefix + 'fw'; - pathdata.bk.id = arrowprefix + 'bk'; - } + pathdata = { + fw: { d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw' }, + bk: { d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk' } + }; + contextTools = [{ + type: 'select', + panel: 'arrow_panel', + id: 'arrow_list', + defval: 'none', + events: { + change: setArrow + } + }]; + return _context2.abrupt('return', { + name: strings.name, + context_tools: strings.contextTools.map(function (contextTool, i) { + return Object.assign(contextTools[i], contextTool); + }), + callback: function callback() { + $('#arrow_panel').hide(); + // Set ID so it can be translated in locale file + $('#arrow_list option')[0].id = 'connector_no_arrow'; + }, + addLangData: function () { + var _ref3 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref2) { + var lang = _ref2.lang, + importLocale = _ref2.importLocale; + var strings; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + _context.next = 2; + return importLocale(); - svgCanvas.bind('setnonce', setArrowNonce); - svgCanvas.bind('unsetnonce', unsetArrowNonce); + case 2: + strings = _context.sent; + return _context.abrupt('return', { + data: strings.langList + }); - if (randomizeIds) { - arrowprefix = prefix + nonce + '_'; - } else { - arrowprefix = prefix; - } + case 4: + case 'end': + return _context.stop(); + } + } + }, _callee, this); + })); - var pathdata = { - fw: { d: 'm0,0l10,5l-10,5l5,-5l-5,-5z', refx: 8, id: arrowprefix + 'fw' }, - bk: { d: 'm10,0l-10,5l10,5l-5,-5l5,-5z', refx: 2, id: arrowprefix + 'bk' } - }; + function addLangData(_x2) { + return _ref3.apply(this, arguments); + } - function getLinked(elem, attr) { - var str = elem.getAttribute(attr); - if (!str) { - return null; - } - var m = str.match(/\(#(.*)\)/); - if (!m || m.length !== 2) { - return null; - } - return S.getElem(m[1]); - } + return addLangData; + }(), + selectedChanged: function selectedChanged(opts) { + // Use this to update the current selected elements + selElems = opts.elems; - function showPanel(on) { - $('#arrow_panel').toggle(on); - if (on) { - var el = selElems[0]; - var end = el.getAttribute('marker-end'); - var start = el.getAttribute('marker-start'); - var mid = el.getAttribute('marker-mid'); - var val = void 0; - if (end && start) { - val = 'both'; - } else if (end) { - val = 'end'; - } else if (start) { - val = 'start'; - } else if (mid) { - val = 'mid'; - if (mid.includes('bk')) { - val = 'mid_bk'; + var markerElems = ['line', 'path', 'polyline', 'polygon']; + var i = selElems.length; + while (i--) { + var elem = selElems[i]; + if (elem && markerElems.includes(elem.tagName)) { + if (opts.selectedElement && !opts.multiselected) { + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + }, + elementChanged: function elementChanged(opts) { + var elem = opts.elems[0]; + if (elem && (elem.getAttribute('marker-start') || elem.getAttribute('marker-mid') || elem.getAttribute('marker-end'))) { + // const start = elem.getAttribute('marker-start'); + // const mid = elem.getAttribute('marker-mid'); + // const end = elem.getAttribute('marker-end'); + // Has marker, so see if it should match color + colorChanged(elem); + } + } + }); + + case 22: + case 'end': + return _context2.stop(); } } + }, _callee2, this); + })); - if (!start && !mid && !end) { - val = 'none'; - } - - $('#arrow_list').val(val); - } + function init(_x) { + return _ref.apply(this, arguments); } - function resetMarker() { - var el = selElems[0]; - el.removeAttribute('marker-start'); - el.removeAttribute('marker-mid'); - el.removeAttribute('marker-end'); - } - - function addMarker(dir, type, id) { - // TODO: Make marker (or use?) per arrow type, since refX can be different - id = id || arrowprefix + dir; - - var data = pathdata[dir]; - - if (type === 'mid') { - data.refx = 5; - } - - var marker = S.getElem(id); - if (!marker) { - marker = addElem({ - element: 'marker', - attr: { - viewBox: '0 0 10 10', - id: id, - refY: 5, - markerUnits: 'strokeWidth', - markerWidth: 5, - markerHeight: 5, - orient: 'auto', - style: 'pointer-events:none' // Currently needed for Opera - } - }); - var arrow = addElem({ - element: 'path', - attr: { - d: data.d, - fill: '#000000' - } - }); - marker.append(arrow); - S.findDefs().append(marker); - } - - marker.setAttribute('refX', data.refx); - - return marker; - } - - function setArrow() { - resetMarker(); - - var type = this.value; - if (type === 'none') { - return; - } - - // Set marker on element - var dir = 'fw'; - if (type === 'mid_bk') { - type = 'mid'; - dir = 'bk'; - } else if (type === 'both') { - addMarker('bk', type); - svgCanvas.changeSelectedAttribute('marker-start', 'url(#' + pathdata.bk.id + ')'); - type = 'end'; - dir = 'fw'; - } else if (type === 'start') { - dir = 'bk'; - } - - addMarker(dir, type); - svgCanvas.changeSelectedAttribute('marker-' + type, 'url(#' + pathdata[dir].id + ')'); - S.call('changed', selElems); - } - - function colorChanged(elem) { - var color = elem.getAttribute('stroke'); - var mtypes = ['start', 'mid', 'end']; - var defs = S.findDefs(); - - $.each(mtypes, function (i, type) { - var marker = getLinked(elem, 'marker-' + type); - if (!marker) { - return; - } - - var curColor = $(marker).children().attr('fill'); - var curD = $(marker).children().attr('d'); - if (curColor === color) { - return; - } - - var allMarkers = $(defs).find('marker'); - var newMarker = null; - // Different color, check if already made - allMarkers.each(function () { - var attrs = $(this).children().attr(['fill', 'd']); - if (attrs.fill === color && attrs.d === curD) { - // Found another marker with this color and this path - newMarker = this; - } - }); - - if (!newMarker) { - // Create a new marker with this color - var lastId = marker.id; - var dir = lastId.includes('_fw') ? 'fw' : 'bk'; - - newMarker = addMarker(dir, type, arrowprefix + dir + allMarkers.length); - - $(newMarker).children().attr('fill', color); - } - - $(elem).attr('marker-' + type, 'url(#' + newMarker.id + ')'); - - // Check if last marker can be removed - var remove = true; - $(S.svgcontent).find('line, polyline, path, polygon').each(function () { - var elem = this; - $.each(mtypes, function (j, mtype) { - if ($(elem).attr('marker-' + mtype) === 'url(#' + marker.id + ')') { - remove = false; - return remove; - } - }); - if (!remove) { - return false; - } - }); - - // Not found, so can safely remove - if (remove) { - $(marker).remove(); - } - }); - } - - return { - name: 'Arrows', - context_tools: [{ - type: 'select', - panel: 'arrow_panel', - title: 'Select arrow type', - id: 'arrow_list', - options: { - none: 'No arrow', - end: '---->', - start: '<----', - both: '<--->', - mid: '-->--', - mid_bk: '--<--' - }, - defval: 'none', - events: { - change: setArrow - } - }], - callback: function callback() { - $('#arrow_panel').hide(); - // Set ID so it can be translated in locale file - $('#arrow_list option')[0].id = 'connector_no_arrow'; - }, - addLangData: function addLangData(lang) { - return { - data: langList[lang] - }; - }, - selectedChanged: function selectedChanged(opts) { - // Use this to update the current selected elements - selElems = opts.elems; - - var markerElems = ['line', 'path', 'polyline', 'polygon']; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (elem && markerElems.includes(elem.tagName)) { - if (opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - }, - elementChanged: function elementChanged(opts) { - var elem = opts.elems[0]; - if (elem && (elem.getAttribute('marker-start') || elem.getAttribute('marker-mid') || elem.getAttribute('marker-end'))) { - // const start = elem.getAttribute('marker-start'); - // const mid = elem.getAttribute('marker-mid'); - // const end = elem.getAttribute('marker-end'); - // Has marker, so see if it should match color - colorChanged(elem); - } - } - }; - } + return init; + }() }; return extArrows; diff --git a/dist/extensions/ext-closepath.js b/dist/extensions/ext-closepath.js index f45ada19..bd1df359 100644 --- a/dist/extensions/ext-closepath.js +++ b/dist/extensions/ext-closepath.js @@ -1,101 +1,160 @@ var svgEditorExtension_closepath = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + /* globals jQuery */ - /* + /** * ext-closepath.js * - * Licensed under the MIT License + * @license MIT * - * Copyright(c) 2010 Jeff Schiller + * @copyright 2010 Jeff Schiller * */ // This extension adds a simple button to the contextual panel for paths // The button toggles whether the path is open or closed var extClosepath = { - name: 'ClosePath', - init: function init() { - var $ = jQuery; - var svgEditor = this; - var selElems = void 0; - var updateButton = function updateButton(path) { - var seglist = path.pathSegList, - closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1, - showbutton = closed ? '#tool_openpath' : '#tool_closepath', - hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; - $(hidebutton).hide(); - $(showbutton).show(); - }; - var showPanel = function showPanel(on) { - $('#closepath_panel').toggle(on); - if (on) { - var path = selElems[0]; - if (path) { - updateButton(path); - } - } - }; - var toggleClosed = function toggleClosed() { - var path = selElems[0]; - if (path) { - var seglist = path.pathSegList, - last = seglist.numberOfItems - 1; - // is closed - if (seglist.getItem(last).pathSegType === 1) { - seglist.removeItem(last); - } else { - seglist.appendItem(path.createSVGPathSegClosePath()); - } - updateButton(path); - } - }; + name: 'closepath', + init: function () { + var _ref2 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref) { + var importLocale = _ref.importLocale; + var strings, $, svgEditor, selElems, updateButton, showPanel, toggleClosed, buttons; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + _context.next = 2; + return importLocale(); - return { - name: 'ClosePath', - svgicons: svgEditor.curConfig.extIconsPath + 'closepath_icons.svg', - buttons: [{ - id: 'tool_openpath', - type: 'context', - panel: 'closepath_panel', - title: 'Open path', - events: { - click: function click() { - toggleClosed(); + case 2: + strings = _context.sent; + $ = jQuery; + svgEditor = this; + selElems = void 0; + + updateButton = function updateButton(path) { + var seglist = path.pathSegList, + closed = seglist.getItem(seglist.numberOfItems - 1).pathSegType === 1, + showbutton = closed ? '#tool_openpath' : '#tool_closepath', + hidebutton = closed ? '#tool_closepath' : '#tool_openpath'; + $(hidebutton).hide(); + $(showbutton).show(); + }; + + showPanel = function showPanel(on) { + $('#closepath_panel').toggle(on); + if (on) { + var path = selElems[0]; + if (path) { + updateButton(path); + } + } + }; + + toggleClosed = function toggleClosed() { + var path = selElems[0]; + if (path) { + var seglist = path.pathSegList, + last = seglist.numberOfItems - 1; + // is closed + if (seglist.getItem(last).pathSegType === 1) { + seglist.removeItem(last); + } else { + seglist.appendItem(path.createSVGPathSegClosePath()); + } + updateButton(path); + } + }; + + buttons = [{ + id: 'tool_openpath', + type: 'context', + panel: 'closepath_panel', + events: { + click: function click() { + toggleClosed(); + } + } + }, { + id: 'tool_closepath', + type: 'context', + panel: 'closepath_panel', + events: { + click: function click() { + toggleClosed(); + } + } + }]; + return _context.abrupt('return', { + name: strings.name, + svgicons: svgEditor.curConfig.extIconsPath + 'closepath_icons.svg', + buttons: strings.buttons.map(function (button, i) { + return Object.assign(buttons[i], button); + }), + callback: function callback() { + $('#closepath_panel').hide(); + }, + selectedChanged: function selectedChanged(opts) { + selElems = opts.elems; + var i = selElems.length; + while (i--) { + var elem = selElems[i]; + if (elem && elem.tagName === 'path') { + if (opts.selectedElement && !opts.multiselected) { + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + } + }); + + case 11: + case 'end': + return _context.stop(); } } - }, { - id: 'tool_closepath', - type: 'context', - panel: 'closepath_panel', - title: 'Close path', - events: { - click: function click() { - toggleClosed(); - } - } - }], - callback: function callback() { - $('#closepath_panel').hide(); - }, - selectedChanged: function selectedChanged(opts) { - selElems = opts.elems; - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (elem && elem.tagName === 'path') { - if (opts.selectedElement && !opts.multiselected) { - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - } - }; - } + }, _callee, this); + })); + + function init(_x) { + return _ref2.apply(this, arguments); + } + + return init; + }() }; return extClosepath; diff --git a/dist/extensions/ext-connector.js b/dist/extensions/ext-connector.js index 53ef77bb..bed3ffe8 100644 --- a/dist/extensions/ext-connector.js +++ b/dist/extensions/ext-connector.js @@ -1,620 +1,679 @@ var svgEditorExtension_connector = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + /* globals jQuery */ - /* + /** * ext-connector.js * - * Licensed under the MIT License + * @license MIT * - * Copyright(c) 2010 Alexis Deveria + * @copyright 2010 Alexis Deveria * */ var extConnector = { - name: 'Connector', - init: function init(S) { - var $ = jQuery; - var svgEditor = this; - var svgCanvas = svgEditor.canvas; - var svgroot = S.svgroot, - getNextId = S.getNextId, - getElem = S.getElem, - addElem = S.addSvgElementFromJson, - selManager = S.selectorManager, - connSel = '.se_connector', - elData = $.data; - var startX = void 0, - startY = void 0, - curLine = void 0, - startElem = void 0, - endElem = void 0, - seNs = void 0, - svgcontent = S.svgcontent, - started = false, - connections = [], - selElems = []; + name: 'connector', + init: function () { + var _ref = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(S) { + var $, svgEditor, svgCanvas, svgroot, getNextId, getElem, importLocale, addElem, selManager, connSel, elData, strings, startX, startY, curLine, startElem, endElem, seNs, svgcontent, started, connections, selElems, getBBintersect, getOffset, showPanel, setPoint, updateLine, findConnectors, updateConnectors, init, buttons; + return regeneratorRuntime.wrap(function _callee2$(_context2) { + while (1) { + switch (_context2.prev = _context2.next) { + case 0: + init = function init() { + // Make sure all connectors have data set + $(svgcontent).find('*').each(function () { + var conn = this.getAttributeNS(seNs, 'connector'); + if (conn) { + this.setAttribute('class', connSel.substr(1)); + var connData = conn.split(' '); + var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]); + var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]); + $(this).data('c_start', connData[0]).data('c_end', connData[1]).data('start_bb', sbb).data('end_bb', ebb); + svgCanvas.getEditorNS(true); + } + }); + // updateConnectors(); + }; + + updateConnectors = function updateConnectors(elems) { + // Updates connector lines based on selected elements + // Is not used on mousemove, as it runs getStrokedBBox every time, + // which isn't necessary there. + findConnectors(elems); + if (connections.length) { + // Update line with element + var i = connections.length; + while (i--) { + var conn = connections[i]; + var line = conn.connector; + var elem = conn.elem; + + // const sw = line.getAttribute('stroke-width') * 5; + + var pre = conn.is_start ? 'start' : 'end'; + + // Update bbox for this element + var bb = svgCanvas.getStrokedBBox([elem]); + bb.x = conn.start_x; + bb.y = conn.start_y; + elData(line, pre + '_bb', bb); + /* const addOffset = */elData(line, pre + '_off'); + + var altPre = conn.is_start ? 'end' : 'start'; + + // Get center pt of connected element + var bb2 = elData(line, altPre + '_bb'); + var srcX = bb2.x + bb2.width / 2; + var srcY = bb2.y + bb2.height / 2; + + // Set point of element being moved + var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); + setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); + + // Set point of connected element + var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); + setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); + + // Update points attribute manually for webkit + if (navigator.userAgent.includes('AppleWebKit')) { + var pts = line.points; + var len = pts.numberOfItems; + var ptArr = []; + for (var j = 0; j < len; j++) { + pt = pts.getItem(j); + ptArr[j] = pt.x + ',' + pt.y; + } + line.setAttribute('points', ptArr.join(' ')); + } + } + } + }; + + findConnectors = function findConnectors() { + var elems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : selElems; + + var connectors = $(svgcontent).find(connSel); + connections = []; + + // Loop through connectors to see if one is connected to the element + connectors.each(function () { + var addThis = void 0; + function add() { + if (elems.includes(this)) { + // Pretend this element is selected + addThis = true; + } + } + + // Grab the ends + var parts = []; + ['start', 'end'].forEach(function (pos, i) { + var key = 'c_' + pos; + var part = elData(this, key); + if (part == null) { + part = document.getElementById(this.attributes['se:connector'].value.split(' ')[i]); + elData(this, 'c_' + pos, part.id); + elData(this, pos + '_bb', svgCanvas.getStrokedBBox([part])); + } else part = document.getElementById(part); + parts.push(part); + }.bind(this)); + + for (var i = 0; i < 2; i++) { + var cElem = parts[i]; + + addThis = false; + // The connected element might be part of a selected group + $(cElem).parents().each(add); + + if (!cElem || !cElem.parentNode) { + $(this).remove(); + continue; + } + if (elems.includes(cElem) || addThis) { + var bb = svgCanvas.getStrokedBBox([cElem]); + connections.push({ + elem: cElem, + connector: this, + is_start: i === 0, + start_x: bb.x, + start_y: bb.y + }); + } + } + }); + }; + + updateLine = function updateLine(diffX, diffY) { + // Update line with element + var i = connections.length; + while (i--) { + var conn = connections[i]; + var line = conn.connector; + // const {elem} = conn; + + var pre = conn.is_start ? 'start' : 'end'; + // const sw = line.getAttribute('stroke-width') * 5; + + // Update bbox for this element + var bb = elData(line, pre + '_bb'); + bb.x = conn.start_x + diffX; + bb.y = conn.start_y + diffY; + elData(line, pre + '_bb', bb); + + var altPre = conn.is_start ? 'end' : 'start'; + + // Get center pt of connected element + var bb2 = elData(line, altPre + '_bb'); + var srcX = bb2.x + bb2.width / 2; + var srcY = bb2.y + bb2.height / 2; + + // Set point of element being moved + var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0 + setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); + + // Set point of connected element + var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); + setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); + } + }; + + setPoint = function setPoint(elem, pos, x, y, setMid) { + var pts = elem.points; + var pt = svgroot.createSVGPoint(); + pt.x = x; + pt.y = y; + if (pos === 'end') { + pos = pts.numberOfItems - 1; + } + // TODO: Test for this on init, then use alt only if needed + try { + pts.replaceItem(pt, pos); + } catch (err) { + // Should only occur in FF which formats points attr as "n,n n,n", so just split + var ptArr = elem.getAttribute('points').split(' '); + for (var i = 0; i < ptArr.length; i++) { + if (i === pos) { + ptArr[i] = x + ',' + y; + } + } + elem.setAttribute('points', ptArr.join(' ')); + } + + if (setMid) { + // Add center point + var ptStart = pts.getItem(0); + var ptEnd = pts.getItem(pts.numberOfItems - 1); + setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2); + } + }; + + showPanel = function showPanel(on) { + var connRules = $('#connector_rules'); + if (!connRules.length) { + connRules = $('').appendTo('head'); + } + connRules.text(!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }'); + $('#connector_panel').toggle(on); + }; + + getOffset = function getOffset(side, line) { + var giveOffset = !!line.getAttribute('marker-' + side); + // const giveOffset = $(line).data(side+'_off'); + + // TODO: Make this number (5) be based on marker width/height + var size = line.getAttribute('stroke-width') * 5; + return giveOffset ? size : 0; + }; + + getBBintersect = function getBBintersect(x, y, bb, offset) { + if (offset) { + offset -= 0; + bb = $.extend({}, bb); + bb.width += offset; + bb.height += offset; + bb.x -= offset / 2; + bb.y -= offset / 2; + } + + var midX = bb.x + bb.width / 2; + var midY = bb.y + bb.height / 2; + var lenX = x - midX; + var lenY = y - midY; + + var slope = Math.abs(lenY / lenX); + + var ratio = void 0; + if (slope < bb.height / bb.width) { + ratio = bb.width / 2 / Math.abs(lenX); + } else { + ratio = lenY ? bb.height / 2 / Math.abs(lenY) : 0; + } + + return { + x: midX + lenX * ratio, + y: midY + lenY * ratio + }; + }; + + $ = jQuery; + svgEditor = this; + svgCanvas = svgEditor.canvas; + svgroot = S.svgroot, getNextId = S.getNextId, getElem = S.getElem, importLocale = S.importLocale, addElem = S.addSVGElementFromJson, selManager = S.selectorManager, connSel = '.se_connector', elData = $.data; + _context2.next = 14; + return importLocale(); + + case 14: + strings = _context2.sent; + startX = void 0, startY = void 0, curLine = void 0, startElem = void 0, endElem = void 0, seNs = void 0, svgcontent = S.svgcontent, started = false, connections = [], selElems = []; + + /** + * + * @param {Element[]} [elem=selElems] Array of elements + */ + + // Do once + (function () { + var gse = svgCanvas.groupSelectedElements; + + svgCanvas.groupSelectedElements = function () { + svgCanvas.removeFromSelection($(connSel).toArray()); + return gse.apply(this, arguments); + }; + + var mse = svgCanvas.moveSelectedElements; + + svgCanvas.moveSelectedElements = function () { + var cmd = mse.apply(this, arguments); + updateConnectors(); + return cmd; + }; + + seNs = svgCanvas.getEditorNS(); + })(); + + // Do on reset - var langList = { - en: [{ id: 'mode_connect', title: 'Connect two objects' }], - fr: [{ id: 'mode_connect', title: 'Connecter deux objets' }] - }; + // $(svgroot).parent().mousemove(function (e) { + // // if (started + // // || svgCanvas.getMode() !== 'connector' + // // || e.target.parentNode.parentNode !== svgcontent) return; + // + // console.log('y') + // // if (e.target.parentNode.parentNode === svgcontent) { + // // + // // } + // }); - function getBBintersect(x, y, bb, offset) { - if (offset) { - offset -= 0; - bb = $.extend({}, bb); - bb.width += offset; - bb.height += offset; - bb.x -= offset / 2; - bb.y -= offset / 2; - } + buttons = [{ + id: 'mode_connect', + type: 'mode', + icon: svgEditor.curConfig.imgPath + 'cut.png', + includeWith: { + button: '#tool_line', + isDefault: false, + position: 1 + }, + events: { + click: function click() { + svgCanvas.setMode('connector'); + } + } + }]; + return _context2.abrupt('return', { + name: strings.name, + svgicons: svgEditor.curConfig.imgPath + 'conn.svg', + buttons: strings.buttons.map(function (button, i) { + return Object.assign(buttons[i], button); + }), + addLangData: function () { + var _ref3 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref2) { + var lang = _ref2.lang, + importLocale = _ref2.importLocale; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + return _context.abrupt('return', { + data: strings.langList + }); - var midX = bb.x + bb.width / 2; - var midY = bb.y + bb.height / 2; - var lenX = x - midX; - var lenY = y - midY; + case 1: + case 'end': + return _context.stop(); + } + } + }, _callee, this); + })); - var slope = Math.abs(lenY / lenX); + function addLangData(_x3) { + return _ref3.apply(this, arguments); + } - var ratio = void 0; - if (slope < bb.height / bb.width) { - ratio = bb.width / 2 / Math.abs(lenX); - } else { - ratio = lenY ? bb.height / 2 / Math.abs(lenY) : 0; - } + return addLangData; + }(), + mouseDown: function mouseDown(opts) { + var e = opts.event; + startX = opts.start_x; + startY = opts.start_y; + var mode = svgCanvas.getMode(); + var initStroke = svgEditor.curConfig.initStroke; - return { - x: midX + lenX * ratio, - y: midY + lenY * ratio - }; + + if (mode === 'connector') { + if (started) { + return; + } + + var mouseTarget = e.target; + + var parents = $(mouseTarget).parents(); + + if ($.inArray(svgcontent, parents) !== -1) { + // Connectable element + + // If child of foreignObject, use parent + var fo = $(mouseTarget).closest('foreignObject'); + startElem = fo.length ? fo[0] : mouseTarget; + + // Get center of source element + var bb = svgCanvas.getStrokedBBox([startElem]); + var x = bb.x + bb.width / 2; + var y = bb.y + bb.height / 2; + + started = true; + curLine = addElem({ + element: 'polyline', + attr: { + id: getNextId(), + points: x + ',' + y + ' ' + x + ',' + y + ' ' + startX + ',' + startY, + stroke: '#' + initStroke.color, + 'stroke-width': !startElem.stroke_width || startElem.stroke_width === 0 ? initStroke.width : startElem.stroke_width, + fill: 'none', + opacity: initStroke.opacity, + style: 'pointer-events:none' + } + }); + elData(curLine, 'start_bb', bb); + } + return { + started: true + }; + } + if (mode === 'select') { + findConnectors(); + } + }, + mouseMove: function mouseMove(opts) { + var zoom = svgCanvas.getZoom(); + // const e = opts.event; + var x = opts.mouse_x / zoom; + var y = opts.mouse_y / zoom; + + var diffX = x - startX, + diffY = y - startY; + + var mode = svgCanvas.getMode(); + + if (mode === 'connector' && started) { + // const sw = curLine.getAttribute('stroke-width') * 3; + // Set start point (adjusts based on bb) + var pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine)); + startX = pt.x; + startY = pt.y; + + setPoint(curLine, 0, pt.x, pt.y, true); + + // Set end point + setPoint(curLine, 'end', x, y, true); + } else if (mode === 'select') { + var slen = selElems.length; + while (slen--) { + var elem = selElems[slen]; + // Look for selected connector elements + if (elem && elData(elem, 'c_start')) { + // Remove the "translate" transform given to move + svgCanvas.removeFromSelection([elem]); + svgCanvas.getTransformList(elem).clear(); + } + } + if (connections.length) { + updateLine(diffX, diffY); + } + } + }, + mouseUp: function mouseUp(opts) { + // const zoom = svgCanvas.getZoom(); + var e = opts.event; + // , x = opts.mouse_x / zoom, + // , y = opts.mouse_y / zoom, + var mouseTarget = e.target; + + if (svgCanvas.getMode() === 'connector') { + var fo = $(mouseTarget).closest('foreignObject'); + if (fo.length) { + mouseTarget = fo[0]; + } + + var parents = $(mouseTarget).parents(); + + if (mouseTarget === startElem) { + // Start line through click + started = true; + return { + keep: true, + element: null, + started: started + }; + } + if ($.inArray(svgcontent, parents) === -1) { + // Not a valid target element, so remove line + $(curLine).remove(); + started = false; + return { + keep: false, + element: null, + started: started + }; + } + // Valid end element + endElem = mouseTarget; + + var startId = startElem.id, + endId = endElem.id; + var connStr = startId + ' ' + endId; + var altStr = endId + ' ' + startId; + // Don't create connector if one already exists + var dupe = $(svgcontent).find(connSel).filter(function () { + var conn = this.getAttributeNS(seNs, 'connector'); + if (conn === connStr || conn === altStr) { + return true; + } + }); + if (dupe.length) { + $(curLine).remove(); + return { + keep: false, + element: null, + started: false + }; + } + + var bb = svgCanvas.getStrokedBBox([endElem]); + + var pt = getBBintersect(startX, startY, bb, getOffset('start', curLine)); + setPoint(curLine, 'end', pt.x, pt.y, true); + $(curLine).data('c_start', startId).data('c_end', endId).data('end_bb', bb); + seNs = svgCanvas.getEditorNS(true); + curLine.setAttributeNS(seNs, 'se:connector', connStr); + curLine.setAttribute('class', connSel.substr(1)); + curLine.setAttribute('opacity', 1); + svgCanvas.addToSelection([curLine]); + svgCanvas.moveToBottomSelectedElement(); + selManager.requestSelector(curLine).showGrips(false); + started = false; + return { + keep: true, + element: curLine, + started: started + }; + } + }, + selectedChanged: function selectedChanged(opts) { + // TODO: Find better way to skip operations if no connectors are in use + if (!$(svgcontent).find(connSel).length) { + return; + } + + if (svgCanvas.getMode() === 'connector') { + svgCanvas.setMode('select'); + } + + // Use this to update the current selected elements + selElems = opts.elems; + + var i = selElems.length; + while (i--) { + var elem = selElems[i]; + if (elem && elData(elem, 'c_start')) { + selManager.requestSelector(elem).showGrips(false); + if (opts.selectedElement && !opts.multiselected) { + // TODO: Set up context tools and hide most regular line tools + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + updateConnectors(); + }, + elementChanged: function elementChanged(opts) { + var elem = opts.elems[0]; + if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') { + // Update svgcontent (can change on import) + svgcontent = elem; + init(); + } + + // Has marker, so change offset + if (elem && (elem.getAttribute('marker-start') || elem.getAttribute('marker-mid') || elem.getAttribute('marker-end'))) { + var start = elem.getAttribute('marker-start'); + var mid = elem.getAttribute('marker-mid'); + var end = elem.getAttribute('marker-end'); + curLine = elem; + $(elem).data('start_off', !!start).data('end_off', !!end); + + if (elem.tagName === 'line' && mid) { + // Convert to polyline to accept mid-arrow + + var x1 = Number(elem.getAttribute('x1')); + var x2 = Number(elem.getAttribute('x2')); + var y1 = Number(elem.getAttribute('y1')); + var y2 = Number(elem.getAttribute('y2')); + var _elem = elem, + id = _elem.id; + + + var midPt = ' ' + (x1 + x2) / 2 + ',' + (y1 + y2) / 2 + ' '; + var pline = addElem({ + element: 'polyline', + attr: { + points: x1 + ',' + y1 + midPt + x2 + ',' + y2, + stroke: elem.getAttribute('stroke'), + 'stroke-width': elem.getAttribute('stroke-width'), + 'marker-mid': mid, + fill: 'none', + opacity: elem.getAttribute('opacity') || 1 + } + }); + $(elem).after(pline).remove(); + svgCanvas.clearSelection(); + pline.id = id; + svgCanvas.addToSelection([pline]); + elem = pline; + } + } + // Update line if it's a connector + if (elem.getAttribute('class') === connSel.substr(1)) { + var _start = getElem(elData(elem, 'c_start')); + updateConnectors([_start]); + } else { + updateConnectors(); + } + }, + IDsUpdated: function IDsUpdated(input) { + var remove = []; + input.elems.forEach(function (elem) { + if ('se:connector' in elem.attr) { + elem.attr['se:connector'] = elem.attr['se:connector'].split(' ').map(function (oldID) { + return input.changes[oldID]; + }).join(' '); + + // Check validity - the field would be something like 'svg_21 svg_22', but + // if one end is missing, it would be 'svg_21' and therefore fail this test + if (!/. ./.test(elem.attr['se:connector'])) { + remove.push(elem.attr.id); + } + } + }); + return { remove: remove }; + }, + toolButtonStateUpdate: function toolButtonStateUpdate(opts) { + if (opts.nostroke) { + if ($('#mode_connect').hasClass('tool_button_current')) { + svgEditor.clickSelect(); + } + } + $('#mode_connect').toggleClass('disabled', opts.nostroke); + } + }); + + case 19: + case 'end': + return _context2.stop(); + } + } + }, _callee2, this); + })); + + function init(_x) { + return _ref.apply(this, arguments); } - function getOffset(side, line) { - var giveOffset = !!line.getAttribute('marker-' + side); - // const giveOffset = $(line).data(side+'_off'); - - // TODO: Make this number (5) be based on marker width/height - var size = line.getAttribute('stroke-width') * 5; - return giveOffset ? size : 0; - } - - function showPanel(on) { - var connRules = $('#connector_rules'); - if (!connRules.length) { - connRules = $('').appendTo('head'); - } - connRules.text(!on ? '' : '#tool_clone, #tool_topath, #tool_angle, #xy_panel { display: none !important; }'); - $('#connector_panel').toggle(on); - } - - function setPoint(elem, pos, x, y, setMid) { - var pts = elem.points; - var pt = svgroot.createSVGPoint(); - pt.x = x; - pt.y = y; - if (pos === 'end') { - pos = pts.numberOfItems - 1; - } - // TODO: Test for this on init, then use alt only if needed - try { - pts.replaceItem(pt, pos); - } catch (err) { - // Should only occur in FF which formats points attr as "n,n n,n", so just split - var ptArr = elem.getAttribute('points').split(' '); - for (var i = 0; i < ptArr.length; i++) { - if (i === pos) { - ptArr[i] = x + ',' + y; - } - } - elem.setAttribute('points', ptArr.join(' ')); - } - - if (setMid) { - // Add center point - var ptStart = pts.getItem(0); - var ptEnd = pts.getItem(pts.numberOfItems - 1); - setPoint(elem, 1, (ptEnd.x + ptStart.x) / 2, (ptEnd.y + ptStart.y) / 2); - } - } - - function updateLine(diffX, diffY) { - // Update line with element - var i = connections.length; - while (i--) { - var conn = connections[i]; - var line = conn.connector; - // const {elem} = conn; - - var pre = conn.is_start ? 'start' : 'end'; - // const sw = line.getAttribute('stroke-width') * 5; - - // Update bbox for this element - var bb = elData(line, pre + '_bb'); - bb.x = conn.start_x + diffX; - bb.y = conn.start_y + diffY; - elData(line, pre + '_bb', bb); - - var altPre = conn.is_start ? 'end' : 'start'; - - // Get center pt of connected element - var bb2 = elData(line, altPre + '_bb'); - var srcX = bb2.x + bb2.width / 2; - var srcY = bb2.y + bb2.height / 2; - - // Set point of element being moved - var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); // $(line).data(pre+'_off')?sw:0 - setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); - - // Set point of connected element - var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); - setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); - } - } - - /** - * - * @param {array} [elem=selElems] Array of elements - */ - function findConnectors() { - var elems = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : selElems; - - var connectors = $(svgcontent).find(connSel); - connections = []; - - // Loop through connectors to see if one is connected to the element - connectors.each(function () { - var addThis = void 0; - function add() { - if (elems.includes(this)) { - // Pretend this element is selected - addThis = true; - } - } - - // Grab the ends - var parts = []; - ['start', 'end'].forEach(function (pos, i) { - var key = 'c_' + pos; - var part = elData(this, key); - if (part == null) { - part = document.getElementById(this.attributes['se:connector'].value.split(' ')[i]); - elData(this, 'c_' + pos, part.id); - elData(this, pos + '_bb', svgCanvas.getStrokedBBox([part])); - } else part = document.getElementById(part); - parts.push(part); - }.bind(this)); - - for (var i = 0; i < 2; i++) { - var cElem = parts[i]; - - addThis = false; - // The connected element might be part of a selected group - $(cElem).parents().each(add); - - if (!cElem || !cElem.parentNode) { - $(this).remove(); - continue; - } - if (elems.includes(cElem) || addThis) { - var bb = svgCanvas.getStrokedBBox([cElem]); - connections.push({ - elem: cElem, - connector: this, - is_start: i === 0, - start_x: bb.x, - start_y: bb.y - }); - } - } - }); - } - - function updateConnectors(elems) { - // Updates connector lines based on selected elements - // Is not used on mousemove, as it runs getStrokedBBox every time, - // which isn't necessary there. - findConnectors(elems); - if (connections.length) { - // Update line with element - var i = connections.length; - while (i--) { - var conn = connections[i]; - var line = conn.connector; - var elem = conn.elem; - - // const sw = line.getAttribute('stroke-width') * 5; - - var pre = conn.is_start ? 'start' : 'end'; - - // Update bbox for this element - var bb = svgCanvas.getStrokedBBox([elem]); - bb.x = conn.start_x; - bb.y = conn.start_y; - elData(line, pre + '_bb', bb); - /* const addOffset = */elData(line, pre + '_off'); - - var altPre = conn.is_start ? 'end' : 'start'; - - // Get center pt of connected element - var bb2 = elData(line, altPre + '_bb'); - var srcX = bb2.x + bb2.width / 2; - var srcY = bb2.y + bb2.height / 2; - - // Set point of element being moved - var pt = getBBintersect(srcX, srcY, bb, getOffset(pre, line)); - setPoint(line, conn.is_start ? 0 : 'end', pt.x, pt.y, true); - - // Set point of connected element - var pt2 = getBBintersect(pt.x, pt.y, elData(line, altPre + '_bb'), getOffset(altPre, line)); - setPoint(line, conn.is_start ? 'end' : 0, pt2.x, pt2.y, true); - - // Update points attribute manually for webkit - if (navigator.userAgent.includes('AppleWebKit')) { - var pts = line.points; - var len = pts.numberOfItems; - var ptArr = []; - for (var j = 0; j < len; j++) { - pt = pts.getItem(j); - ptArr[j] = pt.x + ',' + pt.y; - } - line.setAttribute('points', ptArr.join(' ')); - } - } - } - } - - // Do once - (function () { - var gse = svgCanvas.groupSelectedElements; - - svgCanvas.groupSelectedElements = function () { - svgCanvas.removeFromSelection($(connSel).toArray()); - return gse.apply(this, arguments); - }; - - var mse = svgCanvas.moveSelectedElements; - - svgCanvas.moveSelectedElements = function () { - var cmd = mse.apply(this, arguments); - updateConnectors(); - return cmd; - }; - - seNs = svgCanvas.getEditorNS(); - })(); - - // Do on reset - function init() { - // Make sure all connectors have data set - $(svgcontent).find('*').each(function () { - var conn = this.getAttributeNS(seNs, 'connector'); - if (conn) { - this.setAttribute('class', connSel.substr(1)); - var connData = conn.split(' '); - var sbb = svgCanvas.getStrokedBBox([getElem(connData[0])]); - var ebb = svgCanvas.getStrokedBBox([getElem(connData[1])]); - $(this).data('c_start', connData[0]).data('c_end', connData[1]).data('start_bb', sbb).data('end_bb', ebb); - svgCanvas.getEditorNS(true); - } - }); - // updateConnectors(); - } - - // $(svgroot).parent().mousemove(function (e) { - // // if (started - // // || svgCanvas.getMode() !== 'connector' - // // || e.target.parentNode.parentNode !== svgcontent) return; - // - // console.log('y') - // // if (e.target.parentNode.parentNode === svgcontent) { - // // - // // } - // }); - - return { - name: 'Connector', - svgicons: svgEditor.curConfig.imgPath + 'conn.svg', - 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: function click() { - svgCanvas.setMode('connector'); - } - } - }], - addLangData: function addLangData(lang) { - return { - data: langList[lang] - }; - }, - mouseDown: function mouseDown(opts) { - var e = opts.event; - startX = opts.start_x; - startY = opts.start_y; - var mode = svgCanvas.getMode(); - var initStroke = svgEditor.curConfig.initStroke; - - - if (mode === 'connector') { - if (started) { - return; - } - - var mouseTarget = e.target; - - var parents = $(mouseTarget).parents(); - - if ($.inArray(svgcontent, parents) !== -1) { - // Connectable element - - // If child of foreignObject, use parent - var fo = $(mouseTarget).closest('foreignObject'); - startElem = fo.length ? fo[0] : mouseTarget; - - // Get center of source element - var bb = svgCanvas.getStrokedBBox([startElem]); - var x = bb.x + bb.width / 2; - var y = bb.y + bb.height / 2; - - started = true; - curLine = addElem({ - element: 'polyline', - attr: { - id: getNextId(), - points: x + ',' + y + ' ' + x + ',' + y + ' ' + startX + ',' + startY, - stroke: '#' + initStroke.color, - 'stroke-width': !startElem.stroke_width || startElem.stroke_width === 0 ? initStroke.width : startElem.stroke_width, - fill: 'none', - opacity: initStroke.opacity, - style: 'pointer-events:none' - } - }); - elData(curLine, 'start_bb', bb); - } - return { - started: true - }; - } - if (mode === 'select') { - findConnectors(); - } - }, - mouseMove: function mouseMove(opts) { - var zoom = svgCanvas.getZoom(); - // const e = opts.event; - var x = opts.mouse_x / zoom; - var y = opts.mouse_y / zoom; - - var diffX = x - startX, - diffY = y - startY; - - var mode = svgCanvas.getMode(); - - if (mode === 'connector' && started) { - // const sw = curLine.getAttribute('stroke-width') * 3; - // Set start point (adjusts based on bb) - var pt = getBBintersect(x, y, elData(curLine, 'start_bb'), getOffset('start', curLine)); - startX = pt.x; - startY = pt.y; - - setPoint(curLine, 0, pt.x, pt.y, true); - - // Set end point - setPoint(curLine, 'end', x, y, true); - } else if (mode === 'select') { - var slen = selElems.length; - while (slen--) { - var elem = selElems[slen]; - // Look for selected connector elements - if (elem && elData(elem, 'c_start')) { - // Remove the "translate" transform given to move - svgCanvas.removeFromSelection([elem]); - svgCanvas.getTransformList(elem).clear(); - } - } - if (connections.length) { - updateLine(diffX, diffY); - } - } - }, - mouseUp: function mouseUp(opts) { - // const zoom = svgCanvas.getZoom(); - var e = opts.event; - // , x = opts.mouse_x / zoom, - // , y = opts.mouse_y / zoom, - var mouseTarget = e.target; - - if (svgCanvas.getMode() === 'connector') { - var fo = $(mouseTarget).closest('foreignObject'); - if (fo.length) { - mouseTarget = fo[0]; - } - - var parents = $(mouseTarget).parents(); - - if (mouseTarget === startElem) { - // Start line through click - started = true; - return { - keep: true, - element: null, - started: started - }; - } - if ($.inArray(svgcontent, parents) === -1) { - // Not a valid target element, so remove line - $(curLine).remove(); - started = false; - return { - keep: false, - element: null, - started: started - }; - } - // Valid end element - endElem = mouseTarget; - - var startId = startElem.id, - endId = endElem.id; - var connStr = startId + ' ' + endId; - var altStr = endId + ' ' + startId; - // Don't create connector if one already exists - var dupe = $(svgcontent).find(connSel).filter(function () { - var conn = this.getAttributeNS(seNs, 'connector'); - if (conn === connStr || conn === altStr) { - return true; - } - }); - if (dupe.length) { - $(curLine).remove(); - return { - keep: false, - element: null, - started: false - }; - } - - var bb = svgCanvas.getStrokedBBox([endElem]); - - var pt = getBBintersect(startX, startY, bb, getOffset('start', curLine)); - setPoint(curLine, 'end', pt.x, pt.y, true); - $(curLine).data('c_start', startId).data('c_end', endId).data('end_bb', bb); - seNs = svgCanvas.getEditorNS(true); - curLine.setAttributeNS(seNs, 'se:connector', connStr); - curLine.setAttribute('class', connSel.substr(1)); - curLine.setAttribute('opacity', 1); - svgCanvas.addToSelection([curLine]); - svgCanvas.moveToBottomSelectedElement(); - selManager.requestSelector(curLine).showGrips(false); - started = false; - return { - keep: true, - element: curLine, - started: started - }; - } - }, - selectedChanged: function selectedChanged(opts) { - // TODO: Find better way to skip operations if no connectors are in use - if (!$(svgcontent).find(connSel).length) { - return; - } - - if (svgCanvas.getMode() === 'connector') { - svgCanvas.setMode('select'); - } - - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (elem && elData(elem, 'c_start')) { - selManager.requestSelector(elem).showGrips(false); - if (opts.selectedElement && !opts.multiselected) { - // TODO: Set up context tools and hide most regular line tools - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); - } - } - updateConnectors(); - }, - elementChanged: function elementChanged(opts) { - var elem = opts.elems[0]; - if (elem && elem.tagName === 'svg' && elem.id === 'svgcontent') { - // Update svgcontent (can change on import) - svgcontent = elem; - init(); - } - - // Has marker, so change offset - if (elem && (elem.getAttribute('marker-start') || elem.getAttribute('marker-mid') || elem.getAttribute('marker-end'))) { - var start = elem.getAttribute('marker-start'); - var mid = elem.getAttribute('marker-mid'); - var end = elem.getAttribute('marker-end'); - curLine = elem; - $(elem).data('start_off', !!start).data('end_off', !!end); - - if (elem.tagName === 'line' && mid) { - // Convert to polyline to accept mid-arrow - - var x1 = Number(elem.getAttribute('x1')); - var x2 = Number(elem.getAttribute('x2')); - var y1 = Number(elem.getAttribute('y1')); - var y2 = Number(elem.getAttribute('y2')); - var _elem = elem, - id = _elem.id; - - - var midPt = ' ' + (x1 + x2) / 2 + ',' + (y1 + y2) / 2 + ' '; - var pline = addElem({ - element: 'polyline', - attr: { - points: x1 + ',' + y1 + midPt + x2 + ',' + y2, - stroke: elem.getAttribute('stroke'), - 'stroke-width': elem.getAttribute('stroke-width'), - 'marker-mid': mid, - fill: 'none', - opacity: elem.getAttribute('opacity') || 1 - } - }); - $(elem).after(pline).remove(); - svgCanvas.clearSelection(); - pline.id = id; - svgCanvas.addToSelection([pline]); - elem = pline; - } - } - // Update line if it's a connector - if (elem.getAttribute('class') === connSel.substr(1)) { - var _start = getElem(elData(elem, 'c_start')); - updateConnectors([_start]); - } else { - updateConnectors(); - } - }, - IDsUpdated: function IDsUpdated(input) { - var remove = []; - input.elems.forEach(function (elem) { - if ('se:connector' in elem.attr) { - elem.attr['se:connector'] = elem.attr['se:connector'].split(' ').map(function (oldID) { - return input.changes[oldID]; - }).join(' '); - - // Check validity - the field would be something like 'svg_21 svg_22', but - // if one end is missing, it would be 'svg_21' and therefore fail this test - if (!/. ./.test(elem.attr['se:connector'])) { - remove.push(elem.attr.id); - } - } - }); - return { remove: remove }; - }, - toolButtonStateUpdate: function toolButtonStateUpdate(opts) { - if (opts.nostroke) { - if ($('#mode_connect').hasClass('tool_button_current')) { - svgEditor.clickSelect(); - } - } - $('#mode_connect').toggleClass('disabled', opts.nostroke); - } - }; - } + return init; + }() }; return extConnector; diff --git a/dist/extensions/ext-eyedropper.js b/dist/extensions/ext-eyedropper.js index 5ef3e480..76b48c49 100644 --- a/dist/extensions/ext-eyedropper.js +++ b/dist/extensions/ext-eyedropper.js @@ -1,131 +1,182 @@ var svgEditorExtension_eyedropper = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + /* globals jQuery */ - /* + /** * ext-eyedropper.js * - * Licensed under the MIT License + * @license MIT * - * Copyright(c) 2010 Jeff Schiller + * @copyright 2010 Jeff Schiller * */ var extEyedropper = { name: 'eyedropper', - init: function init(S) { - var svgEditor = this; - var $ = jQuery; - var ChangeElementCommand = S.ChangeElementCommand, - svgCanvas = svgEditor.canvas, - addToHistory = function addToHistory(cmd) { - svgCanvas.undoMgr.addCommandToHistory(cmd); - }, - currentStyle = { - fillPaint: 'red', fillOpacity: 1.0, - strokePaint: 'black', strokeOpacity: 1.0, - strokeWidth: 5, strokeDashArray: null, - opacity: 1.0, - strokeLinecap: 'butt', - strokeLinejoin: 'miter' - }; + init: function () { + var _ref = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(S) { + var strings, svgEditor, $, ChangeElementCommand, svgCanvas, addToHistory, currentStyle, getStyle, buttons; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + getStyle = function getStyle(opts) { + // if we are in eyedropper mode, we don't want to disable the eye-dropper tool + var mode = svgCanvas.getMode(); + if (mode === 'eyedropper') { + return; + } - function getStyle(opts) { - // if we are in eyedropper mode, we don't want to disable the eye-dropper tool - var mode = svgCanvas.getMode(); - if (mode === 'eyedropper') { - return; - } + var tool = $('#tool_eyedropper'); + // enable-eye-dropper if one element is selected + var elem = null; + if (!opts.multiselected && opts.elems[0] && !['svg', 'g', 'use'].includes(opts.elems[0].nodeName)) { + elem = opts.elems[0]; + tool.removeClass('disabled'); + // grab the current style + currentStyle.fillPaint = elem.getAttribute('fill') || 'black'; + currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0; + currentStyle.strokePaint = elem.getAttribute('stroke'); + currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0; + currentStyle.strokeWidth = elem.getAttribute('stroke-width'); + currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray'); + currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap'); + currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin'); + currentStyle.opacity = elem.getAttribute('opacity') || 1.0; + // disable eye-dropper tool + } else { + tool.addClass('disabled'); + } + }; - var tool = $('#tool_eyedropper'); - // enable-eye-dropper if one element is selected - var elem = null; - if (!opts.multiselected && opts.elems[0] && !['svg', 'g', 'use'].includes(opts.elems[0].nodeName)) { - elem = opts.elems[0]; - tool.removeClass('disabled'); - // grab the current style - currentStyle.fillPaint = elem.getAttribute('fill') || 'black'; - currentStyle.fillOpacity = elem.getAttribute('fill-opacity') || 1.0; - currentStyle.strokePaint = elem.getAttribute('stroke'); - currentStyle.strokeOpacity = elem.getAttribute('stroke-opacity') || 1.0; - currentStyle.strokeWidth = elem.getAttribute('stroke-width'); - currentStyle.strokeDashArray = elem.getAttribute('stroke-dasharray'); - currentStyle.strokeLinecap = elem.getAttribute('stroke-linecap'); - currentStyle.strokeLinejoin = elem.getAttribute('stroke-linejoin'); - currentStyle.opacity = elem.getAttribute('opacity') || 1.0; - // disable eye-dropper tool - } else { - tool.addClass('disabled'); - } + _context.next = 3; + return S.importLocale(); + + case 3: + strings = _context.sent; + svgEditor = this; + $ = jQuery; + ChangeElementCommand = S.ChangeElementCommand, svgCanvas = svgEditor.canvas, addToHistory = function addToHistory(cmd) { + svgCanvas.undoMgr.addCommandToHistory(cmd); + }, currentStyle = { + fillPaint: 'red', fillOpacity: 1.0, + strokePaint: 'black', strokeOpacity: 1.0, + strokeWidth: 5, strokeDashArray: null, + opacity: 1.0, + strokeLinecap: 'butt', + strokeLinejoin: 'miter' + }; + buttons = [{ + id: 'tool_eyedropper', + type: 'mode', + events: { + click: function click() { + svgCanvas.setMode('eyedropper'); + } + } + }]; + return _context.abrupt('return', { + name: strings.name, + svgicons: svgEditor.curConfig.extIconsPath + 'eyedropper-icon.xml', + buttons: strings.buttons.map(function (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, + elementChanged: getStyle, + + mouseDown: function mouseDown(opts) { + var mode = svgCanvas.getMode(); + if (mode === 'eyedropper') { + var e = opts.event; + var target = e.target; + + if (!['svg', 'g', 'use'].includes(target.nodeName)) { + var changes = {}; + + var change = function change(elem, attrname, newvalue) { + changes[attrname] = elem.getAttribute(attrname); + elem.setAttribute(attrname, newvalue); + }; + + if (currentStyle.fillPaint) { + change(target, 'fill', currentStyle.fillPaint); + } + if (currentStyle.fillOpacity) { + change(target, 'fill-opacity', currentStyle.fillOpacity); + } + if (currentStyle.strokePaint) { + change(target, 'stroke', currentStyle.strokePaint); + } + if (currentStyle.strokeOpacity) { + change(target, 'stroke-opacity', currentStyle.strokeOpacity); + } + if (currentStyle.strokeWidth) { + change(target, 'stroke-width', currentStyle.strokeWidth); + } + if (currentStyle.strokeDashArray) { + change(target, 'stroke-dasharray', currentStyle.strokeDashArray); + } + if (currentStyle.opacity) { + change(target, 'opacity', currentStyle.opacity); + } + if (currentStyle.strokeLinecap) { + change(target, 'stroke-linecap', currentStyle.strokeLinecap); + } + if (currentStyle.strokeLinejoin) { + change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); + } + + addToHistory(new ChangeElementCommand(target, changes)); + } + } + } + }); + + case 9: + case 'end': + return _context.stop(); + } + } + }, _callee, this); + })); + + function init(_x) { + return _ref.apply(this, arguments); } - return { - name: 'eyedropper', - svgicons: svgEditor.curConfig.extIconsPath + 'eyedropper-icon.xml', - buttons: [{ - id: 'tool_eyedropper', - type: 'mode', - title: 'Eye Dropper Tool', - key: 'I', - events: { - click: function click() { - svgCanvas.setMode('eyedropper'); - } - } - }], - - // if we have selected an element, grab its paint and enable the eye dropper button - selectedChanged: getStyle, - elementChanged: getStyle, - - mouseDown: function mouseDown(opts) { - var mode = svgCanvas.getMode(); - if (mode === 'eyedropper') { - var e = opts.event; - var target = e.target; - - if (!['svg', 'g', 'use'].includes(target.nodeName)) { - var changes = {}; - - var change = function change(elem, attrname, newvalue) { - changes[attrname] = elem.getAttribute(attrname); - elem.setAttribute(attrname, newvalue); - }; - - if (currentStyle.fillPaint) { - change(target, 'fill', currentStyle.fillPaint); - } - if (currentStyle.fillOpacity) { - change(target, 'fill-opacity', currentStyle.fillOpacity); - } - if (currentStyle.strokePaint) { - change(target, 'stroke', currentStyle.strokePaint); - } - if (currentStyle.strokeOpacity) { - change(target, 'stroke-opacity', currentStyle.strokeOpacity); - } - if (currentStyle.strokeWidth) { - change(target, 'stroke-width', currentStyle.strokeWidth); - } - if (currentStyle.strokeDashArray) { - change(target, 'stroke-dasharray', currentStyle.strokeDashArray); - } - if (currentStyle.opacity) { - change(target, 'opacity', currentStyle.opacity); - } - if (currentStyle.strokeLinecap) { - change(target, 'stroke-linecap', currentStyle.strokeLinecap); - } - if (currentStyle.strokeLinejoin) { - change(target, 'stroke-linejoin', currentStyle.strokeLinejoin); - } - - addToHistory(new ChangeElementCommand(target, changes)); - } - } - } - }; - } + return init; + }() }; return extEyedropper; diff --git a/dist/extensions/ext-foreignobject.js b/dist/extensions/ext-foreignobject.js index fd8578df..2b44f0e7 100644 --- a/dist/extensions/ext-foreignobject.js +++ b/dist/extensions/ext-foreignobject.js @@ -1,271 +1,314 @@ var svgEditorExtension_foreignobject = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + /* 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 * */ var extForeignobject = { - name: 'foreignObject', - init: function init(S) { - var svgEditor = this; - var text2xml = S.text2xml, - NS = S.NS; + name: 'foreignobject', + init: function () { + var _ref = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(S) { + var svgEditor, text2xml, NS, importLocale, $, svgCanvas, svgdoc, strings, properlySourceSizeTextArea, showPanel, toggleSourceButtons, selElems, started, newFO, editingforeign, setForeignString, showForeignEditor, setAttr, buttons, contextTools; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + setAttr = function setAttr(attr, val) { + svgCanvas.changeSelectedAttribute(attr, val); + S.call('changed', selElems); + }; - var $ = jQuery; - var svgCanvas = svgEditor.canvas; - var - // {svgcontent} = S, - // addElem = S.addSvgElementFromJson, - svgdoc = S.svgroot.parentNode.ownerDocument; + showForeignEditor = function showForeignEditor() { + var elt = selElems[0]; + if (!elt || editingforeign) { + return; + } + editingforeign = true; + toggleSourceButtons(true); + elt.removeAttribute('fill'); - var properlySourceSizeTextArea = function properlySourceSizeTextArea() { - // TODO: remove magic numbers here and get values from CSS - var height = $('#svg_source_container').height() - 80; - $('#svg_source_textarea').css('height', height); - }; + var str = S.svgToString(elt, 0); + $('#svg_source_textarea').val(str); + $('#svg_source_editor').fadeIn(); + properlySourceSizeTextArea(); + $('#svg_source_textarea').focus(); + }; - function showPanel(on) { - var fcRules = $('#fc_rules'); - if (!fcRules.length) { - fcRules = $('').appendTo('head'); - } - fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); - $('#foreignObject_panel').toggle(on); - } - - function toggleSourceButtons(on) { - $('#tool_source_save, #tool_source_cancel').toggle(!on); - $('#foreign_save, #foreign_cancel').toggle(on); - } - - var selElems = void 0, - started = void 0, - newFO = void 0, - editingforeign = false; - - /** - * This function sets the content of element elt to the input XML. - * @param {String} xmlString - The XML text. - * @param elt - the parent element to append to - * @returns {Boolean} This function returns false if the set was unsuccessful, true otherwise. - */ - function setForeignString(xmlString) { - var elt = selElems[0]; - try { - // convert string into XML document - var newDoc = text2xml('' + xmlString + ''); - // run it through our sanitizer to remove anything we do not support - S.sanitizeSvg(newDoc.documentElement); - elt.replaceWith(svgdoc.importNode(newDoc.documentElement.firstChild, true)); - S.call('changed', [elt]); - svgCanvas.clearSelection(); - } catch (e) { - console.log(e); - return false; - } - - return true; - } - - function showForeignEditor() { - var elt = selElems[0]; - if (!elt || editingforeign) { - return; - } - editingforeign = true; - toggleSourceButtons(true); - elt.removeAttribute('fill'); - - var str = S.svgToString(elt, 0); - $('#svg_source_textarea').val(str); - $('#svg_source_editor').fadeIn(); - properlySourceSizeTextArea(); - $('#svg_source_textarea').focus(); - } - - function setAttr(attr, val) { - svgCanvas.changeSelectedAttribute(attr, val); - S.call('changed', selElems); - } - - return { - name: 'foreignObject', - svgicons: svgEditor.curConfig.extIconsPath + 'foreignobject-icons.xml', - buttons: [{ - id: 'tool_foreign', - type: 'mode', - title: 'Foreign Object Tool', - events: { - click: function click() { - svgCanvas.setMode('foreign'); - } - } - }, { - id: 'edit_foreign', - type: 'context', - panel: 'foreignObject_panel', - title: 'Edit ForeignObject Content', - events: { - click: function click() { - showForeignEditor(); - } - } - }], - - context_tools: [{ - type: 'input', - panel: 'foreignObject_panel', - title: "Change foreignObject's width", - id: 'foreign_width', - label: 'w', - size: 3, - events: { - change: function change() { - setAttr('width', this.value); - } - } - }, { - type: 'input', - panel: 'foreignObject_panel', - title: "Change foreignObject's height", - id: 'foreign_height', - label: 'h', - events: { - change: function change() { - setAttr('height', this.value); - } - } - }, { - type: 'input', - panel: 'foreignObject_panel', - title: "Change foreignObject's font size", - id: 'foreign_font_size', - label: 'font-size', - size: 2, - defval: 16, - events: { - change: function change() { - setAttr('font-size', this.value); - } - } - }], - callback: function callback() { - $('#foreignObject_panel').hide(); - - var endChanges = function endChanges() { - $('#svg_source_editor').hide(); - editingforeign = false; - $('#svg_source_textarea').blur(); - toggleSourceButtons(false); - }; - - // TODO: Needs to be done after orig icon loads - setTimeout(function () { - // Create source save/cancel buttons - /* const save = */$('#tool_source_save').clone().hide().attr('id', 'foreign_save').unbind().appendTo('#tool_source_back').click(function () { - if (!editingforeign) { - return; - } - - if (!setForeignString($('#svg_source_textarea').val())) { - $.confirm('Errors found. Revert to original?', function (ok) { - if (!ok) { + setForeignString = function setForeignString(xmlString) { + var elt = selElems[0]; + try { + // convert string into XML document + var newDoc = text2xml('' + xmlString + ''); + // run it through our sanitizer to remove anything we do not support + S.sanitizeSvg(newDoc.documentElement); + elt.replaceWith(svgdoc.importNode(newDoc.documentElement.firstChild, true)); + S.call('changed', [elt]); + svgCanvas.clearSelection(); + } catch (e) { + console.log(e); return false; } - endChanges(); + + return true; + }; + + toggleSourceButtons = function toggleSourceButtons(on) { + $('#tool_source_save, #tool_source_cancel').toggle(!on); + $('#foreign_save, #foreign_cancel').toggle(on); + }; + + showPanel = function showPanel(on) { + var fcRules = $('#fc_rules'); + if (!fcRules.length) { + fcRules = $('').appendTo('head'); + } + fcRules.text(!on ? '' : ' #tool_topath { display: none !important; }'); + $('#foreignObject_panel').toggle(on); + }; + + svgEditor = this; + text2xml = S.text2xml, NS = S.NS, importLocale = S.importLocale; + $ = jQuery; + svgCanvas = svgEditor.canvas; + svgdoc = S.svgroot.parentNode.ownerDocument; + _context.next = 12; + return importLocale(); + + case 12: + strings = _context.sent; + + properlySourceSizeTextArea = function properlySourceSizeTextArea() { + // TODO: remove magic numbers here and get values from CSS + var height = $('#svg_source_container').height() - 80; + $('#svg_source_textarea').css('height', height); + }; + + selElems = void 0, started = void 0, newFO = void 0, editingforeign = false; + + /** + * This function sets the content of element elt to the input XML. + * @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. + */ + + buttons = [{ + id: 'tool_foreign', + type: 'mode', + events: { + click: function click() { + svgCanvas.setMode('foreign'); + } + } + }, { + id: 'edit_foreign', + type: 'context', + panel: 'foreignObject_panel', + events: { + click: function click() { + showForeignEditor(); + } + } + }]; + contextTools = [{ + type: 'input', + panel: 'foreignObject_panel', + id: 'foreign_width', + size: 3, + events: { + change: function change() { + setAttr('width', this.value); + } + } + }, { + type: 'input', + panel: 'foreignObject_panel', + id: 'foreign_height', + events: { + change: function change() { + setAttr('height', this.value); + } + } + }, { + type: 'input', + panel: 'foreignObject_panel', + id: 'foreign_font_size', + size: 2, + defval: 16, + events: { + change: function change() { + setAttr('font-size', this.value); + } + } + }]; + return _context.abrupt('return', { + name: strings.name, + svgicons: svgEditor.curConfig.extIconsPath + 'foreignobject-icons.xml', + buttons: strings.buttons.map(function (button, i) { + return Object.assign(buttons[i], button); + }), + context_tools: strings.contextTools.map(function (contextTool, i) { + return Object.assign(contextTools[i], contextTool); + }), + callback: function callback() { + $('#foreignObject_panel').hide(); + + var endChanges = function endChanges() { + $('#svg_source_editor').hide(); + editingforeign = false; + $('#svg_source_textarea').blur(); + toggleSourceButtons(false); + }; + + // TODO: Needs to be done after orig icon loads + setTimeout(function () { + // Create source save/cancel buttons + /* const save = */$('#tool_source_save').clone().hide().attr('id', 'foreign_save').unbind().appendTo('#tool_source_back').click(function () { + if (!editingforeign) { + return; + } + + if (!setForeignString($('#svg_source_textarea').val())) { + $.confirm('Errors found. Revert to original?', function (ok) { + if (!ok) { + return false; + } + endChanges(); + }); + } else { + endChanges(); + } + // setSelectMode(); + }); + + /* const cancel = */$('#tool_source_cancel').clone().hide().attr('id', 'foreign_cancel').unbind().appendTo('#tool_source_back').click(function () { + endChanges(); + }); + }, 3000); + }, + mouseDown: function mouseDown(opts) { + // const e = opts.event; + + if (svgCanvas.getMode() === 'foreign') { + started = true; + newFO = S.addSVGElementFromJson({ + element: 'foreignObject', + attr: { + x: opts.start_x, + y: opts.start_y, + id: S.getNextId(), + 'font-size': 16, // cur_text.font_size, + width: '48', + height: '20', + style: 'pointer-events:inherit' + } + }); + var m = svgdoc.createElementNS(NS.MATH, 'math'); + m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH); + m.setAttribute('display', 'inline'); + var mi = svgdoc.createElementNS(NS.MATH, 'mi'); + mi.setAttribute('mathvariant', 'normal'); + mi.textContent = '\u03A6'; + var mo = svgdoc.createElementNS(NS.MATH, 'mo'); + mo.textContent = '\u222A'; + var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); + mi2.textContent = '\u2133'; + m.append(mi, mo, mi2); + newFO.append(m); + return { + started: true + }; + } + }, + mouseUp: function mouseUp(opts) { + // const e = opts.event; + if (svgCanvas.getMode() === 'foreign' && started) { + var attrs = $(newFO).attr(['width', 'height']); + var keep = attrs.width !== '0' || attrs.height !== '0'; + svgCanvas.addToSelection([newFO], true); + + return { + keep: keep, + element: newFO + }; + } + }, + selectedChanged: function selectedChanged(opts) { + // Use this to update the current selected elements + selElems = opts.elems; + + var i = selElems.length; + while (i--) { + var elem = selElems[i]; + if (elem && elem.tagName === 'foreignObject') { + if (opts.selectedElement && !opts.multiselected) { + $('#foreign_font_size').val(elem.getAttribute('font-size')); + $('#foreign_width').val(elem.getAttribute('width')); + $('#foreign_height').val(elem.getAttribute('height')); + showPanel(true); + } else { + showPanel(false); + } + } else { + showPanel(false); + } + } + }, + elementChanged: function elementChanged(opts) { + // const elem = opts.elems[0]; + } }); - } else { - endChanges(); - } - // setSelectMode(); - }); - /* const cancel = */$('#tool_source_cancel').clone().hide().attr('id', 'foreign_cancel').unbind().appendTo('#tool_source_back').click(function () { - endChanges(); - }); - }, 3000); - }, - mouseDown: function mouseDown(opts) { - // const e = opts.event; - - if (svgCanvas.getMode() === 'foreign') { - started = true; - newFO = S.addSvgElementFromJson({ - element: 'foreignObject', - attr: { - x: opts.start_x, - y: opts.start_y, - id: S.getNextId(), - 'font-size': 16, // cur_text.font_size, - width: '48', - height: '20', - style: 'pointer-events:inherit' - } - }); - var m = svgdoc.createElementNS(NS.MATH, 'math'); - m.setAttributeNS(NS.XMLNS, 'xmlns', NS.MATH); - m.setAttribute('display', 'inline'); - var mi = svgdoc.createElementNS(NS.MATH, 'mi'); - mi.setAttribute('mathvariant', 'normal'); - mi.textContent = '\u03A6'; - var mo = svgdoc.createElementNS(NS.MATH, 'mo'); - mo.textContent = '\u222A'; - var mi2 = svgdoc.createElementNS(NS.MATH, 'mi'); - mi2.textContent = '\u2133'; - m.append(mi, mo, mi2); - newFO.append(m); - return { - started: true - }; - } - }, - mouseUp: function mouseUp(opts) { - // const e = opts.event; - if (svgCanvas.getMode() === 'foreign' && started) { - var attrs = $(newFO).attr(['width', 'height']); - var keep = attrs.width !== '0' || attrs.height !== '0'; - svgCanvas.addToSelection([newFO], true); - - return { - keep: keep, - element: newFO - }; - } - }, - selectedChanged: function selectedChanged(opts) { - // Use this to update the current selected elements - selElems = opts.elems; - - var i = selElems.length; - while (i--) { - var elem = selElems[i]; - if (elem && elem.tagName === 'foreignObject') { - if (opts.selectedElement && !opts.multiselected) { - $('#foreign_font_size').val(elem.getAttribute('font-size')); - $('#foreign_width').val(elem.getAttribute('width')); - $('#foreign_height').val(elem.getAttribute('height')); - showPanel(true); - } else { - showPanel(false); - } - } else { - showPanel(false); + case 18: + case 'end': + return _context.stop(); } } - }, - elementChanged: function elementChanged(opts) { - // const elem = opts.elems[0]; - } - }; - } + }, _callee, this); + })); + + function init(_x) { + return _ref.apply(this, arguments); + } + + return init; + }() }; return extForeignobject; diff --git a/dist/extensions/ext-grid.js b/dist/extensions/ext-grid.js index 016cad52..7f3baaa3 100644 --- a/dist/extensions/ext-grid.js +++ b/dist/extensions/ext-grid.js @@ -1,172 +1,227 @@ var svgEditorExtension_grid = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + /* 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 * */ var extGrid = { - name: 'view_grid', - init: function init(_ref) { - var NS = _ref.NS, - getTypeMap = _ref.getTypeMap; + name: 'grid', + init: function () { + var _ref2 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref) { + var NS = _ref.NS, + getTypeMap = _ref.getTypeMap, + importLocale = _ref.importLocale; + var strings, svgEditor, $, svgCanvas, svgdoc, assignAttributes, hcanvas, canvBG, units, intervals, showGrid, canvasGrid, gridPattern, gridimg, gridBox, updateGrid, gridUpdate, buttons; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + gridUpdate = function gridUpdate() { + if (showGrid) { + updateGrid(svgCanvas.getZoom()); + } + $('#canvasGrid').toggle(showGrid); + $('#view_grid').toggleClass('push_button_pressed tool_button'); + }; - var svgEditor = this; - var $ = jQuery; - var svgCanvas = svgEditor.canvas; - var svgdoc = document.getElementById('svgcanvas').ownerDocument, - assignAttributes = svgCanvas.assignAttributes, - hcanvas = document.createElement('canvas'), - canvBG = $('#canvasBackground'), - units = getTypeMap(), - intervals = [0.01, 0.1, 1, 10, 100, 1000]; + updateGrid = function updateGrid(zoom) { + // TODO: Try this with elements, then compare performance difference + var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px + var uMulti = unit * zoom; + // Calculate the main number interval + var rawM = 100 / uMulti; + var multi = 1; + for (var i = 0; i < intervals.length; i++) { + var num = intervals[i]; + multi = num; + if (rawM <= num) { + break; + } + } + var bigInt = multi * uMulti; - var showGrid = svgEditor.curConfig.showGrid || false; + // Set the canvas size to the width of the container + hcanvas.width = bigInt; + hcanvas.height = bigInt; + var ctx = hcanvas.getContext('2d'); + var curD = 0.5; + var part = bigInt / 10; - $(hcanvas).hide().appendTo('body'); + ctx.globalAlpha = 0.2; + ctx.strokeStyle = svgEditor.curConfig.gridColor; + for (var _i = 1; _i < 10; _i++) { + var subD = Math.round(part * _i) + 0.5; + // const lineNum = (i % 2)?12:10; + var lineNum = 0; + ctx.moveTo(subD, bigInt); + ctx.lineTo(subD, lineNum); + ctx.moveTo(bigInt, subD); + ctx.lineTo(lineNum, subD); + } + ctx.stroke(); + ctx.beginPath(); + ctx.globalAlpha = 0.5; + ctx.moveTo(curD, bigInt); + ctx.lineTo(curD, 0); - var canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg'); - assignAttributes(canvasGrid, { - id: 'canvasGrid', - width: '100%', - height: '100%', - x: 0, - y: 0, - overflow: 'visible', - display: 'none' - }); - canvBG.append(canvasGrid); + ctx.moveTo(bigInt, curD); + ctx.lineTo(0, curD); + ctx.stroke(); - // grid-pattern - var gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern'); - assignAttributes(gridPattern, { - id: 'gridpattern', - patternUnits: 'userSpaceOnUse', - x: 0, // -(value.strokeWidth / 2), // position for strokewidth - y: 0, // -(value.strokeWidth / 2), // position for strokewidth - width: 100, - height: 100 - }); + var datauri = hcanvas.toDataURL('image/png'); + gridimg.setAttribute('width', bigInt); + gridimg.setAttribute('height', bigInt); + gridimg.parentNode.setAttribute('width', bigInt); + gridimg.parentNode.setAttribute('height', bigInt); + svgCanvas.setHref(gridimg, datauri); + }; - var gridimg = svgdoc.createElementNS(NS.SVG, 'image'); - assignAttributes(gridimg, { - x: 0, - y: 0, - width: 100, - height: 100 - }); - gridPattern.append(gridimg); - $('#svgroot defs').append(gridPattern); + _context.next = 4; + return importLocale(); - // grid-box - var gridBox = svgdoc.createElementNS(NS.SVG, 'rect'); - assignAttributes(gridBox, { - width: '100%', - height: '100%', - x: 0, - y: 0, - 'stroke-width': 0, - stroke: 'none', - fill: 'url(#gridpattern)', - style: 'pointer-events: none; display:visible;' - }); - $('#canvasGrid').append(gridBox); + case 4: + strings = _context.sent; + svgEditor = this; + $ = jQuery; + svgCanvas = svgEditor.canvas; + svgdoc = document.getElementById('svgcanvas').ownerDocument, assignAttributes = svgCanvas.assignAttributes, hcanvas = document.createElement('canvas'), canvBG = $('#canvasBackground'), units = getTypeMap(), intervals = [0.01, 0.1, 1, 10, 100, 1000]; + showGrid = svgEditor.curConfig.showGrid || false; - function updateGrid(zoom) { - // TODO: Try this with elements, then compare performance difference - var unit = units[svgEditor.curConfig.baseUnit]; // 1 = 1px - var uMulti = unit * zoom; - // Calculate the main number interval - var rawM = 100 / uMulti; - var multi = 1; - for (var i = 0; i < intervals.length; i++) { - var num = intervals[i]; - multi = num; - if (rawM <= num) { - break; - } - } - var bigInt = multi * uMulti; - // Set the canvas size to the width of the container - hcanvas.width = bigInt; - hcanvas.height = bigInt; - var ctx = hcanvas.getContext('2d'); - var curD = 0.5; - var part = bigInt / 10; + $(hcanvas).hide().appendTo('body'); - ctx.globalAlpha = 0.2; - ctx.strokeStyle = svgEditor.curConfig.gridColor; - for (var _i = 1; _i < 10; _i++) { - var subD = Math.round(part * _i) + 0.5; - // const lineNum = (i % 2)?12:10; - var lineNum = 0; - ctx.moveTo(subD, bigInt); - ctx.lineTo(subD, lineNum); - ctx.moveTo(bigInt, subD); - ctx.lineTo(lineNum, subD); - } - ctx.stroke(); - ctx.beginPath(); - ctx.globalAlpha = 0.5; - ctx.moveTo(curD, bigInt); - ctx.lineTo(curD, 0); + canvasGrid = svgdoc.createElementNS(NS.SVG, 'svg'); - ctx.moveTo(bigInt, curD); - ctx.lineTo(0, curD); - ctx.stroke(); + assignAttributes(canvasGrid, { + id: 'canvasGrid', + width: '100%', + height: '100%', + x: 0, + y: 0, + overflow: 'visible', + display: 'none' + }); + canvBG.append(canvasGrid); - var datauri = hcanvas.toDataURL('image/png'); - gridimg.setAttribute('width', bigInt); - gridimg.setAttribute('height', bigInt); - gridimg.parentNode.setAttribute('width', bigInt); - gridimg.parentNode.setAttribute('height', bigInt); - svgCanvas.setHref(gridimg, datauri); - } + // grid-pattern + gridPattern = svgdoc.createElementNS(NS.SVG, 'pattern'); - function gridUpdate() { - if (showGrid) { - updateGrid(svgCanvas.getZoom()); - } - $('#canvasGrid').toggle(showGrid); - $('#view_grid').toggleClass('push_button_pressed tool_button'); - } - return { - name: 'view_grid', - svgicons: svgEditor.curConfig.extIconsPath + 'grid-icon.xml', + assignAttributes(gridPattern, { + id: 'gridpattern', + patternUnits: 'userSpaceOnUse', + x: 0, // -(value.strokeWidth / 2), // position for strokewidth + y: 0, // -(value.strokeWidth / 2), // position for strokewidth + width: 100, + height: 100 + }); - zoomChanged: function zoomChanged(zoom) { - if (showGrid) { - updateGrid(zoom); - } - }, - callback: function callback() { - if (showGrid) { - gridUpdate(); - } - }, + gridimg = svgdoc.createElementNS(NS.SVG, 'image'); - buttons: [{ - id: 'view_grid', - type: 'context', - panel: 'editor_panel', - title: 'Show/Hide Grid', - events: { - click: function click() { - svgEditor.curConfig.showGrid = showGrid = !showGrid; - gridUpdate(); + assignAttributes(gridimg, { + x: 0, + y: 0, + width: 100, + height: 100 + }); + gridPattern.append(gridimg); + $('#svgroot defs').append(gridPattern); + + // grid-box + gridBox = svgdoc.createElementNS(NS.SVG, 'rect'); + + assignAttributes(gridBox, { + width: '100%', + height: '100%', + x: 0, + y: 0, + 'stroke-width': 0, + stroke: 'none', + fill: 'url(#gridpattern)', + style: 'pointer-events: none; display:visible;' + }); + $('#canvasGrid').append(gridBox); + + buttons = [{ + id: 'view_grid', + type: 'context', + panel: 'editor_panel', + events: { + click: function click() { + svgEditor.curConfig.showGrid = showGrid = !showGrid; + gridUpdate(); + } + } + }]; + return _context.abrupt('return', { + name: strings.name, + svgicons: svgEditor.curConfig.extIconsPath + 'grid-icon.xml', + + zoomChanged: function zoomChanged(zoom) { + if (showGrid) { + updateGrid(zoom); + } + }, + callback: function callback() { + if (showGrid) { + gridUpdate(); + } + }, + + buttons: strings.buttons.map(function (button, i) { + return Object.assign(buttons[i], button); + }) + }); + + case 25: + case 'end': + return _context.stop(); } } - }] - }; - } + }, _callee, this); + })); + + function init(_x) { + return _ref2.apply(this, arguments); + } + + return init; + }() }; return extGrid; diff --git a/dist/extensions/ext-helloworld.js b/dist/extensions/ext-helloworld.js index 333a345b..cc4d1211 100644 --- a/dist/extensions/ext-helloworld.js +++ b/dist/extensions/ext-helloworld.js @@ -1,87 +1,188 @@ var svgEditorExtension_helloworld = (function () { 'use strict'; + var asyncToGenerator = function (fn) { + return function () { + var gen = fn.apply(this, arguments); + return new Promise(function (resolve, reject) { + function step(key, arg) { + try { + var info = gen[key](arg); + var value = info.value; + } catch (error) { + reject(error); + return; + } + + if (info.done) { + resolve(value); + } else { + return Promise.resolve(value).then(function (value) { + step("next", value); + }, function (err) { + step("throw", err); + }); + } + } + + return step("next"); + }); + }; + }; + + var slicedToArray = function () { + function sliceIterator(arr, i) { + var _arr = []; + var _n = true; + var _d = false; + var _e = undefined; + + try { + for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { + _arr.push(_s.value); + + if (i && _arr.length === i) break; + } + } catch (err) { + _d = true; + _e = err; + } finally { + try { + if (!_n && _i["return"]) _i["return"](); + } finally { + if (_d) throw _e; + } + } + + return _arr; + } + + return function (arr, i) { + if (Array.isArray(arr)) { + return arr; + } else if (Symbol.iterator in Object(arr)) { + return sliceIterator(arr, i); + } else { + throw new TypeError("Invalid attempt to destructure non-iterable instance"); + } + }; + }(); + /* 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. */ - var extHelloworld = { - name: 'Hello World', - init: function init() { - var svgEditor = this; - var $ = jQuery; - var svgCanvas = svgEditor.canvas; - return { - name: 'Hello World', - // For more notes on how to make an icon file, see the source of - // the helloworld-icon.xml - svgicons: svgEditor.curConfig.extIconsPath + 'helloworld-icon.xml', + name: 'helloworld', + init: function () { + var _ref2 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref) { + var importLocale = _ref.importLocale; + var strings, svgEditor, $, svgCanvas; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + _context.next = 2; + return importLocale(); - // Multiple buttons can be added in this array - buttons: [{ - // Must match the icon ID in helloworld-icon.xml - id: 'hello_world', + case 2: + strings = _context.sent; + svgEditor = this; + $ = jQuery; + svgCanvas = svgEditor.canvas; + return _context.abrupt('return', { + 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', - // This indicates that the button will be added to the "mode" - // button panel on the left side - type: 'mode', + // Multiple buttons can be added in this array + buttons: [{ + // Must match the icon ID in helloworld-icon.xml + id: 'hello_world', - // Tooltip text - title: "Say 'Hello World'", + // This indicates that the button will be added to the "mode" + // button panel on the left side + type: 'mode', - // Events - events: { - click: function click() { - // The action taken when the button is clicked on. - // For "mode" buttons, any other button will - // automatically be de-pressed. - svgCanvas.setMode('hello_world'); + // Tooltip text + title: strings.buttons[0].title, + + // Events + events: { + click: function click() { + // The action taken when the button is clicked on. + // For "mode" buttons, any other button will + // automatically be de-pressed. + svgCanvas.setMode('hello_world'); + } + } + }], + // This is triggered when the main mouse button is pressed down + // on the editor canvas (not the tool panels) + mouseDown: function mouseDown() { + // Check the mode on mousedown + if (svgCanvas.getMode() === 'hello_world') { + // The returned object must include "started" with + // a value of true in order for mouseUp to be triggered + return { started: true }; + } + }, + + + // This is triggered from anywhere, but "started" must have been set + // to true (see above). Note that "opts" is an object with event info + mouseUp: function mouseUp(opts) { + // Check the mode on mouseup + if (svgCanvas.getMode() === 'hello_world') { + var zoom = svgCanvas.getZoom(); + + // Get the actual coordinate by dividing by the zoom value + var x = opts.mouse_x / zoom; + var y = opts.mouse_y / zoom; + + // We do our own formatting + var text = strings.text; + + [['x', x], ['y', y]].forEach(function (_ref3) { + var _ref4 = slicedToArray(_ref3, 2), + prop = _ref4[0], + val = _ref4[1]; + + text = text.replace('{' + prop + '}', val); + }); + + // Show the text using the custom alert function + $.alert(text); + } + } + }); + + case 7: + case 'end': + return _context.stop(); } } - }], - // This is triggered when the main mouse button is pressed down - // on the editor canvas (not the tool panels) - mouseDown: function mouseDown() { - // Check the mode on mousedown - if (svgCanvas.getMode() === 'hello_world') { - // The returned object must include "started" with - // a value of true in order for mouseUp to be triggered - return { started: true }; - } - }, + }, _callee, this); + })); + function init(_x) { + return _ref2.apply(this, arguments); + } - // This is triggered from anywhere, but "started" must have been set - // to true (see above). Note that "opts" is an object with event info - mouseUp: function mouseUp(opts) { - // Check the mode on mouseup - if (svgCanvas.getMode() === 'hello_world') { - var zoom = svgCanvas.getZoom(); - - // Get the actual coordinate by dividing by the zoom value - var x = opts.mouse_x / zoom; - var y = opts.mouse_y / zoom; - - var text = 'Hello World!\n\nYou clicked here: ' + x + ', ' + y; - - // Show the text using the custom alert function - $.alert(text); - } - } - }; - } + return init; + }() }; return extHelloworld; diff --git a/dist/extensions/ext-imagelib.js b/dist/extensions/ext-imagelib.js index 7513bc4b..385cdf19 100644 --- a/dist/extensions/ext-imagelib.js +++ b/dist/extensions/ext-imagelib.js @@ -30,600 +30,397 @@ var svgEditorExtension_imagelib = (function () { }; }; - var _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; - }; - - // MIT License - // From: https://github.com/uupaa/dynamic-import-polyfill/blob/master/importModule.js - - function toAbsoluteURL(url) { - var a = document.createElement('a'); - a.setAttribute('href', url); // - return a.cloneNode(false).href; // -> "http://example.com/hoge.html" - } - - function addScriptAtts(script, atts) { - ['id', 'class', 'type'].forEach(function (prop) { - if (prop in atts) { - script[prop] = atts[prop]; - } - }); - } - - // Additions by Brett - var importSetGlobalDefault = function () { - var _ref = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(url, config) { - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - return _context.abrupt('return', importSetGlobal(url, _extends({}, config, { returnDefault: true }))); - - case 1: - case 'end': - return _context.stop(); - } - } - }, _callee, this); - })); - - return function importSetGlobalDefault(_x, _x2) { - return _ref.apply(this, arguments); - }; - }(); - var importSetGlobal = function () { - var _ref3 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(url, _ref2) { - var global = _ref2.global, - returnDefault = _ref2.returnDefault; - var modularVersion; - return regeneratorRuntime.wrap(function _callee2$(_context2) { - while (1) { - switch (_context2.prev = _context2.next) { - case 0: - // Todo: Replace calls to this function with `import()` when supported - modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; - - if (!modularVersion) { - _context2.next = 3; - break; - } - - return _context2.abrupt('return', importModule(url, undefined, { returnDefault: returnDefault })); - - case 3: - _context2.next = 5; - return importScript(url); - - case 5: - return _context2.abrupt('return', window[global]); - - case 6: - case 'end': - return _context2.stop(); - } - } - }, _callee2, this); - })); - - return function importSetGlobal(_x3, _x4) { - return _ref3.apply(this, arguments); - }; - }(); - // Addition by Brett - function importScript(url) { - var atts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - if (Array.isArray(url)) { - return Promise.all(url.map(function (u) { - return importScript(u, atts); - })); - } - return new Promise(function (resolve, reject) { - var script = document.createElement('script'); - var destructor = function destructor() { - script.onerror = null; - script.onload = null; - script.remove(); - script.src = ''; - }; - script.defer = 'defer'; - addScriptAtts(script, atts); - script.onerror = function () { - reject(new Error('Failed to import: ' + url)); - destructor(); - }; - script.onload = function () { - resolve(); - destructor(); - }; - script.src = url; - - document.head.append(script); - }); - } - - function importModule(url) { - var atts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - var _ref4 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, - _ref4$returnDefault = _ref4.returnDefault, - returnDefault = _ref4$returnDefault === undefined ? false : _ref4$returnDefault; - - if (Array.isArray(url)) { - return Promise.all(url.map(function (u) { - return importModule(u, atts); - })); - } - return new Promise(function (resolve, reject) { - var vector = '$importModule$' + Math.random().toString(32).slice(2); - var script = document.createElement('script'); - var destructor = function destructor() { - delete window[vector]; - script.onerror = null; - script.onload = null; - script.remove(); - URL.revokeObjectURL(script.src); - script.src = ''; - }; - addScriptAtts(script, atts); - script.defer = 'defer'; - script.type = 'module'; - script.onerror = function () { - reject(new Error('Failed to import: ' + url)); - destructor(); - }; - script.onload = function () { - resolve(window[vector]); - destructor(); - }; - var absURL = toAbsoluteURL(url); - var loader = 'import * as m from \'' + absURL.replace(/'/g, "\\'") + '\'; window.' + vector + ' = ' + (returnDefault ? 'm.default || ' : '') + 'm;'; // export Module - var blob = new Blob([loader], { type: 'text/javascript' }); - script.src = URL.createObjectURL(blob); - - document.head.append(script); - }); - } - /* globals jQuery */ - + /** + * ext-imagelib.js + * + * @license MIT + * + * @copyright 2010 Alexis Deveria + * + */ var extImagelib = { name: 'imagelib', - init: function init(_ref) { - var decode64 = _ref.decode64; + init: function () { + var _ref2 = asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(_ref) { + var decode64 = _ref.decode64, + importLocale = _ref.importLocale; + var imagelibStrings, svgEditor, $, uiStrings, svgCanvas, closeBrowser, importImage, pending, mode, multiArr, transferStopped, preview, submit, toggleMulti, showBrowser, buttons; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + showBrowser = function showBrowser() { + var browser = $('#imgbrowse'); + if (!browser.length) { + $('
' + '
').insertAfter('#svg_docprops'); + browser = $('#imgbrowse'); - var svgEditor = this; - var imagelibStrings = void 0; + var allLibs = imagelibStrings.select_lib; - var $ = jQuery; - var uiStrings = svgEditor.uiStrings, - svgCanvas = svgEditor.canvas; + var libOpts = $('