From 0fc64b491283e0dca16c1676728fac542c1bb5c1 Mon Sep 17 00:00:00 2001 From: Brett Zamir Date: Sat, 18 Jul 2020 18:31:34 +0800 Subject: [PATCH] - Linting: Fix .eslintrc.js overrides to point to new paths (and avoid need for inline disabling--except import/no-namespace) --- .eslintrc.js | 22 +- src/editor/embedapi-dom.js | 1 - src/editor/extensions/ext-arrows.js | 2 - src/editor/extensions/ext-closepath.js | 2 - src/editor/extensions/ext-connector.js | 2 - src/editor/extensions/ext-eyedropper.js | 2 - src/editor/extensions/ext-foreignobject.js | 2 - src/editor/extensions/ext-grid.js | 2 - src/editor/extensions/ext-helloworld.js | 2 - src/editor/extensions/ext-imagelib.js | 3 - src/editor/extensions/ext-locale/arrows/en.js | 1 - src/editor/extensions/ext-locale/arrows/fr.js | 1 - .../extensions/ext-locale/arrows/zh-CN.js | 1 - .../extensions/ext-locale/closepath/en.js | 1 - .../extensions/ext-locale/closepath/zh-CN.js | 1 - .../extensions/ext-locale/connector/en.js | 1 - .../extensions/ext-locale/connector/fr.js | 1 - .../extensions/ext-locale/connector/zh-CN.js | 1 - .../extensions/ext-locale/eyedropper/en.js | 1 - .../extensions/ext-locale/eyedropper/zh-CN.js | 1 - .../extensions/ext-locale/foreignobject/en.js | 1 - .../ext-locale/foreignobject/zh-CN.js | 1 - src/editor/extensions/ext-locale/grid/en.js | 1 - .../extensions/ext-locale/grid/zh-CN.js | 1 - .../extensions/ext-locale/helloworld/en.js | 1 - .../extensions/ext-locale/helloworld/zh-CN.js | 1 - .../extensions/ext-locale/imagelib/de.js | 1 - .../extensions/ext-locale/imagelib/en.js | 1 - .../extensions/ext-locale/imagelib/fr.js | 1 - .../extensions/ext-locale/imagelib/pl.js | 1 - .../extensions/ext-locale/imagelib/pt-BR.js | 1 - .../extensions/ext-locale/imagelib/ro.js | 1 - .../extensions/ext-locale/imagelib/sk.js | 1 - .../extensions/ext-locale/imagelib/sl.js | 1 - .../extensions/ext-locale/imagelib/zh-CN.js | 1 - .../extensions/ext-locale/markers/en.js | 1 - .../extensions/ext-locale/markers/zh-CN.js | 1 - .../extensions/ext-locale/mathjax/en.js | 1 - .../extensions/ext-locale/mathjax/zh-CN.js | 1 - .../extensions/ext-locale/panning/en.js | 1 - .../extensions/ext-locale/panning/zh-CN.js | 1 - .../extensions/ext-locale/placemark/en.js | 1 - .../extensions/ext-locale/polygon/en.js | 1 - .../extensions/ext-locale/polygon/zh-CN.js | 1 - .../ext-locale/server_moinsave/en.js | 1 - .../ext-locale/server_moinsave/zh-CN.js | 1 - .../ext-locale/server_opensave/en.js | 1 - .../ext-locale/server_opensave/zh-CN.js | 1 - src/editor/extensions/ext-locale/shapes/en.js | 1 - src/editor/extensions/ext-locale/shapes/fr.js | 1 - .../extensions/ext-locale/shapes/zh-CN.js | 1 - src/editor/extensions/ext-locale/star/en.js | 1 - .../extensions/ext-locale/star/zh-CN.js | 1 - .../extensions/ext-locale/storage/de.js | 1 - .../extensions/ext-locale/storage/en.js | 1 - .../extensions/ext-locale/storage/fr.js | 1 - .../extensions/ext-locale/storage/zh-CN.js | 1 - .../extensions/ext-locale/webappfind/en.js | 1 - .../extensions/ext-locale/webappfind/zh-CN.js | 1 - src/editor/extensions/ext-markers.js | 2 - src/editor/extensions/ext-mathjax.js | 2 - src/editor/extensions/ext-overview_window.js | 1 - src/editor/extensions/ext-panning.js | 2 - src/editor/extensions/ext-php_savefile.js | 2 - src/editor/extensions/ext-placemark.js | 2 - src/editor/extensions/ext-polygon.js | 2 - src/editor/extensions/ext-server_moinsave.js | 3 - src/editor/extensions/ext-server_opensave.js | 2 - src/editor/extensions/ext-shapes.js | 2 - src/editor/extensions/ext-star.js | 2 - src/editor/extensions/ext-storage.js | 3 - src/editor/extensions/ext-webappfind.js | 2 - .../extensions/ext-xdomain-messaging.js | 2 - src/editor/extensions/imagelib/index.js | 1 - src/editor/extensions/imagelib/openclipart.js | 1 - src/editor/locale/lang.af.js | 1 - src/editor/locale/lang.ar.js | 1 - src/editor/locale/lang.az.js | 1 - src/editor/locale/lang.be.js | 1 - src/editor/locale/lang.bg.js | 1 - src/editor/locale/lang.ca.js | 1 - src/editor/locale/lang.cs.js | 1 - src/editor/locale/lang.cy.js | 1 - src/editor/locale/lang.da.js | 1 - src/editor/locale/lang.de.js | 1 - src/editor/locale/lang.el.js | 1 - src/editor/locale/lang.en.js | 1 - src/editor/locale/lang.es.js | 1 - src/editor/locale/lang.et.js | 1 - src/editor/locale/lang.fa.js | 1 - src/editor/locale/lang.fi.js | 1 - src/editor/locale/lang.fr.js | 1 - src/editor/locale/lang.fy.js | 1 - src/editor/locale/lang.ga.js | 1 - src/editor/locale/lang.gl.js | 1 - src/editor/locale/lang.he.js | 1 - src/editor/locale/lang.hi.js | 1 - src/editor/locale/lang.hr.js | 1 - src/editor/locale/lang.hu.js | 1 - src/editor/locale/lang.hy.js | 1 - src/editor/locale/lang.id.js | 1 - src/editor/locale/lang.is.js | 1 - src/editor/locale/lang.it.js | 1 - src/editor/locale/lang.ja.js | 1 - src/editor/locale/lang.ko.js | 1 - src/editor/locale/lang.lt.js | 1 - src/editor/locale/lang.lv.js | 1 - src/editor/locale/lang.mk.js | 1 - src/editor/locale/lang.ms.js | 1 - src/editor/locale/lang.mt.js | 1 - src/editor/locale/lang.nl.js | 1 - src/editor/locale/lang.no.js | 1 - src/editor/locale/lang.pl.js | 1 - src/editor/locale/lang.pt-BR.js | 1 - src/editor/locale/lang.pt-PT.js | 1 - src/editor/locale/lang.ro.js | 1 - src/editor/locale/lang.ru.js | 1 - src/editor/locale/lang.sk.js | 1 - src/editor/locale/lang.sl.js | 1 - src/editor/locale/lang.sq.js | 1 - src/editor/locale/lang.sr.js | 1 - src/editor/locale/lang.sv.js | 1 - src/editor/locale/lang.sw.js | 1 - src/editor/locale/lang.test.js | 1 - src/editor/locale/lang.th.js | 1 - src/editor/locale/lang.tl.js | 1 - src/editor/locale/lang.tr.js | 1 - src/editor/locale/lang.uk.js | 1 - src/editor/locale/lang.vi.js | 1 - src/editor/locale/lang.yi.js | 1 - src/editor/locale/lang.zh-CN.js | 1 - src/editor/locale/lang.zh-HK.js | 1 - src/editor/locale/lang.zh-TW.js | 1 - src/editor/redirect-on-no-module-support.js | 1 - src/editor/svg-editor.js | 2 +- src/editor/touch.js | 1 - src/editor/typedefs.js | 1 - svgedit-config-iife.js | 37916 ++++++++-------- 138 files changed, 18257 insertions(+), 19842 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 823b3cb9..52e284cb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,7 +32,7 @@ module.exports = { // Locales have no need for importing outside of SVG-Edit { files: [ - 'editor/locale/lang.*.js', 'editor/extensions/ext-locale/**', + 'src/editor/locale/lang.*.js', 'src/editor/extensions/ext-locale/**', 'docs/tutorials/ExtensionDocs.md' ], rules: { @@ -42,18 +42,20 @@ module.exports = { // These browser files don't do importing or requiring { files: [ - 'editor/svgpathseg.js', 'editor/touch.js', 'editor/typedefs.js', - 'editor/redirect-on-no-module-support.js', - 'editor/extensions/imagelib/index.js', - 'editor/external/dom-polyfill/dom-polyfill.js', - 'screencasts/svgopen2010/script.js' + 'src/editor/svgpathseg.js', + 'src/editor/touch.js', + 'src/editor/typedefs.js', + 'src/editor/redirect-on-no-module-support.js', + 'src/editor/extensions/imagelib/index.js', + 'src/editor/external/dom-polyfill/dom-polyfill.js', + 'docs/screencasts/svgopen2010/script.js' ], rules: { 'import/unambiguous': ['off'] } }, { - files: ['**/*.html', 'screencasts/**'], + files: ['**/*.html', 'docs/screencasts/**'], globals: { root: 'off' }, @@ -119,7 +121,7 @@ module.exports = { // Dis-apply Node rules mistakenly giving errors with browser files, // and treating Node global `root` as being present for shadowing { - files: ['editor/**'], + files: ['src/editor/**'], globals: { root: 'off' }, @@ -184,7 +186,7 @@ module.exports = { // descriptive `svgEditor`; they also have no need for importing outside // of SVG-Edit { - files: ['editor/extensions/**'], + files: ['src/editor/extensions/**'], settings: { polyfills: [ 'console', @@ -244,7 +246,7 @@ module.exports = { }, { // Should probably have as external, but should still check - files: ['canvg/rgbcolor.js'], + files: ['src/editor/canvg/rgbcolor.js'], settings: { polyfills: [ 'Number.isNaN', diff --git a/src/editor/embedapi-dom.js b/src/editor/embedapi-dom.js index 9a0e9c3a..3eb72974 100644 --- a/src/editor/embedapi-dom.js +++ b/src/editor/embedapi-dom.js @@ -101,7 +101,6 @@ iframe[0].src = frameBase + framePath + : ''); // Append arguments to this file onto the iframe iframe[0].addEventListener('load', function () { - // eslint-disable-next-line node/no-unsupported-features/node-builtins svgCanvas = new EmbeddedSVGEdit(frame, [new URL(frameBase).origin]); // Hide main button, as we will be controlling new, load, save, etc. from the host document let doc; diff --git a/src/editor/extensions/ext-arrows.js b/src/editor/extensions/ext-arrows.js index 0066f2bb..61c703e0 100644 --- a/src/editor/extensions/ext-arrows.js +++ b/src/editor/extensions/ext-arrows.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-arrows.js * @@ -12,7 +11,6 @@ export default { name: 'arrows', async init (S) { const strings = await S.importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const // {svgcontent} = S, diff --git a/src/editor/extensions/ext-closepath.js b/src/editor/extensions/ext-closepath.js index 979bb722..137ec2aa 100644 --- a/src/editor/extensions/ext-closepath.js +++ b/src/editor/extensions/ext-closepath.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-closepath.js * @@ -15,7 +14,6 @@ export default { name: 'closepath', async init ({importLocale, $}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; let selElems; const updateButton = function (path) { diff --git a/src/editor/extensions/ext-connector.js b/src/editor/extensions/ext-connector.js index eadfa2a6..7cd1f70a 100644 --- a/src/editor/extensions/ext-connector.js +++ b/src/editor/extensions/ext-connector.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /* eslint-disable unicorn/no-fn-reference-in-iterator */ /** * @file ext-connector.js @@ -12,7 +11,6 @@ export default { name: 'connector', async init (S) { - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const {getElem} = svgCanvas; diff --git a/src/editor/extensions/ext-eyedropper.js b/src/editor/extensions/ext-eyedropper.js index ce58979d..49a23e8a 100644 --- a/src/editor/extensions/ext-eyedropper.js +++ b/src/editor/extensions/ext-eyedropper.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-eyedropper.js * @@ -12,7 +11,6 @@ export default { name: 'eyedropper', async init (S) { const strings = await S.importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const {$, ChangeElementCommand} = S, // , svgcontent, // svgdoc = S.svgroot.parentNode.ownerDocument, diff --git a/src/editor/extensions/ext-foreignobject.js b/src/editor/extensions/ext-foreignobject.js index 2e16f6df..31a83693 100644 --- a/src/editor/extensions/ext-foreignobject.js +++ b/src/editor/extensions/ext-foreignobject.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-foreignobject.js * @@ -11,7 +10,6 @@ export default { name: 'foreignobject', async init (S) { - // eslint-disable-next-line consistent-this const svgEditor = this; const {$, text2xml, NS, importLocale} = S; const svgCanvas = svgEditor.canvas; diff --git a/src/editor/extensions/ext-grid.js b/src/editor/extensions/ext-grid.js index bb3bc66b..cba3eb91 100644 --- a/src/editor/extensions/ext-grid.js +++ b/src/editor/extensions/ext-grid.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-grid.js * @@ -12,7 +11,6 @@ export default { name: 'grid', async init ({$, NS, getTypeMap, importLocale}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const svgdoc = document.getElementById('svgcanvas').ownerDocument, diff --git a/src/editor/extensions/ext-helloworld.js b/src/editor/extensions/ext-helloworld.js index bdc50caf..fbe2dfa4 100644 --- a/src/editor/extensions/ext-helloworld.js +++ b/src/editor/extensions/ext-helloworld.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-helloworld.js * @@ -18,7 +17,6 @@ export default { async init ({$, importLocale}) { // See `/editor/extensions/ext-locale/helloworld/` const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; return { diff --git a/src/editor/extensions/ext-imagelib.js b/src/editor/extensions/ext-imagelib.js index 75180db7..6ee0c2a7 100644 --- a/src/editor/extensions/ext-imagelib.js +++ b/src/editor/extensions/ext-imagelib.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-imagelib.js * @@ -16,7 +15,6 @@ export default { !window.svgEditor || window.svgEditor.modules !== false; - // eslint-disable-next-line consistent-this const svgEditor = this; const {uiStrings, canvas: svgCanvas, curConfig: {extIconsPath}} = svgEditor; @@ -39,7 +37,6 @@ export default { }); const allowedImageLibOrigins = imagelibStrings.imgLibs.map(({url}) => { try { - // eslint-disable-next-line node/no-unsupported-features/node-builtins return new URL(url).origin; } catch (err) { return location.origin; diff --git a/src/editor/extensions/ext-locale/arrows/en.js b/src/editor/extensions/ext-locale/arrows/en.js index 9aa21dc6..b5f0a884 100644 --- a/src/editor/extensions/ext-locale/arrows/en.js +++ b/src/editor/extensions/ext-locale/arrows/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Arrows', langList: [ diff --git a/src/editor/extensions/ext-locale/arrows/fr.js b/src/editor/extensions/ext-locale/arrows/fr.js index 9ef53adf..ea223018 100644 --- a/src/editor/extensions/ext-locale/arrows/fr.js +++ b/src/editor/extensions/ext-locale/arrows/fr.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Arrows', langList: [ diff --git a/src/editor/extensions/ext-locale/arrows/zh-CN.js b/src/editor/extensions/ext-locale/arrows/zh-CN.js index a985ee29..bbe2e860 100755 --- a/src/editor/extensions/ext-locale/arrows/zh-CN.js +++ b/src/editor/extensions/ext-locale/arrows/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '箭头', langList: [ diff --git a/src/editor/extensions/ext-locale/closepath/en.js b/src/editor/extensions/ext-locale/closepath/en.js index d091f927..5b57d617 100644 --- a/src/editor/extensions/ext-locale/closepath/en.js +++ b/src/editor/extensions/ext-locale/closepath/en.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { name: 'ClosePath', buttons: [ diff --git a/src/editor/extensions/ext-locale/closepath/zh-CN.js b/src/editor/extensions/ext-locale/closepath/zh-CN.js index 71ca0866..20f0c42d 100755 --- a/src/editor/extensions/ext-locale/closepath/zh-CN.js +++ b/src/editor/extensions/ext-locale/closepath/zh-CN.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { name: '闭合路径', buttons: [ diff --git a/src/editor/extensions/ext-locale/connector/en.js b/src/editor/extensions/ext-locale/connector/en.js index 4fd8a9b4..beef9a7f 100644 --- a/src/editor/extensions/ext-locale/connector/en.js +++ b/src/editor/extensions/ext-locale/connector/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Connector', langList: [ diff --git a/src/editor/extensions/ext-locale/connector/fr.js b/src/editor/extensions/ext-locale/connector/fr.js index 0982ce50..aec84749 100644 --- a/src/editor/extensions/ext-locale/connector/fr.js +++ b/src/editor/extensions/ext-locale/connector/fr.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Connector', langList: [ diff --git a/src/editor/extensions/ext-locale/connector/zh-CN.js b/src/editor/extensions/ext-locale/connector/zh-CN.js index 6dc4c7cb..e5749d17 100755 --- a/src/editor/extensions/ext-locale/connector/zh-CN.js +++ b/src/editor/extensions/ext-locale/connector/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '连接器', langList: [ diff --git a/src/editor/extensions/ext-locale/eyedropper/en.js b/src/editor/extensions/ext-locale/eyedropper/en.js index cb9f97e8..8c7fdc54 100644 --- a/src/editor/extensions/ext-locale/eyedropper/en.js +++ b/src/editor/extensions/ext-locale/eyedropper/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'eyedropper', buttons: [ diff --git a/src/editor/extensions/ext-locale/eyedropper/zh-CN.js b/src/editor/extensions/ext-locale/eyedropper/zh-CN.js index 359d7e0d..3f31a971 100755 --- a/src/editor/extensions/ext-locale/eyedropper/zh-CN.js +++ b/src/editor/extensions/ext-locale/eyedropper/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '滴管', buttons: [ diff --git a/src/editor/extensions/ext-locale/foreignobject/en.js b/src/editor/extensions/ext-locale/foreignobject/en.js index 040d1417..79e39cf0 100644 --- a/src/editor/extensions/ext-locale/foreignobject/en.js +++ b/src/editor/extensions/ext-locale/foreignobject/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'foreignObject', buttons: [ diff --git a/src/editor/extensions/ext-locale/foreignobject/zh-CN.js b/src/editor/extensions/ext-locale/foreignobject/zh-CN.js index c2858d20..9b221b8a 100755 --- a/src/editor/extensions/ext-locale/foreignobject/zh-CN.js +++ b/src/editor/extensions/ext-locale/foreignobject/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '外部对象', buttons: [ diff --git a/src/editor/extensions/ext-locale/grid/en.js b/src/editor/extensions/ext-locale/grid/en.js index fbde3137..8472da87 100644 --- a/src/editor/extensions/ext-locale/grid/en.js +++ b/src/editor/extensions/ext-locale/grid/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'View Grid', buttons: [ diff --git a/src/editor/extensions/ext-locale/grid/zh-CN.js b/src/editor/extensions/ext-locale/grid/zh-CN.js index b8912c91..4c264d8a 100755 --- a/src/editor/extensions/ext-locale/grid/zh-CN.js +++ b/src/editor/extensions/ext-locale/grid/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '网格视图', buttons: [ diff --git a/src/editor/extensions/ext-locale/helloworld/en.js b/src/editor/extensions/ext-locale/helloworld/en.js index 0e0b5d64..e52406fa 100644 --- a/src/editor/extensions/ext-locale/helloworld/en.js +++ b/src/editor/extensions/ext-locale/helloworld/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Hello World', text: 'Hello World!\n\nYou clicked here: {x}, {y}', diff --git a/src/editor/extensions/ext-locale/helloworld/zh-CN.js b/src/editor/extensions/ext-locale/helloworld/zh-CN.js index b1678bc8..87912014 100755 --- a/src/editor/extensions/ext-locale/helloworld/zh-CN.js +++ b/src/editor/extensions/ext-locale/helloworld/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Hello World', text: 'Hello World!\n\n 请点击: {x}, {y}', diff --git a/src/editor/extensions/ext-locale/imagelib/de.js b/src/editor/extensions/ext-locale/imagelib/de.js index 09495638..184d0109 100644 --- a/src/editor/extensions/ext-locale/imagelib/de.js +++ b/src/editor/extensions/ext-locale/imagelib/de.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/en.js b/src/editor/extensions/ext-locale/imagelib/en.js index 71a07d5d..e3e0c311 100644 --- a/src/editor/extensions/ext-locale/imagelib/en.js +++ b/src/editor/extensions/ext-locale/imagelib/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/fr.js b/src/editor/extensions/ext-locale/imagelib/fr.js index 84d8681a..f2f5ba16 100644 --- a/src/editor/extensions/ext-locale/imagelib/fr.js +++ b/src/editor/extensions/ext-locale/imagelib/fr.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: "Choisir une bibliothèque d'images", show_list: 'show_list', diff --git a/src/editor/extensions/ext-locale/imagelib/pl.js b/src/editor/extensions/ext-locale/imagelib/pl.js index a281bad0..035649d9 100644 --- a/src/editor/extensions/ext-locale/imagelib/pl.js +++ b/src/editor/extensions/ext-locale/imagelib/pl.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/pt-BR.js b/src/editor/extensions/ext-locale/imagelib/pt-BR.js index fb510201..155c7f3e 100644 --- a/src/editor/extensions/ext-locale/imagelib/pt-BR.js +++ b/src/editor/extensions/ext-locale/imagelib/pt-BR.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/ro.js b/src/editor/extensions/ext-locale/imagelib/ro.js index e9a80781..cb557f02 100644 --- a/src/editor/extensions/ext-locale/imagelib/ro.js +++ b/src/editor/extensions/ext-locale/imagelib/ro.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/sk.js b/src/editor/extensions/ext-locale/imagelib/sk.js index 022dbc4f..cf399c72 100644 --- a/src/editor/extensions/ext-locale/imagelib/sk.js +++ b/src/editor/extensions/ext-locale/imagelib/sk.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/sl.js b/src/editor/extensions/ext-locale/imagelib/sl.js index 5bbc3373..200d0770 100644 --- a/src/editor/extensions/ext-locale/imagelib/sl.js +++ b/src/editor/extensions/ext-locale/imagelib/sl.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/imagelib/zh-CN.js b/src/editor/extensions/ext-locale/imagelib/zh-CN.js index d925f3b7..b67094cb 100644 --- a/src/editor/extensions/ext-locale/imagelib/zh-CN.js +++ b/src/editor/extensions/ext-locale/imagelib/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { select_lib: 'Select an image library', show_list: 'Show library list', diff --git a/src/editor/extensions/ext-locale/markers/en.js b/src/editor/extensions/ext-locale/markers/en.js index 7c99e649..69201e4d 100644 --- a/src/editor/extensions/ext-locale/markers/en.js +++ b/src/editor/extensions/ext-locale/markers/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Markers', langList: [ diff --git a/src/editor/extensions/ext-locale/markers/zh-CN.js b/src/editor/extensions/ext-locale/markers/zh-CN.js index db420dfc..1efe8a0a 100755 --- a/src/editor/extensions/ext-locale/markers/zh-CN.js +++ b/src/editor/extensions/ext-locale/markers/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '标记', langList: [ diff --git a/src/editor/extensions/ext-locale/mathjax/en.js b/src/editor/extensions/ext-locale/mathjax/en.js index aaaf101a..916899ca 100644 --- a/src/editor/extensions/ext-locale/mathjax/en.js +++ b/src/editor/extensions/ext-locale/mathjax/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'MathJax', buttons: [ diff --git a/src/editor/extensions/ext-locale/mathjax/zh-CN.js b/src/editor/extensions/ext-locale/mathjax/zh-CN.js index 45ea353f..0abe8529 100755 --- a/src/editor/extensions/ext-locale/mathjax/zh-CN.js +++ b/src/editor/extensions/ext-locale/mathjax/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '数学', buttons: [ diff --git a/src/editor/extensions/ext-locale/panning/en.js b/src/editor/extensions/ext-locale/panning/en.js index 4580e7e7..5bd26b8b 100644 --- a/src/editor/extensions/ext-locale/panning/en.js +++ b/src/editor/extensions/ext-locale/panning/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'Extension Panning', buttons: [ diff --git a/src/editor/extensions/ext-locale/panning/zh-CN.js b/src/editor/extensions/ext-locale/panning/zh-CN.js index 363393e6..a6264077 100755 --- a/src/editor/extensions/ext-locale/panning/zh-CN.js +++ b/src/editor/extensions/ext-locale/panning/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '移动', buttons: [ diff --git a/src/editor/extensions/ext-locale/placemark/en.js b/src/editor/extensions/ext-locale/placemark/en.js index f9cbbb68..24e53af6 100644 --- a/src/editor/extensions/ext-locale/placemark/en.js +++ b/src/editor/extensions/ext-locale/placemark/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'placemark', langList: [ diff --git a/src/editor/extensions/ext-locale/polygon/en.js b/src/editor/extensions/ext-locale/polygon/en.js index a53c4475..ddca9727 100644 --- a/src/editor/extensions/ext-locale/polygon/en.js +++ b/src/editor/extensions/ext-locale/polygon/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'polygon', buttons: [ diff --git a/src/editor/extensions/ext-locale/polygon/zh-CN.js b/src/editor/extensions/ext-locale/polygon/zh-CN.js index b24a768f..6bfcc476 100755 --- a/src/editor/extensions/ext-locale/polygon/zh-CN.js +++ b/src/editor/extensions/ext-locale/polygon/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '多边形', buttons: [ diff --git a/src/editor/extensions/ext-locale/server_moinsave/en.js b/src/editor/extensions/ext-locale/server_moinsave/en.js index a3ceb651..7b7b4442 100644 --- a/src/editor/extensions/ext-locale/server_moinsave/en.js +++ b/src/editor/extensions/ext-locale/server_moinsave/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { saved: 'Saved! Return to Item View!', hiddenframe: 'Moinsave frame to store hidden values' diff --git a/src/editor/extensions/ext-locale/server_moinsave/zh-CN.js b/src/editor/extensions/ext-locale/server_moinsave/zh-CN.js index c676bef6..bdf4e720 100755 --- a/src/editor/extensions/ext-locale/server_moinsave/zh-CN.js +++ b/src/editor/extensions/ext-locale/server_moinsave/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { saved: '已保存! 返回视图!', hiddenframe: 'Moinsave frame to store hidden values' diff --git a/src/editor/extensions/ext-locale/server_opensave/en.js b/src/editor/extensions/ext-locale/server_opensave/en.js index 7b0e79aa..db251eb6 100644 --- a/src/editor/extensions/ext-locale/server_opensave/en.js +++ b/src/editor/extensions/ext-locale/server_opensave/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { uploading: 'Uploading...', hiddenframe: 'Opensave frame to store hidden values' diff --git a/src/editor/extensions/ext-locale/server_opensave/zh-CN.js b/src/editor/extensions/ext-locale/server_opensave/zh-CN.js index 157a304c..17d9b755 100755 --- a/src/editor/extensions/ext-locale/server_opensave/zh-CN.js +++ b/src/editor/extensions/ext-locale/server_opensave/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { uploading: '正在上传...', hiddenframe: 'Opensave frame to store hidden values' diff --git a/src/editor/extensions/ext-locale/shapes/en.js b/src/editor/extensions/ext-locale/shapes/en.js index e37bce6e..83a67ccf 100644 --- a/src/editor/extensions/ext-locale/shapes/en.js +++ b/src/editor/extensions/ext-locale/shapes/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { loading: 'Loading...', categories: { diff --git a/src/editor/extensions/ext-locale/shapes/fr.js b/src/editor/extensions/ext-locale/shapes/fr.js index 3face77e..4b46c391 100644 --- a/src/editor/extensions/ext-locale/shapes/fr.js +++ b/src/editor/extensions/ext-locale/shapes/fr.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { loading: 'Loading...', categories: { diff --git a/src/editor/extensions/ext-locale/shapes/zh-CN.js b/src/editor/extensions/ext-locale/shapes/zh-CN.js index 6105d031..4b76d7a4 100755 --- a/src/editor/extensions/ext-locale/shapes/zh-CN.js +++ b/src/editor/extensions/ext-locale/shapes/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { loading: '正在加载...', categories: { diff --git a/src/editor/extensions/ext-locale/star/en.js b/src/editor/extensions/ext-locale/star/en.js index dd678fec..da9d857c 100644 --- a/src/editor/extensions/ext-locale/star/en.js +++ b/src/editor/extensions/ext-locale/star/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'star', buttons: [ diff --git a/src/editor/extensions/ext-locale/star/zh-CN.js b/src/editor/extensions/ext-locale/star/zh-CN.js index c132e523..d9ee06da 100755 --- a/src/editor/extensions/ext-locale/star/zh-CN.js +++ b/src/editor/extensions/ext-locale/star/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: '星形', buttons: [ diff --git a/src/editor/extensions/ext-locale/storage/de.js b/src/editor/extensions/ext-locale/storage/de.js index 9c3d2de0..d3160369 100644 --- a/src/editor/extensions/ext-locale/storage/de.js +++ b/src/editor/extensions/ext-locale/storage/de.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { message: 'Standardmäßig kann SVG-Edit Ihre Editor-Einstellungen ' + 'und die SVG-Inhalte lokal auf Ihrem Gerät abspeichern. So brauchen Sie ' + diff --git a/src/editor/extensions/ext-locale/storage/en.js b/src/editor/extensions/ext-locale/storage/en.js index 30f74e76..568e0b9f 100644 --- a/src/editor/extensions/ext-locale/storage/en.js +++ b/src/editor/extensions/ext-locale/storage/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { message: 'By default and where supported, SVG-Edit can store your editor ' + 'preferences and SVG content locally on your machine so you do not ' + diff --git a/src/editor/extensions/ext-locale/storage/fr.js b/src/editor/extensions/ext-locale/storage/fr.js index 8e5823eb..9c454dbb 100644 --- a/src/editor/extensions/ext-locale/storage/fr.js +++ b/src/editor/extensions/ext-locale/storage/fr.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { message: "Par défaut et si supporté, SVG-Edit peut stocker les préférences de l'éditeur " + "et le contenu SVG localement sur votre machine de sorte que vous n'ayez pas besoin de les " + diff --git a/src/editor/extensions/ext-locale/storage/zh-CN.js b/src/editor/extensions/ext-locale/storage/zh-CN.js index 44f54248..1de1f9dc 100755 --- a/src/editor/extensions/ext-locale/storage/zh-CN.js +++ b/src/editor/extensions/ext-locale/storage/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { message: '默认情况下, SVG-Edit 在本地保存配置参数和画布内容. 如果基于隐私考虑, ' + '您可以勾选以下选项修改配置.', diff --git a/src/editor/extensions/ext-locale/webappfind/en.js b/src/editor/extensions/ext-locale/webappfind/en.js index 34cc7d9c..92be802c 100644 --- a/src/editor/extensions/ext-locale/webappfind/en.js +++ b/src/editor/extensions/ext-locale/webappfind/en.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'WebAppFind', buttons: [ diff --git a/src/editor/extensions/ext-locale/webappfind/zh-CN.js b/src/editor/extensions/ext-locale/webappfind/zh-CN.js index 1c46fe9e..0831c4b0 100755 --- a/src/editor/extensions/ext-locale/webappfind/zh-CN.js +++ b/src/editor/extensions/ext-locale/webappfind/zh-CN.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { name: 'WebAppFind', buttons: [ diff --git a/src/editor/extensions/ext-markers.js b/src/editor/extensions/ext-markers.js index 6d451773..c521eff1 100644 --- a/src/editor/extensions/ext-markers.js +++ b/src/editor/extensions/ext-markers.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-markers.js * @@ -33,7 +32,6 @@ export default { name: 'markers', async init (S) { const strings = await S.importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const {$} = S; const svgCanvas = svgEditor.canvas; diff --git a/src/editor/extensions/ext-mathjax.js b/src/editor/extensions/ext-mathjax.js index 4e480c56..9f649b9b 100644 --- a/src/editor/extensions/ext-mathjax.js +++ b/src/editor/extensions/ext-mathjax.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /* globals MathJax */ /** * @file ext-mathjax.js @@ -15,7 +14,6 @@ export default { name: 'mathjax', async init ({$, importLocale}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; diff --git a/src/editor/extensions/ext-overview_window.js b/src/editor/extensions/ext-overview_window.js index d23c0658..8910c79d 100644 --- a/src/editor/extensions/ext-overview_window.js +++ b/src/editor/extensions/ext-overview_window.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-overview_window.js * diff --git a/src/editor/extensions/ext-panning.js b/src/editor/extensions/ext-panning.js index 0215eac3..2a581b75 100644 --- a/src/editor/extensions/ext-panning.js +++ b/src/editor/extensions/ext-panning.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-panning.js * @@ -14,7 +13,6 @@ export default { name: 'panning', async init ({importLocale}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const buttons = [{ diff --git a/src/editor/extensions/ext-php_savefile.js b/src/editor/extensions/ext-php_savefile.js index 779a61d9..a66d747d 100644 --- a/src/editor/extensions/ext-php_savefile.js +++ b/src/editor/extensions/ext-php_savefile.js @@ -1,11 +1,9 @@ -/* eslint-disable import/no-anonymous-default-export */ // TODO: Might add support for "exportImage" custom // handler as in "ext-server_opensave.js" (and in savefile.php) export default { name: 'php_savefile', init ({$}) { - // eslint-disable-next-line consistent-this const svgEditor = this; const { curConfig: {extPath}, diff --git a/src/editor/extensions/ext-placemark.js b/src/editor/extensions/ext-placemark.js index b1e632d1..55d7e398 100644 --- a/src/editor/extensions/ext-placemark.js +++ b/src/editor/extensions/ext-placemark.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-placemark.js * @@ -9,7 +8,6 @@ export default { name: 'placemark', async init (S) { - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const addElem = svgCanvas.addSVGElementFromJson; diff --git a/src/editor/extensions/ext-polygon.js b/src/editor/extensions/ext-polygon.js index de3e6d6a..df026dd7 100644 --- a/src/editor/extensions/ext-polygon.js +++ b/src/editor/extensions/ext-polygon.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-polygon.js * @@ -9,7 +8,6 @@ export default { name: 'polygon', async init (S) { - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const {$, importLocale} = S, // {svgcontent} diff --git a/src/editor/extensions/ext-server_moinsave.js b/src/editor/extensions/ext-server_moinsave.js index a27d0954..6725c255 100644 --- a/src/editor/extensions/ext-server_moinsave.js +++ b/src/editor/extensions/ext-server_moinsave.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-server_moinsave.js * @@ -14,7 +13,6 @@ export default { name: 'server_moinsave', async init ({$, encode64, importLocale}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; const saveSvgAction = '/+modify'; @@ -30,7 +28,6 @@ export default { svgEditor.setCustomHandlers({ async save (win, data) { const svg = '\n' + data; - // eslint-disable-next-line node/no-unsupported-features/node-builtins const {pathname} = new URL(location); const name = pathname.replace(/\/+get\//, ''); const svgData = encode64(svg); diff --git a/src/editor/extensions/ext-server_opensave.js b/src/editor/extensions/ext-server_opensave.js index bf925488..86149dd6 100644 --- a/src/editor/extensions/ext-server_opensave.js +++ b/src/editor/extensions/ext-server_opensave.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-server_opensave.js * @@ -13,7 +12,6 @@ export default { name: 'server_opensave', async init ({$, decode64, encode64, importLocale}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const { curConfig: { diff --git a/src/editor/extensions/ext-shapes.js b/src/editor/extensions/ext-shapes.js index eb32d97c..49084bde 100644 --- a/src/editor/extensions/ext-shapes.js +++ b/src/editor/extensions/ext-shapes.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-shapes.js * @@ -11,7 +10,6 @@ export default { name: 'shapes', async init ({$, importLocale}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const canv = svgEditor.canvas; const svgroot = canv.getRootElem(); diff --git a/src/editor/extensions/ext-star.js b/src/editor/extensions/ext-star.js index e71eb589..c1042360 100644 --- a/src/editor/extensions/ext-star.js +++ b/src/editor/extensions/ext-star.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-star.js * @@ -9,7 +8,6 @@ export default { name: 'star', async init (S) { - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; diff --git a/src/editor/extensions/ext-storage.js b/src/editor/extensions/ext-storage.js index e649d1c7..98a2b266 100644 --- a/src/editor/extensions/ext-storage.js +++ b/src/editor/extensions/ext-storage.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * @file ext-storage.js * @@ -23,7 +22,6 @@ export default { name: 'storage', init ({$}) { - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; @@ -168,7 +166,6 @@ export default { return { name: 'storage', async langReady ({importLocale}) { - // eslint-disable-next-line node/no-unsupported-features/node-builtins const storagePrompt = new URL(top.location).searchParams.get('storagePrompt'); const confirmSetStorage = await importLocale(); diff --git a/src/editor/extensions/ext-webappfind.js b/src/editor/extensions/ext-webappfind.js index 28408406..4eb86c08 100644 --- a/src/editor/extensions/ext-webappfind.js +++ b/src/editor/extensions/ext-webappfind.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * Depends on Firefox add-on and executables from * {@link https://github.com/brettz9/webappfind}. @@ -11,7 +10,6 @@ export default { name: 'webappfind', async init ({importLocale, $}) { const strings = await importLocale(); - // eslint-disable-next-line consistent-this const svgEditor = this; const saveMessage = 'save', readMessage = 'read', diff --git a/src/editor/extensions/ext-xdomain-messaging.js b/src/editor/extensions/ext-xdomain-messaging.js index 576a85e3..78b3144a 100644 --- a/src/editor/extensions/ext-xdomain-messaging.js +++ b/src/editor/extensions/ext-xdomain-messaging.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ /** * Should not be needed for same domain control (just call via child frame), * but an API common for cross-domain and same domain use can be found @@ -7,7 +6,6 @@ export default { name: 'xdomain-messaging', init () { - // eslint-disable-next-line consistent-this const svgEditor = this; const svgCanvas = svgEditor.canvas; try { diff --git a/src/editor/extensions/imagelib/index.js b/src/editor/extensions/imagelib/index.js index 1bcfac5c..6521469a 100644 --- a/src/editor/extensions/imagelib/index.js +++ b/src/editor/extensions/imagelib/index.js @@ -1,4 +1,3 @@ -/* eslint-disable import/unambiguous */ /* globals jQuery */ const $ = jQuery; $('a').click(function () { diff --git a/src/editor/extensions/imagelib/openclipart.js b/src/editor/extensions/imagelib/openclipart.js index d210b001..d033525c 100644 --- a/src/editor/extensions/imagelib/openclipart.js +++ b/src/editor/extensions/imagelib/openclipart.js @@ -248,7 +248,6 @@ jml('div', [ id: 'openclipart', $custom: { async $submit () { - // eslint-disable-next-line node/no-unsupported-features/node-builtins const url = new URL(baseAPIURL); [ 'query', 'sort', 'amount', 'page', 'byids' diff --git a/src/editor/locale/lang.af.js b/src/editor/locale/lang.af.js index 67e75dfe..0cada5d5 100644 --- a/src/editor/locale/lang.af.js +++ b/src/editor/locale/lang.af.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'af', dir: 'ltr', diff --git a/src/editor/locale/lang.ar.js b/src/editor/locale/lang.ar.js index 559334f0..20430852 100644 --- a/src/editor/locale/lang.ar.js +++ b/src/editor/locale/lang.ar.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ar', dir: 'rtl', diff --git a/src/editor/locale/lang.az.js b/src/editor/locale/lang.az.js index 58e61f56..c13c47c4 100644 --- a/src/editor/locale/lang.az.js +++ b/src/editor/locale/lang.az.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'az', dir: 'ltr', diff --git a/src/editor/locale/lang.be.js b/src/editor/locale/lang.be.js index 5e70df93..79976cb8 100644 --- a/src/editor/locale/lang.be.js +++ b/src/editor/locale/lang.be.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'be', dir: 'ltr', diff --git a/src/editor/locale/lang.bg.js b/src/editor/locale/lang.bg.js index 8da10c38..dbf62f8b 100644 --- a/src/editor/locale/lang.bg.js +++ b/src/editor/locale/lang.bg.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'bg', dir: 'ltr', diff --git a/src/editor/locale/lang.ca.js b/src/editor/locale/lang.ca.js index 54f4fc6d..41102438 100644 --- a/src/editor/locale/lang.ca.js +++ b/src/editor/locale/lang.ca.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ca', dir: 'ltr', diff --git a/src/editor/locale/lang.cs.js b/src/editor/locale/lang.cs.js index 02fa5752..13a89596 100644 --- a/src/editor/locale/lang.cs.js +++ b/src/editor/locale/lang.cs.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'cs', dir: 'ltr', diff --git a/src/editor/locale/lang.cy.js b/src/editor/locale/lang.cy.js index bbf6639f..281b258f 100644 --- a/src/editor/locale/lang.cy.js +++ b/src/editor/locale/lang.cy.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'cy', dir: 'ltr', diff --git a/src/editor/locale/lang.da.js b/src/editor/locale/lang.da.js index 2d049f79..69a0ac79 100644 --- a/src/editor/locale/lang.da.js +++ b/src/editor/locale/lang.da.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'da', dir: 'ltr', diff --git a/src/editor/locale/lang.de.js b/src/editor/locale/lang.de.js index d1e1f4a6..867e3fc9 100644 --- a/src/editor/locale/lang.de.js +++ b/src/editor/locale/lang.de.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'de', dir: 'ltr', diff --git a/src/editor/locale/lang.el.js b/src/editor/locale/lang.el.js index 9528a98a..72a37906 100644 --- a/src/editor/locale/lang.el.js +++ b/src/editor/locale/lang.el.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'el', dir: 'ltr', diff --git a/src/editor/locale/lang.en.js b/src/editor/locale/lang.en.js index 628f2c57..f91f7639 100644 --- a/src/editor/locale/lang.en.js +++ b/src/editor/locale/lang.en.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'en', dir: 'ltr', diff --git a/src/editor/locale/lang.es.js b/src/editor/locale/lang.es.js index 8871428c..a25916dd 100644 --- a/src/editor/locale/lang.es.js +++ b/src/editor/locale/lang.es.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'es', dir: 'ltr', diff --git a/src/editor/locale/lang.et.js b/src/editor/locale/lang.et.js index 9b28b225..3fe11c54 100644 --- a/src/editor/locale/lang.et.js +++ b/src/editor/locale/lang.et.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'et', dir: 'ltr', diff --git a/src/editor/locale/lang.fa.js b/src/editor/locale/lang.fa.js index 2b22b91b..a541c2f8 100644 --- a/src/editor/locale/lang.fa.js +++ b/src/editor/locale/lang.fa.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'fa', dir: 'rtl', diff --git a/src/editor/locale/lang.fi.js b/src/editor/locale/lang.fi.js index 2f46c93b..1632b803 100644 --- a/src/editor/locale/lang.fi.js +++ b/src/editor/locale/lang.fi.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'fi', dir: 'ltr', diff --git a/src/editor/locale/lang.fr.js b/src/editor/locale/lang.fr.js index 3eb1b4a6..776bd8fc 100644 --- a/src/editor/locale/lang.fr.js +++ b/src/editor/locale/lang.fr.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'fr', dir: 'ltr', diff --git a/src/editor/locale/lang.fy.js b/src/editor/locale/lang.fy.js index 920a4ee9..fbae581f 100644 --- a/src/editor/locale/lang.fy.js +++ b/src/editor/locale/lang.fy.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'fy', dir: 'ltr', diff --git a/src/editor/locale/lang.ga.js b/src/editor/locale/lang.ga.js index 7a15532e..7c814bdb 100644 --- a/src/editor/locale/lang.ga.js +++ b/src/editor/locale/lang.ga.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ga', dir: 'ltr', diff --git a/src/editor/locale/lang.gl.js b/src/editor/locale/lang.gl.js index fc1a85e7..e50b98c6 100644 --- a/src/editor/locale/lang.gl.js +++ b/src/editor/locale/lang.gl.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'gl', dir: 'ltr', diff --git a/src/editor/locale/lang.he.js b/src/editor/locale/lang.he.js index 8d3d1f36..5c8c5eed 100755 --- a/src/editor/locale/lang.he.js +++ b/src/editor/locale/lang.he.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'he', dir: 'rtl', diff --git a/src/editor/locale/lang.hi.js b/src/editor/locale/lang.hi.js index 952e5021..ef5da6a0 100644 --- a/src/editor/locale/lang.hi.js +++ b/src/editor/locale/lang.hi.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'hi', dir: 'ltr', diff --git a/src/editor/locale/lang.hr.js b/src/editor/locale/lang.hr.js index 04a40a46..6df24a24 100644 --- a/src/editor/locale/lang.hr.js +++ b/src/editor/locale/lang.hr.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'hr', dir: 'ltr', diff --git a/src/editor/locale/lang.hu.js b/src/editor/locale/lang.hu.js index a7ddcf53..5d022e37 100644 --- a/src/editor/locale/lang.hu.js +++ b/src/editor/locale/lang.hu.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'hu', dir: 'ltr', diff --git a/src/editor/locale/lang.hy.js b/src/editor/locale/lang.hy.js index 9d7bb012..08d6ddf3 100644 --- a/src/editor/locale/lang.hy.js +++ b/src/editor/locale/lang.hy.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'hy', dir: 'ltr', diff --git a/src/editor/locale/lang.id.js b/src/editor/locale/lang.id.js index 900e6e22..5d6d1064 100644 --- a/src/editor/locale/lang.id.js +++ b/src/editor/locale/lang.id.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'id', dir: 'ltr', diff --git a/src/editor/locale/lang.is.js b/src/editor/locale/lang.is.js index 5cee3bcd..d659ea1c 100644 --- a/src/editor/locale/lang.is.js +++ b/src/editor/locale/lang.is.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'is', dir: 'ltr', diff --git a/src/editor/locale/lang.it.js b/src/editor/locale/lang.it.js index 3f9f5fea..baca8758 100644 --- a/src/editor/locale/lang.it.js +++ b/src/editor/locale/lang.it.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'it', dir: 'ltr', diff --git a/src/editor/locale/lang.ja.js b/src/editor/locale/lang.ja.js index 69b891e0..da9bbb56 100644 --- a/src/editor/locale/lang.ja.js +++ b/src/editor/locale/lang.ja.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ja', dir: 'ltr', diff --git a/src/editor/locale/lang.ko.js b/src/editor/locale/lang.ko.js index 1d469198..8239ecd9 100644 --- a/src/editor/locale/lang.ko.js +++ b/src/editor/locale/lang.ko.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ko', dir: 'ltr', diff --git a/src/editor/locale/lang.lt.js b/src/editor/locale/lang.lt.js index ed811f36..4ff30991 100644 --- a/src/editor/locale/lang.lt.js +++ b/src/editor/locale/lang.lt.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'lt', dir: 'ltr', diff --git a/src/editor/locale/lang.lv.js b/src/editor/locale/lang.lv.js index eb32a5db..f1b3bc66 100644 --- a/src/editor/locale/lang.lv.js +++ b/src/editor/locale/lang.lv.js @@ -1,4 +1,3 @@ -/* eslint-disable import/no-anonymous-default-export */ export default { lang: 'lv', dir: 'ltr', diff --git a/src/editor/locale/lang.mk.js b/src/editor/locale/lang.mk.js index 75f2b468..2bc615aa 100644 --- a/src/editor/locale/lang.mk.js +++ b/src/editor/locale/lang.mk.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'mk', dir: 'ltr', diff --git a/src/editor/locale/lang.ms.js b/src/editor/locale/lang.ms.js index 23c74437..ff888d19 100644 --- a/src/editor/locale/lang.ms.js +++ b/src/editor/locale/lang.ms.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ms', dir: 'ltr', diff --git a/src/editor/locale/lang.mt.js b/src/editor/locale/lang.mt.js index d0fd4504..887556cf 100644 --- a/src/editor/locale/lang.mt.js +++ b/src/editor/locale/lang.mt.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'mt', dir: 'ltr', diff --git a/src/editor/locale/lang.nl.js b/src/editor/locale/lang.nl.js index abdf8b0d..8a47d270 100644 --- a/src/editor/locale/lang.nl.js +++ b/src/editor/locale/lang.nl.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'nl', dir: 'ltr', diff --git a/src/editor/locale/lang.no.js b/src/editor/locale/lang.no.js index 059f118e..9466ffdc 100644 --- a/src/editor/locale/lang.no.js +++ b/src/editor/locale/lang.no.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'no', dir: 'ltr', diff --git a/src/editor/locale/lang.pl.js b/src/editor/locale/lang.pl.js index 3b17189c..1a9bb30a 100644 --- a/src/editor/locale/lang.pl.js +++ b/src/editor/locale/lang.pl.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'pl', dir: 'ltr', diff --git a/src/editor/locale/lang.pt-BR.js b/src/editor/locale/lang.pt-BR.js index 81e95174..4ea3e734 100644 --- a/src/editor/locale/lang.pt-BR.js +++ b/src/editor/locale/lang.pt-BR.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'pt-BR', dir: 'ltr', diff --git a/src/editor/locale/lang.pt-PT.js b/src/editor/locale/lang.pt-PT.js index 015e70cc..c49e7111 100644 --- a/src/editor/locale/lang.pt-PT.js +++ b/src/editor/locale/lang.pt-PT.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'pt-PT', dir: 'ltr', diff --git a/src/editor/locale/lang.ro.js b/src/editor/locale/lang.ro.js index b7b2b9d5..69cfd2c8 100644 --- a/src/editor/locale/lang.ro.js +++ b/src/editor/locale/lang.ro.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ro', dir: 'ltr', diff --git a/src/editor/locale/lang.ru.js b/src/editor/locale/lang.ru.js index 13f438cf..3f920578 100644 --- a/src/editor/locale/lang.ru.js +++ b/src/editor/locale/lang.ru.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'ru', dir: 'ltr', diff --git a/src/editor/locale/lang.sk.js b/src/editor/locale/lang.sk.js index 4a88539f..89e3c181 100644 --- a/src/editor/locale/lang.sk.js +++ b/src/editor/locale/lang.sk.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'sk', dir: 'ltr', diff --git a/src/editor/locale/lang.sl.js b/src/editor/locale/lang.sl.js index 6ee9d2e5..ac439f07 100644 --- a/src/editor/locale/lang.sl.js +++ b/src/editor/locale/lang.sl.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'sl', dir: 'ltr', diff --git a/src/editor/locale/lang.sq.js b/src/editor/locale/lang.sq.js index ebb80b6a..16d14a3a 100644 --- a/src/editor/locale/lang.sq.js +++ b/src/editor/locale/lang.sq.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'sq', dir: 'ltr', diff --git a/src/editor/locale/lang.sr.js b/src/editor/locale/lang.sr.js index 9fc63588..aa5c0295 100644 --- a/src/editor/locale/lang.sr.js +++ b/src/editor/locale/lang.sr.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'sr', dir: 'ltr', diff --git a/src/editor/locale/lang.sv.js b/src/editor/locale/lang.sv.js index 2369988f..f7e3f967 100644 --- a/src/editor/locale/lang.sv.js +++ b/src/editor/locale/lang.sv.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'sv', dir: 'ltr', diff --git a/src/editor/locale/lang.sw.js b/src/editor/locale/lang.sw.js index 7ef3e58d..288b9eab 100644 --- a/src/editor/locale/lang.sw.js +++ b/src/editor/locale/lang.sw.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'sw', dir: 'ltr', diff --git a/src/editor/locale/lang.test.js b/src/editor/locale/lang.test.js index f503d3d2..45565882 100644 --- a/src/editor/locale/lang.test.js +++ b/src/editor/locale/lang.test.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'test', dir: 'ltr', diff --git a/src/editor/locale/lang.th.js b/src/editor/locale/lang.th.js index 65e64171..fbb455cd 100644 --- a/src/editor/locale/lang.th.js +++ b/src/editor/locale/lang.th.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'th', dir: 'ltr', diff --git a/src/editor/locale/lang.tl.js b/src/editor/locale/lang.tl.js index 1b46f86f..aa4c26f4 100644 --- a/src/editor/locale/lang.tl.js +++ b/src/editor/locale/lang.tl.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'tl', dir: 'ltr', diff --git a/src/editor/locale/lang.tr.js b/src/editor/locale/lang.tr.js index 255797e1..0c734275 100644 --- a/src/editor/locale/lang.tr.js +++ b/src/editor/locale/lang.tr.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'tr', dir: 'ltr', diff --git a/src/editor/locale/lang.uk.js b/src/editor/locale/lang.uk.js index add9dcd5..84f1f29a 100644 --- a/src/editor/locale/lang.uk.js +++ b/src/editor/locale/lang.uk.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'uk', dir: 'ltr', diff --git a/src/editor/locale/lang.vi.js b/src/editor/locale/lang.vi.js index 41a16b76..10daf9f8 100644 --- a/src/editor/locale/lang.vi.js +++ b/src/editor/locale/lang.vi.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'vi', dir: 'ltr', diff --git a/src/editor/locale/lang.yi.js b/src/editor/locale/lang.yi.js index 800563b3..9f6983ea 100644 --- a/src/editor/locale/lang.yi.js +++ b/src/editor/locale/lang.yi.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'yi', dir: 'ltr', diff --git a/src/editor/locale/lang.zh-CN.js b/src/editor/locale/lang.zh-CN.js index c7a5f142..1accbaba 100644 --- a/src/editor/locale/lang.zh-CN.js +++ b/src/editor/locale/lang.zh-CN.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'zh-CN', dir: 'ltr', diff --git a/src/editor/locale/lang.zh-HK.js b/src/editor/locale/lang.zh-HK.js index a50a976a..4d95992c 100644 --- a/src/editor/locale/lang.zh-HK.js +++ b/src/editor/locale/lang.zh-HK.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'zh-HK', dir: 'ltr', diff --git a/src/editor/locale/lang.zh-TW.js b/src/editor/locale/lang.zh-TW.js index faf7c85b..f0aebccf 100644 --- a/src/editor/locale/lang.zh-TW.js +++ b/src/editor/locale/lang.zh-TW.js @@ -1,4 +1,3 @@ -// eslint-disable-next-line import/no-anonymous-default-export export default { lang: 'zh-TW', dir: 'ltr', diff --git a/src/editor/redirect-on-no-module-support.js b/src/editor/redirect-on-no-module-support.js index 5f5a412c..ff5f295a 100644 --- a/src/editor/redirect-on-no-module-support.js +++ b/src/editor/redirect-on-no-module-support.js @@ -1,4 +1,3 @@ -/* eslint-disable import/unambiguous */ // This file should only load if the user's browser doesn't support ESM // This file will be stripped from the non-modular versions diff --git a/src/editor/svg-editor.js b/src/editor/svg-editor.js index ec7710f1..add7b741 100644 --- a/src/editor/svg-editor.js +++ b/src/editor/svg-editor.js @@ -1,4 +1,3 @@ -/* eslint-disable node/no-unsupported-features/node-builtins */ /* globals jQuery */ /** * The main module for the visual SVG Editor. @@ -22,6 +21,7 @@ import {isWebkit, isChrome, isGecko, isIE, isMac, isTouch} from '../common/brows // Until we split this into smaller files, this helps distinguish utilities // from local methods +// eslint-disable-next-line import/no-namespace import * as Utils from '../common/utilities.js'; import {getTypeMap, convertUnit, isValidUnit} from '../common/units.js'; import { diff --git a/src/editor/touch.js b/src/editor/touch.js index c67dc8a5..265b8c38 100644 --- a/src/editor/touch.js +++ b/src/editor/touch.js @@ -1,4 +1,3 @@ -/* eslint-disable import/unambiguous */ // http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ /** * diff --git a/src/editor/typedefs.js b/src/editor/typedefs.js index 95942b45..9dac84f1 100644 --- a/src/editor/typedefs.js +++ b/src/editor/typedefs.js @@ -1,4 +1,3 @@ -/* eslint-disable import/unambiguous */ /** * @typedef {number} Float */ diff --git a/svgedit-config-iife.js b/svgedit-config-iife.js index 28f43f11..807b9953 100644 --- a/svgedit-config-iife.js +++ b/svgedit-config-iife.js @@ -1,306 +1,6 @@ (function () { 'use strict'; - function _typeof(obj) { - "@babel/helpers - typeof"; - - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); - } - - function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { - try { - var info = gen[key](arg); - var value = info.value; - } catch (error) { - reject(error); - return; - } - - if (info.done) { - resolve(value); - } else { - Promise.resolve(value).then(_next, _throw); - } - } - - function _asyncToGenerator(fn) { - return function () { - var self = this, - args = arguments; - return new Promise(function (resolve, reject) { - var gen = fn.apply(self, args); - - function _next(value) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); - } - - function _throw(err) { - asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); - } - - _next(undefined); - }); - }; - } - - function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } - } - - function _defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - Object.defineProperty(target, descriptor.key, descriptor); - } - } - - function _createClass(Constructor, protoProps, staticProps) { - if (protoProps) _defineProperties(Constructor.prototype, protoProps); - if (staticProps) _defineProperties(Constructor, staticProps); - return Constructor; - } - - function _extends() { - _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; - }; - - return _extends.apply(this, arguments); - } - - function _inherits(subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function"); - } - - subClass.prototype = Object.create(superClass && superClass.prototype, { - constructor: { - value: subClass, - writable: true, - configurable: true - } - }); - if (superClass) _setPrototypeOf(subClass, superClass); - } - - function _getPrototypeOf(o) { - _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { - return o.__proto__ || Object.getPrototypeOf(o); - }; - return _getPrototypeOf(o); - } - - function _setPrototypeOf(o, p) { - _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { - o.__proto__ = p; - return o; - }; - - return _setPrototypeOf(o, p); - } - - function _isNativeReflectConstruct() { - if (typeof Reflect === "undefined" || !Reflect.construct) return false; - if (Reflect.construct.sham) return false; - if (typeof Proxy === "function") return true; - - try { - Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); - return true; - } catch (e) { - return false; - } - } - - function _assertThisInitialized(self) { - if (self === void 0) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return self; - } - - function _possibleConstructorReturn(self, call) { - if (call && (typeof call === "object" || typeof call === "function")) { - return call; - } - - return _assertThisInitialized(self); - } - - function _createSuper(Derived) { - var hasNativeReflectConstruct = _isNativeReflectConstruct(); - - return function _createSuperInternal() { - var Super = _getPrototypeOf(Derived), - result; - - if (hasNativeReflectConstruct) { - var NewTarget = _getPrototypeOf(this).constructor; - - result = Reflect.construct(Super, arguments, NewTarget); - } else { - result = Super.apply(this, arguments); - } - - return _possibleConstructorReturn(this, result); - }; - } - - function _slicedToArray(arr, i) { - return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); - } - - function _toConsumableArray(arr) { - return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); - } - - function _arrayWithoutHoles(arr) { - if (Array.isArray(arr)) return _arrayLikeToArray(arr); - } - - function _arrayWithHoles(arr) { - if (Array.isArray(arr)) return arr; - } - - function _iterableToArray(iter) { - if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); - } - - function _iterableToArrayLimit(arr, i) { - if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; - 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"] != null) _i["return"](); - } finally { - if (_d) throw _e; - } - } - - return _arr; - } - - function _unsupportedIterableToArray(o, minLen) { - if (!o) return; - if (typeof o === "string") return _arrayLikeToArray(o, minLen); - var n = Object.prototype.toString.call(o).slice(8, -1); - if (n === "Object" && o.constructor) n = o.constructor.name; - if (n === "Map" || n === "Set") return Array.from(o); - if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); - } - - function _arrayLikeToArray(arr, len) { - if (len == null || len > arr.length) len = arr.length; - - for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; - - return arr2; - } - - function _nonIterableSpread() { - throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - function _nonIterableRest() { - throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - function _createForOfIteratorHelper(o, allowArrayLike) { - var it; - - if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { - if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { - if (it) o = it; - var i = 0; - - var F = function () {}; - - return { - s: F, - n: function () { - if (i >= o.length) return { - done: true - }; - return { - done: false, - value: o[i++] - }; - }, - e: function (e) { - throw e; - }, - f: F - }; - } - - throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); - } - - var normalCompletion = true, - didErr = false, - err; - return { - s: function () { - it = o[Symbol.iterator](); - }, - n: function () { - var step = it.next(); - normalCompletion = step.done; - return step; - }, - e: function (e) { - didErr = true; - err = e; - }, - f: function () { - try { - if (!normalCompletion && it.return != null) it.return(); - } finally { - if (didErr) throw err; - } - } - }; - } - // http://ross.posterous.com/2008/08/19/iphone-touch-events-in-javascript/ /** @@ -309,9 +9,11 @@ * @returns {void} */ function touchHandler(ev) { - var changedTouches = ev.changedTouches, - first = changedTouches[0]; - var type = ''; + const { + changedTouches + } = ev, + first = changedTouches[0]; + let type = ''; switch (ev.type) { case 'touchstart': @@ -330,12 +32,14 @@ return; } - var screenX = first.screenX, - screenY = first.screenY, - clientX = first.clientX, - clientY = first.clientY; // eslint-disable-line no-shadow + const { + screenX, + screenY, + clientX, + clientY + } = first; // eslint-disable-line no-shadow - var simulatedEvent = new MouseEvent(type, { + const simulatedEvent = new MouseEvent(type, { // Event interface bubbles: true, cancelable: true, @@ -344,10 +48,10 @@ detail: 1, // click count // MouseEvent interface (customized) - screenX: screenX, - screenY: screenY, - clientX: clientX, - clientY: clientY, + screenX, + screenY, + clientX, + clientY, // MouseEvent interface (defaults) - these could be removed ctrlKey: false, altKey: false, @@ -381,7 +85,7 @@ * @type {PlainObject} * @memberof module:namespaces */ - var NS = { + const NS = { HTML: 'http://www.w3.org/1999/xhtml', MATH: 'http://www.w3.org/1998/Math/MathML', SE: 'http://svg-edit.googlecode.com', @@ -396,18 +100,16 @@ * @returns {string} The NS with key values switched and lowercase */ - var getReverseNS = function getReverseNS() { - var reverseNS = {}; - Object.entries(NS).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - name = _ref2[0], - URI = _ref2[1]; - + const getReverseNS = function () { + const reverseNS = {}; + Object.entries(NS).forEach(([name, URI]) => { reverseNS[URI] = name.toLowerCase(); }); return reverseNS; }; + /* eslint-disable import/unambiguous */ + /* globals SVGPathSeg, SVGPathSegMovetoRel, SVGPathSegMovetoAbs, SVGPathSegMovetoRel, SVGPathSegLinetoRel, SVGPathSegLinetoAbs, SVGPathSegLinetoHorizontalRel, SVGPathSegLinetoHorizontalAbs, @@ -432,1513 +134,1341 @@ // Linting: We avoid `no-shadow` as ESLint thinks these are still available globals // Linting: We avoid `class-methods-use-this` as this is a polyfill that must // follow the conventions - (function () { + (() => { if (!('SVGPathSeg' in window)) { // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg - var _SVGPathSeg = /*#__PURE__*/function () { - function _SVGPathSeg(type, typeAsLetter, owningPathSegList) { - _classCallCheck(this, _SVGPathSeg); - + class SVGPathSeg { + constructor(type, typeAsLetter, owningPathSegList) { this.pathSegType = type; this.pathSegTypeAsLetter = typeAsLetter; this._owningPathSegList = owningPathSegList; } // Notify owning PathSegList on any changes so they can be synchronized back to the path element. - _createClass(_SVGPathSeg, [{ - key: "_segmentChanged", - value: function _segmentChanged() { - if (this._owningPathSegList) { - this._owningPathSegList.segmentChanged(this); - } + _segmentChanged() { + if (this._owningPathSegList) { + this._owningPathSegList.segmentChanged(this); } - }]); - - return _SVGPathSeg; - }(); - - _SVGPathSeg.prototype.classname = 'SVGPathSeg'; - _SVGPathSeg.PATHSEG_UNKNOWN = 0; - _SVGPathSeg.PATHSEG_CLOSEPATH = 1; - _SVGPathSeg.PATHSEG_MOVETO_ABS = 2; - _SVGPathSeg.PATHSEG_MOVETO_REL = 3; - _SVGPathSeg.PATHSEG_LINETO_ABS = 4; - _SVGPathSeg.PATHSEG_LINETO_REL = 5; - _SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6; - _SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7; - _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8; - _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9; - _SVGPathSeg.PATHSEG_ARC_ABS = 10; - _SVGPathSeg.PATHSEG_ARC_REL = 11; - _SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12; - _SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13; - _SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14; - _SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15; - _SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16; - _SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; - _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; - _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; - - var _SVGPathSegClosePath = /*#__PURE__*/function (_SVGPathSeg2) { - _inherits(_SVGPathSegClosePath, _SVGPathSeg2); - - var _super = _createSuper(_SVGPathSegClosePath); - - function _SVGPathSegClosePath(owningPathSegList) { - _classCallCheck(this, _SVGPathSegClosePath); - - return _super.call(this, _SVGPathSeg.PATHSEG_CLOSEPATH, 'z', owningPathSegList); } - _createClass(_SVGPathSegClosePath, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegClosePath]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegClosePath(undefined); - } - }]); + } - return _SVGPathSegClosePath; - }(_SVGPathSeg); + SVGPathSeg.prototype.classname = 'SVGPathSeg'; + SVGPathSeg.PATHSEG_UNKNOWN = 0; + SVGPathSeg.PATHSEG_CLOSEPATH = 1; + SVGPathSeg.PATHSEG_MOVETO_ABS = 2; + SVGPathSeg.PATHSEG_MOVETO_REL = 3; + SVGPathSeg.PATHSEG_LINETO_ABS = 4; + SVGPathSeg.PATHSEG_LINETO_REL = 5; + SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6; + SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7; + SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8; + SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9; + SVGPathSeg.PATHSEG_ARC_ABS = 10; + SVGPathSeg.PATHSEG_ARC_REL = 11; + SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12; + SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13; + SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14; + SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15; + SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16; + SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17; + SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18; + SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19; - var _SVGPathSegMovetoAbs = /*#__PURE__*/function (_SVGPathSeg3) { - _inherits(_SVGPathSegMovetoAbs, _SVGPathSeg3); - - var _super2 = _createSuper(_SVGPathSegMovetoAbs); - - function _SVGPathSegMovetoAbs(owningPathSegList, x, y) { - var _this; - - _classCallCheck(this, _SVGPathSegMovetoAbs); - - _this = _super2.call(this, _SVGPathSeg.PATHSEG_MOVETO_ABS, 'M', owningPathSegList); - _this._x = x; - _this._y = y; - return _this; + class SVGPathSegClosePath extends SVGPathSeg { + constructor(owningPathSegList) { + super(SVGPathSeg.PATHSEG_CLOSEPATH, 'z', owningPathSegList); } - _createClass(_SVGPathSegMovetoAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegMovetoAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegMovetoAbs(undefined, this._x, this._y); - } - }]); + toString() { + return '[object SVGPathSegClosePath]'; + } - return _SVGPathSegMovetoAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter; + } - Object.defineProperties(_SVGPathSegMovetoAbs.prototype, { + clone() { + return new SVGPathSegClosePath(undefined); + } + + } + + class SVGPathSegMovetoAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y) { + super(SVGPathSeg.PATHSEG_MOVETO_ABS, 'M', owningPathSegList); + this._x = x; + this._y = y; + } + + toString() { + return '[object SVGPathSegMovetoAbs]'; + } + + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; + } + + clone() { + return new SVGPathSegMovetoAbs(undefined, this._x, this._y); + } + + } + + Object.defineProperties(SVGPathSegMovetoAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegMovetoRel = /*#__PURE__*/function (_SVGPathSeg4) { - _inherits(_SVGPathSegMovetoRel, _SVGPathSeg4); - - var _super3 = _createSuper(_SVGPathSegMovetoRel); - - function _SVGPathSegMovetoRel(owningPathSegList, x, y) { - var _this2; - - _classCallCheck(this, _SVGPathSegMovetoRel); - - _this2 = _super3.call(this, _SVGPathSeg.PATHSEG_MOVETO_REL, 'm', owningPathSegList); - _this2._x = x; - _this2._y = y; - return _this2; + class SVGPathSegMovetoRel extends SVGPathSeg { + constructor(owningPathSegList, x, y) { + super(SVGPathSeg.PATHSEG_MOVETO_REL, 'm', owningPathSegList); + this._x = x; + this._y = y; } - _createClass(_SVGPathSegMovetoRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegMovetoRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegMovetoRel(undefined, this._x, this._y); - } - }]); + toString() { + return '[object SVGPathSegMovetoRel]'; + } - return _SVGPathSegMovetoRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegMovetoRel.prototype, { + clone() { + return new SVGPathSegMovetoRel(undefined, this._x, this._y); + } + + } + + Object.defineProperties(SVGPathSegMovetoRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegLinetoAbs = /*#__PURE__*/function (_SVGPathSeg5) { - _inherits(_SVGPathSegLinetoAbs, _SVGPathSeg5); - - var _super4 = _createSuper(_SVGPathSegLinetoAbs); - - function _SVGPathSegLinetoAbs(owningPathSegList, x, y) { - var _this3; - - _classCallCheck(this, _SVGPathSegLinetoAbs); - - _this3 = _super4.call(this, _SVGPathSeg.PATHSEG_LINETO_ABS, 'L', owningPathSegList); - _this3._x = x; - _this3._y = y; - return _this3; + class SVGPathSegLinetoAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y) { + super(SVGPathSeg.PATHSEG_LINETO_ABS, 'L', owningPathSegList); + this._x = x; + this._y = y; } - _createClass(_SVGPathSegLinetoAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegLinetoAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegLinetoAbs(undefined, this._x, this._y); - } - }]); + toString() { + return '[object SVGPathSegLinetoAbs]'; + } - return _SVGPathSegLinetoAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegLinetoAbs.prototype, { + clone() { + return new SVGPathSegLinetoAbs(undefined, this._x, this._y); + } + + } + + Object.defineProperties(SVGPathSegLinetoAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegLinetoRel = /*#__PURE__*/function (_SVGPathSeg6) { - _inherits(_SVGPathSegLinetoRel, _SVGPathSeg6); - - var _super5 = _createSuper(_SVGPathSegLinetoRel); - - function _SVGPathSegLinetoRel(owningPathSegList, x, y) { - var _this4; - - _classCallCheck(this, _SVGPathSegLinetoRel); - - _this4 = _super5.call(this, _SVGPathSeg.PATHSEG_LINETO_REL, 'l', owningPathSegList); - _this4._x = x; - _this4._y = y; - return _this4; + class SVGPathSegLinetoRel extends SVGPathSeg { + constructor(owningPathSegList, x, y) { + super(SVGPathSeg.PATHSEG_LINETO_REL, 'l', owningPathSegList); + this._x = x; + this._y = y; } - _createClass(_SVGPathSegLinetoRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegLinetoRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegLinetoRel(undefined, this._x, this._y); - } - }]); + toString() { + return '[object SVGPathSegLinetoRel]'; + } - return _SVGPathSegLinetoRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegLinetoRel.prototype, { + clone() { + return new SVGPathSegLinetoRel(undefined, this._x, this._y); + } + + } + + Object.defineProperties(SVGPathSegLinetoRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoCubicAbs = /*#__PURE__*/function (_SVGPathSeg7) { - _inherits(_SVGPathSegCurvetoCubicAbs, _SVGPathSeg7); - - var _super6 = _createSuper(_SVGPathSegCurvetoCubicAbs); - - function _SVGPathSegCurvetoCubicAbs(owningPathSegList, x, y, x1, y1, x2, y2) { - var _this5; - - _classCallCheck(this, _SVGPathSegCurvetoCubicAbs); - - _this5 = _super6.call(this, _SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, 'C', owningPathSegList); - _this5._x = x; - _this5._y = y; - _this5._x1 = x1; - _this5._y1 = y1; - _this5._x2 = x2; - _this5._y2 = y2; - return _this5; + class SVGPathSegCurvetoCubicAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y, x1, y1, x2, y2) { + super(SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, 'C', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + this._x2 = x2; + this._y2 = y2; } - _createClass(_SVGPathSegCurvetoCubicAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoCubicAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); - } - }]); + toString() { + return '[object SVGPathSegCurvetoCubicAbs]'; + } - return _SVGPathSegCurvetoCubicAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoCubicAbs.prototype, { + clone() { + return new SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); + } + + } + + Object.defineProperties(SVGPathSegCurvetoCubicAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, x1: { - get: function get() { + get() { return this._x1; }, - set: function set(x1) { + + set(x1) { this._x1 = x1; this._segmentChanged(); }, + enumerable: true }, y1: { - get: function get() { + get() { return this._y1; }, - set: function set(y1) { + + set(y1) { this._y1 = y1; this._segmentChanged(); }, + enumerable: true }, x2: { - get: function get() { + get() { return this._x2; }, - set: function set(x2) { + + set(x2) { this._x2 = x2; this._segmentChanged(); }, + enumerable: true }, y2: { - get: function get() { + get() { return this._y2; }, - set: function set(y2) { + + set(y2) { this._y2 = y2; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoCubicRel = /*#__PURE__*/function (_SVGPathSeg8) { - _inherits(_SVGPathSegCurvetoCubicRel, _SVGPathSeg8); - - var _super7 = _createSuper(_SVGPathSegCurvetoCubicRel); - - function _SVGPathSegCurvetoCubicRel(owningPathSegList, x, y, x1, y1, x2, y2) { - var _this6; - - _classCallCheck(this, _SVGPathSegCurvetoCubicRel); - - _this6 = _super7.call(this, _SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, 'c', owningPathSegList); - _this6._x = x; - _this6._y = y; - _this6._x1 = x1; - _this6._y1 = y1; - _this6._x2 = x2; - _this6._y2 = y2; - return _this6; + class SVGPathSegCurvetoCubicRel extends SVGPathSeg { + constructor(owningPathSegList, x, y, x1, y1, x2, y2) { + super(SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, 'c', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; + this._x2 = x2; + this._y2 = y2; } - _createClass(_SVGPathSegCurvetoCubicRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoCubicRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); - } - }]); + toString() { + return '[object SVGPathSegCurvetoCubicRel]'; + } - return _SVGPathSegCurvetoCubicRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoCubicRel.prototype, { + clone() { + return new SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); + } + + } + + Object.defineProperties(SVGPathSegCurvetoCubicRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, x1: { - get: function get() { + get() { return this._x1; }, - set: function set(x1) { + + set(x1) { this._x1 = x1; this._segmentChanged(); }, + enumerable: true }, y1: { - get: function get() { + get() { return this._y1; }, - set: function set(y1) { + + set(y1) { this._y1 = y1; this._segmentChanged(); }, + enumerable: true }, x2: { - get: function get() { + get() { return this._x2; }, - set: function set(x2) { + + set(x2) { this._x2 = x2; this._segmentChanged(); }, + enumerable: true }, y2: { - get: function get() { + get() { return this._y2; }, - set: function set(y2) { + + set(y2) { this._y2 = y2; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoQuadraticAbs = /*#__PURE__*/function (_SVGPathSeg9) { - _inherits(_SVGPathSegCurvetoQuadraticAbs, _SVGPathSeg9); - - var _super8 = _createSuper(_SVGPathSegCurvetoQuadraticAbs); - - function _SVGPathSegCurvetoQuadraticAbs(owningPathSegList, x, y, x1, y1) { - var _this7; - - _classCallCheck(this, _SVGPathSegCurvetoQuadraticAbs); - - _this7 = _super8.call(this, _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, 'Q', owningPathSegList); - _this7._x = x; - _this7._y = y; - _this7._x1 = x1; - _this7._y1 = y1; - return _this7; + class SVGPathSegCurvetoQuadraticAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y, x1, y1) { + super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, 'Q', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; } - _createClass(_SVGPathSegCurvetoQuadraticAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoQuadraticAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); - } - }]); + toString() { + return '[object SVGPathSegCurvetoQuadraticAbs]'; + } - return _SVGPathSegCurvetoQuadraticAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoQuadraticAbs.prototype, { + clone() { + return new SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); + } + + } + + Object.defineProperties(SVGPathSegCurvetoQuadraticAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, x1: { - get: function get() { + get() { return this._x1; }, - set: function set(x1) { + + set(x1) { this._x1 = x1; this._segmentChanged(); }, + enumerable: true }, y1: { - get: function get() { + get() { return this._y1; }, - set: function set(y1) { + + set(y1) { this._y1 = y1; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoQuadraticRel = /*#__PURE__*/function (_SVGPathSeg10) { - _inherits(_SVGPathSegCurvetoQuadraticRel, _SVGPathSeg10); - - var _super9 = _createSuper(_SVGPathSegCurvetoQuadraticRel); - - function _SVGPathSegCurvetoQuadraticRel(owningPathSegList, x, y, x1, y1) { - var _this8; - - _classCallCheck(this, _SVGPathSegCurvetoQuadraticRel); - - _this8 = _super9.call(this, _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, 'q', owningPathSegList); - _this8._x = x; - _this8._y = y; - _this8._x1 = x1; - _this8._y1 = y1; - return _this8; + class SVGPathSegCurvetoQuadraticRel extends SVGPathSeg { + constructor(owningPathSegList, x, y, x1, y1) { + super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, 'q', owningPathSegList); + this._x = x; + this._y = y; + this._x1 = x1; + this._y1 = y1; } - _createClass(_SVGPathSegCurvetoQuadraticRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoQuadraticRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); - } - }]); + toString() { + return '[object SVGPathSegCurvetoQuadraticRel]'; + } - return _SVGPathSegCurvetoQuadraticRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x1 + ' ' + this._y1 + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoQuadraticRel.prototype, { + clone() { + return new SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); + } + + } + + Object.defineProperties(SVGPathSegCurvetoQuadraticRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, x1: { - get: function get() { + get() { return this._x1; }, - set: function set(x1) { + + set(x1) { this._x1 = x1; this._segmentChanged(); }, + enumerable: true }, y1: { - get: function get() { + get() { return this._y1; }, - set: function set(y1) { + + set(y1) { this._y1 = y1; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegArcAbs = /*#__PURE__*/function (_SVGPathSeg11) { - _inherits(_SVGPathSegArcAbs, _SVGPathSeg11); - - var _super10 = _createSuper(_SVGPathSegArcAbs); - - function _SVGPathSegArcAbs(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { - var _this9; - - _classCallCheck(this, _SVGPathSegArcAbs); - - _this9 = _super10.call(this, _SVGPathSeg.PATHSEG_ARC_ABS, 'A', owningPathSegList); - _this9._x = x; - _this9._y = y; - _this9._r1 = r1; - _this9._r2 = r2; - _this9._angle = angle; - _this9._largeArcFlag = largeArcFlag; - _this9._sweepFlag = sweepFlag; - return _this9; + class SVGPathSegArcAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { + super(SVGPathSeg.PATHSEG_ARC_ABS, 'A', owningPathSegList); + this._x = x; + this._y = y; + this._r1 = r1; + this._r2 = r2; + this._angle = angle; + this._largeArcFlag = largeArcFlag; + this._sweepFlag = sweepFlag; } - _createClass(_SVGPathSegArcAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegArcAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); - } - }]); + toString() { + return '[object SVGPathSegArcAbs]'; + } - return _SVGPathSegArcAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegArcAbs.prototype, { + clone() { + return new SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); + } + + } + + Object.defineProperties(SVGPathSegArcAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, r1: { - get: function get() { + get() { return this._r1; }, - set: function set(r1) { + + set(r1) { this._r1 = r1; this._segmentChanged(); }, + enumerable: true }, r2: { - get: function get() { + get() { return this._r2; }, - set: function set(r2) { + + set(r2) { this._r2 = r2; this._segmentChanged(); }, + enumerable: true }, angle: { - get: function get() { + get() { return this._angle; }, - set: function set(angle) { + + set(angle) { this._angle = angle; this._segmentChanged(); }, + enumerable: true }, largeArcFlag: { - get: function get() { + get() { return this._largeArcFlag; }, - set: function set(largeArcFlag) { + + set(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, + enumerable: true }, sweepFlag: { - get: function get() { + get() { return this._sweepFlag; }, - set: function set(sweepFlag) { + + set(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegArcRel = /*#__PURE__*/function (_SVGPathSeg12) { - _inherits(_SVGPathSegArcRel, _SVGPathSeg12); - - var _super11 = _createSuper(_SVGPathSegArcRel); - - function _SVGPathSegArcRel(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { - var _this10; - - _classCallCheck(this, _SVGPathSegArcRel); - - _this10 = _super11.call(this, _SVGPathSeg.PATHSEG_ARC_REL, 'a', owningPathSegList); - _this10._x = x; - _this10._y = y; - _this10._r1 = r1; - _this10._r2 = r2; - _this10._angle = angle; - _this10._largeArcFlag = largeArcFlag; - _this10._sweepFlag = sweepFlag; - return _this10; + class SVGPathSegArcRel extends SVGPathSeg { + constructor(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) { + super(SVGPathSeg.PATHSEG_ARC_REL, 'a', owningPathSegList); + this._x = x; + this._y = y; + this._r1 = r1; + this._r2 = r2; + this._angle = angle; + this._largeArcFlag = largeArcFlag; + this._sweepFlag = sweepFlag; } - _createClass(_SVGPathSegArcRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegArcRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); - } - }]); + toString() { + return '[object SVGPathSegArcRel]'; + } - return _SVGPathSegArcRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._r1 + ' ' + this._r2 + ' ' + this._angle + ' ' + (this._largeArcFlag ? '1' : '0') + ' ' + (this._sweepFlag ? '1' : '0') + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegArcRel.prototype, { + clone() { + return new SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); + } + + } + + Object.defineProperties(SVGPathSegArcRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, r1: { - get: function get() { + get() { return this._r1; }, - set: function set(r1) { + + set(r1) { this._r1 = r1; this._segmentChanged(); }, + enumerable: true }, r2: { - get: function get() { + get() { return this._r2; }, - set: function set(r2) { + + set(r2) { this._r2 = r2; this._segmentChanged(); }, + enumerable: true }, angle: { - get: function get() { + get() { return this._angle; }, - set: function set(angle) { + + set(angle) { this._angle = angle; this._segmentChanged(); }, + enumerable: true }, largeArcFlag: { - get: function get() { + get() { return this._largeArcFlag; }, - set: function set(largeArcFlag) { + + set(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, + enumerable: true }, sweepFlag: { - get: function get() { + get() { return this._sweepFlag; }, - set: function set(sweepFlag) { + + set(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegLinetoHorizontalAbs = /*#__PURE__*/function (_SVGPathSeg13) { - _inherits(_SVGPathSegLinetoHorizontalAbs, _SVGPathSeg13); - - var _super12 = _createSuper(_SVGPathSegLinetoHorizontalAbs); - - function _SVGPathSegLinetoHorizontalAbs(owningPathSegList, x) { - var _this11; - - _classCallCheck(this, _SVGPathSegLinetoHorizontalAbs); - - _this11 = _super12.call(this, _SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, 'H', owningPathSegList); - _this11._x = x; - return _this11; + class SVGPathSegLinetoHorizontalAbs extends SVGPathSeg { + constructor(owningPathSegList, x) { + super(SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, 'H', owningPathSegList); + this._x = x; } - _createClass(_SVGPathSegLinetoHorizontalAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegLinetoHorizontalAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegLinetoHorizontalAbs(undefined, this._x); - } - }]); + toString() { + return '[object SVGPathSegLinetoHorizontalAbs]'; + } - return _SVGPathSegLinetoHorizontalAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x; + } - Object.defineProperty(_SVGPathSegLinetoHorizontalAbs.prototype, 'x', { - get: function get() { + clone() { + return new SVGPathSegLinetoHorizontalAbs(undefined, this._x); + } + + } + + Object.defineProperty(SVGPathSegLinetoHorizontalAbs.prototype, 'x', { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }); - var _SVGPathSegLinetoHorizontalRel = /*#__PURE__*/function (_SVGPathSeg14) { - _inherits(_SVGPathSegLinetoHorizontalRel, _SVGPathSeg14); - - var _super13 = _createSuper(_SVGPathSegLinetoHorizontalRel); - - function _SVGPathSegLinetoHorizontalRel(owningPathSegList, x) { - var _this12; - - _classCallCheck(this, _SVGPathSegLinetoHorizontalRel); - - _this12 = _super13.call(this, _SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, 'h', owningPathSegList); - _this12._x = x; - return _this12; + class SVGPathSegLinetoHorizontalRel extends SVGPathSeg { + constructor(owningPathSegList, x) { + super(SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, 'h', owningPathSegList); + this._x = x; } - _createClass(_SVGPathSegLinetoHorizontalRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegLinetoHorizontalRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegLinetoHorizontalRel(undefined, this._x); - } - }]); + toString() { + return '[object SVGPathSegLinetoHorizontalRel]'; + } - return _SVGPathSegLinetoHorizontalRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x; + } - Object.defineProperty(_SVGPathSegLinetoHorizontalRel.prototype, 'x', { - get: function get() { + clone() { + return new SVGPathSegLinetoHorizontalRel(undefined, this._x); + } + + } + + Object.defineProperty(SVGPathSegLinetoHorizontalRel.prototype, 'x', { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }); - var _SVGPathSegLinetoVerticalAbs = /*#__PURE__*/function (_SVGPathSeg15) { - _inherits(_SVGPathSegLinetoVerticalAbs, _SVGPathSeg15); - - var _super14 = _createSuper(_SVGPathSegLinetoVerticalAbs); - - function _SVGPathSegLinetoVerticalAbs(owningPathSegList, y) { - var _this13; - - _classCallCheck(this, _SVGPathSegLinetoVerticalAbs); - - _this13 = _super14.call(this, _SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, 'V', owningPathSegList); - _this13._y = y; - return _this13; + class SVGPathSegLinetoVerticalAbs extends SVGPathSeg { + constructor(owningPathSegList, y) { + super(SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, 'V', owningPathSegList); + this._y = y; } - _createClass(_SVGPathSegLinetoVerticalAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegLinetoVerticalAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegLinetoVerticalAbs(undefined, this._y); - } - }]); + toString() { + return '[object SVGPathSegLinetoVerticalAbs]'; + } - return _SVGPathSegLinetoVerticalAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._y; + } - Object.defineProperty(_SVGPathSegLinetoVerticalAbs.prototype, 'y', { - get: function get() { + clone() { + return new SVGPathSegLinetoVerticalAbs(undefined, this._y); + } + + } + + Object.defineProperty(SVGPathSegLinetoVerticalAbs.prototype, 'y', { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }); - var _SVGPathSegLinetoVerticalRel = /*#__PURE__*/function (_SVGPathSeg16) { - _inherits(_SVGPathSegLinetoVerticalRel, _SVGPathSeg16); - - var _super15 = _createSuper(_SVGPathSegLinetoVerticalRel); - - function _SVGPathSegLinetoVerticalRel(owningPathSegList, y) { - var _this14; - - _classCallCheck(this, _SVGPathSegLinetoVerticalRel); - - _this14 = _super15.call(this, _SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, 'v', owningPathSegList); - _this14._y = y; - return _this14; + class SVGPathSegLinetoVerticalRel extends SVGPathSeg { + constructor(owningPathSegList, y) { + super(SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, 'v', owningPathSegList); + this._y = y; } - _createClass(_SVGPathSegLinetoVerticalRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegLinetoVerticalRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegLinetoVerticalRel(undefined, this._y); - } - }]); + toString() { + return '[object SVGPathSegLinetoVerticalRel]'; + } - return _SVGPathSegLinetoVerticalRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._y; + } - Object.defineProperty(_SVGPathSegLinetoVerticalRel.prototype, 'y', { - get: function get() { + clone() { + return new SVGPathSegLinetoVerticalRel(undefined, this._y); + } + + } + + Object.defineProperty(SVGPathSegLinetoVerticalRel.prototype, 'y', { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }); - var _SVGPathSegCurvetoCubicSmoothAbs = /*#__PURE__*/function (_SVGPathSeg17) { - _inherits(_SVGPathSegCurvetoCubicSmoothAbs, _SVGPathSeg17); - - var _super16 = _createSuper(_SVGPathSegCurvetoCubicSmoothAbs); - - function _SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, x, y, x2, y2) { - var _this15; - - _classCallCheck(this, _SVGPathSegCurvetoCubicSmoothAbs); - - _this15 = _super16.call(this, _SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, 'S', owningPathSegList); - _this15._x = x; - _this15._y = y; - _this15._x2 = x2; - _this15._y2 = y2; - return _this15; + class SVGPathSegCurvetoCubicSmoothAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y, x2, y2) { + super(SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, 'S', owningPathSegList); + this._x = x; + this._y = y; + this._x2 = x2; + this._y2 = y2; } - _createClass(_SVGPathSegCurvetoCubicSmoothAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoCubicSmoothAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); - } - }]); + toString() { + return '[object SVGPathSegCurvetoCubicSmoothAbs]'; + } - return _SVGPathSegCurvetoCubicSmoothAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoCubicSmoothAbs.prototype, { + clone() { + return new SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); + } + + } + + Object.defineProperties(SVGPathSegCurvetoCubicSmoothAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, x2: { - get: function get() { + get() { return this._x2; }, - set: function set(x2) { + + set(x2) { this._x2 = x2; this._segmentChanged(); }, + enumerable: true }, y2: { - get: function get() { + get() { return this._y2; }, - set: function set(y2) { + + set(y2) { this._y2 = y2; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoCubicSmoothRel = /*#__PURE__*/function (_SVGPathSeg18) { - _inherits(_SVGPathSegCurvetoCubicSmoothRel, _SVGPathSeg18); - - var _super17 = _createSuper(_SVGPathSegCurvetoCubicSmoothRel); - - function _SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, x, y, x2, y2) { - var _this16; - - _classCallCheck(this, _SVGPathSegCurvetoCubicSmoothRel); - - _this16 = _super17.call(this, _SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, 's', owningPathSegList); - _this16._x = x; - _this16._y = y; - _this16._x2 = x2; - _this16._y2 = y2; - return _this16; + class SVGPathSegCurvetoCubicSmoothRel extends SVGPathSeg { + constructor(owningPathSegList, x, y, x2, y2) { + super(SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, 's', owningPathSegList); + this._x = x; + this._y = y; + this._x2 = x2; + this._y2 = y2; } - _createClass(_SVGPathSegCurvetoCubicSmoothRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoCubicSmoothRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); - } - }]); + toString() { + return '[object SVGPathSegCurvetoCubicSmoothRel]'; + } - return _SVGPathSegCurvetoCubicSmoothRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x2 + ' ' + this._y2 + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoCubicSmoothRel.prototype, { + clone() { + return new SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); + } + + } + + Object.defineProperties(SVGPathSegCurvetoCubicSmoothRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true }, x2: { - get: function get() { + get() { return this._x2; }, - set: function set(x2) { + + set(x2) { this._x2 = x2; this._segmentChanged(); }, + enumerable: true }, y2: { - get: function get() { + get() { return this._y2; }, - set: function set(y2) { + + set(y2) { this._y2 = y2; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoQuadraticSmoothAbs = /*#__PURE__*/function (_SVGPathSeg19) { - _inherits(_SVGPathSegCurvetoQuadraticSmoothAbs, _SVGPathSeg19); - - var _super18 = _createSuper(_SVGPathSegCurvetoQuadraticSmoothAbs); - - function _SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, x, y) { - var _this17; - - _classCallCheck(this, _SVGPathSegCurvetoQuadraticSmoothAbs); - - _this17 = _super18.call(this, _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, 'T', owningPathSegList); - _this17._x = x; - _this17._y = y; - return _this17; + class SVGPathSegCurvetoQuadraticSmoothAbs extends SVGPathSeg { + constructor(owningPathSegList, x, y) { + super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, 'T', owningPathSegList); + this._x = x; + this._y = y; } - _createClass(_SVGPathSegCurvetoQuadraticSmoothAbs, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoQuadraticSmoothAbs]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); - } - }]); + toString() { + return '[object SVGPathSegCurvetoQuadraticSmoothAbs]'; + } - return _SVGPathSegCurvetoQuadraticSmoothAbs; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoQuadraticSmoothAbs.prototype, { + clone() { + return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); + } + + } + + Object.defineProperties(SVGPathSegCurvetoQuadraticSmoothAbs.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true } }); - var _SVGPathSegCurvetoQuadraticSmoothRel = /*#__PURE__*/function (_SVGPathSeg20) { - _inherits(_SVGPathSegCurvetoQuadraticSmoothRel, _SVGPathSeg20); - - var _super19 = _createSuper(_SVGPathSegCurvetoQuadraticSmoothRel); - - function _SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, x, y) { - var _this18; - - _classCallCheck(this, _SVGPathSegCurvetoQuadraticSmoothRel); - - _this18 = _super19.call(this, _SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, 't', owningPathSegList); - _this18._x = x; - _this18._y = y; - return _this18; + class SVGPathSegCurvetoQuadraticSmoothRel extends SVGPathSeg { + constructor(owningPathSegList, x, y) { + super(SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, 't', owningPathSegList); + this._x = x; + this._y = y; } - _createClass(_SVGPathSegCurvetoQuadraticSmoothRel, [{ - key: "toString", - value: function toString() { - return '[object SVGPathSegCurvetoQuadraticSmoothRel]'; - } - }, { - key: "_asPathString", - value: function _asPathString() { - return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; - } - }, { - key: "clone", - value: function clone() { - return new _SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); - } - }]); + toString() { + return '[object SVGPathSegCurvetoQuadraticSmoothRel]'; + } - return _SVGPathSegCurvetoQuadraticSmoothRel; - }(_SVGPathSeg); + _asPathString() { + return this.pathSegTypeAsLetter + ' ' + this._x + ' ' + this._y; + } - Object.defineProperties(_SVGPathSegCurvetoQuadraticSmoothRel.prototype, { + clone() { + return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); + } + + } + + Object.defineProperties(SVGPathSegCurvetoQuadraticSmoothRel.prototype, { x: { - get: function get() { + get() { return this._x; }, - set: function set(x) { + + set(x) { this._x = x; this._segmentChanged(); }, + enumerable: true }, y: { - get: function get() { + get() { return this._y; }, - set: function set(y) { + + set(y) { this._y = y; this._segmentChanged(); }, + enumerable: true } }); // Add createSVGPathSeg* functions to SVGPathElement. // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathElement. SVGPathElement.prototype.createSVGPathSegClosePath = function () { - return new _SVGPathSegClosePath(undefined); + return new SVGPathSegClosePath(undefined); }; SVGPathElement.prototype.createSVGPathSegMovetoAbs = function (x, y) { - return new _SVGPathSegMovetoAbs(undefined, x, y); + return new SVGPathSegMovetoAbs(undefined, x, y); }; SVGPathElement.prototype.createSVGPathSegMovetoRel = function (x, y) { - return new _SVGPathSegMovetoRel(undefined, x, y); + return new SVGPathSegMovetoRel(undefined, x, y); }; SVGPathElement.prototype.createSVGPathSegLinetoAbs = function (x, y) { - return new _SVGPathSegLinetoAbs(undefined, x, y); + return new SVGPathSegLinetoAbs(undefined, x, y); }; SVGPathElement.prototype.createSVGPathSegLinetoRel = function (x, y) { - return new _SVGPathSegLinetoRel(undefined, x, y); + return new SVGPathSegLinetoRel(undefined, x, y); }; SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function (x, y, x1, y1, x2, y2) { - return new _SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); + return new SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); }; SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function (x, y, x1, y1, x2, y2) { - return new _SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); + return new SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); }; SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function (x, y, x1, y1) { - return new _SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); + return new SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); }; SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function (x, y, x1, y1) { - return new _SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); + return new SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); }; SVGPathElement.prototype.createSVGPathSegArcAbs = function (x, y, r1, r2, angle, largeArcFlag, sweepFlag) { - return new _SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); + return new SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }; SVGPathElement.prototype.createSVGPathSegArcRel = function (x, y, r1, r2, angle, largeArcFlag, sweepFlag) { - return new _SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); + return new SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }; SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function (x) { - return new _SVGPathSegLinetoHorizontalAbs(undefined, x); + return new SVGPathSegLinetoHorizontalAbs(undefined, x); }; SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function (x) { - return new _SVGPathSegLinetoHorizontalRel(undefined, x); + return new SVGPathSegLinetoHorizontalRel(undefined, x); }; SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function (y) { - return new _SVGPathSegLinetoVerticalAbs(undefined, y); + return new SVGPathSegLinetoVerticalAbs(undefined, y); }; SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function (y) { - return new _SVGPathSegLinetoVerticalRel(undefined, y); + return new SVGPathSegLinetoVerticalRel(undefined, y); }; SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function (x, y, x2, y2) { - return new _SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); + return new SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); }; SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function (x, y, x2, y2) { - return new _SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); + return new SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); }; SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function (x, y) { - return new _SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); + return new SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); }; SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function (x, y) { - return new _SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); + return new SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); }; if (!('getPathSegAtLength' in SVGPathElement.prototype)) { @@ -1950,9 +1480,9 @@ throw new Error('Invalid arguments.'); } - var measurementElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + const measurementElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); measurementElement.setAttribute('d', this.getAttribute('d')); - var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1; // If the path is empty, return 0. + let lastPathSegment = measurementElement.pathSegList.numberOfItems - 1; // If the path is empty, return 0. if (lastPathSegment <= 0) { return 0; @@ -1972,26 +1502,26 @@ }; } - window.SVGPathSeg = _SVGPathSeg; - window.SVGPathSegClosePath = _SVGPathSegClosePath; - window.SVGPathSegMovetoAbs = _SVGPathSegMovetoAbs; - window.SVGPathSegMovetoRel = _SVGPathSegMovetoRel; - window.SVGPathSegLinetoAbs = _SVGPathSegLinetoAbs; - window.SVGPathSegLinetoRel = _SVGPathSegLinetoRel; - window.SVGPathSegCurvetoCubicAbs = _SVGPathSegCurvetoCubicAbs; - window.SVGPathSegCurvetoCubicRel = _SVGPathSegCurvetoCubicRel; - window.SVGPathSegCurvetoQuadraticAbs = _SVGPathSegCurvetoQuadraticAbs; - window.SVGPathSegCurvetoQuadraticRel = _SVGPathSegCurvetoQuadraticRel; - window.SVGPathSegArcAbs = _SVGPathSegArcAbs; - window.SVGPathSegArcRel = _SVGPathSegArcRel; - window.SVGPathSegLinetoHorizontalAbs = _SVGPathSegLinetoHorizontalAbs; - window.SVGPathSegLinetoHorizontalRel = _SVGPathSegLinetoHorizontalRel; - window.SVGPathSegLinetoVerticalAbs = _SVGPathSegLinetoVerticalAbs; - window.SVGPathSegLinetoVerticalRel = _SVGPathSegLinetoVerticalRel; - window.SVGPathSegCurvetoCubicSmoothAbs = _SVGPathSegCurvetoCubicSmoothAbs; - window.SVGPathSegCurvetoCubicSmoothRel = _SVGPathSegCurvetoCubicSmoothRel; - window.SVGPathSegCurvetoQuadraticSmoothAbs = _SVGPathSegCurvetoQuadraticSmoothAbs; - window.SVGPathSegCurvetoQuadraticSmoothRel = _SVGPathSegCurvetoQuadraticSmoothRel; + window.SVGPathSeg = SVGPathSeg; + window.SVGPathSegClosePath = SVGPathSegClosePath; + window.SVGPathSegMovetoAbs = SVGPathSegMovetoAbs; + window.SVGPathSegMovetoRel = SVGPathSegMovetoRel; + window.SVGPathSegLinetoAbs = SVGPathSegLinetoAbs; + window.SVGPathSegLinetoRel = SVGPathSegLinetoRel; + window.SVGPathSegCurvetoCubicAbs = SVGPathSegCurvetoCubicAbs; + window.SVGPathSegCurvetoCubicRel = SVGPathSegCurvetoCubicRel; + window.SVGPathSegCurvetoQuadraticAbs = SVGPathSegCurvetoQuadraticAbs; + window.SVGPathSegCurvetoQuadraticRel = SVGPathSegCurvetoQuadraticRel; + window.SVGPathSegArcAbs = SVGPathSegArcAbs; + window.SVGPathSegArcRel = SVGPathSegArcRel; + window.SVGPathSegLinetoHorizontalAbs = SVGPathSegLinetoHorizontalAbs; + window.SVGPathSegLinetoHorizontalRel = SVGPathSegLinetoHorizontalRel; + window.SVGPathSegLinetoVerticalAbs = SVGPathSegLinetoVerticalAbs; + window.SVGPathSegLinetoVerticalRel = SVGPathSegLinetoVerticalRel; + window.SVGPathSegCurvetoCubicSmoothAbs = SVGPathSegCurvetoCubicSmoothAbs; + window.SVGPathSegCurvetoCubicSmoothRel = SVGPathSegCurvetoCubicSmoothRel; + window.SVGPathSegCurvetoQuadraticSmoothAbs = SVGPathSegCurvetoQuadraticSmoothAbs; + window.SVGPathSegCurvetoQuadraticSmoothRel = SVGPathSegCurvetoQuadraticSmoothRel; } // Checking for SVGPathSegList in window checks for the case of an implementation without the // SVGPathSegList API. // The second check for appendItem is specific to Firefox 59+ which removed only parts of the @@ -2001,10 +1531,8 @@ if (!('SVGPathSegList' in window) || !('appendItem' in window.SVGPathSegList.prototype)) { // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList - var SVGPathSegList = /*#__PURE__*/function () { - function SVGPathSegList(pathElement) { - _classCallCheck(this, SVGPathSegList); - + class SVGPathSegList { + constructor(pathElement) { this._pathElement = pathElement; this._list = this._parsePath(this._pathElement.getAttribute('d')); // Use a MutationObserver to catch changes to the path's "d" attribute. @@ -2020,706 +1548,672 @@ // MutationObservers are not synchronous so we can have pending asynchronous mutations. - _createClass(SVGPathSegList, [{ - key: "_checkPathSynchronizedToList", - value: function _checkPathSynchronizedToList() { - this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords()); + _checkPathSynchronizedToList() { + this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords()); + } + + _updateListFromPathMutations(mutationRecords) { + if (!this._pathElement) { + return; } - }, { - key: "_updateListFromPathMutations", - value: function _updateListFromPathMutations(mutationRecords) { - if (!this._pathElement) { - return; + + let hasPathMutations = false; + mutationRecords.forEach(record => { + if (record.attributeName === 'd') { + hasPathMutations = true; + } + }); + + if (hasPathMutations) { + this._list = this._parsePath(this._pathElement.getAttribute('d')); + } + } // Serialize the list and update the path's 'd' attribute. + + + _writeListToPath() { + this._pathElementMutationObserver.disconnect(); + + this._pathElement.setAttribute('d', SVGPathSegList._pathSegArrayAsString(this._list)); + + this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); + } // When a path segment changes the list needs to be synchronized back to the path element. + + + segmentChanged(pathSeg) { + this._writeListToPath(); + } + + clear() { + this._checkPathSynchronizedToList(); + + this._list.forEach(pathSeg => { + pathSeg._owningPathSegList = null; + }); + + this._list = []; + + this._writeListToPath(); + } + + initialize(newItem) { + this._checkPathSynchronizedToList(); + + this._list = [newItem]; + newItem._owningPathSegList = this; + + this._writeListToPath(); + + return newItem; + } + + _checkValidIndex(index) { + if (isNaN(index) || index < 0 || index >= this.numberOfItems) { + throw new Error('INDEX_SIZE_ERR'); + } + } + + getItem(index) { + this._checkPathSynchronizedToList(); + + this._checkValidIndex(index); + + return this._list[index]; + } + + insertItemBefore(newItem, index) { + this._checkPathSynchronizedToList(); // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list. + + + if (index > this.numberOfItems) { + index = this.numberOfItems; + } + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + + this._list.splice(index, 0, newItem); + + newItem._owningPathSegList = this; + + this._writeListToPath(); + + return newItem; + } + + replaceItem(newItem, index) { + this._checkPathSynchronizedToList(); + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + + this._checkValidIndex(index); + + this._list[index] = newItem; + newItem._owningPathSegList = this; + + this._writeListToPath(); + + return newItem; + } + + removeItem(index) { + this._checkPathSynchronizedToList(); + + this._checkValidIndex(index); + + const item = this._list[index]; + + this._list.splice(index, 1); + + this._writeListToPath(); + + return item; + } + + appendItem(newItem) { + this._checkPathSynchronizedToList(); + + if (newItem._owningPathSegList) { + // SVG2 spec says to make a copy. + newItem = newItem.clone(); + } + + this._list.push(newItem); + + newItem._owningPathSegList = this; // TODO: Optimize this to just append to the existing attribute. + + this._writeListToPath(); + + return newItem; + } // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp. + + + _parsePath(string) { + if (!string || !string.length) { + return []; + } + + const owningPathSegList = this; // eslint-disable-line consistent-this + + class Builder { + constructor() { + this.pathSegList = []; } - var hasPathMutations = false; - mutationRecords.forEach(function (record) { - if (record.attributeName === 'd') { - hasPathMutations = true; - } - }); - - if (hasPathMutations) { - this._list = this._parsePath(this._pathElement.getAttribute('d')); - } - } // Serialize the list and update the path's 'd' attribute. - - }, { - key: "_writeListToPath", - value: function _writeListToPath() { - this._pathElementMutationObserver.disconnect(); - - this._pathElement.setAttribute('d', SVGPathSegList._pathSegArrayAsString(this._list)); - - this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig); - } // When a path segment changes the list needs to be synchronized back to the path element. - - }, { - key: "segmentChanged", - value: function segmentChanged(pathSeg) { - this._writeListToPath(); - } - }, { - key: "clear", - value: function clear() { - this._checkPathSynchronizedToList(); - - this._list.forEach(function (pathSeg) { - pathSeg._owningPathSegList = null; - }); - - this._list = []; - - this._writeListToPath(); - } - }, { - key: "initialize", - value: function initialize(newItem) { - this._checkPathSynchronizedToList(); - - this._list = [newItem]; - newItem._owningPathSegList = this; - - this._writeListToPath(); - - return newItem; - } - }, { - key: "_checkValidIndex", - value: function _checkValidIndex(index) { - if (isNaN(index) || index < 0 || index >= this.numberOfItems) { - throw new Error('INDEX_SIZE_ERR'); - } - } - }, { - key: "getItem", - value: function getItem(index) { - this._checkPathSynchronizedToList(); - - this._checkValidIndex(index); - - return this._list[index]; - } - }, { - key: "insertItemBefore", - value: function insertItemBefore(newItem, index) { - this._checkPathSynchronizedToList(); // Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list. - - - if (index > this.numberOfItems) { - index = this.numberOfItems; + appendSegment(pathSeg) { + this.pathSegList.push(pathSeg); } - if (newItem._owningPathSegList) { - // SVG2 spec says to make a copy. - newItem = newItem.clone(); - } - - this._list.splice(index, 0, newItem); - - newItem._owningPathSegList = this; - - this._writeListToPath(); - - return newItem; } - }, { - key: "replaceItem", - value: function replaceItem(newItem, index) { - this._checkPathSynchronizedToList(); - if (newItem._owningPathSegList) { - // SVG2 spec says to make a copy. - newItem = newItem.clone(); + class Source { + constructor(string) { + this._string = string; + this._currentIndex = 0; + this._endIndex = this._string.length; + this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN; + + this._skipOptionalSpaces(); } - this._checkValidIndex(index); - - this._list[index] = newItem; - newItem._owningPathSegList = this; - - this._writeListToPath(); - - return newItem; - } - }, { - key: "removeItem", - value: function removeItem(index) { - this._checkPathSynchronizedToList(); - - this._checkValidIndex(index); - - var item = this._list[index]; - - this._list.splice(index, 1); - - this._writeListToPath(); - - return item; - } - }, { - key: "appendItem", - value: function appendItem(newItem) { - this._checkPathSynchronizedToList(); - - if (newItem._owningPathSegList) { - // SVG2 spec says to make a copy. - newItem = newItem.clone(); + _isCurrentSpace() { + const character = this._string[this._currentIndex]; + return character <= ' ' && (character === ' ' || character === '\n' || character === '\t' || character === '\r' || character === '\f'); } - this._list.push(newItem); - - newItem._owningPathSegList = this; // TODO: Optimize this to just append to the existing attribute. - - this._writeListToPath(); - - return newItem; - } // This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp. - - }, { - key: "_parsePath", - value: function _parsePath(string) { - if (!string || !string.length) { - return []; - } - - var owningPathSegList = this; // eslint-disable-line consistent-this - - var Builder = /*#__PURE__*/function () { - function Builder() { - _classCallCheck(this, Builder); - - this.pathSegList = []; + _skipOptionalSpaces() { + while (this._currentIndex < this._endIndex && this._isCurrentSpace()) { + this._currentIndex++; } - _createClass(Builder, [{ - key: "appendSegment", - value: function appendSegment(pathSeg) { - this.pathSegList.push(pathSeg); - } - }]); + return this._currentIndex < this._endIndex; + } - return Builder; - }(); - - var Source = /*#__PURE__*/function () { - function Source(string) { - _classCallCheck(this, Source); - - this._string = string; - this._currentIndex = 0; - this._endIndex = this._string.length; - this._previousCommand = SVGPathSeg.PATHSEG_UNKNOWN; - - this._skipOptionalSpaces(); + _skipOptionalSpacesOrDelimiter() { + if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) !== ',') { + return false; } - _createClass(Source, [{ - key: "_isCurrentSpace", - value: function _isCurrentSpace() { - var character = this._string[this._currentIndex]; - return character <= ' ' && (character === ' ' || character === '\n' || character === '\t' || character === '\r' || character === '\f'); + if (this._skipOptionalSpaces()) { + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === ',') { + this._currentIndex++; + + this._skipOptionalSpaces(); } - }, { - key: "_skipOptionalSpaces", - value: function _skipOptionalSpaces() { - while (this._currentIndex < this._endIndex && this._isCurrentSpace()) { - this._currentIndex++; - } + } - return this._currentIndex < this._endIndex; - } - }, { - key: "_skipOptionalSpacesOrDelimiter", - value: function _skipOptionalSpacesOrDelimiter() { - if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) !== ',') { - return false; - } + return this._currentIndex < this._endIndex; + } - if (this._skipOptionalSpaces()) { - if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === ',') { - this._currentIndex++; + hasMoreData() { + return this._currentIndex < this._endIndex; + } - this._skipOptionalSpaces(); - } - } + peekSegmentType() { + const lookahead = this._string[this._currentIndex]; + return this._pathSegTypeFromChar(lookahead); + } - return this._currentIndex < this._endIndex; - } - }, { - key: "hasMoreData", - value: function hasMoreData() { - return this._currentIndex < this._endIndex; - } - }, { - key: "peekSegmentType", - value: function peekSegmentType() { - var lookahead = this._string[this._currentIndex]; - return this._pathSegTypeFromChar(lookahead); - } - }, { - key: "_pathSegTypeFromChar", - value: function _pathSegTypeFromChar(lookahead) { - switch (lookahead) { - case 'Z': - case 'z': - return SVGPathSeg.PATHSEG_CLOSEPATH; + _pathSegTypeFromChar(lookahead) { + switch (lookahead) { + case 'Z': + case 'z': + return SVGPathSeg.PATHSEG_CLOSEPATH; - case 'M': - return SVGPathSeg.PATHSEG_MOVETO_ABS; + case 'M': + return SVGPathSeg.PATHSEG_MOVETO_ABS; - case 'm': - return SVGPathSeg.PATHSEG_MOVETO_REL; + case 'm': + return SVGPathSeg.PATHSEG_MOVETO_REL; - case 'L': - return SVGPathSeg.PATHSEG_LINETO_ABS; + case 'L': + return SVGPathSeg.PATHSEG_LINETO_ABS; - case 'l': - return SVGPathSeg.PATHSEG_LINETO_REL; + case 'l': + return SVGPathSeg.PATHSEG_LINETO_REL; - case 'C': - return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS; + case 'C': + return SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS; - case 'c': - return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL; + case 'c': + return SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL; - case 'Q': - return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS; + case 'Q': + return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS; - case 'q': - return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL; + case 'q': + return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL; - case 'A': - return SVGPathSeg.PATHSEG_ARC_ABS; + case 'A': + return SVGPathSeg.PATHSEG_ARC_ABS; - case 'a': - return SVGPathSeg.PATHSEG_ARC_REL; + case 'a': + return SVGPathSeg.PATHSEG_ARC_REL; - case 'H': - return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS; + case 'H': + return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS; - case 'h': - return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL; + case 'h': + return SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL; - case 'V': - return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS; + case 'V': + return SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS; - case 'v': - return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL; + case 'v': + return SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL; - case 'S': - return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; + case 'S': + return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; - case 's': - return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL; + case 's': + return SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL; - case 'T': - return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; + case 'T': + return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; - case 't': - return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; - - default: - return SVGPathSeg.PATHSEG_UNKNOWN; - } - } - }, { - key: "_nextCommandHelper", - value: function _nextCommandHelper(lookahead, previousCommand) { - // Check for remaining coordinates in the current command. - if ((lookahead === '+' || lookahead === '-' || lookahead === '.' || lookahead >= '0' && lookahead <= '9') && previousCommand !== SVGPathSeg.PATHSEG_CLOSEPATH) { - if (previousCommand === SVGPathSeg.PATHSEG_MOVETO_ABS) { - return SVGPathSeg.PATHSEG_LINETO_ABS; - } - - if (previousCommand === SVGPathSeg.PATHSEG_MOVETO_REL) { - return SVGPathSeg.PATHSEG_LINETO_REL; - } - - return previousCommand; - } + case 't': + return SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; + default: return SVGPathSeg.PATHSEG_UNKNOWN; + } + } + + _nextCommandHelper(lookahead, previousCommand) { + // Check for remaining coordinates in the current command. + if ((lookahead === '+' || lookahead === '-' || lookahead === '.' || lookahead >= '0' && lookahead <= '9') && previousCommand !== SVGPathSeg.PATHSEG_CLOSEPATH) { + if (previousCommand === SVGPathSeg.PATHSEG_MOVETO_ABS) { + return SVGPathSeg.PATHSEG_LINETO_ABS; } - }, { - key: "initialCommandIsMoveTo", - value: function initialCommandIsMoveTo() { - // If the path is empty it is still valid, so return true. - if (!this.hasMoreData()) { - return true; - } - var command = this.peekSegmentType(); // Path must start with moveTo. - - return command === SVGPathSeg.PATHSEG_MOVETO_ABS || command === SVGPathSeg.PATHSEG_MOVETO_REL; - } // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp. - // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF - - }, { - key: "_parseNumber", - value: function _parseNumber() { - var exponent = 0; - var integer = 0; - var frac = 1; - var decimal = 0; - var sign = 1; - var expsign = 1; - var startIndex = this._currentIndex; - - this._skipOptionalSpaces(); // Read the sign. - - - if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === '+') { - this._currentIndex++; - } else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === '-') { - this._currentIndex++; - sign = -1; - } - - if (this._currentIndex === this._endIndex || (this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') && this._string.charAt(this._currentIndex) !== '.') { - // The first character of a number must be one of [0-9+-.]. - return undefined; - } // Read the integer part, build right-to-left. - - - var startIntPartIndex = this._currentIndex; - - while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { - this._currentIndex++; // Advance to first non-digit. - } - - if (this._currentIndex !== startIntPartIndex) { - var scanIntPartIndex = this._currentIndex - 1; - var multiplier = 1; - - while (scanIntPartIndex >= startIntPartIndex) { - integer += multiplier * (this._string.charAt(scanIntPartIndex--) - '0'); - multiplier *= 10; - } - } // Read the decimals. - - - if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === '.') { - this._currentIndex++; // There must be a least one digit following the . - - if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') { - return undefined; - } - - while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { - frac *= 10; - decimal += (this._string.charAt(this._currentIndex) - '0') / frac; - this._currentIndex += 1; - } - } // Read the exponent part. - - - if (this._currentIndex !== startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) === 'e' || this._string.charAt(this._currentIndex) === 'E') && this._string.charAt(this._currentIndex + 1) !== 'x' && this._string.charAt(this._currentIndex + 1) !== 'm') { - this._currentIndex++; // Read the sign of the exponent. - - if (this._string.charAt(this._currentIndex) === '+') { - this._currentIndex++; - } else if (this._string.charAt(this._currentIndex) === '-') { - this._currentIndex++; - expsign = -1; - } // There must be an exponent. - - - if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') { - return undefined; - } - - while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { - exponent *= 10; - exponent += this._string.charAt(this._currentIndex) - '0'; - this._currentIndex++; - } - } - - var number = integer + decimal; - number *= sign; - - if (exponent) { - number *= Math.pow(10, expsign * exponent); - } - - if (startIndex === this._currentIndex) { - return undefined; - } - - this._skipOptionalSpacesOrDelimiter(); - - return number; + if (previousCommand === SVGPathSeg.PATHSEG_MOVETO_REL) { + return SVGPathSeg.PATHSEG_LINETO_REL; } - }, { - key: "_parseArcFlag", - value: function _parseArcFlag() { - if (this._currentIndex >= this._endIndex) { - return undefined; - } - var flag = false; + return previousCommand; + } - var flagChar = this._string.charAt(this._currentIndex++); + return SVGPathSeg.PATHSEG_UNKNOWN; + } - if (flagChar === '0') { - flag = false; - } else if (flagChar === '1') { - flag = true; - } else { - return undefined; - } + initialCommandIsMoveTo() { + // If the path is empty it is still valid, so return true. + if (!this.hasMoreData()) { + return true; + } - this._skipOptionalSpacesOrDelimiter(); + const command = this.peekSegmentType(); // Path must start with moveTo. - return flag; + return command === SVGPathSeg.PATHSEG_MOVETO_ABS || command === SVGPathSeg.PATHSEG_MOVETO_REL; + } // Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp. + // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF + + + _parseNumber() { + let exponent = 0; + let integer = 0; + let frac = 1; + let decimal = 0; + let sign = 1; + let expsign = 1; + const startIndex = this._currentIndex; + + this._skipOptionalSpaces(); // Read the sign. + + + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === '+') { + this._currentIndex++; + } else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === '-') { + this._currentIndex++; + sign = -1; + } + + if (this._currentIndex === this._endIndex || (this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') && this._string.charAt(this._currentIndex) !== '.') { + // The first character of a number must be one of [0-9+-.]. + return undefined; + } // Read the integer part, build right-to-left. + + + const startIntPartIndex = this._currentIndex; + + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { + this._currentIndex++; // Advance to first non-digit. + } + + if (this._currentIndex !== startIntPartIndex) { + let scanIntPartIndex = this._currentIndex - 1; + let multiplier = 1; + + while (scanIntPartIndex >= startIntPartIndex) { + integer += multiplier * (this._string.charAt(scanIntPartIndex--) - '0'); + multiplier *= 10; } - }, { - key: "parseSegment", - value: function parseSegment() { - var lookahead = this._string[this._currentIndex]; + } // Read the decimals. - var command = this._pathSegTypeFromChar(lookahead); - if (command === SVGPathSeg.PATHSEG_UNKNOWN) { - // Possibly an implicit command. Not allowed if this is the first command. - if (this._previousCommand === SVGPathSeg.PATHSEG_UNKNOWN) { - return null; - } + if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) === '.') { + this._currentIndex++; // There must be a least one digit following the . - command = this._nextCommandHelper(lookahead, this._previousCommand); - - if (command === SVGPathSeg.PATHSEG_UNKNOWN) { - return null; - } - } else { - this._currentIndex++; - } - - this._previousCommand = command; - - switch (command) { - case SVGPathSeg.PATHSEG_MOVETO_REL: - return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); - - case SVGPathSeg.PATHSEG_MOVETO_ABS: - return new SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); - - case SVGPathSeg.PATHSEG_LINETO_REL: - return new SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); - - case SVGPathSeg.PATHSEG_LINETO_ABS: - return new SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); - - case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: - return new SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber()); - - case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: - return new SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber()); - - case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: - return new SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber()); - - case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: - return new SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber()); - - case SVGPathSeg.PATHSEG_CLOSEPATH: - this._skipOptionalSpaces(); - - return new SVGPathSegClosePath(owningPathSegList); - - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: - { - var points = { - x1: this._parseNumber(), - y1: this._parseNumber(), - x2: this._parseNumber(), - y2: this._parseNumber(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); - } - - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: - { - var _points = { - x1: this._parseNumber(), - y1: this._parseNumber(), - x2: this._parseNumber(), - y2: this._parseNumber(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegCurvetoCubicAbs(owningPathSegList, _points.x, _points.y, _points.x1, _points.y1, _points.x2, _points.y2); - } - - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: - { - var _points2 = { - x2: this._parseNumber(), - y2: this._parseNumber(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, _points2.x, _points2.y, _points2.x2, _points2.y2); - } - - case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: - { - var _points3 = { - x2: this._parseNumber(), - y2: this._parseNumber(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, _points3.x, _points3.y, _points3.x2, _points3.y2); - } - - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: - { - var _points4 = { - x1: this._parseNumber(), - y1: this._parseNumber(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegCurvetoQuadraticRel(owningPathSegList, _points4.x, _points4.y, _points4.x1, _points4.y1); - } - - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: - { - var _points5 = { - x1: this._parseNumber(), - y1: this._parseNumber(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegCurvetoQuadraticAbs(owningPathSegList, _points5.x, _points5.y, _points5.x1, _points5.y1); - } - - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: - return new SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber()); - - case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: - return new SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); - - case SVGPathSeg.PATHSEG_ARC_REL: - { - var _points6 = { - x1: this._parseNumber(), - y1: this._parseNumber(), - arcAngle: this._parseNumber(), - arcLarge: this._parseArcFlag(), - arcSweep: this._parseArcFlag(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegArcRel(owningPathSegList, _points6.x, _points6.y, _points6.x1, _points6.y1, _points6.arcAngle, _points6.arcLarge, _points6.arcSweep); - } - - case SVGPathSeg.PATHSEG_ARC_ABS: - { - var _points7 = { - x1: this._parseNumber(), - y1: this._parseNumber(), - arcAngle: this._parseNumber(), - arcLarge: this._parseArcFlag(), - arcSweep: this._parseArcFlag(), - x: this._parseNumber(), - y: this._parseNumber() - }; - return new SVGPathSegArcAbs(owningPathSegList, _points7.x, _points7.y, _points7.x1, _points7.y1, _points7.arcAngle, _points7.arcLarge, _points7.arcSweep); - } - - default: - throw new Error('Unknown path seg type.'); - } + if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') { + return undefined; } - }]); - return Source; - }(); + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { + frac *= 10; + decimal += (this._string.charAt(this._currentIndex) - '0') / frac; + this._currentIndex += 1; + } + } // Read the exponent part. - var builder = new Builder(); - var source = new Source(string); - if (!source.initialCommandIsMoveTo()) { + if (this._currentIndex !== startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) === 'e' || this._string.charAt(this._currentIndex) === 'E') && this._string.charAt(this._currentIndex + 1) !== 'x' && this._string.charAt(this._currentIndex + 1) !== 'm') { + this._currentIndex++; // Read the sign of the exponent. + + if (this._string.charAt(this._currentIndex) === '+') { + this._currentIndex++; + } else if (this._string.charAt(this._currentIndex) === '-') { + this._currentIndex++; + expsign = -1; + } // There must be an exponent. + + + if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < '0' || this._string.charAt(this._currentIndex) > '9') { + return undefined; + } + + while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= '0' && this._string.charAt(this._currentIndex) <= '9') { + exponent *= 10; + exponent += this._string.charAt(this._currentIndex) - '0'; + this._currentIndex++; + } + } + + let number = integer + decimal; + number *= sign; + + if (exponent) { + number *= 10 ** (expsign * exponent); + } + + if (startIndex === this._currentIndex) { + return undefined; + } + + this._skipOptionalSpacesOrDelimiter(); + + return number; + } + + _parseArcFlag() { + if (this._currentIndex >= this._endIndex) { + return undefined; + } + + let flag = false; + + const flagChar = this._string.charAt(this._currentIndex++); + + if (flagChar === '0') { + flag = false; + } else if (flagChar === '1') { + flag = true; + } else { + return undefined; + } + + this._skipOptionalSpacesOrDelimiter(); + + return flag; + } + + parseSegment() { + const lookahead = this._string[this._currentIndex]; + + let command = this._pathSegTypeFromChar(lookahead); + + if (command === SVGPathSeg.PATHSEG_UNKNOWN) { + // Possibly an implicit command. Not allowed if this is the first command. + if (this._previousCommand === SVGPathSeg.PATHSEG_UNKNOWN) { + return null; + } + + command = this._nextCommandHelper(lookahead, this._previousCommand); + + if (command === SVGPathSeg.PATHSEG_UNKNOWN) { + return null; + } + } else { + this._currentIndex++; + } + + this._previousCommand = command; + + switch (command) { + case SVGPathSeg.PATHSEG_MOVETO_REL: + return new SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + + case SVGPathSeg.PATHSEG_MOVETO_ABS: + return new SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + + case SVGPathSeg.PATHSEG_LINETO_REL: + return new SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + + case SVGPathSeg.PATHSEG_LINETO_ABS: + return new SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL: + return new SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber()); + + case SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS: + return new SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber()); + + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL: + return new SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber()); + + case SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS: + return new SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber()); + + case SVGPathSeg.PATHSEG_CLOSEPATH: + this._skipOptionalSpaces(); + + return new SVGPathSegClosePath(owningPathSegList); + + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL: + { + const points = { + x1: this._parseNumber(), + y1: this._parseNumber(), + x2: this._parseNumber(), + y2: this._parseNumber(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); + } + + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS: + { + const points = { + x1: this._parseNumber(), + y1: this._parseNumber(), + x2: this._parseNumber(), + y2: this._parseNumber(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2); + } + + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL: + { + const points = { + x2: this._parseNumber(), + y2: this._parseNumber(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2); + } + + case SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS: + { + const points = { + x2: this._parseNumber(), + y2: this._parseNumber(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2); + } + + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL: + { + const points = { + x1: this._parseNumber(), + y1: this._parseNumber(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1); + } + + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS: + { + const points = { + x1: this._parseNumber(), + y1: this._parseNumber(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1); + } + + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL: + return new SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber()); + + case SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS: + return new SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber()); + + case SVGPathSeg.PATHSEG_ARC_REL: + { + const points = { + x1: this._parseNumber(), + y1: this._parseNumber(), + arcAngle: this._parseNumber(), + arcLarge: this._parseArcFlag(), + arcSweep: this._parseArcFlag(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep); + } + + case SVGPathSeg.PATHSEG_ARC_ABS: + { + const points = { + x1: this._parseNumber(), + y1: this._parseNumber(), + arcAngle: this._parseNumber(), + arcLarge: this._parseArcFlag(), + arcSweep: this._parseArcFlag(), + x: this._parseNumber(), + y: this._parseNumber() + }; + return new SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep); + } + + default: + throw new Error('Unknown path seg type.'); + } + } + + } + + const builder = new Builder(); + const source = new Source(string); + + if (!source.initialCommandIsMoveTo()) { + return []; + } + + while (source.hasMoreData()) { + const pathSeg = source.parseSegment(); + + if (!pathSeg) { return []; } - while (source.hasMoreData()) { - var pathSeg = source.parseSegment(); - - if (!pathSeg) { - return []; - } - - builder.appendSegment(pathSeg); - } - - return builder.pathSegList; - } // STATIC - - }], [{ - key: "_pathSegArrayAsString", - value: function _pathSegArrayAsString(pathSegArray) { - var string = ''; - var first = true; - pathSegArray.forEach(function (pathSeg) { - if (first) { - first = false; - string += pathSeg._asPathString(); - } else { - string += ' ' + pathSeg._asPathString(); - } - }); - return string; + builder.appendSegment(pathSeg); } - }]); - return SVGPathSegList; - }(); + return builder.pathSegList; + } // STATIC + + + static _pathSegArrayAsString(pathSegArray) { + let string = ''; + let first = true; + pathSegArray.forEach(pathSeg => { + if (first) { + first = false; + string += pathSeg._asPathString(); + } else { + string += ' ' + pathSeg._asPathString(); + } + }); + return string; + } + + } SVGPathSegList.prototype.classname = 'SVGPathSegList'; Object.defineProperty(SVGPathSegList.prototype, 'numberOfItems', { - get: function get() { + get() { this._checkPathSynchronizedToList(); return this._list.length; }, + enumerable: true }); // Add the pathSegList accessors to SVGPathElement. // Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData Object.defineProperties(SVGPathElement.prototype, { pathSegList: { - get: function get() { + get() { if (!this._pathSegList) { this._pathSegList = new SVGPathSegList(this); } return this._pathSegList; }, + enumerable: true }, // TODO: The following are not implemented and simply return SVGPathElement.pathSegList. normalizedPathSegList: { - get: function get() { + get() { return this.pathSegList; }, + enumerable: true }, animatedPathSegList: { - get: function get() { + get() { return this.pathSegList; }, + enumerable: true }, animatedNormalizedPathSegList: { - get: function get() { + get() { return this.pathSegList; }, + enumerable: true } }); @@ -2727,38 +2221,40 @@ } })(); - var $ = jQuery; + /* globals jQuery */ + const $ = jQuery; - var supportsSVG_ = function () { + const supportsSVG_ = function () { return Boolean(document.createElementNS && document.createElementNS(NS.SVG, 'svg').createSVGRect); }(); - var _navigator = navigator, - userAgent = _navigator.userAgent; - var svg = document.createElementNS(NS.SVG, 'svg'); // Note: Browser sniffing should only be used if no other detection method is possible + const { + userAgent + } = navigator; + const svg = document.createElementNS(NS.SVG, 'svg'); // Note: Browser sniffing should only be used if no other detection method is possible - var isOpera_ = Boolean(window.opera); - var isWebkit_ = userAgent.includes('AppleWebKit'); - var isGecko_ = userAgent.includes('Gecko/'); - var isIE_ = userAgent.includes('MSIE'); - var isChrome_ = userAgent.includes('Chrome/'); - var isWindows_ = userAgent.includes('Windows'); - var isMac_ = userAgent.includes('Macintosh'); - var isTouch_ = ('ontouchstart' in window); + const isOpera_ = Boolean(window.opera); + const isWebkit_ = userAgent.includes('AppleWebKit'); + const isGecko_ = userAgent.includes('Gecko/'); + const isIE_ = userAgent.includes('MSIE'); + const isChrome_ = userAgent.includes('Chrome/'); + const isWindows_ = userAgent.includes('Windows'); + const isMac_ = userAgent.includes('Macintosh'); + const isTouch_ = ('ontouchstart' in window); - var supportsSelectors_ = function () { + const supportsSelectors_ = function () { return Boolean(svg.querySelector); }(); - var supportsXpath_ = function () { + const supportsXpath_ = function () { return Boolean(document.evaluate); }(); // segList functions (for FF1.5 and 2.0) - var supportsPathReplaceItem_ = function () { - var path = document.createElementNS(NS.SVG, 'path'); + const supportsPathReplaceItem_ = function () { + const path = document.createElementNS(NS.SVG, 'path'); path.setAttribute('d', 'M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5, 5); + const seglist = path.pathSegList; + const seg = path.createSVGPathSegLinetoAbs(5, 5); try { seglist.replaceItem(seg, 1); @@ -2768,11 +2264,11 @@ return false; }(); - var supportsPathInsertItemBefore_ = function () { - var path = document.createElementNS(NS.SVG, 'path'); + const supportsPathInsertItemBefore_ = function () { + const path = document.createElementNS(NS.SVG, 'path'); path.setAttribute('d', 'M0,0 10,10'); - var seglist = path.pathSegList; - var seg = path.createSVGPathSegLinetoAbs(5, 5); + const seglist = path.pathSegList; + const seg = path.createSVGPathSegLinetoAbs(5, 5); try { seglist.insertItemBefore(seg, 1); @@ -2783,19 +2279,19 @@ }(); // text character positioning (for IE9 and now Chrome) - var supportsGoodTextCharPos_ = function () { - var svgroot = document.createElementNS(NS.SVG, 'svg'); - var svgcontent = document.createElementNS(NS.SVG, 'svg'); + const supportsGoodTextCharPos_ = function () { + const svgroot = document.createElementNS(NS.SVG, 'svg'); + const svgcontent = document.createElementNS(NS.SVG, 'svg'); document.documentElement.append(svgroot); svgcontent.setAttribute('x', 5); svgroot.append(svgcontent); - var text = document.createElementNS(NS.SVG, 'text'); + const text = document.createElementNS(NS.SVG, 'text'); text.textContent = 'a'; svgcontent.append(text); try { // Chrome now fails here - var pos = text.getStartPositionOfChar(0).x; + const pos = text.getStartPositionOfChar(0).x; return pos === 0; } catch (err) { return false; @@ -2804,40 +2300,40 @@ } }(); - var supportsPathBBox_ = function () { - var svgcontent = document.createElementNS(NS.SVG, 'svg'); + const supportsPathBBox_ = function () { + const svgcontent = document.createElementNS(NS.SVG, 'svg'); document.documentElement.append(svgcontent); - var path = document.createElementNS(NS.SVG, 'path'); + const path = document.createElementNS(NS.SVG, 'path'); path.setAttribute('d', 'M0,0 C0,0 10,10 10,0'); svgcontent.append(path); - var bbox = path.getBBox(); + const bbox = path.getBBox(); svgcontent.remove(); return bbox.height > 4 && bbox.height < 5; }(); // Support for correct bbox sizing on groups with horizontal/vertical lines - var supportsHVLineContainerBBox_ = function () { - var svgcontent = document.createElementNS(NS.SVG, 'svg'); + const supportsHVLineContainerBBox_ = function () { + const svgcontent = document.createElementNS(NS.SVG, 'svg'); document.documentElement.append(svgcontent); - var path = document.createElementNS(NS.SVG, 'path'); + const path = document.createElementNS(NS.SVG, 'path'); path.setAttribute('d', 'M0,0 10,0'); - var path2 = document.createElementNS(NS.SVG, 'path'); + const path2 = document.createElementNS(NS.SVG, 'path'); path2.setAttribute('d', 'M5,0 15,0'); - var g = document.createElementNS(NS.SVG, 'g'); + const g = document.createElementNS(NS.SVG, 'g'); g.append(path, path2); svgcontent.append(g); - var bbox = g.getBBox(); + const bbox = g.getBBox(); svgcontent.remove(); // Webkit gives 0, FF gives 10, Opera (correctly) gives 15 return bbox.width === 15; }(); - var supportsGoodDecimals_ = function () { + const supportsGoodDecimals_ = function () { // Correct decimals on clone attributes (Opera < 10.5/win/non-en) - var rect = document.createElementNS(NS.SVG, 'rect'); + const rect = document.createElementNS(NS.SVG, 'rect'); rect.setAttribute('x', 0.1); - var crect = rect.cloneNode(false); - var retValue = !crect.getAttribute('x').includes(','); + const crect = rect.cloneNode(false); + const retValue = !crect.getAttribute('x').includes(','); if (!retValue) { // Todo: i18nize or remove @@ -2847,22 +2343,22 @@ return retValue; }(); - var supportsNonScalingStroke_ = function () { - var rect = document.createElementNS(NS.SVG, 'rect'); + const supportsNonScalingStroke_ = function () { + const rect = document.createElementNS(NS.SVG, 'rect'); rect.setAttribute('style', 'vector-effect:non-scaling-stroke'); return rect.style.vectorEffect === 'non-scaling-stroke'; }(); - var supportsNativeSVGTransformLists_ = function () { - var rect = document.createElementNS(NS.SVG, 'rect'); - var rxform = rect.transform.baseVal; - var t1 = svg.createSVGTransform(); + let supportsNativeSVGTransformLists_ = function () { + const rect = document.createElementNS(NS.SVG, 'rect'); + const rxform = rect.transform.baseVal; + const t1 = svg.createSVGTransform(); rxform.appendItem(t1); - var r1 = rxform.getItem(0); + const r1 = rxform.getItem(0); - var isSVGTransform = function isSVGTransform(o) { + const isSVGTransform = o => { // https://developer.mozilla.org/en-US/docs/Web/API/SVGTransform - return o && _typeof(o) === 'object' && typeof o.setMatrix === 'function' && 'angle' in o; + return o && typeof o === 'object' && typeof o.setMatrix === 'function' && 'angle' in o; }; return isSVGTransform(r1) && isSVGTransform(t1) && r1.type === t1.type && r1.angle === t1.angle && r1.matrix.a === t1.matrix.a && r1.matrix.b === t1.matrix.b && r1.matrix.c === t1.matrix.c && r1.matrix.d === t1.matrix.d && r1.matrix.e === t1.matrix.e && r1.matrix.f === t1.matrix.f; @@ -2874,129 +2370,97 @@ */ - var isOpera = function isOpera() { - return isOpera_; - }; + const isOpera = () => isOpera_; /** * @function module:browser.isWebkit * @returns {boolean} */ - var isWebkit = function isWebkit() { - return isWebkit_; - }; + const isWebkit = () => isWebkit_; /** * @function module:browser.isGecko * @returns {boolean} */ - var isGecko = function isGecko() { - return isGecko_; - }; + const isGecko = () => isGecko_; /** * @function module:browser.isIE * @returns {boolean} */ - var isIE = function isIE() { - return isIE_; - }; + const isIE = () => isIE_; /** * @function module:browser.isChrome * @returns {boolean} */ - var isChrome = function isChrome() { - return isChrome_; - }; + const isChrome = () => isChrome_; /** * @function module:browser.isMac * @returns {boolean} */ - var isMac = function isMac() { - return isMac_; - }; + const isMac = () => isMac_; /** * @function module:browser.isTouch * @returns {boolean} */ - var isTouch = function isTouch() { - return isTouch_; - }; + const isTouch = () => isTouch_; /** * @function module:browser.supportsSelectors * @returns {boolean} */ - var supportsSelectors = function supportsSelectors() { - return supportsSelectors_; - }; + const supportsSelectors = () => supportsSelectors_; /** * @function module:browser.supportsXpath * @returns {boolean} */ - var supportsXpath = function supportsXpath() { - return supportsXpath_; - }; + const supportsXpath = () => supportsXpath_; /** * @function module:browser.supportsPathReplaceItem * @returns {boolean} */ - var supportsPathReplaceItem = function supportsPathReplaceItem() { - return supportsPathReplaceItem_; - }; + const supportsPathReplaceItem = () => supportsPathReplaceItem_; /** * @function module:browser.supportsPathInsertItemBefore * @returns {boolean} */ - var supportsPathInsertItemBefore = function supportsPathInsertItemBefore() { - return supportsPathInsertItemBefore_; - }; + const supportsPathInsertItemBefore = () => supportsPathInsertItemBefore_; /** * @function module:browser.supportsPathBBox * @returns {boolean} */ - var supportsPathBBox = function supportsPathBBox() { - return supportsPathBBox_; - }; + const supportsPathBBox = () => supportsPathBBox_; /** * @function module:browser.supportsHVLineContainerBBox * @returns {boolean} */ - var supportsHVLineContainerBBox = function supportsHVLineContainerBBox() { - return supportsHVLineContainerBBox_; - }; + const supportsHVLineContainerBBox = () => supportsHVLineContainerBBox_; /** * @function module:browser.supportsGoodTextCharPos * @returns {boolean} */ - var supportsGoodTextCharPos = function supportsGoodTextCharPos() { - return supportsGoodTextCharPos_; - }; + const supportsGoodTextCharPos = () => supportsGoodTextCharPos_; /** * @function module:browser.supportsNonScalingStroke * @returns {boolean} */ - var supportsNonScalingStroke = function supportsNonScalingStroke() { - return supportsNonScalingStroke_; - }; + const supportsNonScalingStroke = () => supportsNonScalingStroke_; /** * @function module:browser.supportsNativeTransformLists * @returns {boolean} */ - var supportsNativeTransformLists = function supportsNativeTransformLists() { - return supportsNativeSVGTransformLists_; - }; + const supportsNativeTransformLists = () => supportsNativeSVGTransformLists_; /** * A jQuery module to work with SVG attributes. @@ -3019,8 +2483,8 @@ * @returns {external:jQuery} */ function jQueryPluginSVG($) { - var proxied = $.fn.attr, - svgns = 'http://www.w3.org/2000/svg'; + const proxied = $.fn.attr, + svgns = 'http://www.w3.org/2000/svg'; /** * @typedef {PlainObject} module:jQueryAttr.Attributes */ @@ -3033,14 +2497,14 @@ */ $.fn.attr = function (key, value) { - var len = this.length; + const len = this.length; if (!len) { return proxied.call(this, key, value); } - for (var i = 0; i < len; ++i) { - var elem = this[i]; // set/get SVG attribute + for (let i = 0; i < len; ++i) { + const elem = this[i]; // set/get SVG attribute if (elem.namespaceURI === svgns) { // Setting attribute @@ -3048,12 +2512,12 @@ elem.setAttribute(key, value); } else if (Array.isArray(key)) { // Getting attributes from array - var obj = {}; - var j = key.length; + const obj = {}; + let j = key.length; while (j--) { - var aname = key[j]; - var attr = elem.getAttribute(aname); // This returns a number when appropriate + const aname = key[j]; + let attr = elem.getAttribute(aname); // This returns a number when appropriate if (attr || attr === '0') { attr = isNaN(attr) ? attr : attr - 0; @@ -3065,24 +2529,20 @@ return obj; } - if (_typeof(key) === 'object') { + if (typeof key === 'object') { // Setting attributes from object - for (var _i = 0, _Object$entries = Object.entries(key); _i < _Object$entries.length; _i++) { - var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), - name = _Object$entries$_i[0], - val = _Object$entries$_i[1]; - + for (const [name, val] of Object.entries(key)) { elem.setAttribute(name, val); } // Getting attribute } else { - var _attr = elem.getAttribute(key); + let attr = elem.getAttribute(key); - if (_attr || _attr === '0') { - _attr = isNaN(_attr) ? _attr : _attr - 0; + if (attr || attr === '0') { + attr = isNaN(attr) ? attr : attr - 0; } - return _attr; + return attr; } } else { return proxied.call(this, key, value); @@ -3095,7 +2555,15 @@ return $; } - var svgroot = document.createElementNS(NS.SVG, 'svg'); + /** + * Partial polyfill of `SVGTransformList` + * @module SVGTransformList + * + * @license MIT + * + * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller + */ + const svgroot = document.createElementNS(NS.SVG, 'svg'); /** * Helper function to convert `SVGTransform` to a string. * @param {SVGTransform} xform @@ -3103,8 +2571,8 @@ */ function transformToString(xform) { - var m = xform.matrix; - var text = ''; + const m = xform.matrix; + let text = ''; switch (xform.type) { case 1: @@ -3130,11 +2598,11 @@ case 4: { // ROTATE - var cx = 0; - var cy = 0; // this prevents divide by zero + let cx = 0; + let cy = 0; // this prevents divide by zero if (xform.angle !== 0) { - var K = 1 - m.a; + const K = 1 - m.a; cy = (K * m.f + m.b * m.e) / (K * K + m.b * m.b); cx = (m.e - m.b * cy) / K; } @@ -3151,7 +2619,7 @@ */ - var listMap_ = {}; + let listMap_ = {}; /** * @interface module:SVGTransformList.SVGEditTransformList * @property {Integer} numberOfItems unsigned long @@ -3227,24 +2695,22 @@ * @implements {module:SVGTransformList.SVGEditTransformList} */ - var SVGTransformList = /*#__PURE__*/function () { + class SVGTransformList { // eslint-disable-line no-shadow /** * @param {Element} elem * @returns {SVGTransformList} */ - function SVGTransformList(elem) { - _classCallCheck(this, SVGTransformList); - + constructor(elem) { this._elem = elem || null; this._xforms = []; // TODO: how do we capture the undo-ability in the changed transform list? this._update = function () { - var tstr = ''; // /* const concatMatrix = */ svgroot.createSVGMatrix(); + let tstr = ''; // /* const concatMatrix = */ svgroot.createSVGMatrix(); - for (var i = 0; i < this.numberOfItems; ++i) { - var xform = this._list.getItem(i); + for (let i = 0; i < this.numberOfItems; ++i) { + const xform = this._list.getItem(i); tstr += transformToString(xform) + ' '; } @@ -3255,69 +2721,65 @@ this._list = this; this._init = function () { - var _this = this; - // Transform attribute parser - var str = this._elem.getAttribute('transform'); + let str = this._elem.getAttribute('transform'); if (!str) { return; } // TODO: Add skew support in future - var re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; // const re = /\s*(?(?:scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; + const re = /\s*((scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; // const re = /\s*(?(?:scale|matrix|rotate|translate)\s*\(.*?\))\s*,?\s*/; - var m = true; + let m = true; while (m) { m = str.match(re); str = str.replace(re, ''); if (m && m[1]) { - (function () { - var x = m[1]; - var bits = x.split(/\s*\(/); - var name = bits[0]; - var valBits = bits[1].match(/\s*(.*?)\s*\)/); - valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -'); - var valArr = valBits[1].split(/[, ]+/); - var letters = 'abcdef'.split(''); - /* - if (m && m.groups.xform) { - const x = m.groups.xform; - const [name, bits] = x.split(/\s*\(/); - const valBits = bits.match(/\s*(?.*?)\s*\)/); - valBits.groups.nonWhitespace = valBits.groups.nonWhitespace.replace( - /(?\d)-/g, '$ -' - ); - const valArr = valBits.groups.nonWhitespace.split(/[, ]+/); - const letters = [...'abcdef']; - */ + const x = m[1]; + const bits = x.split(/\s*\(/); + const name = bits[0]; + const valBits = bits[1].match(/\s*(.*?)\s*\)/); + valBits[1] = valBits[1].replace(/(\d)-/g, '$1 -'); + const valArr = valBits[1].split(/[, ]+/); + const letters = 'abcdef'.split(''); + /* + if (m && m.groups.xform) { + const x = m.groups.xform; + const [name, bits] = x.split(/\s*\(/); + const valBits = bits.match(/\s*(?.*?)\s*\)/); + valBits.groups.nonWhitespace = valBits.groups.nonWhitespace.replace( + /(?\d)-/g, '$ -' + ); + const valArr = valBits.groups.nonWhitespace.split(/[, ]+/); + const letters = [...'abcdef']; + */ - var mtx = svgroot.createSVGMatrix(); - Object.values(valArr).forEach(function (item, i) { - valArr[i] = Number.parseFloat(item); + const mtx = svgroot.createSVGMatrix(); + Object.values(valArr).forEach(function (item, i) { + valArr[i] = Number.parseFloat(item); - if (name === 'matrix') { - mtx[letters[i]] = valArr[i]; - } - }); - var xform = svgroot.createSVGTransform(); - var fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1); - var values = name === 'matrix' ? [mtx] : valArr; - - if (name === 'scale' && values.length === 1) { - values.push(values[0]); - } else if (name === 'translate' && values.length === 1) { - values.push(0); - } else if (name === 'rotate' && values.length === 1) { - values.push(0, 0); + if (name === 'matrix') { + mtx[letters[i]] = valArr[i]; } + }); + const xform = svgroot.createSVGTransform(); + const fname = 'set' + name.charAt(0).toUpperCase() + name.slice(1); + const values = name === 'matrix' ? [mtx] : valArr; - xform[fname].apply(xform, _toConsumableArray(values)); + if (name === 'scale' && values.length === 1) { + values.push(values[0]); + } else if (name === 'translate' && values.length === 1) { + values.push(0); + } else if (name === 'rotate' && values.length === 1) { + values.push(0, 0); + } - _this._list.appendItem(xform); - })(); + xform[fname](...values); + + this._list.appendItem(xform); } } }; @@ -3326,8 +2788,8 @@ if (item) { // Check if this transform is already in a transformlist, and // remove it if so. - Object.values(listMap_).some(function (tl) { - for (var i = 0, len = tl._xforms.length; i < len; ++i) { + Object.values(listMap_).some(tl => { + for (let i = 0, len = tl._xforms.length; i < len; ++i) { if (tl._xforms[i] === item) { tl.removeItem(i); return true; @@ -3346,168 +2808,158 @@ */ - _createClass(SVGTransformList, [{ - key: "clear", - value: function clear() { - this.numberOfItems = 0; - this._xforms = []; + clear() { + this.numberOfItems = 0; + this._xforms = []; + } + /** + * @param {SVGTransform} newItem + * @returns {void} + */ + + + initialize(newItem) { + this.numberOfItems = 1; + + this._removeFromOtherLists(newItem); + + this._xforms = [newItem]; + } + /** + * @param {Integer} index unsigned long + * @throws {Error} + * @returns {SVGTransform} + */ + + + getItem(index) { + if (index < this.numberOfItems && index >= 0) { + return this._xforms[index]; } - /** - * @param {SVGTransform} newItem - * @returns {void} - */ - }, { - key: "initialize", - value: function initialize(newItem) { - this.numberOfItems = 1; + const err = new Error('DOMException with code=INDEX_SIZE_ERR'); + err.code = 1; + throw err; + } + /** + * @param {SVGTransform} newItem + * @param {Integer} index unsigned long + * @returns {SVGTransform} + */ - this._removeFromOtherLists(newItem); - this._xforms = [newItem]; - } - /** - * @param {Integer} index unsigned long - * @throws {Error} - * @returns {SVGTransform} - */ + insertItemBefore(newItem, index) { + let retValue = null; - }, { - key: "getItem", - value: function getItem(index) { - if (index < this.numberOfItems && index >= 0) { - return this._xforms[index]; - } - - var err = new Error('DOMException with code=INDEX_SIZE_ERR'); - err.code = 1; - throw err; - } - /** - * @param {SVGTransform} newItem - * @param {Integer} index unsigned long - * @returns {SVGTransform} - */ - - }, { - key: "insertItemBefore", - value: function insertItemBefore(newItem, index) { - var retValue = null; - - if (index >= 0) { - if (index < this.numberOfItems) { - this._removeFromOtherLists(newItem); - - var newxforms = new Array(this.numberOfItems + 1); // TODO: use array copying and slicing - - var i; - - for (i = 0; i < index; ++i) { - newxforms[i] = this._xforms[i]; - } - - newxforms[i] = newItem; - - for (var j = i + 1; i < this.numberOfItems; ++j, ++i) { - newxforms[j] = this._xforms[i]; - } - - this.numberOfItems++; - this._xforms = newxforms; - retValue = newItem; - - this._list._update(); - } else { - retValue = this._list.appendItem(newItem); - } - } - - return retValue; - } - /** - * @param {SVGTransform} newItem - * @param {Integer} index unsigned long - * @returns {SVGTransform} - */ - - }, { - key: "replaceItem", - value: function replaceItem(newItem, index) { - var retValue = null; - - if (index < this.numberOfItems && index >= 0) { + if (index >= 0) { + if (index < this.numberOfItems) { this._removeFromOtherLists(newItem); - this._xforms[index] = newItem; - retValue = newItem; + const newxforms = new Array(this.numberOfItems + 1); // TODO: use array copying and slicing - this._list._update(); - } - - return retValue; - } - /** - * @param {Integer} index unsigned long - * @throws {Error} - * @returns {SVGTransform} - */ - - }, { - key: "removeItem", - value: function removeItem(index) { - if (index < this.numberOfItems && index >= 0) { - var retValue = this._xforms[index]; - var newxforms = new Array(this.numberOfItems - 1); - var i; + let i; for (i = 0; i < index; ++i) { newxforms[i] = this._xforms[i]; } - for (var j = i; j < this.numberOfItems - 1; ++j, ++i) { - newxforms[j] = this._xforms[i + 1]; + newxforms[i] = newItem; + + for (let j = i + 1; i < this.numberOfItems; ++j, ++i) { + newxforms[j] = this._xforms[i]; } - this.numberOfItems--; + this.numberOfItems++; this._xforms = newxforms; + retValue = newItem; this._list._update(); - - return retValue; + } else { + retValue = this._list.appendItem(newItem); } - - var err = new Error('DOMException with code=INDEX_SIZE_ERR'); - err.code = 1; - throw err; } - /** - * @param {SVGTransform} newItem - * @returns {SVGTransform} - */ - }, { - key: "appendItem", - value: function appendItem(newItem) { + return retValue; + } + /** + * @param {SVGTransform} newItem + * @param {Integer} index unsigned long + * @returns {SVGTransform} + */ + + + replaceItem(newItem, index) { + let retValue = null; + + if (index < this.numberOfItems && index >= 0) { this._removeFromOtherLists(newItem); - this._xforms.push(newItem); + this._xforms[index] = newItem; + retValue = newItem; - this.numberOfItems++; + this._list._update(); + } + + return retValue; + } + /** + * @param {Integer} index unsigned long + * @throws {Error} + * @returns {SVGTransform} + */ + + + removeItem(index) { + if (index < this.numberOfItems && index >= 0) { + const retValue = this._xforms[index]; + const newxforms = new Array(this.numberOfItems - 1); + let i; + + for (i = 0; i < index; ++i) { + newxforms[i] = this._xforms[i]; + } + + for (let j = i; j < this.numberOfItems - 1; ++j, ++i) { + newxforms[j] = this._xforms[i + 1]; + } + + this.numberOfItems--; + this._xforms = newxforms; this._list._update(); - return newItem; + return retValue; } - }]); - return SVGTransformList; - }(); + const err = new Error('DOMException with code=INDEX_SIZE_ERR'); + err.code = 1; + throw err; + } + /** + * @param {SVGTransform} newItem + * @returns {SVGTransform} + */ + + + appendItem(newItem) { + this._removeFromOtherLists(newItem); + + this._xforms.push(newItem); + + this.numberOfItems++; + + this._list._update(); + + return newItem; + } + + } /** * @function module:SVGTransformList.resetListMap * @returns {void} */ - var resetListMap = function resetListMap() { + const resetListMap = function () { listMap_ = {}; }; /** @@ -3517,7 +2969,7 @@ * @returns {void} */ - var removeElementFromListMap = function removeElementFromListMap(elem) { + let removeElementFromListMap = function (elem) { // eslint-disable-line import/no-mutable-exports if (elem.id && listMap_[elem.id]) { delete listMap_[elem.id]; @@ -3531,10 +2983,10 @@ * @returns {SVGAnimatedTransformList|SVGTransformList} */ - var getTransformList = function getTransformList(elem) { + const getTransformList = function (elem) { if (!supportsNativeTransformLists()) { - var id = elem.id || 'temp'; - var t = listMap_[id]; + const id = elem.id || 'temp'; + let t = listMap_[id]; if (!t || id === 'temp') { listMap_[id] = new SVGTransformList(elem); @@ -3569,9 +3021,9 @@ * * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller */ - var wAttrs = ['x', 'x1', 'cx', 'rx', 'width']; - var hAttrs = ['y', 'y1', 'cy', 'ry', 'height']; - var unitAttrs = ['r', 'radius'].concat(wAttrs, hAttrs); // unused + const wAttrs = ['x', 'x1', 'cx', 'rx', 'width']; + const hAttrs = ['y', 'y1', 'cy', 'ry', 'height']; + const unitAttrs = ['r', 'radius', ...wAttrs, ...hAttrs]; // unused /* const unitNumMap = { @@ -3588,9 +3040,9 @@ */ // Container of elements. - var elementContainer_; // Stores mapping of unit type to user coordinates. + let elementContainer_; // Stores mapping of unit type to user coordinates. - var typeMap_ = {}; + let typeMap_ = {}; /** * @interface module:units.ElementContainer */ @@ -3619,7 +3071,6 @@ * @function module:units.ElementContainer#getRoundDigits * @returns {Integer} The number of digits number should be rounded to */ - // Todo[eslint-plugin-jsdoc@>=29.0.0]: See if parsing fixed to allow '%' /* eslint-disable jsdoc/valid-types */ @@ -3646,23 +3097,23 @@ * @returns {void} */ - var init = function init(elementContainer) { + const init = function (elementContainer) { elementContainer_ = elementContainer; // Get correct em/ex values by creating a temporary SVG. - var svg = document.createElementNS(NS.SVG, 'svg'); + const svg = document.createElementNS(NS.SVG, 'svg'); document.body.append(svg); - var rect = document.createElementNS(NS.SVG, 'rect'); + const rect = document.createElementNS(NS.SVG, 'rect'); rect.setAttribute('width', '1em'); rect.setAttribute('height', '1ex'); rect.setAttribute('x', '1in'); svg.append(rect); - var bb = rect.getBBox(); + const bb = rect.getBBox(); svg.remove(); - var inch = bb.x; + const inch = bb.x; typeMap_ = { em: bb.width, ex: bb.height, - "in": inch, + in: inch, cm: inch / 2.54, mm: inch / 25.4, pt: inch / 72, @@ -3680,7 +3131,7 @@ * @returns {module:units.TypeMap} The unit object with values for each unit */ - var getTypeMap = function getTypeMap() { + const getTypeMap = function () { return typeMap_; }; /** @@ -3700,8 +3151,8 @@ * with comma-separated floats */ - var shortFloat = function shortFloat(val) { - var digits = elementContainer_.getRoundDigits(); + const shortFloat = function (val) { + const digits = elementContainer_.getRoundDigits(); if (!isNaN(val)) { return Number(Number(val).toFixed(digits)); @@ -3721,7 +3172,7 @@ * @returns {Float} */ - var convertUnit = function convertUnit(val, unit) { + const convertUnit = function (val, unit) { unit = unit || elementContainer_.getBaseUnit(); // baseVal.convertToSpecifiedUnits(unitNumMap[unit]); // const val = baseVal.valueInSpecifiedUnits; // baseVal.convertToSpecifiedUnits(1); @@ -3738,7 +3189,7 @@ * @returns {void} */ - var setUnitAttr = function setUnitAttr(elem, attr, val) { + const setUnitAttr = function (elem, attr, val) { // if (!isNaN(val)) { // New value is a number, so check currently used unit // const oldVal = elem.getAttribute(attr); @@ -3781,7 +3232,7 @@ * @returns {Float} The converted number */ - var convertToNum = function convertToNum(attr, val) { + const convertToNum = function (attr, val) { // Return a number if that's what it already is if (!isNaN(val)) { return val - 0; @@ -3789,24 +3240,23 @@ if (val.substr(-1) === '%') { // Deal with percentage, depends on attribute - var _num = val.substr(0, val.length - 1) / 100; - - var width = elementContainer_.getWidth(); - var height = elementContainer_.getHeight(); + const num = val.substr(0, val.length - 1) / 100; + const width = elementContainer_.getWidth(); + const height = elementContainer_.getHeight(); if (wAttrs.includes(attr)) { - return _num * width; + return num * width; } if (hAttrs.includes(attr)) { - return _num * height; + return num * height; } - return _num * Math.sqrt(width * width + height * height) / Math.sqrt(2); + return num * Math.sqrt(width * width + height * height) / Math.sqrt(2); } - var unit = val.substr(-2); - var num = val.substr(0, val.length - 2); // Note that this multiplication turns the string into a number + const unit = val.substr(-2); + const num = val.substr(0, val.length - 2); // Note that this multiplication turns the string into a number return num * typeMap_[unit]; }; @@ -3819,7 +3269,7 @@ * @returns {boolean} Whether the unit is valid */ - var isValidUnit = function isValidUnit(attr, val, selectedElement) { + const isValidUnit = function (attr, val, selectedElement) { if (unitAttrs.includes(attr)) { // True if it's just a number if (!isNaN(val)) { @@ -3828,8 +3278,8 @@ val = val.toLowerCase(); - return Object.keys(typeMap_).some(function (unit) { - var re = new RegExp('^-?[\\d\\.]+' + unit + '$'); + return Object.keys(typeMap_).some(unit => { + const re = new RegExp('^-?[\\d\\.]+' + unit + '$'); return re.test(val); }); } @@ -3837,13 +3287,13 @@ if (attr === 'id') { // if we're trying to change the id, make sure it's not already present in the doc // and the id value is valid. - var result = false; // because getElem() can throw an exception in the case of an invalid id + let result = false; // because getElem() can throw an exception in the case of an invalid id // (according to https://www.w3.org/TR/xml-id/ IDs must be a NCName) // we wrap it in an exception and only return true if the ID was valid and // not already present try { - var elem = elementContainer_.getElement(val); + const elem = elementContainer_.getElement(val); result = isNullish(elem) || elem === selectedElement; } catch (e) {} @@ -3853,39 +3303,2359 @@ return true; }; + /** + * Mathematical utilities. + * @module math + * @license MIT + * + * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller + */ + + const NEAR_ZERO = 1e-14; // Throw away SVGSVGElement used for creating matrices/transforms. + + const svg$1 = document.createElementNS(NS.SVG, 'svg'); + /** + * A (hopefully) quicker function to transform a point by a matrix + * (this function avoids any DOM calls and just does the math). + * @function module:math.transformPoint + * @param {Float} x - Float representing the x coordinate + * @param {Float} y - Float representing the y coordinate + * @param {SVGMatrix} m - Matrix object to transform the point with + * @returns {module:math.XYObject} An x, y object representing the transformed point + */ + + const transformPoint = function (x, y, m) { + return { + x: m.a * x + m.c * y + m.e, + y: m.b * x + m.d * y + m.f + }; + }; + /** + * Helper function to check if the matrix performs no actual transform + * (i.e. exists for identity purposes). + * @function module:math.isIdentity + * @param {SVGMatrix} m - The matrix object to check + * @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0 + */ + + const isIdentity = function (m) { + return m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0; + }; + /** + * This function tries to return a `SVGMatrix` that is the multiplication `m1 * m2`. + * We also round to zero when it's near zero. + * @function module:math.matrixMultiply + * @param {...SVGMatrix} args - Matrix objects to multiply + * @returns {SVGMatrix} The matrix object resulting from the calculation + */ + + const matrixMultiply = function (...args) { + const m = args.reduceRight((prev, m1) => { + return m1.multiply(prev); + }); + + if (Math.abs(m.a) < NEAR_ZERO) { + m.a = 0; + } + + if (Math.abs(m.b) < NEAR_ZERO) { + m.b = 0; + } + + if (Math.abs(m.c) < NEAR_ZERO) { + m.c = 0; + } + + if (Math.abs(m.d) < NEAR_ZERO) { + m.d = 0; + } + + if (Math.abs(m.e) < NEAR_ZERO) { + m.e = 0; + } + + if (Math.abs(m.f) < NEAR_ZERO) { + m.f = 0; + } + + return m; + }; + const hasMatrixTransform = function (tlist) { + if (!tlist) { + return false; + } + + let num = tlist.numberOfItems; + + while (num--) { + const xform = tlist.getItem(num); + + if (xform.type === 1 && !isIdentity(xform.matrix)) { + return true; + } + } + + return false; + }; + /** + * @typedef {PlainObject} module:math.TransformedBox An object with the following values + * @property {module:math.XYObject} tl - The top left coordinate + * @property {module:math.XYObject} tr - The top right coordinate + * @property {module:math.XYObject} bl - The bottom left coordinate + * @property {module:math.XYObject} br - The bottom right coordinate + * @property {PlainObject} aabox - Object with the following values: + * @property {Float} aabox.x - Float with the axis-aligned x coordinate + * @property {Float} aabox.y - Float with the axis-aligned y coordinate + * @property {Float} aabox.width - Float with the axis-aligned width coordinate + * @property {Float} aabox.height - Float with the axis-aligned height coordinate + */ + + /** + * Transforms a rectangle based on the given matrix. + * @function module:math.transformBox + * @param {Float} l - Float with the box's left coordinate + * @param {Float} t - Float with the box's top coordinate + * @param {Float} w - Float with the box width + * @param {Float} h - Float with the box height + * @param {SVGMatrix} m - Matrix object to transform the box by + * @returns {module:math.TransformedBox} + */ + + const transformBox = function (l, t, w, h, m) { + const tl = transformPoint(l, t, m), + tr = transformPoint(l + w, t, m), + bl = transformPoint(l, t + h, m), + br = transformPoint(l + w, t + h, m), + minx = Math.min(tl.x, tr.x, bl.x, br.x), + maxx = Math.max(tl.x, tr.x, bl.x, br.x), + miny = Math.min(tl.y, tr.y, bl.y, br.y), + maxy = Math.max(tl.y, tr.y, bl.y, br.y); + return { + tl, + tr, + bl, + br, + aabox: { + x: minx, + y: miny, + width: maxx - minx, + height: maxy - miny + } + }; + }; + /** + * This returns a single matrix Transform for a given Transform List + * (this is the equivalent of `SVGTransformList.consolidate()` but unlike + * that method, this one does not modify the actual `SVGTransformList`). + * This function is very liberal with its `min`, `max` arguments. + * @function module:math.transformListToTransform + * @param {SVGTransformList} tlist - The transformlist object + * @param {Integer} [min=0] - Optional integer indicating start transform position + * @param {Integer} [max] - Optional integer indicating end transform position; + * defaults to one less than the tlist's `numberOfItems` + * @returns {SVGTransform} A single matrix transform object + */ + + const transformListToTransform = function (tlist, min, max) { + if (isNullish(tlist)) { + // Or should tlist = null have been prevented before this? + return svg$1.createSVGTransformFromMatrix(svg$1.createSVGMatrix()); + } + + min = min || 0; + max = max || tlist.numberOfItems - 1; + min = Number.parseInt(min); + max = Number.parseInt(max); + + if (min > max) { + const temp = max; + max = min; + min = temp; + } + + let m = svg$1.createSVGMatrix(); + + for (let i = min; i <= max; ++i) { + // if our indices are out of range, just use a harmless identity matrix + const mtom = i >= 0 && i < tlist.numberOfItems ? tlist.getItem(i).matrix : svg$1.createSVGMatrix(); + m = matrixMultiply(m, mtom); + } + + return svg$1.createSVGTransformFromMatrix(m); + }; + /** + * Get the matrix object for a given element. + * @function module:math.getMatrix + * @param {Element} elem - The DOM element to check + * @returns {SVGMatrix} The matrix object associated with the element's transformlist + */ + + const getMatrix = function (elem) { + const tlist = getTransformList(elem); + return transformListToTransform(tlist).matrix; + }; + /** + * Returns a 45 degree angle coordinate associated with the two given + * coordinates. + * @function module:math.snapToAngle + * @param {Integer} x1 - First coordinate's x value + * @param {Integer} y1 - First coordinate's y value + * @param {Integer} x2 - Second coordinate's x value + * @param {Integer} y2 - Second coordinate's y value + * @returns {module:math.AngleCoord45} + */ + + const snapToAngle = function (x1, y1, x2, y2) { + const snap = Math.PI / 4; // 45 degrees + + const dx = x2 - x1; + const dy = y2 - y1; + const angle = Math.atan2(dy, dx); + const dist = Math.sqrt(dx * dx + dy * dy); + const snapangle = Math.round(angle / snap) * snap; + return { + x: x1 + dist * Math.cos(snapangle), + y: y1 + dist * Math.sin(snapangle), + a: snapangle + }; + }; + /** + * Check if two rectangles (BBoxes objects) intersect each other. + * @function module:math.rectsIntersect + * @param {SVGRect} r1 - The first BBox-like object + * @param {SVGRect} r2 - The second BBox-like object + * @returns {boolean} True if rectangles intersect + */ + + const rectsIntersect = function (r1, r2) { + return r2.x < r1.x + r1.width && r2.x + r2.width > r1.x && r2.y < r1.y + r1.height && r2.y + r2.height > r1.y; + }; + + /* eslint-disable node/no-unsupported-features/node-builtins */ + + const $$1 = jQueryPluginSVG(jQuery); // String used to encode base64. + + const KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; // Much faster than running getBBox() every time + + const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use,clipPath'; + const visElemsArr = visElems.split(','); // const hidElems = 'defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath'; + + let editorContext_ = null; + let domdoc_ = null; + let domcontainer_ = null; + let svgroot_ = null; + /** + * Object with the following keys/values. + * @typedef {PlainObject} module:utilities.SVGElementJSON + * @property {string} element - Tag name of the SVG element to create + * @property {PlainObject} attr - Has key-value attributes to assign to the new element. An `id` should be set so that {@link module:utilities.EditorContext#addSVGElementFromJson} can later re-identify the element for modification or replacement. + * @property {boolean} [curStyles=false] - Indicates whether current style attributes should be applied first + * @property {module:utilities.SVGElementJSON[]} [children] - Data objects to be added recursively as children + * @property {string} [namespace="http://www.w3.org/2000/svg"] - Indicate a (non-SVG) namespace + */ + + /** + * An object that creates SVG elements for the canvas. + * + * @interface module:utilities.EditorContext + * @property {module:path.pathActions} pathActions + */ + + /** + * @function module:utilities.EditorContext#getSVGContent + * @returns {SVGSVGElement} + */ + + /** + * Create a new SVG element based on the given object keys/values and add it + * to the current layer. + * The element will be run through `cleanupElement` before being returned. + * @function module:utilities.EditorContext#addSVGElementFromJson + * @param {module:utilities.SVGElementJSON} data + * @returns {Element} The new element + */ + + /** + * @function module:utilities.EditorContext#getSelectedElements + * @returns {Element[]} the array with selected DOM elements + */ + + /** + * @function module:utilities.EditorContext#getDOMDocument + * @returns {HTMLDocument} + */ + + /** + * @function module:utilities.EditorContext#getDOMContainer + * @returns {HTMLElement} + */ + + /** + * @function module:utilities.EditorContext#getSVGRoot + * @returns {SVGSVGElement} + */ + + /** + * @function module:utilities.EditorContext#getBaseUnit + * @returns {string} + */ + + /** + * @function module:utilities.EditorContext#getSnappingStep + * @returns {Float|string} + */ + + /** + * @function module:utilities.init + * @param {module:utilities.EditorContext} editorContext + * @returns {void} + */ + + const init$1 = function (editorContext) { + editorContext_ = editorContext; + domdoc_ = editorContext.getDOMDocument(); + domcontainer_ = editorContext.getDOMContainer(); + svgroot_ = editorContext.getSVGRoot(); + }; + /** + * Used to prevent the [Billion laughs attack]{@link https://en.wikipedia.org/wiki/Billion_laughs_attack}. + * @function module:utilities.dropXMLInternalSubset + * @param {string} str String to be processed + * @returns {string} The string with entity declarations in the internal subset removed + * @todo This might be needed in other places `parseFromString` is used even without LGTM flagging + */ + + const dropXMLInternalSubset = str => { + return str.replace(/()/, '$1$2'); // return str.replace(/(?\?\]>)/, '$$'); + }; + /** + * Converts characters in a string to XML-friendly entities. + * @function module:utilities.toXml + * @example `&` becomes `&` + * @param {string} str - The string to be converted + * @returns {string} The converted string + */ + + const toXml = function (str) { + // ' is ok in XML, but not HTML + // > does not normally need escaping, though it can if within a CDATA expression (and preceded by "]]") + return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); // Note: `'` is XML only + }; + /** + * Converts XML entities in a string to single characters. + * @function module:utilities.fromXml + * @example `&` becomes `&` + * @param {string} str - The string to be converted + * @returns {string} The converted string + */ + + function fromXml(str) { + return $$1('

').html(str).text(); + } // This code was written by Tyler Akins and has been placed in the + // public domain. It would be nice if you left this header intact. + // Base64 code from Tyler Akins -- http://rumkin.com + // schiller: Removed string concatenation in favour of Array.join() optimization, + // also precalculate the size of the array needed. + + /** + * Converts a string to base64. + * @function module:utilities.encode64 + * @param {string} input + * @returns {string} Base64 output + */ + + function encode64(input) { + // base64 strings are 4/3 larger than the original string + input = encodeUTF8(input); // convert non-ASCII characters + // input = convertToXMLReferences(input); + + if (window.btoa) { + return window.btoa(input); // Use native if available + } + + const output = new Array(Math.floor((input.length + 2) / 3) * 4); + let i = 0, + p = 0; + + do { + const chr1 = input.charCodeAt(i++); + const chr2 = input.charCodeAt(i++); + const chr3 = input.charCodeAt(i++); + /* eslint-disable no-bitwise */ + + const enc1 = chr1 >> 2; + const enc2 = (chr1 & 3) << 4 | chr2 >> 4; + let enc3 = (chr2 & 15) << 2 | chr3 >> 6; + let enc4 = chr3 & 63; + /* eslint-enable no-bitwise */ + + if (Number.isNaN(chr2)) { + enc3 = 64; + enc4 = 64; + } else if (Number.isNaN(chr3)) { + enc4 = 64; + } + + output[p++] = KEYSTR.charAt(enc1); + output[p++] = KEYSTR.charAt(enc2); + output[p++] = KEYSTR.charAt(enc3); + output[p++] = KEYSTR.charAt(enc4); + } while (i < input.length); + + return output.join(''); + } + /** + * Converts a string from base64. + * @function module:utilities.decode64 + * @param {string} input Base64-encoded input + * @returns {string} Decoded output + */ + + function decode64(input) { + if (window.atob) { + return decodeUTF8(window.atob(input)); + } // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + + + input = input.replace(/[^A-Za-z\d+/=]/g, ''); + let output = ''; + let i = 0; + + do { + const enc1 = KEYSTR.indexOf(input.charAt(i++)); + const enc2 = KEYSTR.indexOf(input.charAt(i++)); + const enc3 = KEYSTR.indexOf(input.charAt(i++)); + const enc4 = KEYSTR.indexOf(input.charAt(i++)); + /* eslint-disable no-bitwise */ + + const chr1 = enc1 << 2 | enc2 >> 4; + const chr2 = (enc2 & 15) << 4 | enc3 >> 2; + const chr3 = (enc3 & 3) << 6 | enc4; + /* eslint-enable no-bitwise */ + + output += String.fromCharCode(chr1); + + if (enc3 !== 64) { + output += String.fromCharCode(chr2); + } + + if (enc4 !== 64) { + output += String.fromCharCode(chr3); + } + } while (i < input.length); + + return decodeUTF8(output); + } + /** + * @function module:utilities.decodeUTF8 + * @param {string} argString + * @returns {string} + */ + + function decodeUTF8(argString) { + return decodeURIComponent(escape(argString)); + } // codedread:does not seem to work with webkit-based browsers on OSX // Brettz9: please test again as function upgraded + + /** + * @function module:utilities.encodeUTF8 + * @param {string} argString + * @returns {string} + */ + + const encodeUTF8 = function (argString) { + return unescape(encodeURIComponent(argString)); + }; + /** + * Convert dataURL to object URL. + * @function module:utilities.dataURLToObjectURL + * @param {string} dataurl + * @returns {string} object URL or empty string + */ + + const dataURLToObjectURL = function (dataurl) { + if (typeof Uint8Array === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined' || !URL.createObjectURL) { + return ''; + } + + const arr = dataurl.split(','), + mime = arr[0].match(/:(.*?);/)[1], + bstr = atob(arr[1]); + /* + const [prefix, suffix] = dataurl.split(','), + {groups: {mime}} = prefix.match(/:(?.*?);/), + bstr = atob(suffix); + */ + + let n = bstr.length; + const u8arr = new Uint8Array(n); + + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + + const blob = new Blob([u8arr], { + type: mime + }); + return URL.createObjectURL(blob); + }; + /** + * Get object URL for a blob object. + * @function module:utilities.createObjectURL + * @param {Blob} blob A Blob object or File object + * @returns {string} object URL or empty string + */ + + const createObjectURL = function (blob) { + if (!blob || typeof URL === 'undefined' || !URL.createObjectURL) { + return ''; + } + + return URL.createObjectURL(blob); + }; + /** + * @property {string} blankPageObjectURL + */ + + const blankPageObjectURL = function () { + if (typeof Blob === 'undefined') { + return ''; + } + + const blob = new Blob(['SVG-edit '], { + type: 'text/html' + }); + return createObjectURL(blob); + }(); + /** + * Converts a string to use XML references (for non-ASCII). + * @function module:utilities.convertToXMLReferences + * @param {string} input + * @returns {string} Decimal numeric character references + */ + + const convertToXMLReferences = function (input) { + let output = ''; + [...input].forEach(ch => { + const c = ch.charCodeAt(); + + if (c <= 127) { + output += ch; + } else { + output += `&#${c};`; + } + }); + return output; + }; + /** + * Cross-browser compatible method of converting a string to an XML tree. + * Found this function [here]{@link http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f}. + * @function module:utilities.text2xml + * @param {string} sXML + * @throws {Error} + * @returns {XMLDocument} + */ + + const text2xml = function (sXML) { + if (sXML.includes('` + * - `` + * - `` + * @function module:utilities.getUrlFromAttr + * @param {string} attrVal The attribute value as a string + * @returns {string} String with just the URL, like "someFile.svg#foo" + */ + + const getUrlFromAttr = function (attrVal) { + if (attrVal) { + // url('#somegrad') + if (attrVal.startsWith('url("')) { + return attrVal.substring(5, attrVal.indexOf('"', 6)); + } // url('#somegrad') + + + if (attrVal.startsWith("url('")) { + return attrVal.substring(5, attrVal.indexOf("'", 6)); + } + + if (attrVal.startsWith('url(')) { + return attrVal.substring(4, attrVal.indexOf(')')); + } + } + + return null; + }; + /** + * @function module:utilities.getHref + * @param {Element} elem + * @returns {string} The given element's `xlink:href` value + */ + + let getHref = function (elem) { + // eslint-disable-line import/no-mutable-exports + return elem.getAttributeNS(NS.XLINK, 'href'); + }; + /** + * Sets the given element's `xlink:href` value. + * @function module:utilities.setHref + * @param {Element} elem + * @param {string} val + * @returns {void} + */ + + let setHref = function (elem, val) { + // eslint-disable-line import/no-mutable-exports + elem.setAttributeNS(NS.XLINK, 'xlink:href', val); + }; + /** + * @function module:utilities.findDefs + * @returns {SVGDefsElement} The document's `` element, creating it first if necessary + */ + + const findDefs = function () { + const svgElement = editorContext_.getSVGContent(); + let defs = svgElement.getElementsByTagNameNS(NS.SVG, 'defs'); + + if (defs.length > 0) { + defs = defs[0]; + } else { + defs = svgElement.ownerDocument.createElementNS(NS.SVG, 'defs'); + + if (svgElement.firstChild) { + // first child is a comment, so call nextSibling + svgElement.insertBefore(defs, svgElement.firstChild.nextSibling); // svgElement.firstChild.nextSibling.before(defs); // Not safe + } else { + svgElement.append(defs); + } + } + + return defs; + }; // TODO(codedread): Consider moving the next to functions to bbox.js + + /** + * Get correct BBox for a path in Webkit. + * Converted from code found [here]{@link http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html}. + * @function module:utilities.getPathBBox + * @param {SVGPathElement} path - The path DOM element to get the BBox for + * @returns {module:utilities.BBoxObject} A BBox-like object + */ + + const getPathBBox = function (path) { + const seglist = path.pathSegList; + const tot = seglist.numberOfItems; + const bounds = [[], []]; + const start = seglist.getItem(0); + let P0 = [start.x, start.y]; + + const getCalc = function (j, P1, P2, P3) { + return function (t) { + return 1 - t ** 3 * P0[j] + 3 * 1 - t ** 2 * t * P1[j] + 3 * (1 - t) * t ** 2 * P2[j] + t ** 3 * P3[j]; + }; + }; + + for (let i = 0; i < tot; i++) { + const seg = seglist.getItem(i); + + if (seg.x === undefined) { + continue; + } // Add actual points to limits + + + bounds[0].push(P0[0]); + bounds[1].push(P0[1]); + + if (seg.x1) { + const P1 = [seg.x1, seg.y1], + P2 = [seg.x2, seg.y2], + P3 = [seg.x, seg.y]; + + for (let j = 0; j < 2; j++) { + const calc = getCalc(j, P1, P2, P3); + const b = 6 * P0[j] - 12 * P1[j] + 6 * P2[j]; + const a = -3 * P0[j] + 9 * P1[j] - 9 * P2[j] + 3 * P3[j]; + const c = 3 * P1[j] - 3 * P0[j]; + + if (a === 0) { + if (b === 0) { + continue; + } + + const t = -c / b; + + if (t > 0 && t < 1) { + bounds[j].push(calc(t)); + } + + continue; + } + + const b2ac = b ** 2 - 4 * c * a; + + if (b2ac < 0) { + continue; + } + + const t1 = (-b + Math.sqrt(b2ac)) / (2 * a); + + if (t1 > 0 && t1 < 1) { + bounds[j].push(calc(t1)); + } + + const t2 = (-b - Math.sqrt(b2ac)) / (2 * a); + + if (t2 > 0 && t2 < 1) { + bounds[j].push(calc(t2)); + } + } + + P0 = P3; + } else { + bounds[0].push(seg.x); + bounds[1].push(seg.y); + } + } + + const x = Math.min.apply(null, bounds[0]); + const w = Math.max.apply(null, bounds[0]) - x; + const y = Math.min.apply(null, bounds[1]); + const h = Math.max.apply(null, bounds[1]) - y; + return { + x, + y, + width: w, + height: h + }; + }; + /** + * Get the given/selected element's bounding box object, checking for + * horizontal/vertical lines (see issue 717) + * Note that performance is currently terrible, so some way to improve would + * be great. + * @param {Element} selected - Container or `` DOM element + * @returns {DOMRect} Bounding box object + */ + + function groupBBFix(selected) { + if (supportsHVLineContainerBBox()) { + try { + return selected.getBBox(); + } catch (e) {} + } + + const ref = $$1.data(selected, 'ref'); + let matched = null; + let ret, copy; + + if (ref) { + copy = $$1(ref).children().clone().attr('visibility', 'hidden'); + $$1(svgroot_).append(copy); + matched = copy.filter('line, path'); + } else { + matched = $$1(selected).find('line, path'); + } + + let issue = false; + + if (matched.length) { + matched.each(function () { + const bb = this.getBBox(); + + if (!bb.width || !bb.height) { + issue = true; + } + }); + + if (issue) { + const elems = ref ? copy : $$1(selected).children(); + ret = getStrokedBBox(elems); + } else { + ret = selected.getBBox(); + } + } else { + ret = selected.getBBox(); + } + + if (ref) { + copy.remove(); + } + + return ret; + } + /** + * Get the given/selected element's bounding box object, convert it to be more + * usable when necessary. + * @function module:utilities.getBBox + * @param {Element} elem - Optional DOM element to get the BBox for + * @returns {module:utilities.BBoxObject} Bounding box object + */ + + + const getBBox = function (elem) { + const selected = elem || editorContext_.geSelectedElements()[0]; + + if (elem.nodeType !== 1) { + return null; + } + + const elname = selected.nodeName; + let ret = null; + + switch (elname) { + case 'text': + if (selected.textContent === '') { + selected.textContent = 'a'; // Some character needed for the selector to use. + + ret = selected.getBBox(); + selected.textContent = ''; + } else if (selected.getBBox) { + ret = selected.getBBox(); + } + + break; + + case 'path': + if (!supportsPathBBox()) { + ret = getPathBBox(selected); + } else if (selected.getBBox) { + ret = selected.getBBox(); + } + + break; + + case 'g': + case 'a': + ret = groupBBFix(selected); + break; + + default: + if (elname === 'use') { + ret = groupBBFix(selected); // , true); + } + + if (elname === 'use' || elname === 'foreignObject' && isWebkit()) { + if (!ret) { + ret = selected.getBBox(); + } // This is resolved in later versions of webkit, perhaps we should + // have a featured detection for correct 'use' behavior? + // —————————— + + + if (!isWebkit()) { + const { + x, + y, + width, + height + } = ret; + const bb = { + width, + height, + x: x + Number.parseFloat(selected.getAttribute('x') || 0), + y: y + Number.parseFloat(selected.getAttribute('y') || 0) + }; + ret = bb; + } + } else if (visElemsArr.includes(elname)) { + if (selected) { + try { + ret = selected.getBBox(); + } catch (err) { + // tspan (and textPath apparently) have no `getBBox` in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=937268 + // Re: Chrome returning bbox for containing text element, see: https://bugs.chromium.org/p/chromium/issues/detail?id=349835 + const extent = selected.getExtentOfChar(0); // pos+dimensions of the first glyph + + const width = selected.getComputedTextLength(); // width of the tspan + + ret = { + x: extent.x, + y: extent.y, + width, + height: extent.height + }; + } + } else { + // Check if element is child of a foreignObject + const fo = $$1(selected).closest('foreignObject'); + + if (fo.length) { + if (fo[0].getBBox) { + ret = fo[0].getBBox(); + } + } + } + } + + } + + if (ret) { + ret = bboxToObj(ret); + } // get the bounding box from the DOM (which is in that element's coordinate system) + + + return ret; + }; + /** + * @typedef {GenericArray} module:utilities.PathSegmentArray + * @property {Integer} length 2 + * @property {"M"|"L"|"C"|"Z"} 0 + * @property {Float[]} 1 + */ + + /** + * Create a path 'd' attribute from path segments. + * Each segment is an array of the form: `[singleChar, [x,y, x,y, ...]]` + * @function module:utilities.getPathDFromSegments + * @param {module:utilities.PathSegmentArray[]} pathSegments - An array of path segments to be converted + * @returns {string} The converted path d attribute. + */ + + const getPathDFromSegments = function (pathSegments) { + let d = ''; + $$1.each(pathSegments, function (j, [singleChar, pts]) { + d += singleChar; + + for (let i = 0; i < pts.length; i += 2) { + d += pts[i] + ',' + pts[i + 1] + ' '; + } + }); + return d; + }; + /** + * Make a path 'd' attribute from a simple SVG element shape. + * @function module:utilities.getPathDFromElement + * @param {Element} elem - The element to be converted + * @returns {string} The path d attribute or `undefined` if the element type is unknown. + */ + + const getPathDFromElement = function (elem) { + // Possibly the cubed root of 6, but 1.81 works best + let num = 1.81; + let d, a, rx, ry; + + switch (elem.tagName) { + case 'ellipse': + case 'circle': + { + a = $$1(elem).attr(['rx', 'ry', 'cx', 'cy']); + const { + cx, + cy + } = a; + ({ + rx, + ry + } = a); + + if (elem.tagName === 'circle') { + ry = $$1(elem).attr('r'); + rx = ry; + } + + d = getPathDFromSegments([['M', [cx - rx, cy]], ['C', [cx - rx, cy - ry / num, cx - rx / num, cy - ry, cx, cy - ry]], ['C', [cx + rx / num, cy - ry, cx + rx, cy - ry / num, cx + rx, cy]], ['C', [cx + rx, cy + ry / num, cx + rx / num, cy + ry, cx, cy + ry]], ['C', [cx - rx / num, cy + ry, cx - rx, cy + ry / num, cx - rx, cy]], ['Z', []]]); + break; + } + + case 'path': + d = elem.getAttribute('d'); + break; + + case 'line': + a = $$1(elem).attr(['x1', 'y1', 'x2', 'y2']); + d = 'M' + a.x1 + ',' + a.y1 + 'L' + a.x2 + ',' + a.y2; + break; + + case 'polyline': + d = 'M' + elem.getAttribute('points'); + break; + + case 'polygon': + d = 'M' + elem.getAttribute('points') + ' Z'; + break; + + case 'rect': + { + const r = $$1(elem).attr(['rx', 'ry']); + ({ + rx, + ry + } = r); + const b = elem.getBBox(); + const { + x, + y + } = b, + w = b.width, + h = b.height; + num = 4 - num; // Why? Because! + + if (!rx && !ry) { + // Regular rect + d = getPathDFromSegments([['M', [x, y]], ['L', [x + w, y]], ['L', [x + w, y + h]], ['L', [x, y + h]], ['L', [x, y]], ['Z', []]]); + } else { + d = getPathDFromSegments([['M', [x, y + ry]], ['C', [x, y + ry / num, x + rx / num, y, x + rx, y]], ['L', [x + w - rx, y]], ['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]], ['L', [x + w, y + h - ry]], ['C', [x + w, y + h - ry / num, x + w - rx / num, y + h, x + w - rx, y + h]], ['L', [x + rx, y + h]], ['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]], ['L', [x, y + ry]], ['Z', []]]); + } + + break; + } + } + + return d; + }; + /** + * Get a set of attributes from an element that is useful for convertToPath. + * @function module:utilities.getExtraAttributesForConvertToPath + * @param {Element} elem - The element to be probed + * @returns {PlainObject<"marker-start"|"marker-end"|"marker-mid"|"filter"|"clip-path", string>} An object with attributes. + */ + + const getExtraAttributesForConvertToPath = function (elem) { + const attrs = {}; // TODO: make this list global so that we can properly maintain it + // TODO: what about @transform, @clip-rule, @fill-rule, etc? + + $$1.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function () { + const a = elem.getAttribute(this); + + if (a) { + attrs[this] = a; + } + }); + return attrs; + }; + /** + * Get the BBox of an element-as-path. + * @function module:utilities.getBBoxOfElementAsPath + * @param {Element} elem - The DOM element to be probed + * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson + * @param {module:path.pathActions} pathActions - If a transform exists, `pathActions.resetOrientation()` is used. See: canvas.pathActions. + * @returns {DOMRect|false} The resulting path's bounding box object. + */ + + const getBBoxOfElementAsPath = function (elem, addSVGElementFromJson, pathActions) { + const path = addSVGElementFromJson({ + element: 'path', + attr: getExtraAttributesForConvertToPath(elem) + }); + const eltrans = elem.getAttribute('transform'); + + if (eltrans) { + path.setAttribute('transform', eltrans); + } + + const { + parentNode + } = elem; + + if (elem.nextSibling) { + elem.before(path); + } else { + parentNode.append(path); + } + + const d = getPathDFromElement(elem); + + if (d) { + path.setAttribute('d', d); + } else { + path.remove(); + } // Get the correct BBox of the new path, then discard it + + + pathActions.resetOrientation(path); + let bb = false; + + try { + bb = path.getBBox(); + } catch (e) {// Firefox fails + } + + path.remove(); + return bb; + }; + /** + * Convert selected element to a path. + * @function module:utilities.convertToPath + * @param {Element} elem - The DOM element to be converted + * @param {module:utilities.SVGElementJSON} attrs - Apply attributes to new path. see canvas.convertToPath + * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson + * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. + * @param {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} clearSelection - see [canvas.clearSelection]{@link module:svgcanvas.SvgCanvas#clearSelection} + * @param {module:path.EditorContext#addToSelection} addToSelection - see [canvas.addToSelection]{@link module:svgcanvas.SvgCanvas#addToSelection} + * @param {module:history} hstry - see history module + * @param {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} addCommandToHistory - see [canvas.addCommandToHistory]{@link module:svgcanvas~addCommandToHistory} + * @returns {SVGPathElement|null} The converted path element or null if the DOM element was not recognized. + */ + + const convertToPath = function (elem, attrs, addSVGElementFromJson, pathActions, clearSelection, addToSelection, hstry, addCommandToHistory) { + const batchCmd = new hstry.BatchCommand('Convert element to Path'); // Any attribute on the element not covered by the passed-in attributes + + attrs = $$1.extend({}, attrs, getExtraAttributesForConvertToPath(elem)); + const path = addSVGElementFromJson({ + element: 'path', + attr: attrs + }); + const eltrans = elem.getAttribute('transform'); + + if (eltrans) { + path.setAttribute('transform', eltrans); + } + + const { + id + } = elem; + const { + parentNode + } = elem; + + if (elem.nextSibling) { + elem.before(path); + } else { + parentNode.append(path); + } + + const d = getPathDFromElement(elem); + + if (d) { + path.setAttribute('d', d); // Replace the current element with the converted one + // Reorient if it has a matrix + + if (eltrans) { + const tlist = getTransformList(path); + + if (hasMatrixTransform(tlist)) { + pathActions.resetOrientation(path); + } + } + + const { + nextSibling + } = elem; + batchCmd.addSubCommand(new hstry.RemoveElementCommand(elem, nextSibling, parent)); + batchCmd.addSubCommand(new hstry.InsertElementCommand(path)); + clearSelection(); + elem.remove(); + path.setAttribute('id', id); + path.removeAttribute('visibility'); + addToSelection([path], true); + addCommandToHistory(batchCmd); + return path; + } // the elem.tagName was not recognized, so no "d" attribute. Remove it, so we've haven't changed anything. + + + path.remove(); + return null; + }; + /** + * Can the bbox be optimized over the native getBBox? The optimized bbox is the same as the native getBBox when + * the rotation angle is a multiple of 90 degrees and there are no complex transforms. + * Getting an optimized bbox can be dramatically slower, so we want to make sure it's worth it. + * + * The best example for this is a circle rotate 45 degrees. The circle doesn't get wider or taller when rotated + * about it's center. + * + * The standard, unoptimized technique gets the native bbox of the circle, rotates the box 45 degrees, uses + * that width and height, and applies any transforms to get the final bbox. This means the calculated bbox + * is much wider than the original circle. If the angle had been 0, 90, 180, etc. both techniques render the + * same bbox. + * + * The optimization is not needed if the rotation is a multiple 90 degrees. The default technique is to call + * getBBox then apply the angle and any transforms. + * + * @param {Float} angle - The rotation angle in degrees + * @param {boolean} hasAMatrixTransform - True if there is a matrix transform + * @returns {boolean} True if the bbox can be optimized. + */ + + function bBoxCanBeOptimizedOverNativeGetBBox(angle, hasAMatrixTransform) { + const angleModulo90 = angle % 90; + const closeTo90 = angleModulo90 < -89.99 || angleModulo90 > 89.99; + const closeTo0 = angleModulo90 > -0.001 && angleModulo90 < 0.001; + return hasAMatrixTransform || !(closeTo0 || closeTo90); + } + /** + * Get bounding box that includes any transforms. + * @function module:utilities.getBBoxWithTransform + * @param {Element} elem - The DOM element to be converted + * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson + * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. + * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object + */ + + + const getBBoxWithTransform = function (elem, addSVGElementFromJson, pathActions) { + // TODO: Fix issue with rotated groups. Currently they work + // fine in FF, but not in other browsers (same problem mentioned + // in Issue 339 comment #2). + let bb = getBBox(elem); + + if (!bb) { + return null; + } + + const tlist = getTransformList(elem); + const angle = getRotationAngleFromTransformList(tlist); + const hasMatrixXForm = hasMatrixTransform(tlist); + + if (angle || hasMatrixXForm) { + let goodBb = false; + + if (bBoxCanBeOptimizedOverNativeGetBBox(angle, hasMatrixXForm)) { + // Get the BBox from the raw path for these elements + // TODO: why ellipse and not circle + const elemNames = ['ellipse', 'path', 'line', 'polyline', 'polygon']; + + if (elemNames.includes(elem.tagName)) { + goodBb = getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); + bb = goodBb; + } else if (elem.tagName === 'rect') { + // Look for radius + const rx = elem.getAttribute('rx'); + const ry = elem.getAttribute('ry'); + + if (rx || ry) { + goodBb = getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); + bb = goodBb; + } + } + } + + if (!goodBb) { + const { + matrix + } = transformListToTransform(tlist); + bb = transformBox(bb.x, bb.y, bb.width, bb.height, matrix).aabox; // Old technique that was exceedingly slow with large documents. + // + // Accurate way to get BBox of rotated element in Firefox: + // Put element in group and get its BBox + // + // Must use clone else FF freaks out + // const clone = elem.cloneNode(true); + // const g = document.createElementNS(NS.SVG, 'g'); + // const parent = elem.parentNode; + // parent.append(g); + // g.append(clone); + // const bb2 = bboxToObj(g.getBBox()); + // g.remove(); + } + } + + return bb; + }; + /** + * @param {Element} elem + * @returns {Float} + * @todo This is problematic with large stroke-width and, for example, a single + * horizontal line. The calculated BBox extends way beyond left and right sides. + */ + + function getStrokeOffsetForBBox(elem) { + const sw = elem.getAttribute('stroke-width'); + return !isNaN(sw) && elem.getAttribute('stroke') !== 'none' ? sw / 2 : 0; + } + /** + * @typedef {PlainObject} BBox + * @property {Integer} x The x value + * @property {Integer} y The y value + * @property {Float} width + * @property {Float} height + */ + + /** + * Get the bounding box for one or more stroked and/or transformed elements. + * @function module:utilities.getStrokedBBox + * @param {Element[]} elems - Array with DOM elements to check + * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson + * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. + * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object + */ + + + const getStrokedBBox = function (elems, addSVGElementFromJson, pathActions) { + if (!elems || !elems.length) { + return false; + } + + let fullBb; + $$1.each(elems, function () { + if (fullBb) { + return; + } + + if (!this.parentNode) { + return; + } + + fullBb = getBBoxWithTransform(this, addSVGElementFromJson, pathActions); + }); // This shouldn't ever happen... + + if (fullBb === undefined) { + return null; + } // fullBb doesn't include the stoke, so this does no good! + // if (elems.length == 1) return fullBb; + + + let maxX = fullBb.x + fullBb.width; + let maxY = fullBb.y + fullBb.height; + let minX = fullBb.x; + let minY = fullBb.y; // If only one elem, don't call the potentially slow getBBoxWithTransform method again. + + if (elems.length === 1) { + const offset = getStrokeOffsetForBBox(elems[0]); + minX -= offset; + minY -= offset; + maxX += offset; + maxY += offset; + } else { + $$1.each(elems, function (i, elem) { + const curBb = getBBoxWithTransform(elem, addSVGElementFromJson, pathActions); + + if (curBb) { + const offset = getStrokeOffsetForBBox(elem); + minX = Math.min(minX, curBb.x - offset); + minY = Math.min(minY, curBb.y - offset); // TODO: The old code had this test for max, but not min. I suspect this test should be for both min and max + + if (elem.nodeType === 1) { + maxX = Math.max(maxX, curBb.x + curBb.width + offset); + maxY = Math.max(maxY, curBb.y + curBb.height + offset); + } + } + }); + } + + fullBb.x = minX; + fullBb.y = minY; + fullBb.width = maxX - minX; + fullBb.height = maxY - minY; + return fullBb; + }; + /** + * Get all elements that have a BBox (excludes ``, ``, etc). + * Note that 0-opacity, off-screen etc elements are still considered "visible" + * for this function. + * @function module:utilities.getVisibleElements + * @param {Element} parentElement - The parent DOM element to search within + * @returns {Element[]} All "visible" elements. + */ + + const getVisibleElements = function (parentElement) { + if (!parentElement) { + parentElement = $$1(editorContext_.getSVGContent()).children(); // Prevent layers from being included + } + + const contentElems = []; + $$1(parentElement).children().each(function (i, elem) { + if (elem.getBBox) { + contentElems.push(elem); + } + }); + return contentElems.reverse(); + }; + /** + * Get the bounding box for one or more stroked and/or transformed elements. + * @function module:utilities.getStrokedBBoxDefaultVisible + * @param {Element[]} elems - Array with DOM elements to check + * @returns {module:utilities.BBoxObject} A single bounding box object + */ + + const getStrokedBBoxDefaultVisible = function (elems) { + if (!elems) { + elems = getVisibleElements(); + } + + return getStrokedBBox(elems, editorContext_.addSVGElementFromJson, editorContext_.pathActions); + }; + /** + * Get the rotation angle of the given transform list. + * @function module:utilities.getRotationAngleFromTransformList + * @param {SVGTransformList} tlist - List of transforms + * @param {boolean} toRad - When true returns the value in radians rather than degrees + * @returns {Float} The angle in degrees or radians + */ + + const getRotationAngleFromTransformList = function (tlist, toRad) { + if (!tlist) { + return 0; + } // <svg> elements have no tlist + + + const N = tlist.numberOfItems; + + for (let i = 0; i < N; ++i) { + const xform = tlist.getItem(i); + + if (xform.type === 4) { + return toRad ? xform.angle * Math.PI / 180.0 : xform.angle; + } + } + + return 0.0; + }; + /** + * Get the rotation angle of the given/selected DOM element. + * @function module:utilities.getRotationAngle + * @param {Element} [elem] - DOM element to get the angle for. Default to first of selected elements. + * @param {boolean} [toRad=false] - When true returns the value in radians rather than degrees + * @returns {Float} The angle in degrees or radians + */ + + let getRotationAngle = function (elem, toRad) { + // eslint-disable-line import/no-mutable-exports + const selected = elem || editorContext_.getSelectedElements()[0]; // find the rotation transform (if any) and set it + + const tlist = getTransformList(selected); + return getRotationAngleFromTransformList(tlist, toRad); + }; + /** + * Get the reference element associated with the given attribute value. + * @function module:utilities.getRefElem + * @param {string} attrVal - The attribute value as a string + * @returns {Element} Reference element + */ + + const getRefElem = function (attrVal) { + return getElem(getUrlFromAttr(attrVal).substr(1)); + }; + /** + * Get a DOM element by ID within the SVG root element. + * @function module:utilities.getElem + * @param {string} id - String with the element's new ID + * @returns {?Element} + */ + + const getElem = supportsSelectors() ? function (id) { + // querySelector lookup + return svgroot_.querySelector('#' + id); + } : supportsXpath() ? function (id) { + // xpath lookup + return domdoc_.evaluate('svg:svg[@id="svgroot"]//svg:*[@id="' + id + '"]', domcontainer_, function () { + return NS.SVG; + }, 9, null).singleNodeValue; + } : function (id) { + // jQuery lookup: twice as slow as xpath in FF + // eslint-disable-next-line unicorn/no-fn-reference-in-iterator + return $$1(svgroot_).find('[id=' + id + ']')[0]; + }; + /** + * Assigns multiple attributes to an element. + * @function module:utilities.assignAttributes + * @param {Element} elem - DOM element to apply new attribute values to + * @param {PlainObject<string, string>} attrs - Object with attribute keys/values + * @param {Integer} [suspendLength] - Milliseconds to suspend redraw + * @param {boolean} [unitCheck=false] - Boolean to indicate the need to use units.setUnitAttr + * @returns {void} + */ + + const assignAttributes = function (elem, attrs, suspendLength, unitCheck) { + for (const [key, value] of Object.entries(attrs)) { + const ns = key.substr(0, 4) === 'xml:' ? NS.XML : key.substr(0, 6) === 'xlink:' ? NS.XLINK : null; + + if (isNullish(value)) { + if (ns) { + elem.removeAttributeNS(ns, key); + } else { + elem.removeAttribute(key); + } + + continue; + } + + if (ns) { + elem.setAttributeNS(ns, key, value); + } else if (!unitCheck) { + elem.setAttribute(key, value); + } else { + setUnitAttr(elem, key, value); + } + } + }; + /** + * Remove unneeded (default) attributes, making resulting SVG smaller. + * @function module:utilities.cleanupElement + * @param {Element} element - DOM element to clean up + * @returns {void} + */ + + const cleanupElement = function (element) { + const defaults = { + 'fill-opacity': 1, + 'stop-opacity': 1, + opacity: 1, + stroke: 'none', + 'stroke-dasharray': 'none', + 'stroke-linejoin': 'miter', + 'stroke-linecap': 'butt', + 'stroke-opacity': 1, + 'stroke-width': 1, + rx: 0, + ry: 0 + }; + + if (element.nodeName === 'ellipse') { + // Ellipse elements require rx and ry attributes + delete defaults.rx; + delete defaults.ry; + } + + Object.entries(defaults).forEach(([attr, val]) => { + if (element.getAttribute(attr) === String(val)) { + element.removeAttribute(attr); + } + }); + }; + /** + * Round value to for snapping. + * @function module:utilities.snapToGrid + * @param {Float} value + * @returns {Integer} + */ + + const snapToGrid = function (value) { + const unit = editorContext_.getBaseUnit(); + let stepSize = editorContext_.getSnappingStep(); + + if (unit !== 'px') { + stepSize *= getTypeMap()[unit]; + } + + value = Math.round(value / stepSize) * stepSize; + return value; + }; + /** + * Escapes special characters in a regular expression. + * @function module:utilities.regexEscape + * @param {string} str + * @returns {string} + */ + + const regexEscape = function (str) { + // Originally from: http://phpjs.org/functions + return String(str).replace(/[.\\+*?[^\]$(){}=!<>|:-]/g, '\\$&'); + }; + /** + * Prevents default browser click behaviour on the given element. + * @function module:utilities.preventClickDefault + * @param {Element} img - The DOM element to prevent the click on + * @returns {void} + */ + + const preventClickDefault = function (img) { + $$1(img).click(function (e) { + e.preventDefault(); + }); + }; + /** + * @callback module:utilities.GetNextID + * @returns {string} The ID + */ + + /** + * Whether a value is `null` or `undefined`. + * @param {any} val + * @returns {boolean} + */ + + const isNullish = val => { + return val === null || val === undefined; + }; + /** + * Overwrite methods for unit testing. + * @function module:utilities.mock + * @param {PlainObject} mockMethods + * @param {module:utilities.getHref} mockMethods.getHref + * @param {module:utilities.setHref} mockMethods.setHref + * @param {module:utilities.getRotationAngle} mockMethods.getRotationAngle + * @returns {void} + */ + + const mock = ({ + getHref: getHrefUser, + setHref: setHrefUser, + getRotationAngle: getRotationAngleUser + }) => { + getHref = getHrefUser; + setHref = setHrefUser; + getRotationAngle = getRotationAngleUser; + }; + const $q = sel => document.querySelector(sel); + const $qq = sel => [...document.querySelectorAll(sel)]; + + var Utils = /*#__PURE__*/Object.freeze({ + __proto__: null, + init: init$1, + dropXMLInternalSubset: dropXMLInternalSubset, + toXml: toXml, + fromXml: fromXml, + encode64: encode64, + decode64: decode64, + decodeUTF8: decodeUTF8, + encodeUTF8: encodeUTF8, + dataURLToObjectURL: dataURLToObjectURL, + createObjectURL: createObjectURL, + blankPageObjectURL: blankPageObjectURL, + convertToXMLReferences: convertToXMLReferences, + text2xml: text2xml, + bboxToObj: bboxToObj, + walkTree: walkTree, + walkTreePost: walkTreePost, + getUrlFromAttr: getUrlFromAttr, + get getHref () { return getHref; }, + get setHref () { return setHref; }, + findDefs: findDefs, + getPathBBox: getPathBBox, + getBBox: getBBox, + getPathDFromSegments: getPathDFromSegments, + getPathDFromElement: getPathDFromElement, + getExtraAttributesForConvertToPath: getExtraAttributesForConvertToPath, + getBBoxOfElementAsPath: getBBoxOfElementAsPath, + convertToPath: convertToPath, + getBBoxWithTransform: getBBoxWithTransform, + getStrokedBBox: getStrokedBBox, + getVisibleElements: getVisibleElements, + getStrokedBBoxDefaultVisible: getStrokedBBoxDefaultVisible, + getRotationAngleFromTransformList: getRotationAngleFromTransformList, + get getRotationAngle () { return getRotationAngle; }, + getRefElem: getRefElem, + getElem: getElem, + assignAttributes: assignAttributes, + cleanupElement: cleanupElement, + snapToGrid: snapToGrid, + regexEscape: regexEscape, + preventClickDefault: preventClickDefault, + isNullish: isNullish, + mock: mock, + $q: $q, + $qq: $qq + }); + + /* globals jQuery */ + + /** + * Adds context menu functionality. + * @module contextmenu + * @license Apache-2.0 + * @author Adam Bender + */ + // Dependencies: + // 1) jQuery (for dom injection of context menus) + const $$2 = jQuery; + let contextMenuExtensions = {}; + /** + * @function module:contextmenu.hasCustomHandler + * @param {string} handlerKey + * @returns {boolean} + */ + + const hasCustomHandler = function (handlerKey) { + return Boolean(contextMenuExtensions[handlerKey]); + }; + /** + * @function module:contextmenu.getCustomHandler + * @param {string} handlerKey + * @returns {module:contextmenu.MenuItemAction} + */ + + const getCustomHandler = function (handlerKey) { + return contextMenuExtensions[handlerKey].action; + }; + /** + * @param {module:contextmenu.MenuItem} menuItem + * @returns {void} + */ + + const injectExtendedContextMenuItemIntoDom = function (menuItem) { + if (!Object.keys(contextMenuExtensions).length) { + // all menuItems appear at the bottom of the menu in their own container. + // if this is the first extension menu we need to add the separator. + $$2('#cmenu_canvas').append("<li class='separator'>"); + } + + const shortcut = menuItem.shortcut || ''; + $$2('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" + menuItem.label + "<span class='shortcut'>" + shortcut + '</span></a></li>'); + }; + /** + * @function module:contextmenu.injectExtendedContextMenuItemsIntoDom + * @returns {void} + */ + + + const injectExtendedContextMenuItemsIntoDom = function () { + Object.values(contextMenuExtensions).forEach(menuItem => { + injectExtendedContextMenuItemIntoDom(menuItem); + }); + }; + + function _extends() { + _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; + }; + + return _extends.apply(this, arguments); + } + + /* eslint-disable jsdoc/require-file-overview */ + + /** + * Adapted from {@link https://github.com/uupaa/dynamic-import-polyfill/blob/master/importModule.js}. + * @module importModule + * @license MIT + */ + + /** + * Converts a possible relative URL into an absolute one. + * @param {string} url + * @returns {string} + */ + function toAbsoluteURL(url) { + const a = document.createElement('a'); + a.setAttribute('href', url); // <a href="hoge.html"> + + return a.cloneNode(false).href; // -> "http://example.com/hoge.html" + } + /** + * Add any of the whitelisted attributes to the script tag. + * @param {HTMLScriptElement} script + * @param {PlainObject<string, string>} atts + * @returns {void} + */ + + + function addScriptAtts(script, atts) { + ['id', 'class', 'type'].forEach(prop => { + if (prop in atts) { + script[prop] = atts[prop]; + } + }); + } // Additions by Brett + + /** + * @typedef {PlainObject} module:importModule.ImportConfig + * @property {string} global The variable name to set on `window` (when not using the modular version) + * @property {boolean} [returnDefault=false] + */ + + /** + * @function module:importModule.importSetGlobalDefault + * @param {string|GenericArray<any>} url + * @param {module:importModule.ImportConfig} config + * @returns {Promise<any>} The value to which it resolves depends on the export of the targeted module. + */ + + + function importSetGlobalDefault(url, config) { + return importSetGlobal(url, _extends({}, config, { + returnDefault: true + })); + } + /** + * @function module:importModule.importSetGlobal + * @param {string|string[]} url + * @param {module:importModule.ImportConfig} config + * @returns {Promise<ArbitraryModule>} The promise resolves to either an `ArbitraryModule` or + * any other value depends on the export of the targeted module. + */ + + async function importSetGlobal(url, { + global: glob, + returnDefault + }) { + // Todo: Replace calls to this function with `import()` when supported + const modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; + + if (modularVersion) { + return importModule(url, undefined, { + returnDefault + }); + } + + await importScript(url); + return window[glob]; + } + /** + * + * @author Brett Zamir (other items are from `dynamic-import-polyfill`) + * @param {string|string[]} url + * @param {PlainObject} [atts={}] + * @returns {Promise<void|Error>} Resolves to `undefined` or rejects with an `Error` upon a + * script loading error + */ + + function importScript(url, atts = {}) { + if (Array.isArray(url)) { + return Promise.all(url.map(u => { + return importScript(u, atts); + })); + } + + return new Promise((resolve, reject) => { + // eslint-disable-line promise/avoid-new + const script = document.createElement('script'); + /** + * + * @returns {void} + */ + + function scriptOnError() { + reject(new Error(`Failed to import: ${url}`)); + destructor(); + } + /** + * + * @returns {void} + */ + + + function scriptOnLoad() { + resolve(); + destructor(); + } + + const destructor = () => { + script.removeEventListener('error', scriptOnError); + script.removeEventListener('load', scriptOnLoad); + script.remove(); + script.src = ''; + }; + + script.defer = 'defer'; + addScriptAtts(script, atts); + script.addEventListener('error', scriptOnError); + script.addEventListener('load', scriptOnLoad); + script.src = url; + document.head.append(script); + }); + } + /** + * + * @param {string|string[]} url + * @param {PlainObject} [atts={}] + * @param {PlainObject} opts + * @param {boolean} [opts.returnDefault=false} = {}] + * @returns {Promise<any>} Resolves to value of loading module or rejects with + * `Error` upon a script loading error. + */ + + function importModule(url, atts = {}, { + returnDefault = false + } = {}) { + if (Array.isArray(url)) { + return Promise.all(url.map(u => { + return importModule(u, atts); + })); + } + + return new Promise((resolve, reject) => { + // eslint-disable-line promise/avoid-new + const vector = '$importModule$' + Math.random().toString(32).slice(2); + const script = document.createElement('script'); + /** + * + * @returns {void} + */ + + function scriptOnError() { + reject(new Error(`Failed to import: ${url}`)); + destructor(); + } + /** + * + * @returns {void} + */ + + + function scriptOnLoad() { + resolve(window[vector]); + destructor(); + } + + const destructor = () => { + delete window[vector]; + script.removeEventListener('error', scriptOnError); + script.removeEventListener('load', scriptOnLoad); + script.remove(); + URL.revokeObjectURL(script.src); + script.src = ''; + }; + + addScriptAtts(script, atts); + script.defer = 'defer'; + script.type = 'module'; + script.addEventListener('error', scriptOnError); + script.addEventListener('load', scriptOnLoad); + const absURL = toAbsoluteURL(url); + const loader = `import * as m from '${absURL.replace(/'/g, "\\'")}'; window.${vector} = ${returnDefault ? 'm.default || ' : ''}m;`; // export Module + + const blob = new Blob([loader], { + type: 'text/javascript' + }); + script.src = URL.createObjectURL(blob); + document.head.append(script); + }); + } + + /** + * Created by alexey2baranov on 28.01.17. + */ + + /* + An extraction of the deparam method from Ben Alman's jQuery BBQ + http://benalman.com/projects/jquery-bbq-plugin/ + */ + const coerce_types = { + 'true': !0, + 'false': !1, + 'null': null + }; + + function deparam(params, coerce) { + // console.log(params) + const obj = {}; // Iterate over all name=value pairs. + + params.replace(/\+/g, ' ').split('&').forEach(function (v) { + const param = v.split('='); + let key = decodeURIComponent(param[0]), + // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it + // into its component parts. + keys = key.split(']['), + keys_last = keys.length - 1; // If the first keys part contains [ and the last ends with ], then [] + // are correctly balanced. + + if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) { + // Remove the trailing ] from the last keys part. + keys[keys_last] = keys[keys_last].replace(/\]$/, ''); // Split first keys part into two parts on the [ and add them back onto + // the beginning of the keys array. + + keys = keys.shift().split('[').concat(keys); + keys_last = keys.length - 1; + } else { + // Basic 'foo' style key. + keys_last = 0; + } // Are we dealing with a name=value pair, or just a name? + + + if (param.length >= 2) { + let val = decodeURIComponent(param.slice(1).join('=')); // Coerce values. + + if (coerce) { + val = val && !isNaN(val) ? +val // number + : val === 'undefined' ? undefined // undefined + : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null + : val; // string + } + + if (keys_last) { + let cur = obj; // Complex key, build deep object structure based on a few rules: + // * The 'cur' pointer starts at the object top-level. + // * [] = array push (n is set to array length), [n] = array if n is + // numeric, otherwise object. + // * If at the last keys part, set the value. + // * For each keys part, if the current level is undefined create an + // object or array based on the type of the next keys part. + // * Move the 'cur' pointer to the next level. + // * Rinse & repeat. + + for (let i = 0; i <= keys_last; i++) { + key = keys[i] === '' ? cur.length : keys[i]; + cur = cur[key] = i < keys_last ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : []) : val; + } + } else { + // Simple key, even simpler rules, since only scalars and shallow + // arrays are allowed. + if (Array.isArray(obj[key])) { + // val is already an array, so push on the next value. + obj[key].push(val); + } else if (obj[key] !== undefined) { + // val isn't an array, but since a second value has been specified, + // convert val into an array. + obj[key] = [obj[key], val]; + } else { + // val is a scalar. + obj[key] = val; + } + } + } else if (key) { + // No value was defined, so set something meaningful. + obj[key] = coerce ? undefined : ''; + } + }); + return obj; + } + + /** + * @module jQueryPluginDBox + */ + + /** + * @param {external:jQuery} $ + * @param {PlainObject} [strings] + * @param {PlainObject} [strings.ok] + * @param {PlainObject} [strings.cancel] + * @returns {external:jQuery} + */ + function jQueryPluginDBox($, strings = { + ok: 'Ok', + cancel: 'Cancel' + }) { + // This sets up alternative dialog boxes. They mostly work the same way as + // their UI counterparts, expect instead of returning the result, a callback + // needs to be included that returns the result as its first parameter. + // In the future we may want to add additional types of dialog boxes, since + // they should be easy to handle this way. + $('#dialog_container').draggable({ + cancel: '#dialog_content, #dialog_buttons *', + containment: 'window' + }).css('position', 'absolute'); + const box = $('#dialog_box'), + btnHolder = $('#dialog_buttons'), + dialogContent = $('#dialog_content'); + /** + * @typedef {PlainObject} module:jQueryPluginDBox.PromiseResultObject + * @property {string|true} response + * @property {boolean} checked + */ + + /** + * Resolves to `false` (if cancelled), for prompts and selects + * without checkboxes, it resolves to the value of the form control. For other + * types without checkboxes, it resolves to `true`. For checkboxes, it resolves + * to an object with the `response` key containing the same value as the previous + * mentioned (string or `true`) and a `checked` (boolean) property. + * @typedef {Promise<boolean|string|module:jQueryPluginDBox.PromiseResultObject>} module:jQueryPluginDBox.ResultPromise + */ + + /** + * @typedef {PlainObject} module:jQueryPluginDBox.SelectOption + * @property {string} text + * @property {string} value + */ + + /** + * @typedef {PlainObject} module:jQueryPluginDBox.CheckboxInfo + * @property {string} label Label for the checkbox + * @property {string} value Value of the checkbox + * @property {string} tooltip Tooltip on the checkbox label + * @property {boolean} checked Whether the checkbox is checked by default + */ + + /** + * Triggered upon a change of value for the select pull-down. + * @callback module:jQueryPluginDBox.SelectChangeListener + * @returns {void} + */ + + /** + * Creates a dialog of the specified type with a given message + * and any defaults and type-specific metadata. Returns a `Promise` + * which resolves differently depending on whether the dialog + * was cancelled or okayed (with the response and any checked state). + * @param {"alert"|"prompt"|"select"|"process"} type + * @param {string} msg + * @param {string} [defaultVal] + * @param {module:jQueryPluginDBox.SelectOption[]} [opts] + * @param {module:jQueryPluginDBox.SelectChangeListener} [changeListener] + * @param {module:jQueryPluginDBox.CheckboxInfo} [checkbox] + * @returns {jQueryPluginDBox.ResultPromise} + */ + + function dbox(type, msg, defaultVal, opts, changeListener, checkbox) { + dialogContent.html('<p>' + msg.replace(/\n/g, '</p><p>') + '</p>').toggleClass('prompt', type === 'prompt'); + btnHolder.empty(); + const ok = $('<input type="button" data-ok="" value="' + strings.ok + '">').appendTo(btnHolder); + return new Promise((resolve, reject) => { + // eslint-disable-line promise/avoid-new + if (type !== 'alert') { + $('<input type="button" value="' + strings.cancel + '">').appendTo(btnHolder).click(function () { + box.hide(); + resolve(false); + }); + } + + let ctrl, chkbx; + + if (type === 'prompt') { + ctrl = $('<input type="text">').prependTo(btnHolder); + ctrl.val(defaultVal || ''); + ctrl.bind('keydown', 'return', function () { + ok.click(); + }); + } else if (type === 'select') { + const div = $('<div style="text-align:center;">'); + ctrl = $(`<select aria-label="${msg}">`).appendTo(div); + + if (checkbox) { + const label = $('<label>').text(checkbox.label); + chkbx = $('<input type="checkbox">').appendTo(label); + chkbx.val(checkbox.value); + + if (checkbox.tooltip) { + label.attr('title', checkbox.tooltip); + } + + chkbx.prop('checked', Boolean(checkbox.checked)); + div.append($('<div>').append(label)); + } + + $.each(opts || [], function (opt, val) { + if (typeof val === 'object') { + ctrl.append($('<option>').val(val.value).html(val.text)); + } else { + ctrl.append($('<option>').html(val)); + } + }); + dialogContent.append(div); + + if (defaultVal) { + ctrl.val(defaultVal); + } + + if (changeListener) { + ctrl.bind('change', 'return', changeListener); + } + + ctrl.bind('keydown', 'return', function () { + ok.click(); + }); + } else if (type === 'process') { + ok.hide(); + } + + box.show(); + ok.click(function () { + box.hide(); + const response = type === 'prompt' || type === 'select' ? ctrl.val() : true; + + if (chkbx) { + resolve({ + response, + checked: chkbx.prop('checked') + }); + return; + } + + resolve(response); + }).focus(); + + if (type === 'prompt' || type === 'select') { + ctrl.focus(); + } + }); + } + /** + * @param {string} msg Message to alert + * @returns {jQueryPluginDBox.ResultPromise} + */ + + + $.alert = function (msg) { + return dbox('alert', msg); + }; + /** + * @param {string} msg Message for which to ask confirmation + * @returns {jQueryPluginDBox.ResultPromise} + */ + + + $.confirm = function (msg) { + return dbox('confirm', msg); + }; + /** + * @param {string} msg Message to indicate upon cancelable indicator + * @returns {jQueryPluginDBox.ResultPromise} + */ + + + $.process_cancel = function (msg) { + return dbox('process', msg); + }; + /** + * @param {string} msg Message to accompany the prompt + * @param {string} [defaultText=''] The default text to show for the prompt + * @returns {jQueryPluginDBox.ResultPromise} + */ + + + $.prompt = function (msg, defaultText = '') { + return dbox('prompt', msg, defaultText); + }; + + $.select = function (msg, opts, changeListener, txt, checkbox) { + return dbox('select', msg, txt, opts, changeListener, checkbox); + }; + + return $; + } + + /* eslint-disable no-console */ /** * Group: Undo/Redo history management. */ - var HistoryEventTypes = { + const HistoryEventTypes = { BEFORE_APPLY: 'before_apply', AFTER_APPLY: 'after_apply', BEFORE_UNAPPLY: 'before_unapply', AFTER_UNAPPLY: 'after_unapply' - }; // const removedElements = {}; - + }; /** * Base class for commands. */ - var Command = /*#__PURE__*/function () { - function Command() { - _classCallCheck(this, Command); + class Command { + /** + * @returns {string} + */ + getText() { + return this.text; + } + /** + * @param {module:history.HistoryEventHandler} handler + * @param {callback} applyFunction + * @returns {void} + */ + + + apply(handler, applyFunction) { + handler && handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this); + applyFunction(handler); + handler && handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this); + } + /** + * @param {module:history.HistoryEventHandler} handler + * @param {callback} unapplyFunction + * @returns {void} + */ + + + unapply(handler, unapplyFunction) { + handler && handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); + unapplyFunction(); + handler && handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); + } + /** + * @returns {Element[]} Array with element associated with this command + * This function needs to be surcharged if multiple elements are returned. + */ + + + elements() { + return [this.elem]; + } + /** + * @returns {string} String with element associated with this command + */ + + + type() { + return this.constructor.name; } - _createClass(Command, [{ - key: "getText", - - /** - * @returns {string} - */ - value: function getText() { - return this.text; - } - }]); - - return Command; - }(); // Todo: Figure out why the interface members aren't showing + } // Todo: Figure out why the interface members aren't showing // up (with or without modules applied), despite our apparently following // http://usejsdoc.org/tags-interface.html#virtual-comments @@ -3930,12 +5700,6 @@ * @returns {string} */ - /** - * Gives the type. - * @function module:history.HistoryCommand#type - * @returns {string} - */ - /** * @event module:history~Command#event:history * @type {module:history.HistoryCommand} @@ -3962,294 +5726,155 @@ */ - var MoveElementCommand = /*#__PURE__*/function (_Command) { - _inherits(MoveElementCommand, _Command); - - var _super = _createSuper(MoveElementCommand); - + class MoveElementCommand extends Command { /** * @param {Element} elem - The DOM element that was moved * @param {Element} oldNextSibling - The element's next sibling before it was moved * @param {Element} oldParent - The element's parent before it was moved * @param {string} [text] - An optional string visible to user related to this change */ - function MoveElementCommand(elem, oldNextSibling, oldParent, text) { - var _this; - - _classCallCheck(this, MoveElementCommand); - - _this = _super.call(this); - _this.elem = elem; - _this.text = text ? 'Move ' + elem.tagName + ' to ' + text : 'Move ' + elem.tagName; - _this.oldNextSibling = oldNextSibling; - _this.oldParent = oldParent; - _this.newNextSibling = elem.nextSibling; - _this.newParent = elem.parentNode; - return _this; + constructor(elem, oldNextSibling, oldParent, text) { + super(); + this.elem = elem; + this.text = text ? 'Move ' + elem.tagName + ' to ' + text : 'Move ' + elem.tagName; + this.oldNextSibling = oldNextSibling; + this.oldParent = oldParent; + this.newNextSibling = elem.nextSibling; + this.newParent = elem.parentNode; } /** - * @returns {"svgedit.history.MoveElementCommand"} - */ + * Re-positions the element. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - _createClass(MoveElementCommand, [{ - key: "type", - value: function type() { - // eslint-disable-line class-methods-use-this - return 'svgedit.history.MoveElementCommand'; - } - /** - * Re-positions the element. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ - - }, { - key: "apply", - value: function apply(handler) { - // TODO(codedread): Refactor this common event code into a base HistoryCommand class. - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this); - } - + apply(handler) { + super.apply(handler, () => { this.elem = this.newParent.insertBefore(this.elem, this.newNextSibling); + }); + } + /** + * Positions the element back to its original location. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this); - } - } - /** - * Positions the element back to its original location. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ - - }, { - key: "unapply", - value: function unapply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); - } + unapply(handler) { + super.unapply(handler, () => { this.elem = this.oldParent.insertBefore(this.elem, this.oldNextSibling); + }); + } - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); - } - } - /** - * @returns {Element[]} Array with element associated with this command - */ - - }, { - key: "elements", - value: function elements() { - return [this.elem]; - } - }]); - - return MoveElementCommand; - }(Command); - MoveElementCommand.type = MoveElementCommand.prototype.type; + } /** * History command for an element that was added to the DOM. * @implements {module:history.HistoryCommand} */ - var InsertElementCommand = /*#__PURE__*/function (_Command2) { - _inherits(InsertElementCommand, _Command2); - - var _super2 = _createSuper(InsertElementCommand); - + class InsertElementCommand extends Command { /** * @param {Element} elem - The newly added DOM element * @param {string} text - An optional string visible to user related to this change */ - function InsertElementCommand(elem, text) { - var _this2; - - _classCallCheck(this, InsertElementCommand); - - _this2 = _super2.call(this); - _this2.elem = elem; - _this2.text = text || 'Create ' + elem.tagName; - _this2.parent = elem.parentNode; - _this2.nextSibling = _this2.elem.nextSibling; - return _this2; + constructor(elem, text) { + super(); + this.elem = elem; + this.text = text || 'Create ' + elem.tagName; + this.parent = elem.parentNode; + this.nextSibling = this.elem.nextSibling; } /** - * @returns {"svgedit.history.InsertElementCommand"} - */ + * Re-inserts the new element. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - _createClass(InsertElementCommand, [{ - key: "type", - value: function type() { - // eslint-disable-line class-methods-use-this - return 'svgedit.history.InsertElementCommand'; - } - /** - * Re-inserts the new element. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ - - }, { - key: "apply", - value: function apply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this); - } - + apply(handler) { + super.apply(handler, () => { this.elem = this.parent.insertBefore(this.elem, this.nextSibling); + }); + } + /** + * Removes the element. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this); - } - } - /** - * Removes the element. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ - - }, { - key: "unapply", - value: function unapply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); - } + unapply(handler) { + super.unapply(handler, () => { this.parent = this.elem.parentNode; this.elem.remove(); + }); + } - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); - } - } - /** - * @returns {Element[]} Array with element associated with this command - */ - - }, { - key: "elements", - value: function elements() { - return [this.elem]; - } - }]); - - return InsertElementCommand; - }(Command); - InsertElementCommand.type = InsertElementCommand.prototype.type; + } /** * History command for an element removed from the DOM. * @implements {module:history.HistoryCommand} */ - var RemoveElementCommand = /*#__PURE__*/function (_Command3) { - _inherits(RemoveElementCommand, _Command3); - - var _super3 = _createSuper(RemoveElementCommand); - + class RemoveElementCommand extends Command { /** * @param {Element} elem - The removed DOM element * @param {Node} oldNextSibling - The DOM element's nextSibling when it was in the DOM * @param {Element} oldParent - The DOM element's parent * @param {string} [text] - An optional string visible to user related to this change */ - function RemoveElementCommand(elem, oldNextSibling, oldParent, text) { - var _this3; - - _classCallCheck(this, RemoveElementCommand); - - _this3 = _super3.call(this); - _this3.elem = elem; - _this3.text = text || 'Delete ' + elem.tagName; - _this3.nextSibling = oldNextSibling; - _this3.parent = oldParent; // special hack for webkit: remove this element's entry in the svgTransformLists map + constructor(elem, oldNextSibling, oldParent, text) { + super(); + this.elem = elem; + this.text = text || 'Delete ' + elem.tagName; + this.nextSibling = oldNextSibling; + this.parent = oldParent; // special hack for webkit: remove this element's entry in the svgTransformLists map removeElementFromListMap(elem); - return _this3; } /** - * @returns {"svgedit.history.RemoveElementCommand"} - */ + * Re-removes the new element. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - _createClass(RemoveElementCommand, [{ - key: "type", - value: function type() { - // eslint-disable-line class-methods-use-this - return 'svgedit.history.RemoveElementCommand'; - } - /** - * Re-removes the new element. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ - - }, { - key: "apply", - value: function apply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this); - } - + apply(handler) { + super.apply(handler, () => { removeElementFromListMap(this.elem); this.parent = this.elem.parentNode; this.elem.remove(); + }); + } + /** + * Re-adds the new element. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this); - } - } - /** - * Re-adds the new element. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ - - }, { - key: "unapply", - value: function unapply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); - } + unapply(handler) { + super.unapply(handler, () => { removeElementFromListMap(this.elem); if (isNullish(this.nextSibling)) { if (window.console) { - console.log('Error: reference element was lost'); // eslint-disable-line no-console + console.error('Reference element was lost'); } } this.parent.insertBefore(this.elem, this.nextSibling); // Don't use `before` or `prepend` as `this.nextSibling` may be `null` + }); + } - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); - } - } - /** - * @returns {Element[]} Array with element associated with this command - */ - - }, { - key: "elements", - value: function elements() { - return [this.elem]; - } - }]); - - return RemoveElementCommand; - }(Command); - RemoveElementCommand.type = RemoveElementCommand.prototype.type; + } /** * @typedef {"#text"|"#href"|string} module:history.CommandAttributeName */ @@ -4264,86 +5889,54 @@ * @implements {module:history.HistoryCommand} */ - var ChangeElementCommand = /*#__PURE__*/function (_Command4) { - _inherits(ChangeElementCommand, _Command4); - - var _super4 = _createSuper(ChangeElementCommand); - + class ChangeElementCommand extends Command { /** * @param {Element} elem - The DOM element that was changed * @param {module:history.CommandAttributes} attrs - Attributes to be changed with the values they had *before* the change * @param {string} text - An optional string visible to user related to this change */ - function ChangeElementCommand(elem, attrs, text) { - var _this4; + constructor(elem, attrs, text) { + super(); + this.elem = elem; + this.text = text ? 'Change ' + elem.tagName + ' ' + text : 'Change ' + elem.tagName; + this.newValues = {}; + this.oldValues = attrs; - _classCallCheck(this, ChangeElementCommand); - - _this4 = _super4.call(this); - _this4.elem = elem; - _this4.text = text ? 'Change ' + elem.tagName + ' ' + text : 'Change ' + elem.tagName; - _this4.newValues = {}; - _this4.oldValues = attrs; - - for (var attr in attrs) { + for (const attr in attrs) { if (attr === '#text') { - _this4.newValues[attr] = elem.textContent; + this.newValues[attr] = elem.textContent; } else if (attr === '#href') { - _this4.newValues[attr] = getHref(elem); + this.newValues[attr] = getHref(elem); } else { - _this4.newValues[attr] = elem.getAttribute(attr); + this.newValues[attr] = elem.getAttribute(attr); } } - - return _this4; } /** - * @returns {"svgedit.history.ChangeElementCommand"} - */ + * Performs the stored change action. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - _createClass(ChangeElementCommand, [{ - key: "type", - value: function type() { - // eslint-disable-line class-methods-use-this - return 'svgedit.history.ChangeElementCommand'; - } - /** - * Performs the stored change action. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {true} - */ - - }, { - key: "apply", - value: function apply(handler) { - var _this5 = this; - - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this); - } - - var bChangedTransform = false; - Object.entries(this.newValues).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - attr = _ref2[0], - value = _ref2[1]; - + apply(handler) { + super.apply(handler, () => { + let bChangedTransform = false; + Object.entries(this.newValues).forEach(([attr, value]) => { if (value) { if (attr === '#text') { - _this5.elem.textContent = value; + this.elem.textContent = value; } else if (attr === '#href') { - setHref(_this5.elem, value); + setHref(this.elem, value); } else { - _this5.elem.setAttribute(attr, value); + this.elem.setAttribute(attr, value); } } else if (attr === '#text') { - _this5.elem.textContent = ''; + this.elem.textContent = ''; } else { - _this5.elem.setAttribute(attr, ''); - - _this5.elem.removeAttribute(attr); + this.elem.setAttribute(attr, ''); + this.elem.removeAttribute(attr); } if (attr === 'transform') { @@ -4352,60 +5945,45 @@ }); // relocate rotational transform, if necessary if (!bChangedTransform) { - var angle = getRotationAngle(this.elem); + const angle = getRotationAngle(this.elem); if (angle) { - var bbox = this.elem.getBBox(); - var cx = bbox.x + bbox.width / 2, - cy = bbox.y + bbox.height / 2; - var rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join(''); + const bbox = this.elem.getBBox(); + const cx = bbox.x + bbox.width / 2; + const cy = bbox.y + bbox.height / 2; + const rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join(''); if (rotate !== this.elem.getAttribute('transform')) { this.elem.setAttribute('transform', rotate); } } } + }); + } + /** + * Reverses the stored change action. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this); - } - - return true; - } - /** - * Reverses the stored change action. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {true} - */ - - }, { - key: "unapply", - value: function unapply(handler) { - var _this6 = this; - - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); - } - - var bChangedTransform = false; - Object.entries(this.oldValues).forEach(function (_ref3) { - var _ref4 = _slicedToArray(_ref3, 2), - attr = _ref4[0], - value = _ref4[1]; + unapply(handler) { + super.unapply(handler, () => { + let bChangedTransform = false; + Object.entries(this.oldValues).forEach(([attr, value]) => { if (value) { if (attr === '#text') { - _this6.elem.textContent = value; + this.elem.textContent = value; } else if (attr === '#href') { - setHref(_this6.elem, value); + setHref(this.elem, value); } else { - _this6.elem.setAttribute(attr, value); + this.elem.setAttribute(attr, value); } } else if (attr === '#text') { - _this6.elem.textContent = ''; + this.elem.textContent = ''; } else { - _this6.elem.removeAttribute(attr); + this.elem.removeAttribute(attr); } if (attr === 'transform') { @@ -4414,13 +5992,13 @@ }); // relocate rotational transform, if necessary if (!bChangedTransform) { - var angle = getRotationAngle(this.elem); + const angle = getRotationAngle(this.elem); if (angle) { - var bbox = this.elem.getBBox(); - var cx = bbox.x + bbox.width / 2, - cy = bbox.y + bbox.height / 2; - var rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join(''); + const bbox = this.elem.getBBox(); + const cx = bbox.x + bbox.width / 2, + cy = bbox.y + bbox.height / 2; + const rotate = ['rotate(', angle, ' ', cx, ',', cy, ')'].join(''); if (rotate !== this.elem.getAttribute('transform')) { this.elem.setAttribute('transform', rotate); @@ -4430,27 +6008,10 @@ removeElementFromListMap(this.elem); + }); + } - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); - } - - return true; - } - /** - * @returns {Element[]} Array with element associated with this command - */ - - }, { - key: "elements", - value: function elements() { - return [this.elem]; - } - }]); - - return ChangeElementCommand; - }(Command); - ChangeElementCommand.type = ChangeElementCommand.prototype.type; // TODO: create a 'typing' command object that tracks changes in text + } // TODO: create a 'typing' command object that tracks changes in text // if a new Typing command is created and the top command on the stack is also a Typing // and they both affect the same element, then collapse the two commands into one @@ -4459,141 +6020,101 @@ * @implements {module:history.HistoryCommand} */ - var BatchCommand = /*#__PURE__*/function (_Command5) { - _inherits(BatchCommand, _Command5); - - var _super5 = _createSuper(BatchCommand); - + class BatchCommand extends Command { /** * @param {string} [text] - An optional string visible to user related to this change */ - function BatchCommand(text) { - var _this7; - - _classCallCheck(this, BatchCommand); - - _this7 = _super5.call(this); - _this7.text = text || 'Batch Command'; - _this7.stack = []; - return _this7; + constructor(text) { + super(); + this.text = text || 'Batch Command'; + this.stack = []; } /** - * @returns {"svgedit.history.BatchCommand"} - */ + * Runs "apply" on all subcommands. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - _createClass(BatchCommand, [{ - key: "type", - value: function type() { - // eslint-disable-line class-methods-use-this - return 'svgedit.history.BatchCommand'; - } - /** - * Runs "apply" on all subcommands. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ + apply(handler) { + super.apply(handler, () => { + this.stack.forEach(stackItem => { + console.assert(stackItem, 'stack item should not be null'); + stackItem && stackItem.apply(handler); + }); + }); + } + /** + * Runs "unapply" on all subcommands. + * @param {module:history.HistoryEventHandler} handler + * @fires module:history~Command#event:history + * @returns {void} + */ - }, { - key: "apply", - value: function apply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_APPLY, this); - } - var len = this.stack.length; + unapply(handler) { + super.unapply(handler, () => { + this.stack.forEach(stackItem => { + console.assert(stackItem, 'stack item should not be null'); + stackItem && stackItem.unapply(handler); + }); + }); + } + /** + * Iterate through all our subcommands. + * @returns {Element[]} All the elements we are changing + */ - for (var i = 0; i < len; ++i) { - this.stack[i].apply(handler); - } - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_APPLY, this); - } - } - /** - * Runs "unapply" on all subcommands. - * @param {module:history.HistoryEventHandler} handler - * @fires module:history~Command#event:history - * @returns {void} - */ + elements() { + const elems = []; + let cmd = this.stack.length; - }, { - key: "unapply", - value: function unapply(handler) { - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.BEFORE_UNAPPLY, this); - } + while (cmd--) { + if (!this.stack[cmd]) continue; + const thisElems = this.stack[cmd].elements(); + let elem = thisElems.length; - for (var i = this.stack.length - 1; i >= 0; i--) { - this.stack[i].unapply(handler); - } - - if (handler) { - handler.handleHistoryEvent(HistoryEventTypes.AFTER_UNAPPLY, this); - } - } - /** - * Iterate through all our subcommands. - * @returns {Element[]} All the elements we are changing - */ - - }, { - key: "elements", - value: function elements() { - var elems = []; - var cmd = this.stack.length; - - while (cmd--) { - var thisElems = this.stack[cmd].elements(); - var elem = thisElems.length; - - while (elem--) { - if (!elems.includes(thisElems[elem])) { - elems.push(thisElems[elem]); - } + while (elem--) { + if (!elems.includes(thisElems[elem])) { + elems.push(thisElems[elem]); } } - - return elems; } - /** - * Adds a given command to the history stack. - * @param {Command} cmd - The undo command object to add - * @returns {void} - */ - }, { - key: "addSubCommand", - value: function addSubCommand(cmd) { - this.stack.push(cmd); - } - /** - * @returns {boolean} Indicates whether or not the batch command is empty - */ + return elems; + } + /** + * Adds a given command to the history stack. + * @param {Command} cmd - The undo command object to add + * @returns {void} + */ - }, { - key: "isEmpty", - value: function isEmpty() { - return !this.stack.length; - } - }]); - return BatchCommand; - }(Command); - BatchCommand.type = BatchCommand.prototype.type; + addSubCommand(cmd) { + console.assert(cmd !== null, 'cmd should not be null'); + this.stack.push(cmd); + } + /** + * @returns {boolean} Indicates whether or not the batch command is empty + */ + + + isEmpty() { + return !this.stack.length; + } + + } /** * */ - var UndoManager = /*#__PURE__*/function () { + class UndoManager { /** * @param {module:history.HistoryEventHandler} historyEventHandler */ - function UndoManager(historyEventHandler) { - _classCallCheck(this, UndoManager); - + constructor(historyEventHandler) { this.handler_ = historyEventHandler || null; this.undoStackPointer = 0; this.undoStack = []; // this is the stack that stores the original values, the elements and @@ -4608,170 +6129,159 @@ */ - _createClass(UndoManager, [{ - key: "resetUndoStack", - value: function resetUndoStack() { - this.undoStack = []; - this.undoStackPointer = 0; + resetUndoStack() { + this.undoStack = []; + this.undoStackPointer = 0; + } + /** + * @returns {Integer} Current size of the undo history stack + */ + + + getUndoStackSize() { + return this.undoStackPointer; + } + /** + * @returns {Integer} Current size of the redo history stack + */ + + + getRedoStackSize() { + return this.undoStack.length - this.undoStackPointer; + } + /** + * @returns {string} String associated with the next undo command + */ + + + getNextUndoCommandText() { + return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer - 1].getText() : ''; + } + /** + * @returns {string} String associated with the next redo command + */ + + + getNextRedoCommandText() { + return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : ''; + } + /** + * Performs an undo step. + * @returns {void} + */ + + + undo() { + if (this.undoStackPointer > 0) { + const cmd = this.undoStack[--this.undoStackPointer]; + cmd.unapply(this.handler_); } - /** - * @returns {Integer} Current size of the undo history stack - */ + } + /** + * Performs a redo step. + * @returns {void} + */ - }, { - key: "getUndoStackSize", - value: function getUndoStackSize() { - return this.undoStackPointer; + + redo() { + if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) { + const cmd = this.undoStack[this.undoStackPointer++]; + cmd.apply(this.handler_); } - /** - * @returns {Integer} Current size of the redo history stack - */ + } + /** + * Adds a command object to the undo history stack. + * @param {Command} cmd - The command object to add + * @returns {void} + */ - }, { - key: "getRedoStackSize", - value: function getRedoStackSize() { - return this.undoStack.length - this.undoStackPointer; + + addCommandToHistory(cmd) { + // TODO: we MUST compress consecutive text changes to the same element + // (right now each keystroke is saved as a separate command that includes the + // entire text contents of the text element) + // TODO: consider limiting the history that we store here (need to do some slicing) + // if our stack pointer is not at the end, then we have to remove + // all commands after the pointer and insert the new command + if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) { + this.undoStack = this.undoStack.splice(0, this.undoStackPointer); } - /** - * @returns {string} String associated with the next undo command - */ - }, { - key: "getNextUndoCommandText", - value: function getNextUndoCommandText() { - return this.undoStackPointer > 0 ? this.undoStack[this.undoStackPointer - 1].getText() : ''; - } - /** - * @returns {string} String associated with the next redo command - */ + this.undoStack.push(cmd); + this.undoStackPointer = this.undoStack.length; + } + /** + * This function tells the canvas to remember the old values of the + * `attrName` attribute for each element sent in. The elements and values + * are stored on a stack, so the next call to `finishUndoableChange()` will + * pop the elements and old values off the stack, gets the current values + * from the DOM and uses all of these to construct the undo-able command. + * @param {string} attrName - The name of the attribute being changed + * @param {Element[]} elems - Array of DOM elements being changed + * @returns {void} + */ - }, { - key: "getNextRedoCommandText", - value: function getNextRedoCommandText() { - return this.undoStackPointer < this.undoStack.length ? this.undoStack[this.undoStackPointer].getText() : ''; - } - /** - * Performs an undo step. - * @returns {void} - */ - }, { - key: "undo", - value: function undo() { - if (this.undoStackPointer > 0) { - var cmd = this.undoStack[--this.undoStackPointer]; - cmd.unapply(this.handler_); - } - } - /** - * Performs a redo step. - * @returns {void} - */ - - }, { - key: "redo", - value: function redo() { - if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) { - var cmd = this.undoStack[this.undoStackPointer++]; - cmd.apply(this.handler_); - } - } - /** - * Adds a command object to the undo history stack. - * @param {Command} cmd - The command object to add - * @returns {void} - */ - - }, { - key: "addCommandToHistory", - value: function addCommandToHistory(cmd) { - // TODO: we MUST compress consecutive text changes to the same element - // (right now each keystroke is saved as a separate command that includes the - // entire text contents of the text element) - // TODO: consider limiting the history that we store here (need to do some slicing) - // if our stack pointer is not at the end, then we have to remove - // all commands after the pointer and insert the new command - if (this.undoStackPointer < this.undoStack.length && this.undoStack.length > 0) { - this.undoStack = this.undoStack.splice(0, this.undoStackPointer); - } - - this.undoStack.push(cmd); - this.undoStackPointer = this.undoStack.length; - } - /** - * This function tells the canvas to remember the old values of the - * `attrName` attribute for each element sent in. The elements and values - * are stored on a stack, so the next call to `finishUndoableChange()` will - * pop the elements and old values off the stack, gets the current values - * from the DOM and uses all of these to construct the undo-able command. - * @param {string} attrName - The name of the attribute being changed - * @param {Element[]} elems - Array of DOM elements being changed - * @returns {void} - */ - - }, { - key: "beginUndoableChange", - value: function beginUndoableChange(attrName, elems) { - var p = ++this.undoChangeStackPointer; - var i = elems.length; - var oldValues = new Array(i), + beginUndoableChange(attrName, elems) { + const p = ++this.undoChangeStackPointer; + let i = elems.length; + const oldValues = new Array(i), elements = new Array(i); - while (i--) { - var elem = elems[i]; + while (i--) { + const elem = elems[i]; - if (isNullish(elem)) { - continue; - } - - elements[i] = elem; - oldValues[i] = elem.getAttribute(attrName); + if (isNullish(elem)) { + continue; } - this.undoableChangeStack[p] = { - attrName: attrName, - oldValues: oldValues, - elements: elements - }; + elements[i] = elem; + oldValues[i] = elem.getAttribute(attrName); } - /** - * This function returns a `BatchCommand` object which summarizes the - * change since `beginUndoableChange` was called. The command can then - * be added to the command history. - * @returns {BatchCommand} Batch command object with resulting changes - */ - }, { - key: "finishUndoableChange", - value: function finishUndoableChange() { - var p = this.undoChangeStackPointer--; - var changeset = this.undoableChangeStack[p]; - var attrName = changeset.attrName; - var batchCmd = new BatchCommand('Change ' + attrName); - var i = changeset.elements.length; + this.undoableChangeStack[p] = { + attrName, + oldValues, + elements + }; + } + /** + * This function returns a `BatchCommand` object which summarizes the + * change since `beginUndoableChange` was called. The command can then + * be added to the command history. + * @returns {BatchCommand} Batch command object with resulting changes + */ - while (i--) { - var elem = changeset.elements[i]; - if (isNullish(elem)) { - continue; - } + finishUndoableChange() { + const p = this.undoChangeStackPointer--; + const changeset = this.undoableChangeStack[p]; + const { + attrName + } = changeset; + const batchCmd = new BatchCommand('Change ' + attrName); + let i = changeset.elements.length; - var changes = {}; - changes[attrName] = changeset.oldValues[i]; + while (i--) { + const elem = changeset.elements[i]; - if (changes[attrName] !== elem.getAttribute(attrName)) { - batchCmd.addSubCommand(new ChangeElementCommand(elem, changes, attrName)); - } + if (isNullish(elem)) { + continue; } - this.undoableChangeStack[p] = null; - return batchCmd; - } - }]); + const changes = {}; + changes[attrName] = changeset.oldValues[i]; - return UndoManager; - }(); + if (changes[attrName] !== elem.getAttribute(attrName)) { + batchCmd.addSubCommand(new ChangeElementCommand(elem, changes, attrName)); + } + } + + this.undoableChangeStack[p] = null; + return batchCmd; + } + + } var hstry = /*#__PURE__*/Object.freeze({ __proto__: null, @@ -4784,240 +6294,9 @@ UndoManager: UndoManager }); - /** - * Mathematical utilities. - * @module math - * @license MIT - * - * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller - */ - - var NEAR_ZERO = 1e-14; // Throw away SVGSVGElement used for creating matrices/transforms. - - var svg$1 = document.createElementNS(NS.SVG, 'svg'); - /** - * A (hopefully) quicker function to transform a point by a matrix - * (this function avoids any DOM calls and just does the math). - * @function module:math.transformPoint - * @param {Float} x - Float representing the x coordinate - * @param {Float} y - Float representing the y coordinate - * @param {SVGMatrix} m - Matrix object to transform the point with - * @returns {module:math.XYObject} An x, y object representing the transformed point - */ - - var transformPoint = function transformPoint(x, y, m) { - return { - x: m.a * x + m.c * y + m.e, - y: m.b * x + m.d * y + m.f - }; - }; - /** - * Helper function to check if the matrix performs no actual transform - * (i.e. exists for identity purposes). - * @function module:math.isIdentity - * @param {SVGMatrix} m - The matrix object to check - * @returns {boolean} Indicates whether or not the matrix is 1,0,0,1,0,0 - */ - - var isIdentity = function isIdentity(m) { - return m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && m.e === 0 && m.f === 0; - }; - /** - * This function tries to return a `SVGMatrix` that is the multiplication `m1 * m2`. - * We also round to zero when it's near zero. - * @function module:math.matrixMultiply - * @param {...SVGMatrix} args - Matrix objects to multiply - * @returns {SVGMatrix} The matrix object resulting from the calculation - */ - - var matrixMultiply = function matrixMultiply() { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - var m = args.reduceRight(function (prev, m1) { - return m1.multiply(prev); - }); - - if (Math.abs(m.a) < NEAR_ZERO) { - m.a = 0; - } - - if (Math.abs(m.b) < NEAR_ZERO) { - m.b = 0; - } - - if (Math.abs(m.c) < NEAR_ZERO) { - m.c = 0; - } - - if (Math.abs(m.d) < NEAR_ZERO) { - m.d = 0; - } - - if (Math.abs(m.e) < NEAR_ZERO) { - m.e = 0; - } - - if (Math.abs(m.f) < NEAR_ZERO) { - m.f = 0; - } - - return m; - }; - var hasMatrixTransform = function hasMatrixTransform(tlist) { - if (!tlist) { - return false; - } - - var num = tlist.numberOfItems; - - while (num--) { - var xform = tlist.getItem(num); - - if (xform.type === 1 && !isIdentity(xform.matrix)) { - return true; - } - } - - return false; - }; - /** - * @typedef {PlainObject} module:math.TransformedBox An object with the following values - * @property {module:math.XYObject} tl - The top left coordinate - * @property {module:math.XYObject} tr - The top right coordinate - * @property {module:math.XYObject} bl - The bottom left coordinate - * @property {module:math.XYObject} br - The bottom right coordinate - * @property {PlainObject} aabox - Object with the following values: - * @property {Float} aabox.x - Float with the axis-aligned x coordinate - * @property {Float} aabox.y - Float with the axis-aligned y coordinate - * @property {Float} aabox.width - Float with the axis-aligned width coordinate - * @property {Float} aabox.height - Float with the axis-aligned height coordinate - */ - - /** - * Transforms a rectangle based on the given matrix. - * @function module:math.transformBox - * @param {Float} l - Float with the box's left coordinate - * @param {Float} t - Float with the box's top coordinate - * @param {Float} w - Float with the box width - * @param {Float} h - Float with the box height - * @param {SVGMatrix} m - Matrix object to transform the box by - * @returns {module:math.TransformedBox} - */ - - var transformBox = function transformBox(l, t, w, h, m) { - var tl = transformPoint(l, t, m), - tr = transformPoint(l + w, t, m), - bl = transformPoint(l, t + h, m), - br = transformPoint(l + w, t + h, m), - minx = Math.min(tl.x, tr.x, bl.x, br.x), - maxx = Math.max(tl.x, tr.x, bl.x, br.x), - miny = Math.min(tl.y, tr.y, bl.y, br.y), - maxy = Math.max(tl.y, tr.y, bl.y, br.y); - return { - tl: tl, - tr: tr, - bl: bl, - br: br, - aabox: { - x: minx, - y: miny, - width: maxx - minx, - height: maxy - miny - } - }; - }; - /** - * This returns a single matrix Transform for a given Transform List - * (this is the equivalent of `SVGTransformList.consolidate()` but unlike - * that method, this one does not modify the actual `SVGTransformList`). - * This function is very liberal with its `min`, `max` arguments. - * @function module:math.transformListToTransform - * @param {SVGTransformList} tlist - The transformlist object - * @param {Integer} [min=0] - Optional integer indicating start transform position - * @param {Integer} [max] - Optional integer indicating end transform position; - * defaults to one less than the tlist's `numberOfItems` - * @returns {SVGTransform} A single matrix transform object - */ - - var transformListToTransform = function transformListToTransform(tlist, min, max) { - if (isNullish(tlist)) { - // Or should tlist = null have been prevented before this? - return svg$1.createSVGTransformFromMatrix(svg$1.createSVGMatrix()); - } - - min = min || 0; - max = max || tlist.numberOfItems - 1; - min = Number.parseInt(min); - max = Number.parseInt(max); - - if (min > max) { - var temp = max; - max = min; - min = temp; - } - - var m = svg$1.createSVGMatrix(); - - for (var i = min; i <= max; ++i) { - // if our indices are out of range, just use a harmless identity matrix - var mtom = i >= 0 && i < tlist.numberOfItems ? tlist.getItem(i).matrix : svg$1.createSVGMatrix(); - m = matrixMultiply(m, mtom); - } - - return svg$1.createSVGTransformFromMatrix(m); - }; - /** - * Get the matrix object for a given element. - * @function module:math.getMatrix - * @param {Element} elem - The DOM element to check - * @returns {SVGMatrix} The matrix object associated with the element's transformlist - */ - - var getMatrix = function getMatrix(elem) { - var tlist = getTransformList(elem); - return transformListToTransform(tlist).matrix; - }; - /** - * Returns a 45 degree angle coordinate associated with the two given - * coordinates. - * @function module:math.snapToAngle - * @param {Integer} x1 - First coordinate's x value - * @param {Integer} y1 - First coordinate's y value - * @param {Integer} x2 - Second coordinate's x value - * @param {Integer} y2 - Second coordinate's y value - * @returns {module:math.AngleCoord45} - */ - - var snapToAngle = function snapToAngle(x1, y1, x2, y2) { - var snap = Math.PI / 4; // 45 degrees - - var dx = x2 - x1; - var dy = y2 - y1; - var angle = Math.atan2(dy, dx); - var dist = Math.sqrt(dx * dx + dy * dy); - var snapangle = Math.round(angle / snap) * snap; - return { - x: x1 + dist * Math.cos(snapangle), - y: y1 + dist * Math.sin(snapangle), - a: snapangle - }; - }; - /** - * Check if two rectangles (BBoxes objects) intersect each other. - * @function module:math.rectsIntersect - * @param {SVGRect} r1 - The first BBox-like object - * @param {SVGRect} r2 - The second BBox-like object - * @returns {boolean} True if rectangles intersect - */ - - var rectsIntersect = function rectsIntersect(r1, r2) { - return r2.x < r1.x + r1.width && r2.x + r2.width > r1.x && r2.y < r1.y + r1.height && r2.y + r2.height > r1.y; - }; - - var $$1 = jQuery; - var segData = { + /* globals jQuery */ + const $$3 = jQuery; + const segData = { 2: ['x', 'y'], // PATHSEG_MOVETO_ABS 4: ['x', 'y'], @@ -5043,28 +6322,28 @@ * @property {PlainObject<string, string>} ui */ - var uiStrings = {}; + const uiStrings = {}; /** * @function module:path.setUiStrings * @param {module:path.uiStrings} strs * @returns {void} */ - var setUiStrings = function setUiStrings(strs) { + const setUiStrings = function (strs) { Object.assign(uiStrings, strs.ui); }; - var pathFuncs = []; - var linkControlPts = true; // Stores references to paths via IDs. + let pathFuncs = []; + let linkControlPts = true; // Stores references to paths via IDs. // TODO: Make this cross-document happy. - var pathData = {}; + let pathData = {}; /** * @function module:path.setLinkControlPoints * @param {boolean} lcp * @returns {void} */ - var setLinkControlPoints = function setLinkControlPoints(lcp) { + const setLinkControlPoints = function (lcp) { linkControlPts = lcp; }; /** @@ -5073,9 +6352,9 @@ * @memberof module:path */ - var path = null; // eslint-disable-line import/no-mutable-exports + let path = null; // eslint-disable-line import/no-mutable-exports - var editorContext_ = null; + let editorContext_$1 = null; /** * @external MouseEvent */ @@ -5259,11 +6538,11 @@ * @returns {void} */ - var init$1 = function init(editorContext) { - editorContext_ = editorContext; + const init$2 = function (editorContext) { + editorContext_$1 = editorContext; pathFuncs = [0, 'ClosePath']; - var pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', 'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth']; - $$1.each(pathFuncsStrs, function (i, s) { + const pathFuncsStrs = ['Moveto', 'Lineto', 'CurvetoCubic', 'CurvetoQuadratic', 'Arc', 'LinetoHorizontal', 'LinetoVertical', 'CurvetoCubicSmooth', 'CurvetoQuadraticSmooth']; + $$3.each(pathFuncsStrs, function (i, s) { pathFuncs.push(s + 'Abs'); pathFuncs.push(s + 'Rel'); }); @@ -5276,32 +6555,32 @@ * @returns {void} */ - var insertItemBefore = function insertItemBefore(elem, newseg, index) { + const insertItemBefore = function (elem, newseg, index) { // Support insertItemBefore on paths for FF2 - var list = elem.pathSegList; + const list = elem.pathSegList; if (supportsPathInsertItemBefore()) { list.insertItemBefore(newseg, index); return; } - var len = list.numberOfItems; - var arr = []; + const len = list.numberOfItems; + const arr = []; - for (var i = 0; i < len; i++) { - var curSeg = list.getItem(i); + for (let i = 0; i < len; i++) { + const curSeg = list.getItem(i); arr.push(curSeg); } list.clear(); - for (var _i = 0; _i < len; _i++) { - if (_i === index) { + for (let i = 0; i < len; i++) { + if (i === index) { // index + 1 list.appendItem(newseg); } - list.appendItem(arr[_i]); + list.appendItem(arr[i]); } }; /** @@ -5312,9 +6591,9 @@ * @returns {ArgumentsArray} */ - var ptObjToArr = function ptObjToArr(type, segItem) { - var props = segData[type]; - return props.map(function (prop) { + const ptObjToArr = function (type, segItem) { + const props = segData[type]; + return props.map(prop => { return segItem[prop]; }); }; @@ -5325,19 +6604,21 @@ * @returns {module:math.XYObject} */ - var getGripPt = function getGripPt(seg, altPt) { - var pth = seg.path; - var out = { + const getGripPt = function (seg, altPt) { + const { + path: pth + } = seg; + let out = { x: altPt ? altPt.x : seg.item.x, y: altPt ? altPt.y : seg.item.y }; if (pth.matrix) { - var pt = transformPoint(out.x, out.y, pth.matrix); + const pt = transformPoint(out.x, out.y, pth.matrix); out = pt; } - var currentZoom = editorContext_.getCurrentZoom(); + const currentZoom = editorContext_$1.getCurrentZoom(); out.x *= currentZoom; out.y *= currentZoom; return out; @@ -5349,8 +6630,8 @@ * @returns {module:math.XYObject} */ - var getPointFromGrip = function getPointFromGrip(pt, pth) { - var out = { + const getPointFromGrip = function (pt, pth) { + const out = { x: pt.x, y: pt.y }; @@ -5361,7 +6642,7 @@ out.y = pt.y; } - var currentZoom = editorContext_.getCurrentZoom(); + const currentZoom = editorContext_$1.getCurrentZoom(); out.x /= currentZoom; out.y /= currentZoom; return out; @@ -5376,14 +6657,14 @@ * @returns {SVGCircleElement} */ - var addPointGrip = function addPointGrip(index, x, y) { + const addPointGrip = function (index, x, y) { // create the container of all the point grips - var pointGripContainer = getGripContainer(); - var pointGrip = getElem('pathpointgrip_' + index); // create it + const pointGripContainer = getGripContainer(); + let pointGrip = getElem('pathpointgrip_' + index); // create it if (!pointGrip) { pointGrip = document.createElementNS(NS.SVG, 'circle'); - var atts = { + const atts = { id: 'pathpointgrip_' + index, display: 'none', r: 4, @@ -5401,7 +6682,7 @@ assignAttributes(pointGrip, atts); pointGrip = pointGripContainer.appendChild(pointGrip); - var grip = $$1('#pathpointgrip_' + index); + const grip = $$3('#pathpointgrip_' + index); grip.dblclick(function () { if (path) { path.setSegType(); @@ -5425,11 +6706,11 @@ * @returns {Element} */ - var getGripContainer = function getGripContainer() { - var c = getElem('pathpointgrip_container'); + const getGripContainer = function () { + let c = getElem('pathpointgrip_container'); if (!c) { - var parentElement = getElem('selectorParentGroup'); + const parentElement = getElem('selectorParentGroup'); c = parentElement.appendChild(document.createElementNS(NS.SVG, 'g')); c.id = 'pathpointgrip_container'; } @@ -5444,15 +6725,15 @@ * @returns {SVGCircleElement} */ - var addCtrlGrip = function addCtrlGrip(id) { - var pointGrip = getElem('ctrlpointgrip_' + id); + const addCtrlGrip = function (id) { + let pointGrip = getElem('ctrlpointgrip_' + id); if (pointGrip) { return pointGrip; } pointGrip = document.createElementNS(NS.SVG, 'circle'); - var atts = { + const atts = { id: 'ctrlpointgrip_' + id, display: 'none', r: 4, @@ -5478,8 +6759,8 @@ * @returns {SVGLineElement} */ - var getCtrlLine = function getCtrlLine(id) { - var ctrlLine = getElem('ctrlLine_' + id); + const getCtrlLine = function (id) { + let ctrlLine = getElem('ctrlLine_' + id); if (ctrlLine) { return ctrlLine; @@ -5502,12 +6783,14 @@ * @returns {SVGCircleElement} */ - var getPointGrip = function getPointGrip(seg, update) { - var index = seg.index; - var pointGrip = addPointGrip(index); + const getPointGrip = function (seg, update) { + const { + index + } = seg; + const pointGrip = addPointGrip(index); if (update) { - var pt = getGripPt(seg); + const pt = getGripPt(seg); assignAttributes(pointGrip, { cx: pt.x, cy: pt.y, @@ -5523,30 +6806,32 @@ * @returns {PlainObject<string, SVGLineElement|SVGCircleElement>} */ - var getControlPoints = function getControlPoints(seg) { - var item = seg.item, - index = seg.index; + const getControlPoints = function (seg) { + const { + item, + index + } = seg; if (!('x1' in item) || !('x2' in item)) { return null; } - var cpt = {}; + const cpt = {}; /* const pointGripContainer = */ getGripContainer(); // Note that this is intentionally not seg.prev.item - var prev = path.segs[index - 1].item; - var segItems = [prev, item]; + const prev = path.segs[index - 1].item; + const segItems = [prev, item]; - for (var i = 1; i < 3; i++) { - var id = index + 'c' + i; - var ctrlLine = cpt['c' + i + '_line'] = getCtrlLine(id); - var pt = getGripPt(seg, { + for (let i = 1; i < 3; i++) { + const id = index + 'c' + i; + const ctrlLine = cpt['c' + i + '_line'] = getCtrlLine(id); + const pt = getGripPt(seg, { x: item['x' + i], y: item['y' + i] }); - var gpt = getGripPt(seg, { + const gpt = getGripPt(seg, { x: segItems[i - 1].x, y: segItems[i - 1].y }); @@ -5559,7 +6844,7 @@ }); cpt['c' + i + '_line'] = ctrlLine; // create it - var pointGrip = cpt['c' + i] = addCtrlGrip(id); + const pointGrip = cpt['c' + i] = addCtrlGrip(id); assignAttributes(pointGrip, { cx: pt.x, cy: pt.y, @@ -5580,30 +6865,30 @@ * @returns {void} */ - var replacePathSeg = function replacePathSeg(type, index, pts, elem) { - var pth = elem || path.elem; - var func = 'createSVGPathSeg' + pathFuncs[type]; - var seg = pth[func].apply(pth, _toConsumableArray(pts)); + const replacePathSeg = function (type, index, pts, elem) { + const pth = elem || path.elem; + const func = 'createSVGPathSeg' + pathFuncs[type]; + const seg = pth[func](...pts); if (supportsPathReplaceItem()) { pth.pathSegList.replaceItem(seg, index); } else { - var segList = pth.pathSegList; - var len = segList.numberOfItems; - var arr = []; + const segList = pth.pathSegList; + const len = segList.numberOfItems; + const arr = []; - for (var i = 0; i < len; i++) { - var curSeg = segList.getItem(i); + for (let i = 0; i < len; i++) { + const curSeg = segList.getItem(i); arr.push(curSeg); } segList.clear(); - for (var _i2 = 0; _i2 < len; _i2++) { - if (_i2 === index) { + for (let i = 0; i < len; i++) { + if (i === index) { segList.appendItem(seg); } else { - segList.appendItem(arr[_i2]); + segList.appendItem(arr[i]); } } } @@ -5615,12 +6900,14 @@ * @returns {SVGPathElement} */ - var getSegSelector = function getSegSelector(seg, update) { - var index = seg.index; - var segLine = getElem('segline_' + index); + const getSegSelector = function (seg, update) { + const { + index + } = seg; + let segLine = getElem('segline_' + index); if (!segLine) { - var pointGripContainer = getGripContainer(); // create segline + const pointGripContainer = getGripContainer(); // create segline segLine = document.createElementNS(NS.SVG, 'path'); assignAttributes(segLine, { @@ -5636,20 +6923,22 @@ } if (update) { - var prev = seg.prev; + const { + prev + } = seg; if (!prev) { segLine.setAttribute('display', 'none'); return segLine; } - var pt = getGripPt(prev); // Set start point + const pt = getGripPt(prev); // Set start point replacePathSeg(2, 0, [pt.x, pt.y], segLine); - var pts = ptObjToArr(seg.type, seg.item); // , true); + const pts = ptObjToArr(seg.type, seg.item); // , true); - for (var i = 0; i < pts.length; i += 2) { - var point = getGripPt(seg, { + for (let i = 0; i < pts.length; i += 2) { + const point = getGripPt(seg, { x: pts[i], y: pts[i + 1] }); @@ -5677,19 +6966,19 @@ * @returns {Point[]} Array of two "smoothed" point objects */ - var smoothControlPoints = function smoothControlPoints(ct1, ct2, pt) { + const smoothControlPoints = function (ct1, ct2, pt) { // each point must not be the origin - var x1 = ct1.x - pt.x, - y1 = ct1.y - pt.y, - x2 = ct2.x - pt.x, - y2 = ct2.y - pt.y; + const x1 = ct1.x - pt.x, + y1 = ct1.y - pt.y, + x2 = ct2.x - pt.x, + y2 = ct2.y - pt.y; if ((x1 !== 0 || y1 !== 0) && (x2 !== 0 || y2 !== 0)) { - var r1 = Math.sqrt(x1 * x1 + y1 * y1), - r2 = Math.sqrt(x2 * x2 + y2 * y2), - nct1 = editorContext_.getSVGRoot().createSVGPoint(), - nct2 = editorContext_.getSVGRoot().createSVGPoint(); - var anglea = Math.atan2(y1, x1), + const r1 = Math.sqrt(x1 * x1 + y1 * y1), + r2 = Math.sqrt(x2 * x2 + y2 * y2), + nct1 = editorContext_$1.getSVGRoot().createSVGPoint(), + nct2 = editorContext_$1.getSVGRoot().createSVGPoint(); + let anglea = Math.atan2(y1, x1), angleb = Math.atan2(y2, x2); if (anglea < 0) { @@ -5700,9 +6989,9 @@ angleb += 2 * Math.PI; } - var angleBetween = Math.abs(anglea - angleb), - angleDiff = Math.abs(Math.PI - angleBetween) / 2; - var newAnglea, newAngleb; + const angleBetween = Math.abs(anglea - angleb), + angleDiff = Math.abs(Math.PI - angleBetween) / 2; + let newAnglea, newAngleb; if (anglea - angleb > 0) { newAnglea = angleBetween < Math.PI ? anglea + angleDiff : anglea - angleDiff; @@ -5726,15 +7015,13 @@ * */ - var Segment = /*#__PURE__*/function () { + class Segment { /** * @param {Integer} index * @param {SVGPathSeg} item * @todo Is `item` be more constrained here? */ - function Segment(index, item) { - _classCallCheck(this, Segment); - + constructor(index, item) { this.selected = false; this.index = index; this.item = item; @@ -5749,219 +7036,211 @@ */ - _createClass(Segment, [{ - key: "showCtrlPts", - value: function showCtrlPts(y) { - for (var i in this.ctrlpts) { - if ({}.hasOwnProperty.call(this.ctrlpts, i)) { - this.ctrlpts[i].setAttribute('display', y ? 'inline' : 'none'); - } + showCtrlPts(y) { + for (const i in this.ctrlpts) { + if ({}.hasOwnProperty.call(this.ctrlpts, i)) { + this.ctrlpts[i].setAttribute('display', y ? 'inline' : 'none'); } } - /** - * @param {boolean} y - * @returns {void} - */ + } + /** + * @param {boolean} y + * @returns {void} + */ - }, { - key: "selectCtrls", - value: function selectCtrls(y) { - $$1('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2').attr('fill', y ? '#0FF' : '#EEE'); + + selectCtrls(y) { + $$3('#ctrlpointgrip_' + this.index + 'c1, #ctrlpointgrip_' + this.index + 'c2').attr('fill', y ? '#0FF' : '#EEE'); + } + /** + * @param {boolean} y + * @returns {void} + */ + + + show(y) { + if (this.ptgrip) { + this.ptgrip.setAttribute('display', y ? 'inline' : 'none'); + this.segsel.setAttribute('display', y ? 'inline' : 'none'); // Show/hide all control points if available + + this.showCtrlPts(y); } - /** - * @param {boolean} y - * @returns {void} - */ + } + /** + * @param {boolean} y + * @returns {void} + */ - }, { - key: "show", - value: function show(y) { - if (this.ptgrip) { - this.ptgrip.setAttribute('display', y ? 'inline' : 'none'); - this.segsel.setAttribute('display', y ? 'inline' : 'none'); // Show/hide all control points if available - this.showCtrlPts(y); + select(y) { + if (this.ptgrip) { + this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F'); + this.segsel.setAttribute('display', y ? 'inline' : 'none'); + + if (this.ctrlpts) { + this.selectCtrls(y); } + + this.selected = y; } - /** - * @param {boolean} y - * @returns {void} - */ + } + /** + * @returns {void} + */ - }, { - key: "select", - value: function select(y) { - if (this.ptgrip) { - this.ptgrip.setAttribute('stroke', y ? '#0FF' : '#00F'); - this.segsel.setAttribute('display', y ? 'inline' : 'none'); - if (this.ctrlpts) { - this.selectCtrls(y); + addGrip() { + this.ptgrip = getPointGrip(this, true); + this.ctrlpts = getControlPoints(this); // , true); + + this.segsel = getSegSelector(this, true); + } + /** + * @param {boolean} full + * @returns {void} + */ + + + update(full) { + if (this.ptgrip) { + const pt = getGripPt(this); + assignAttributes(this.ptgrip, { + cx: pt.x, + cy: pt.y + }); + getSegSelector(this, true); + + if (this.ctrlpts) { + if (full) { + this.item = path.elem.pathSegList.getItem(this.index); + this.type = this.item.pathSegType; } - this.selected = y; - } + getControlPoints(this); + } // this.segsel.setAttribute('display', y ? 'inline' : 'none'); + } - /** - * @returns {void} - */ + } + /** + * @param {Integer} dx + * @param {Integer} dy + * @returns {void} + */ - }, { - key: "addGrip", - value: function addGrip() { - this.ptgrip = getPointGrip(this, true); - this.ctrlpts = getControlPoints(this); // , true); - this.segsel = getSegSelector(this, true); + move(dx, dy) { + const { + item + } = this; + const curPts = this.ctrlpts ? [item.x += dx, item.y += dy, item.x1, item.y1, item.x2 += dx, item.y2 += dy] : [item.x += dx, item.y += dy]; + replacePathSeg(this.type, this.index, // type 10 means ARC + this.type === 10 ? ptObjToArr(this.type, item) : curPts); + + if (this.next && this.next.ctrlpts) { + const next = this.next.item; + const nextPts = [next.x, next.y, next.x1 += dx, next.y1 += dy, next.x2, next.y2]; + replacePathSeg(this.next.type, this.next.index, nextPts); } - /** - * @param {boolean} full - * @returns {void} - */ - }, { - key: "update", - value: function update(full) { - if (this.ptgrip) { - var pt = getGripPt(this); - assignAttributes(this.ptgrip, { - cx: pt.x, - cy: pt.y - }); - getSegSelector(this, true); - - if (this.ctrlpts) { - if (full) { - this.item = path.elem.pathSegList.getItem(this.index); - this.type = this.item.pathSegType; - } - - getControlPoints(this); - } // this.segsel.setAttribute('display', y ? 'inline' : 'none'); - - } + if (this.mate) { + // The last point of a closed subpath has a 'mate', + // which is the 'M' segment of the subpath + const { + item: itm + } = this.mate; + const pts = [itm.x += dx, itm.y += dy]; + replacePathSeg(this.mate.type, this.mate.index, pts); // Has no grip, so does not need 'updating'? } - /** - * @param {Integer} dx - * @param {Integer} dy - * @returns {void} - */ - }, { - key: "move", - value: function move(dx, dy) { - var item = this.item; - var curPts = this.ctrlpts ? [item.x += dx, item.y += dy, item.x1, item.y1, item.x2 += dx, item.y2 += dy] : [item.x += dx, item.y += dy]; - replacePathSeg(this.type, this.index, // type 10 means ARC - this.type === 10 ? ptObjToArr(this.type, item) : curPts); + this.update(true); - if (this.next && this.next.ctrlpts) { - var next = this.next.item; - var nextPts = [next.x, next.y, next.x1 += dx, next.y1 += dy, next.x2, next.y2]; - replacePathSeg(this.next.type, this.next.index, nextPts); + if (this.next) { + this.next.update(true); + } + } + /** + * @param {Integer} num + * @returns {void} + */ + + + setLinked(num) { + let seg, anum, pt; + + if (num === 2) { + anum = 1; + seg = this.next; + + if (!seg) { + return; } - if (this.mate) { - // The last point of a closed subpath has a 'mate', - // which is the 'M' segment of the subpath - var itm = this.mate.item; - var pts = [itm.x += dx, itm.y += dy]; - replacePathSeg(this.mate.type, this.mate.index, pts); // Has no grip, so does not need 'updating'? + pt = this.item; + } else { + anum = 2; + seg = this.prev; + + if (!seg) { + return; } - this.update(true); - - if (this.next) { - this.next.update(true); - } + pt = seg.item; } - /** - * @param {Integer} num - * @returns {void} - */ - }, { - key: "setLinked", - value: function setLinked(num) { - var seg, anum, pt; + const { + item + } = seg; + item['x' + anum] = pt.x + (pt.x - this.item['x' + num]); + item['y' + anum] = pt.y + (pt.y - this.item['y' + num]); + const pts = [item.x, item.y, item.x1, item.y1, item.x2, item.y2]; + replacePathSeg(seg.type, seg.index, pts); + seg.update(true); + } + /** + * @param {Integer} num + * @param {Integer} dx + * @param {Integer} dy + * @returns {void} + */ - if (num === 2) { - anum = 1; - seg = this.next; - if (!seg) { - return; - } + moveCtrl(num, dx, dy) { + const { + item + } = this; + item['x' + num] += dx; + item['y' + num] += dy; + const pts = [item.x, item.y, item.x1, item.y1, item.x2, item.y2]; + replacePathSeg(this.type, this.index, pts); + this.update(true); + } + /** + * @param {Integer} newType Possible values set during {@link module:path.init} + * @param {ArgumentsArray} pts + * @returns {void} + */ - pt = this.item; - } else { - anum = 2; - seg = this.prev; - if (!seg) { - return; - } + setType(newType, pts) { + replacePathSeg(newType, this.index, pts); + this.type = newType; + this.item = path.elem.pathSegList.getItem(this.index); + this.showCtrlPts(newType === 6); + this.ctrlpts = getControlPoints(this); + this.update(true); + } - pt = seg.item; - } - - var _seg = seg, - item = _seg.item; - item['x' + anum] = pt.x + (pt.x - this.item['x' + num]); - item['y' + anum] = pt.y + (pt.y - this.item['y' + num]); - var pts = [item.x, item.y, item.x1, item.y1, item.x2, item.y2]; - replacePathSeg(seg.type, seg.index, pts); - seg.update(true); - } - /** - * @param {Integer} num - * @param {Integer} dx - * @param {Integer} dy - * @returns {void} - */ - - }, { - key: "moveCtrl", - value: function moveCtrl(num, dx, dy) { - var item = this.item; - item['x' + num] += dx; - item['y' + num] += dy; - var pts = [item.x, item.y, item.x1, item.y1, item.x2, item.y2]; - replacePathSeg(this.type, this.index, pts); - this.update(true); - } - /** - * @param {Integer} newType Possible values set during {@link module:path.init} - * @param {ArgumentsArray} pts - * @returns {void} - */ - - }, { - key: "setType", - value: function setType(newType, pts) { - replacePathSeg(newType, this.index, pts); - this.type = newType; - this.item = path.elem.pathSegList.getItem(this.index); - this.showCtrlPts(newType === 6); - this.ctrlpts = getControlPoints(this); - this.update(true); - } - }]); - - return Segment; - }(); + } /** * */ - var Path = /*#__PURE__*/function () { + class Path { /** * @param {SVGPathElement} elem * @throws {Error} If constructed without a path element */ - function Path(elem) { - _classCallCheck(this, Path); - + constructor(elem) { if (!elem || elem.tagName !== 'path') { throw new Error('svgedit.path.Path constructed without a <path> element'); } @@ -5979,525 +7258,512 @@ */ - _createClass(Path, [{ - key: "init", - value: function init() { - // Hide all grips, etc - // fixed, needed to work on all found elements, not just first - $$1(getGripContainer()).find('*').each(function () { - $$1(this).attr('display', 'none'); - }); - var segList = this.elem.pathSegList; - var len = segList.numberOfItems; - this.segs = []; - this.selected_pts = []; - this.first_seg = null; // Set up segs array + init() { + // Hide all grips, etc + // fixed, needed to work on all found elements, not just first + $$3(getGripContainer()).find('*').each(function () { + $$3(this).attr('display', 'none'); + }); + const segList = this.elem.pathSegList; + const len = segList.numberOfItems; + this.segs = []; + this.selected_pts = []; + this.first_seg = null; // Set up segs array - for (var i = 0; i < len; i++) { - var item = segList.getItem(i); - var segment = new Segment(i, item); - segment.path = this; - this.segs.push(segment); - } + for (let i = 0; i < len; i++) { + const item = segList.getItem(i); + const segment = new Segment(i, item); + segment.path = this; + this.segs.push(segment); + } - var segs = this.segs; - var startI = null; + const { + segs + } = this; + let startI = null; - for (var _i3 = 0; _i3 < len; _i3++) { - var seg = segs[_i3]; - var nextSeg = _i3 + 1 >= len ? null : segs[_i3 + 1]; - var prevSeg = _i3 - 1 < 0 ? null : segs[_i3 - 1]; + for (let i = 0; i < len; i++) { + const seg = segs[i]; + const nextSeg = i + 1 >= len ? null : segs[i + 1]; + const prevSeg = i - 1 < 0 ? null : segs[i - 1]; - if (seg.type === 2) { - if (prevSeg && prevSeg.type !== 1) { - // New sub-path, last one is open, - // so add a grip to last sub-path's first point - var startSeg = segs[startI]; - startSeg.next = segs[startI + 1]; - startSeg.next.prev = startSeg; - startSeg.addGrip(); - } // Remember that this is a starter seg + if (seg.type === 2) { + if (prevSeg && prevSeg.type !== 1) { + // New sub-path, last one is open, + // so add a grip to last sub-path's first point + const startSeg = segs[startI]; + startSeg.next = segs[startI + 1]; + startSeg.next.prev = startSeg; + startSeg.addGrip(); + } // Remember that this is a starter seg - startI = _i3; - } else if (nextSeg && nextSeg.type === 1) { - // This is the last real segment of a closed sub-path - // Next is first seg after "M" - seg.next = segs[startI + 1]; // First seg after "M"'s prev is this + startI = i; + } else if (nextSeg && nextSeg.type === 1) { + // This is the last real segment of a closed sub-path + // Next is first seg after "M" + seg.next = segs[startI + 1]; // First seg after "M"'s prev is this - seg.next.prev = seg; - seg.mate = segs[startI]; + seg.next.prev = seg; + seg.mate = segs[startI]; + seg.addGrip(); + + if (isNullish(this.first_seg)) { + this.first_seg = seg; + } + } else if (!nextSeg) { + if (seg.type !== 1) { + // Last seg, doesn't close so add a grip + // to last sub-path's first point + const startSeg = segs[startI]; + startSeg.next = segs[startI + 1]; + startSeg.next.prev = startSeg; + startSeg.addGrip(); seg.addGrip(); - if (isNullish(this.first_seg)) { - this.first_seg = seg; - } - } else if (!nextSeg) { - if (seg.type !== 1) { - // Last seg, doesn't close so add a grip - // to last sub-path's first point - var _startSeg = segs[startI]; - _startSeg.next = segs[startI + 1]; - _startSeg.next.prev = _startSeg; - - _startSeg.addGrip(); - - seg.addGrip(); - - if (!this.first_seg) { - // Open path, so set first as real first and add grip - this.first_seg = segs[startI]; - } - } - } else if (seg.type !== 1) { - // Regular segment, so add grip and its "next" - seg.addGrip(); // Don't set its "next" if it's an "M" - - if (nextSeg && nextSeg.type !== 2) { - seg.next = nextSeg; - seg.next.prev = seg; + if (!this.first_seg) { + // Open path, so set first as real first and add grip + this.first_seg = segs[startI]; } } + } else if (seg.type !== 1) { + // Regular segment, so add grip and its "next" + seg.addGrip(); // Don't set its "next" if it's an "M" + + if (nextSeg && nextSeg.type !== 2) { + seg.next = nextSeg; + seg.next.prev = seg; + } } - - return this; } - /** - * @callback module:path.PathEachSegCallback - * @this module:path.Segment - * @param {Integer} i The index of the seg being iterated - * @returns {boolean|void} Will stop execution of `eachSeg` if returns `false` - */ - /** - * @param {module:path.PathEachSegCallback} fn - * @returns {void} - */ + return this; + } + /** + * @callback module:path.PathEachSegCallback + * @this module:path.Segment + * @param {Integer} i The index of the seg being iterated + * @returns {boolean|void} Will stop execution of `eachSeg` if returns `false` + */ - }, { - key: "eachSeg", - value: function eachSeg(fn) { - var len = this.segs.length; + /** + * @param {module:path.PathEachSegCallback} fn + * @returns {void} + */ - for (var i = 0; i < len; i++) { - var ret = fn.call(this.segs[i], i); - if (ret === false) { + eachSeg(fn) { + const len = this.segs.length; + + for (let i = 0; i < len; i++) { + const ret = fn.call(this.segs[i], i); + + if (ret === false) { + break; + } + } + } + /** + * @param {Integer} index + * @returns {void} + */ + + + addSeg(index) { + // Adds a new segment + const seg = this.segs[index]; + + if (!seg.prev) { + return; + } + + const { + prev + } = seg; + let newseg, newX, newY; + + switch (seg.item.pathSegType) { + case 4: + { + newX = (seg.item.x + prev.item.x) / 2; + newY = (seg.item.y + prev.item.y) / 2; + newseg = this.elem.createSVGPathSegLinetoAbs(newX, newY); + break; + } + + case 6: + { + // make it a curved segment to preserve the shape (WRS) + // https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation + const p0x = (prev.item.x + seg.item.x1) / 2; + const p1x = (seg.item.x1 + seg.item.x2) / 2; + const p2x = (seg.item.x2 + seg.item.x) / 2; + const p01x = (p0x + p1x) / 2; + const p12x = (p1x + p2x) / 2; + newX = (p01x + p12x) / 2; + const p0y = (prev.item.y + seg.item.y1) / 2; + const p1y = (seg.item.y1 + seg.item.y2) / 2; + const p2y = (seg.item.y2 + seg.item.y) / 2; + const p01y = (p0y + p1y) / 2; + const p12y = (p1y + p2y) / 2; + newY = (p01y + p12y) / 2; + newseg = this.elem.createSVGPathSegCurvetoCubicAbs(newX, newY, p0x, p0y, p01x, p01y); + const pts = [seg.item.x, seg.item.y, p12x, p12y, p2x, p2y]; + replacePathSeg(seg.type, index, pts); break; } - } } - /** - * @param {Integer} index - * @returns {void} - */ - }, { - key: "addSeg", - value: function addSeg(index) { - // Adds a new segment - var seg = this.segs[index]; + insertItemBefore(this.elem, newseg, index); + } + /** + * @param {Integer} index + * @returns {void} + */ - if (!seg.prev) { - return; + + deleteSeg(index) { + const seg = this.segs[index]; + const list = this.elem.pathSegList; + seg.show(false); + const { + next + } = seg; + + if (seg.mate) { + // Make the next point be the "M" point + const pt = [next.item.x, next.item.y]; + replacePathSeg(2, next.index, pt); // Reposition last node + + replacePathSeg(4, seg.index, pt); + list.removeItem(seg.mate.index); + } else if (!seg.prev) { + // First node of open path, make next point the M + // const {item} = seg; + const pt = [next.item.x, next.item.y]; + replacePathSeg(2, seg.next.index, pt); + list.removeItem(index); + } else { + list.removeItem(index); + } + } + /** + * @param {Integer} index + * @returns {void} + */ + + + removePtFromSelection(index) { + const pos = this.selected_pts.indexOf(index); + + if (pos === -1) { + return; + } + + this.segs[index].select(false); + this.selected_pts.splice(pos, 1); + } + /** + * @returns {void} + */ + + + clearSelection() { + this.eachSeg(function () { + // 'this' is the segment here + this.select(false); + }); + this.selected_pts = []; + } + /** + * @returns {void} + */ + + + storeD() { + this.last_d = this.elem.getAttribute('d'); + } + /** + * @param {Integer} y + * @returns {Path} + */ + + + show(y) { + // Shows this path's segment grips + this.eachSeg(function () { + // 'this' is the segment here + this.show(y); + }); + + if (y) { + this.selectPt(this.first_seg.index); + } + + return this; + } + /** + * Move selected points. + * @param {Integer} dx + * @param {Integer} dy + * @returns {void} + */ + + + movePts(dx, dy) { + let i = this.selected_pts.length; + + while (i--) { + const seg = this.segs[this.selected_pts[i]]; + seg.move(dx, dy); + } + } + /** + * @param {Integer} dx + * @param {Integer} dy + * @returns {void} + */ + + + moveCtrl(dx, dy) { + const seg = this.segs[this.selected_pts[0]]; + seg.moveCtrl(this.dragctrl, dx, dy); + + if (linkControlPts) { + seg.setLinked(this.dragctrl); + } + } + /** + * @param {?Integer} newType See {@link https://www.w3.org/TR/SVG/single-page.html#paths-InterfaceSVGPathSeg} + * @returns {void} + */ + + + setSegType(newType) { + this.storeD(); + let i = this.selected_pts.length; + let text; + + while (i--) { + const selPt = this.selected_pts[i]; // Selected seg + + const cur = this.segs[selPt]; + const { + prev + } = cur; + + if (!prev) { + continue; } - var prev = seg.prev; - var newseg, newX, newY; + if (!newType) { + // double-click, so just toggle + text = 'Toggle Path Segment Type'; // Toggle segment to curve/straight line - switch (seg.item.pathSegType) { - case 4: - { - newX = (seg.item.x + prev.item.x) / 2; - newY = (seg.item.y + prev.item.y) / 2; - newseg = this.elem.createSVGPathSegLinetoAbs(newX, newY); - break; - } + const oldType = cur.type; + newType = oldType === 6 ? 4 : 6; + } + newType = Number(newType); + const curX = cur.item.x; + const curY = cur.item.y; + const prevX = prev.item.x; + const prevY = prev.item.y; + let points; + + switch (newType) { case 6: { - // make it a curved segment to preserve the shape (WRS) - // https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm#Geometric_interpretation - var p0x = (prev.item.x + seg.item.x1) / 2; - var p1x = (seg.item.x1 + seg.item.x2) / 2; - var p2x = (seg.item.x2 + seg.item.x) / 2; - var p01x = (p0x + p1x) / 2; - var p12x = (p1x + p2x) / 2; - newX = (p01x + p12x) / 2; - var p0y = (prev.item.y + seg.item.y1) / 2; - var p1y = (seg.item.y1 + seg.item.y2) / 2; - var p2y = (seg.item.y2 + seg.item.y) / 2; - var p01y = (p0y + p1y) / 2; - var p12y = (p1y + p2y) / 2; - newY = (p01y + p12y) / 2; - newseg = this.elem.createSVGPathSegCurvetoCubicAbs(newX, newY, p0x, p0y, p01x, p01y); - var pts = [seg.item.x, seg.item.y, p12x, p12y, p2x, p2y]; - replacePathSeg(seg.type, index, pts); + if (cur.olditem) { + const old = cur.olditem; + points = [curX, curY, old.x1, old.y1, old.x2, old.y2]; + } else { + const diffX = curX - prevX; + const diffY = curY - prevY; // get control points from straight line segment + + /* + const ct1x = (prevX + (diffY/2)); + const ct1y = (prevY - (diffX/2)); + const ct2x = (curX + (diffY/2)); + const ct2y = (curY - (diffX/2)); + */ + // create control points on the line to preserve the shape (WRS) + + const ct1x = prevX + diffX / 3; + const ct1y = prevY + diffY / 3; + const ct2x = curX - diffX / 3; + const ct2y = curY - diffY / 3; + points = [curX, curY, ct1x, ct1y, ct2x, ct2y]; + } + + break; + } + + case 4: + { + points = [curX, curY]; // Store original prevve segment nums + + cur.olditem = cur.item; break; } } - insertItemBefore(this.elem, newseg, index); + cur.setType(newType, points); } - /** - * @param {Integer} index - * @returns {void} - */ - }, { - key: "deleteSeg", - value: function deleteSeg(index) { - var seg = this.segs[index]; - var list = this.elem.pathSegList; - seg.show(false); - var next = seg.next; + path.endChanges(text); + } + /** + * @param {Integer} pt + * @param {Integer} ctrlNum + * @returns {void} + */ - if (seg.mate) { - // Make the next point be the "M" point - var pt = [next.item.x, next.item.y]; - replacePathSeg(2, next.index, pt); // Reposition last node - replacePathSeg(4, seg.index, pt); - list.removeItem(seg.mate.index); - } else if (!seg.prev) { - // First node of open path, make next point the M - // const {item} = seg; - var _pt = [next.item.x, next.item.y]; - replacePathSeg(2, seg.next.index, _pt); - list.removeItem(index); - } else { - list.removeItem(index); - } - } - /** - * @param {Integer} index - * @returns {void} - */ + selectPt(pt, ctrlNum) { + this.clearSelection(); - }, { - key: "removePtFromSelection", - value: function removePtFromSelection(index) { - var pos = this.selected_pts.indexOf(index); - - if (pos === -1) { - return; - } - - this.segs[index].select(false); - this.selected_pts.splice(pos, 1); - } - /** - * @returns {void} - */ - - }, { - key: "clearSelection", - value: function clearSelection() { - this.eachSeg(function () { - // 'this' is the segment here - this.select(false); + if (isNullish(pt)) { + this.eachSeg(function (i) { + // 'this' is the segment here. + if (this.prev) { + pt = i; + } }); - this.selected_pts = []; } - /** - * @returns {void} - */ - }, { - key: "storeD", - value: function storeD() { - this.last_d = this.elem.getAttribute('d'); - } - /** - * @param {Integer} y - * @returns {Path} - */ + this.addPtsToSelection(pt); - }, { - key: "show", - value: function show(y) { - // Shows this path's segment grips - this.eachSeg(function () { - // 'this' is the segment here - this.show(y); - }); - - if (y) { - this.selectPt(this.first_seg.index); - } - - return this; - } - /** - * Move selected points. - * @param {Integer} dx - * @param {Integer} dy - * @returns {void} - */ - - }, { - key: "movePts", - value: function movePts(dx, dy) { - var i = this.selected_pts.length; - - while (i--) { - var seg = this.segs[this.selected_pts[i]]; - seg.move(dx, dy); - } - } - /** - * @param {Integer} dx - * @param {Integer} dy - * @returns {void} - */ - - }, { - key: "moveCtrl", - value: function moveCtrl(dx, dy) { - var seg = this.segs[this.selected_pts[0]]; - seg.moveCtrl(this.dragctrl, dx, dy); + if (ctrlNum) { + this.dragctrl = ctrlNum; if (linkControlPts) { - seg.setLinked(this.dragctrl); + this.segs[pt].setLinked(ctrlNum); } } - /** - * @param {?Integer} newType See {@link https://www.w3.org/TR/SVG/single-page.html#paths-InterfaceSVGPathSeg} - * @returns {void} - */ + } + /** + * Update position of all points. + * @returns {Path} + */ - }, { - key: "setSegType", - value: function setSegType(newType) { - this.storeD(); - var i = this.selected_pts.length; - var text; - while (i--) { - var selPt = this.selected_pts[i]; // Selected seg + update() { + const { + elem + } = this; - var cur = this.segs[selPt]; - var prev = cur.prev; - - if (!prev) { - continue; - } - - if (!newType) { - // double-click, so just toggle - text = 'Toggle Path Segment Type'; // Toggle segment to curve/straight line - - var oldType = cur.type; - newType = oldType === 6 ? 4 : 6; - } - - newType = Number(newType); - var curX = cur.item.x; - var curY = cur.item.y; - var prevX = prev.item.x; - var prevY = prev.item.y; - var points = void 0; - - switch (newType) { - case 6: - { - if (cur.olditem) { - var old = cur.olditem; - points = [curX, curY, old.x1, old.y1, old.x2, old.y2]; - } else { - var diffX = curX - prevX; - var diffY = curY - prevY; // get control points from straight line segment - - /* - const ct1x = (prevX + (diffY/2)); - const ct1y = (prevY - (diffX/2)); - const ct2x = (curX + (diffY/2)); - const ct2y = (curY - (diffX/2)); - */ - // create control points on the line to preserve the shape (WRS) - - var ct1x = prevX + diffX / 3; - var ct1y = prevY + diffY / 3; - var ct2x = curX - diffX / 3; - var ct2y = curY - diffY / 3; - points = [curX, curY, ct1x, ct1y, ct2x, ct2y]; - } - - break; - } - - case 4: - { - points = [curX, curY]; // Store original prevve segment nums - - cur.olditem = cur.item; - break; - } - } - - cur.setType(newType, points); - } - - path.endChanges(text); + if (getRotationAngle(elem)) { + this.matrix = getMatrix(elem); + this.imatrix = this.matrix.inverse(); + } else { + this.matrix = null; + this.imatrix = null; } - /** - * @param {Integer} pt - * @param {Integer} ctrlNum - * @returns {void} - */ - }, { - key: "selectPt", - value: function selectPt(pt, ctrlNum) { - this.clearSelection(); + this.eachSeg(function (i) { + this.item = elem.pathSegList.getItem(i); + this.update(); + }); + return this; + } + /** + * @param {string} text + * @returns {void} + */ - if (isNullish(pt)) { - this.eachSeg(function (i) { - // 'this' is the segment here. - if (this.prev) { - pt = i; - } - }); - } - this.addPtsToSelection(pt); - - if (ctrlNum) { - this.dragctrl = ctrlNum; - - if (linkControlPts) { - this.segs[pt].setLinked(ctrlNum); - } - } + endChanges(text) { + if (isWebkit()) { + editorContext_$1.resetD(this.elem); } - /** - * Update position of all points. - * @returns {Path} - */ - }, { - key: "update", - value: function update() { - var elem = this.elem; + const cmd = new ChangeElementCommand(this.elem, { + d: this.last_d + }, text); + editorContext_$1.endChanges({ + cmd, + elem: this.elem + }); + } + /** + * @param {Integer|Integer[]} indexes + * @returns {void} + */ - if (getRotationAngle(elem)) { - this.matrix = getMatrix(elem); - this.imatrix = this.matrix.inverse(); - } else { - this.matrix = null; - this.imatrix = null; - } - this.eachSeg(function (i) { - this.item = elem.pathSegList.getItem(i); - this.update(); - }); - return this; + addPtsToSelection(indexes) { + if (!Array.isArray(indexes)) { + indexes = [indexes]; } - /** - * @param {string} text - * @returns {void} - */ - }, { - key: "endChanges", - value: function endChanges(text) { - if (isWebkit()) { - editorContext_.resetD(this.elem); + indexes.forEach(index => { + const seg = this.segs[index]; + + if (seg.ptgrip) { + if (!this.selected_pts.includes(index) && index >= 0) { + this.selected_pts.push(index); + } } + }); + this.selected_pts.sort(); + let i = this.selected_pts.length; + const grips = []; + grips.length = i; // Loop through points to be selected and highlight each - var cmd = new ChangeElementCommand(this.elem, { - d: this.last_d - }, text); - editorContext_.endChanges({ - cmd: cmd, - elem: this.elem - }); + while (i--) { + const pt = this.selected_pts[i]; + const seg = this.segs[pt]; + seg.select(true); + grips[i] = seg.ptgrip; } - /** - * @param {Integer|Integer[]} indexes - * @returns {void} - */ - }, { - key: "addPtsToSelection", - value: function addPtsToSelection(indexes) { - var _this = this; + const closedSubpath = Path.subpathIsClosed(this.selected_pts[0]); + editorContext_$1.addPtsToSelection({ + grips, + closedSubpath + }); + } // STATIC - if (!Array.isArray(indexes)) { - indexes = [indexes]; - } + /** + * @param {Integer} index + * @returns {boolean} + */ - indexes.forEach(function (index) { - var seg = _this.segs[index]; - if (seg.ptgrip) { - if (!_this.selected_pts.includes(index) && index >= 0) { - _this.selected_pts.push(index); - } - } - }); - this.selected_pts.sort(); - var i = this.selected_pts.length; - var grips = []; - grips.length = i; // Loop through points to be selected and highlight each - - while (i--) { - var pt = this.selected_pts[i]; - var seg = this.segs[pt]; - seg.select(true); - grips[i] = seg.ptgrip; - } - - var closedSubpath = Path.subpathIsClosed(this.selected_pts[0]); - editorContext_.addPtsToSelection({ - grips: grips, - closedSubpath: closedSubpath - }); - } // STATIC - - /** - * @param {Integer} index - * @returns {boolean} - */ - - }], [{ - key: "subpathIsClosed", - value: function subpathIsClosed(index) { - var clsd = false; // Check if subpath is already open - - path.eachSeg(function (i) { - if (i <= index) { - return true; - } - - if (this.type === 2) { - // Found M first, so open - return false; - } - - if (this.type === 1) { - // Found Z first, so closed - clsd = true; - return false; - } + static subpathIsClosed(index) { + let clsd = false; // Check if subpath is already open + path.eachSeg(function (i) { + if (i <= index) { return true; - }); - return clsd; - } - }]); + } - return Path; - }(); + if (this.type === 2) { + // Found M first, so open + return false; + } + + if (this.type === 1) { + // Found Z first, so closed + clsd = true; + return false; + } + + return true; + }); + return clsd; + } + + } /** * @function module:path.getPath_ * @param {SVGPathElement} elem * @returns {module:path.Path} */ - var getPath_ = function getPath_(elem) { - var p = pathData[elem.id]; + const getPath_ = function (elem) { + let p = pathData[elem.id]; if (!p) { p = pathData[elem.id] = new Path(elem); @@ -6511,19 +7777,19 @@ * @returns {void} */ - var removePath_ = function removePath_(id) { + const removePath_ = function (id) { if (id in pathData) { delete pathData[id]; } }; - var newcx, newcy, oldcx, oldcy, angle; + let newcx, newcy, oldcx, oldcy, angle; - var getRotVals = function getRotVals(x, y) { - var dx = x - oldcx; - var dy = y - oldcy; // rotate the point around the old center + const getRotVals = function (x, y) { + let dx = x - oldcx; + let dy = y - oldcy; // rotate the point around the old center - var r = Math.sqrt(dx * dx + dy * dy); - var theta = Math.atan2(dy, dx) + angle; + let r = Math.sqrt(dx * dx + dy * dy); + let theta = Math.atan2(dy, dx) + angle; dx = r * Math.cos(theta) + oldcx; dy = r * Math.sin(theta) + oldcy; // dx,dy should now hold the actual coordinates of each // point after being rotated @@ -6550,8 +7816,8 @@ */ - var recalcRotatedPath = function recalcRotatedPath() { - var currentPath = path.elem; + const recalcRotatedPath = function () { + const currentPath = path.elem; angle = getRotationAngle(currentPath, true); if (!angle) { @@ -6559,38 +7825,38 @@ } // selectedBBoxes[0] = path.oldbbox; - var oldbox = path.oldbbox; // selectedBBoxes[0], + const oldbox = path.oldbbox; // selectedBBoxes[0], oldcx = oldbox.x + oldbox.width / 2; oldcy = oldbox.y + oldbox.height / 2; - var box = getBBox(currentPath); + const box = getBBox(currentPath); newcx = box.x + box.width / 2; newcy = box.y + box.height / 2; // un-rotate the new center to the proper position - var dx = newcx - oldcx, - dy = newcy - oldcy, - r = Math.sqrt(dx * dx + dy * dy), - theta = Math.atan2(dy, dx) + angle; + const dx = newcx - oldcx, + dy = newcy - oldcy, + r = Math.sqrt(dx * dx + dy * dy), + theta = Math.atan2(dy, dx) + angle; newcx = r * Math.cos(theta) + oldcx; newcy = r * Math.sin(theta) + oldcy; - var list = currentPath.pathSegList; - var i = list.numberOfItems; + const list = currentPath.pathSegList; + let i = list.numberOfItems; while (i) { i -= 1; - var seg = list.getItem(i), - type = seg.pathSegType; + const seg = list.getItem(i), + type = seg.pathSegType; if (type === 1) { continue; } - var rvals = getRotVals(seg.x, seg.y), - points = [rvals.x, rvals.y]; + const rvals = getRotVals(seg.x, seg.y), + points = [rvals.x, rvals.y]; if (!isNullish(seg.x1) && !isNullish(seg.x2)) { - var cVals1 = getRotVals(seg.x1, seg.y1); - var cVals2 = getRotVals(seg.x2, seg.y2); + const cVals1 = getRotVals(seg.x1, seg.y1); + const cVals2 = getRotVals(seg.x2, seg.y2); points.splice(points.length, 0, cVals1.x, cVals1.y, cVals2.x, cVals2.y); } @@ -6604,8 +7870,8 @@ // selectedBBoxes[0].width = box.width; selectedBBoxes[0].height = box.height; // now we must set the new transform to be rotated around the new center - var Rnc = editorContext_.getSVGRoot().createSVGTransform(), - tlist = getTransformList(currentPath); + const Rnc = editorContext_$1.getSVGRoot().createSVGTransform(), + tlist = getTransformList(currentPath); Rnc.setRotate(angle * 180.0 / Math.PI, newcx, newcy); tlist.replaceItem(Rnc, 0); }; // ==================================== @@ -6616,7 +7882,7 @@ * @returns {void} */ - var clearData = function clearData() { + const clearData = function () { pathData = {}; }; // Making public for mocking @@ -6627,39 +7893,39 @@ * @returns {void} */ - var reorientGrads = function reorientGrads(elem, m) { - var bb = getBBox(elem); + const reorientGrads = function (elem, m) { + const bb = getBBox(elem); - for (var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = elem.getAttribute(type); + for (let i = 0; i < 2; i++) { + const type = i === 0 ? 'fill' : 'stroke'; + const attrVal = elem.getAttribute(type); if (attrVal && attrVal.startsWith('url(')) { - var grad = getRefElem(attrVal); + const grad = getRefElem(attrVal); if (grad.tagName === 'linearGradient') { - var x1 = grad.getAttribute('x1') || 0; - var y1 = grad.getAttribute('y1') || 0; - var x2 = grad.getAttribute('x2') || 1; - var y2 = grad.getAttribute('y2') || 0; // Convert to USOU points + let x1 = grad.getAttribute('x1') || 0; + let y1 = grad.getAttribute('y1') || 0; + let x2 = grad.getAttribute('x2') || 1; + let y2 = grad.getAttribute('y2') || 0; // Convert to USOU points x1 = bb.width * x1 + bb.x; y1 = bb.height * y1 + bb.y; x2 = bb.width * x2 + bb.x; y2 = bb.height * y2 + bb.y; // Transform those points - var pt1 = transformPoint(x1, y1, m); - var pt2 = transformPoint(x2, y2, m); // Convert back to BB points + const pt1 = transformPoint(x1, y1, m); + const pt2 = transformPoint(x2, y2, m); // Convert back to BB points - var gCoords = { + const gCoords = { x1: (pt1.x - bb.x) / bb.width, y1: (pt1.y - bb.y) / bb.height, x2: (pt2.x - bb.x) / bb.width, y2: (pt2.y - bb.y) / bb.height }; - var newgrad = grad.cloneNode(true); - $$1(newgrad).attr(gCoords); - newgrad.id = editorContext_.getNextId(); + const newgrad = grad.cloneNode(true); + $$3(newgrad).attr(gCoords); + newgrad.id = editorContext_$1.getNextId(); findDefs().append(newgrad); elem.setAttribute(type, 'url(#' + newgrad.id + ')'); } @@ -6672,7 +7938,7 @@ * @type {GenericArray} */ - var pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; + const pathMap = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; /** * Convert a path to one with only absolute or relative values. * @todo move to pathActions.js @@ -6682,25 +7948,27 @@ * @returns {string} */ - var convertPath = function convertPath(pth, toRel) { - var pathSegList = pth.pathSegList; - var len = pathSegList.numberOfItems; - var curx = 0, + const convertPath = function (pth, toRel) { + const { + pathSegList + } = pth; + const len = pathSegList.numberOfItems; + let curx = 0, cury = 0; - var d = ''; - var lastM = null; + let d = ''; + let lastM = null; - for (var i = 0; i < len; ++i) { - var seg = pathSegList.getItem(i); // if these properties are not in the segment, set them to zero + for (let i = 0; i < len; ++i) { + const seg = pathSegList.getItem(i); // if these properties are not in the segment, set them to zero - var x = seg.x || 0, + let x = seg.x || 0, y = seg.y || 0, x1 = seg.x1 || 0, y1 = seg.y1 || 0, x2 = seg.x2 || 0, y2 = seg.y2 || 0; - var type = seg.pathSegType; - var letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); + const type = seg.pathSegType; + let letter = pathMap[type][toRel ? 'toLowerCase' : 'toUpperCase'](); switch (type) { case 1: @@ -6909,10 +8177,10 @@ */ function pathDSegment(letter, points, morePoints, lastPoint) { - $$1.each(points, function (i, pnt) { + $$3.each(points, function (i, pnt) { points[i] = shortFloat(pnt); }); - var segment = letter + points.join(' '); + let segment = letter + points.join(' '); if (morePoints) { segment += ' ' + morePoints.join(' '); @@ -6934,12 +8202,12 @@ */ - var pathActions = function () { + const pathActions = function () { /* eslint-enable jsdoc/require-property */ - var subpath = false; - var newPoint, firstCtrl; - var currentPath = null; - var hasMoved = false; // No `editorContext_` yet but should be ok as is `null` by default + let subpath = false; + let newPoint, firstCtrl; + let currentPath = null; + let hasMoved = false; // No `editorContext_` yet but should be ok as is `null` by default // editorContext_.setDrawnPath(null); /** @@ -6951,11 +8219,12 @@ * @returns {Element} */ - var smoothPolylineIntoPath = function smoothPolylineIntoPath(element) { - var i; - var _element = element, - points = _element.points; - var N = points.numberOfItems; + const smoothPolylineIntoPath = function (element) { + let i; + const { + points + } = element; + const N = points.numberOfItems; if (N >= 4) { // loop through every 3 points and convert to a cubic bezier curve segment @@ -6971,22 +8240,22 @@ // - https://www.codeproject.com/KB/graphics/BezierSpline.aspx?msg=2956963 // - https://www.ian-ko.com/ET_GeoWizards/UserGuide/smooth.htm // - https://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html - var curpos = points.getItem(0), + let curpos = points.getItem(0), prevCtlPt = null; - var d = []; + let d = []; d.push(['M', curpos.x, ',', curpos.y, ' C'].join('')); for (i = 1; i <= N - 4; i += 3) { - var ct1 = points.getItem(i); - var ct2 = points.getItem(i + 1); - var end = points.getItem(i + 2); // if the previous segment had a control point, we want to smooth out + let ct1 = points.getItem(i); + const ct2 = points.getItem(i + 1); + const end = points.getItem(i + 2); // if the previous segment had a control point, we want to smooth out // the control points on both sides if (prevCtlPt) { - var newpts = smoothControlPoints(prevCtlPt, ct1, curpos); + const newpts = smoothControlPoints(prevCtlPt, ct1, curpos); if (newpts && newpts.length === 2) { - var prevArr = d[d.length - 1].split(','); + const prevArr = d[d.length - 1].split(','); prevArr[2] = newpts[0].x; prevArr[3] = newpts[0].y; d[d.length - 1] = prevArr.join(','); @@ -7003,19 +8272,19 @@ d.push('L'); while (i < N) { - var pt = points.getItem(i); + const pt = points.getItem(i); d.push([pt.x, pt.y].join(',')); i++; } d = d.join(' '); // create new path element - element = editorContext_.addSVGElementFromJson({ + element = editorContext_$1.addSVGElementFromJson({ element: 'path', curStyles: true, attr: { - id: editorContext_.getId(), - d: d, + id: editorContext_$1.getId(), + d, fill: 'none' } }); // No need to call "changed", as this is already done under mouseUp @@ -7034,21 +8303,21 @@ * @param {Float} startY * @returns {boolean|void} */ - mouseDown: function mouseDown(evt, mouseTarget, startX, startY) { - var id; + mouseDown(evt, mouseTarget, startX, startY) { + let id; - if (editorContext_.getCurrentMode() === 'path') { - var mouseX = startX; // Was this meant to work with the other `mouseX`? (was defined globally so adding `let` to at least avoid a global) + if (editorContext_$1.getCurrentMode() === 'path') { + let mouseX = startX; // Was this meant to work with the other `mouseX`? (was defined globally so adding `let` to at least avoid a global) - var mouseY = startY; // Was this meant to work with the other `mouseY`? (was defined globally so adding `let` to at least avoid a global) + let mouseY = startY; // Was this meant to work with the other `mouseY`? (was defined globally so adding `let` to at least avoid a global) - var currentZoom = editorContext_.getCurrentZoom(); - var x = mouseX / currentZoom, + const currentZoom = editorContext_$1.getCurrentZoom(); + let x = mouseX / currentZoom, y = mouseY / currentZoom, stretchy = getElem('path_stretch_line'); newPoint = [x, y]; - if (editorContext_.getGridSnapping()) { + if (editorContext_$1.getGridSnapping()) { x = snapToGrid(x); y = snapToGrid(y); mouseX = snapToGrid(mouseX); @@ -7067,23 +8336,23 @@ } stretchy.setAttribute('display', 'inline'); - var keep = null; - var index; // if pts array is empty, create path element with M at current point + let keep = null; + let index; // if pts array is empty, create path element with M at current point - var drawnPath = editorContext_.getDrawnPath(); + const drawnPath = editorContext_$1.getDrawnPath(); if (!drawnPath) { - var dAttr = 'M' + x + ',' + y + ' '; // Was this meant to work with the other `dAttr`? (was defined globally so adding `var` to at least avoid a global) + const dAttr = 'M' + x + ',' + y + ' '; // Was this meant to work with the other `dAttr`? (was defined globally so adding `var` to at least avoid a global) /* drawnPath = */ - editorContext_.setDrawnPath(editorContext_.addSVGElementFromJson({ + editorContext_$1.setDrawnPath(editorContext_$1.addSVGElementFromJson({ element: 'path', curStyles: true, attr: { d: dAttr, - id: editorContext_.getNextId(), - opacity: editorContext_.getOpacity() / 2 + id: editorContext_$1.getNextId(), + opacity: editorContext_$1.getOpacity() / 2 } })); // set stretchy line to first point @@ -7092,16 +8361,16 @@ addPointGrip(index, mouseX, mouseY); } else { // determine if we clicked on an existing point - var seglist = drawnPath.pathSegList; - var i = seglist.numberOfItems; - var FUZZ = 6 / currentZoom; - var clickOnPoint = false; + const seglist = drawnPath.pathSegList; + let i = seglist.numberOfItems; + const FUZZ = 6 / currentZoom; + let clickOnPoint = false; while (i) { i--; - var item = seglist.getItem(i); - var px = item.x, - py = item.y; // found a matching point + const item = seglist.getItem(i); + const px = item.x, + py = item.y; // found a matching point if (x >= px - FUZZ && x <= px + FUZZ && y >= py - FUZZ && y <= py + FUZZ) { clickOnPoint = true; @@ -7110,13 +8379,13 @@ } // get path element that we are in the process of creating - id = editorContext_.getId(); // Remove previous path object if previously created + id = editorContext_$1.getId(); // Remove previous path object if previously created removePath_(id); - var newpath = getElem(id); - var newseg; - var sSeg; - var len = seglist.numberOfItems; // if we clicked on an existing point, then we are done this path, commit it + const newpath = getElem(id); + let newseg; + let sSeg; + const len = seglist.numberOfItems; // if we clicked on an existing point, then we are done this path, commit it // (i, i+1) are the x,y that were clicked on if (clickOnPoint) { @@ -7126,8 +8395,8 @@ // otherwise, close the path if (i <= 1 && len >= 2) { // Create end segment - var absX = seglist.getItem(0).x; - var absY = seglist.getItem(0).y; + const absX = seglist.getItem(0).x; + const absY = seglist.getItem(0).y; sSeg = stretchy.pathSegList.getItem(1); if (sSeg.pathSegType === 4) { @@ -7136,7 +8405,7 @@ newseg = drawnPath.createSVGPathSegCurvetoCubicAbs(absX, absY, sSeg.x1 / currentZoom, sSeg.y1 / currentZoom, absX, absY); } - var endseg = drawnPath.createSVGPathSegClosePath(); + const endseg = drawnPath.createSVGPathSegClosePath(); seglist.appendItem(newseg); seglist.appendItem(endseg); } else if (len < 3) { @@ -7144,29 +8413,29 @@ return keep; } - $$1(stretchy).remove(); // This will signal to commit the path + $$3(stretchy).remove(); // This will signal to commit the path // const element = newpath; // Other event handlers define own `element`, so this was probably not meant to interact with them or one which shares state (as there were none); I therefore adding a missing `var` to avoid a global /* drawnPath = */ - editorContext_.setDrawnPath(null); - editorContext_.setStarted(false); + editorContext_$1.setDrawnPath(null); + editorContext_$1.setStarted(false); if (subpath) { if (path.matrix) { - editorContext_.remapElement(newpath, {}, path.matrix.inverse()); + editorContext_$1.remapElement(newpath, {}, path.matrix.inverse()); } - var newD = newpath.getAttribute('d'); - var origD = $$1(path.elem).attr('d'); - $$1(path.elem).attr('d', origD + newD); - $$1(newpath).remove(); + const newD = newpath.getAttribute('d'); + const origD = $$3(path.elem).attr('d'); + $$3(path.elem).attr('d', origD + newD); + $$3(newpath).remove(); if (path.matrix) { recalcRotatedPath(); } - init$1(); + init$2(); pathActions.toEditMode(path.elem); path.selectPt(); return false; @@ -7174,30 +8443,32 @@ } else { // Checks if current target or parents are #svgcontent - if (!$$1.contains(editorContext_.getContainer(), editorContext_.getMouseTarget(evt))) { + if (!$$3.contains(editorContext_$1.getContainer(), editorContext_$1.getMouseTarget(evt))) { // Clicked outside canvas, so don't make point // console.log('Clicked outside canvas'); return false; } - var num = drawnPath.pathSegList.numberOfItems; - var last = drawnPath.pathSegList.getItem(num - 1); - var lastx = last.x, - lasty = last.y; + const num = drawnPath.pathSegList.numberOfItems; + const last = drawnPath.pathSegList.getItem(num - 1); + const lastx = last.x, + lasty = last.y; if (evt.shiftKey) { - var xya = snapToAngle(lastx, lasty, x, y); - x = xya.x; - y = xya.y; + const xya = snapToAngle(lastx, lasty, x, y); + ({ + x, + y + } = xya); } // Use the segment defined by stretchy sSeg = stretchy.pathSegList.getItem(1); if (sSeg.pathSegType === 4) { - newseg = drawnPath.createSVGPathSegLinetoAbs(editorContext_.round(x), editorContext_.round(y)); + newseg = drawnPath.createSVGPathSegLinetoAbs(editorContext_$1.round(x), editorContext_$1.round(y)); } else { - newseg = drawnPath.createSVGPathSegCurvetoCubicAbs(editorContext_.round(x), editorContext_.round(y), sSeg.x1 / currentZoom, sSeg.y1 / currentZoom, sSeg.x2 / currentZoom, sSeg.y2 / currentZoom); + newseg = drawnPath.createSVGPathSegCurvetoCubicAbs(editorContext_$1.round(x), editorContext_$1.round(y), sSeg.x1 / currentZoom, sSeg.y1 / currentZoom, sSeg.x2 / currentZoom, sSeg.y2 / currentZoom); } drawnPath.pathSegList.appendItem(newseg); @@ -7225,14 +8496,16 @@ } path.storeD(); - id = evt.target.id; - var curPt; + ({ + id + } = evt.target); + let curPt; if (id.substr(0, 14) === 'pathpointgrip_') { // Select this point curPt = path.cur_pt = Number.parseInt(id.substr(14)); path.dragging = [startX, startY]; - var seg = path.segs[curPt]; // only clear selection if shift is not pressed (otherwise, add + const seg = path.segs[curPt]; // only clear selection if shift is not pressed (otherwise, add // node to selection) if (!evt.shiftKey) { @@ -7248,21 +8521,21 @@ } } else if (id.startsWith('ctrlpointgrip_')) { path.dragging = [startX, startY]; - var parts = id.split('_')[1].split('c'); + const parts = id.split('_')[1].split('c'); curPt = Number(parts[0]); - var ctrlNum = Number(parts[1]); + const ctrlNum = Number(parts[1]); path.selectPt(curPt, ctrlNum); } // Start selection box if (!path.dragging) { - var rubberBox = editorContext_.getRubberBox(); + let rubberBox = editorContext_$1.getRubberBox(); if (isNullish(rubberBox)) { - rubberBox = editorContext_.setRubberBox(editorContext_.selectorManager.getRubberBandBox()); + rubberBox = editorContext_$1.setRubberBox(editorContext_$1.selectorManager.getRubberBandBox()); } - var currentZoom = editorContext_.getCurrentZoom(); + const currentZoom = editorContext_$1.getCurrentZoom(); assignAttributes(rubberBox, { x: startX * currentZoom, y: startY * currentZoom, @@ -7280,41 +8553,41 @@ * @param {Float} mouseY * @returns {void} */ - mouseMove: function mouseMove(mouseX, mouseY) { - var currentZoom = editorContext_.getCurrentZoom(); + mouseMove(mouseX, mouseY) { + const currentZoom = editorContext_$1.getCurrentZoom(); hasMoved = true; - var drawnPath = editorContext_.getDrawnPath(); + const drawnPath = editorContext_$1.getDrawnPath(); - if (editorContext_.getCurrentMode() === 'path') { + if (editorContext_$1.getCurrentMode() === 'path') { if (!drawnPath) { return; } - var seglist = drawnPath.pathSegList; - var index = seglist.numberOfItems - 1; + const seglist = drawnPath.pathSegList; + const index = seglist.numberOfItems - 1; if (newPoint) { // First point // if (!index) { return; } // Set control points - var pointGrip1 = addCtrlGrip('1c1'); - var pointGrip2 = addCtrlGrip('0c2'); // dragging pointGrip1 + const pointGrip1 = addCtrlGrip('1c1'); + const pointGrip2 = addCtrlGrip('0c2'); // dragging pointGrip1 pointGrip1.setAttribute('cx', mouseX); pointGrip1.setAttribute('cy', mouseY); pointGrip1.setAttribute('display', 'inline'); - var ptX = newPoint[0]; - var ptY = newPoint[1]; // set curve + const ptX = newPoint[0]; + const ptY = newPoint[1]; // set curve // const seg = seglist.getItem(index); - var curX = mouseX / currentZoom; - var curY = mouseY / currentZoom; - var altX = ptX + (ptX - curX); - var altY = ptY + (ptY - curY); + const curX = mouseX / currentZoom; + const curY = mouseY / currentZoom; + const altX = ptX + (ptX - curX); + const altY = ptY + (ptY - curY); pointGrip2.setAttribute('cx', altX * currentZoom); pointGrip2.setAttribute('cy', altY * currentZoom); pointGrip2.setAttribute('display', 'inline'); - var ctrlLine = getCtrlLine(1); + const ctrlLine = getCtrlLine(1); assignAttributes(ctrlLine, { x1: mouseX, y1: mouseY, @@ -7326,9 +8599,9 @@ if (index === 0) { firstCtrl = [mouseX, mouseY]; } else { - var last = seglist.getItem(index - 1); - var lastX = last.x; - var lastY = last.y; + const last = seglist.getItem(index - 1); + let lastX = last.x; + let lastY = last.y; if (last.pathSegType === 6) { lastX += lastX - last.x2; @@ -7341,14 +8614,14 @@ replacePathSeg(6, index, [ptX, ptY, lastX, lastY, altX, altY], drawnPath); } } else { - var stretchy = getElem('path_stretch_line'); + const stretchy = getElem('path_stretch_line'); if (stretchy) { - var prev = seglist.getItem(index); + const prev = seglist.getItem(index); if (prev.pathSegType === 6) { - var prevX = prev.x + (prev.x - prev.x2); - var prevY = prev.y + (prev.y - prev.y2); + const prevX = prev.x + (prev.x - prev.x2); + const prevY = prev.y + (prev.y - prev.y2); replacePathSeg(6, 1, [mouseX, mouseY, prevX * currentZoom, prevY * currentZoom, mouseX, mouseY], stretchy); } else if (firstCtrl) { replacePathSeg(6, 1, [mouseX, mouseY, firstCtrl[0], firstCtrl[1], mouseX, mouseY], stretchy); @@ -7363,16 +8636,16 @@ if (path.dragging) { - var pt = getPointFromGrip({ + const pt = getPointFromGrip({ x: path.dragging[0], y: path.dragging[1] }, path); - var mpt = getPointFromGrip({ + const mpt = getPointFromGrip({ x: mouseX, y: mouseY }, path); - var diffX = mpt.x - pt.x; - var diffY = mpt.y - pt.y; + const diffX = mpt.x - pt.x; + const diffY = mpt.y - pt.y; path.dragging = [mouseX, mouseY]; if (path.dragctrl) { @@ -7383,23 +8656,23 @@ } else { path.selected_pts = []; path.eachSeg(function (i) { - var seg = this; // eslint-disable-line consistent-this + const seg = this; // eslint-disable-line consistent-this if (!seg.next && !seg.prev) { return; } // const {item} = seg; - var rubberBox = editorContext_.getRubberBox(); - var rbb = rubberBox.getBBox(); - var pt = getGripPt(seg); - var ptBb = { + const rubberBox = editorContext_$1.getRubberBox(); + const rbb = rubberBox.getBBox(); + const pt = getGripPt(seg); + const ptBb = { x: pt.x, y: pt.y, width: 0, height: 0 }; - var sel = rectsIntersect(rbb, ptBb); + const sel = rectsIntersect(rbb, ptBb); this.select(sel); // Note that addPtsToSelection is not being run if (sel) { @@ -7423,29 +8696,29 @@ * @param {Float} mouseY * @returns {module:path.keepElement|void} */ - mouseUp: function mouseUp(evt, element, mouseX, mouseY) { - var drawnPath = editorContext_.getDrawnPath(); // Create mode + mouseUp(evt, element, mouseX, mouseY) { + const drawnPath = editorContext_$1.getDrawnPath(); // Create mode - if (editorContext_.getCurrentMode() === 'path') { + if (editorContext_$1.getCurrentMode() === 'path') { newPoint = null; if (!drawnPath) { - element = getElem(editorContext_.getId()); - editorContext_.setStarted(false); + element = getElem(editorContext_$1.getId()); + editorContext_$1.setStarted(false); firstCtrl = null; } return { keep: true, - element: element + element }; } // Edit mode - var rubberBox = editorContext_.getRubberBox(); + const rubberBox = editorContext_$1.getRubberBox(); if (path.dragging) { - var lastPt = path.cur_pt; + const lastPt = path.cur_pt; path.dragging = false; path.dragctrl = false; path.update(); @@ -7477,10 +8750,10 @@ * @param {Element} element * @returns {void} */ - toEditMode: function toEditMode(element) { + toEditMode(element) { path = getPath_(element); - editorContext_.setCurrentMode('pathedit'); - editorContext_.clearSelection(); + editorContext_$1.setCurrentMode('pathedit'); + editorContext_$1.clearSelection(); path.show(true).update(); path.oldbbox = getBBox(path.elem); subpath = false; @@ -7491,12 +8764,12 @@ * @fires module:svgcanvas.SvgCanvas#event:selected * @returns {void} */ - toSelectMode: function toSelectMode(elem) { - var selPath = elem === path.elem; - editorContext_.setCurrentMode('select'); + toSelectMode(elem) { + const selPath = elem === path.elem; + editorContext_$1.setCurrentMode('select'); path.show(false); currentPath = false; - editorContext_.clearSelection(); + editorContext_$1.clearSelection(); if (path.matrix) { // Rotated, so may need to re-calculate the center @@ -7504,8 +8777,8 @@ } if (selPath) { - editorContext_.call('selected', [elem]); - editorContext_.addToSelection([elem], true); + editorContext_$1.call('selected', [elem]); + editorContext_$1.addToSelection([elem], true); } }, @@ -7513,11 +8786,11 @@ * @param {boolean} on * @returns {void} */ - addSubPath: function addSubPath(on) { + addSubPath(on) { if (on) { // Internally we go into "path" mode, but in the UI it will // still appear as if in "pathedit" mode. - editorContext_.setCurrentMode('path'); + editorContext_$1.setCurrentMode('path'); subpath = true; } else { pathActions.clear(true); @@ -7529,10 +8802,10 @@ * @param {Element} target * @returns {void} */ - select: function select(target) { + select(target) { if (currentPath === target) { pathActions.toEditMode(target); - editorContext_.setCurrentMode('pathedit'); // going into pathedit mode + editorContext_$1.setCurrentMode('pathedit'); // going into pathedit mode } else { currentPath = target; } @@ -7542,52 +8815,52 @@ * @fires module:svgcanvas.SvgCanvas#event:changed * @returns {void} */ - reorient: function reorient() { - var elem = editorContext_.getSelectedElements()[0]; + reorient() { + const elem = editorContext_$1.getSelectedElements()[0]; if (!elem) { return; } - var angl = getRotationAngle(elem); + const angl = getRotationAngle(elem); if (angl === 0) { return; } - var batchCmd = new BatchCommand('Reorient path'); - var changes = { + const batchCmd = new BatchCommand('Reorient path'); + const changes = { d: elem.getAttribute('d'), transform: elem.getAttribute('transform') }; batchCmd.addSubCommand(new ChangeElementCommand(elem, changes)); - editorContext_.clearSelection(); + editorContext_$1.clearSelection(); this.resetOrientation(elem); - editorContext_.addCommandToHistory(batchCmd); // Set matrix to null + editorContext_$1.addCommandToHistory(batchCmd); // Set matrix to null getPath_(elem).show(false).matrix = null; this.clear(); - editorContext_.addToSelection([elem], true); - editorContext_.call('changed', editorContext_.getSelectedElements()); + editorContext_$1.addToSelection([elem], true); + editorContext_$1.call('changed', editorContext_$1.getSelectedElements()); }, /** * @param {boolean} remove Not in use * @returns {void} */ - clear: function clear(remove) { - var drawnPath = editorContext_.getDrawnPath(); + clear(remove) { + const drawnPath = editorContext_$1.getDrawnPath(); currentPath = null; if (drawnPath) { - var elem = getElem(editorContext_.getId()); - $$1(getElem('path_stretch_line')).remove(); - $$1(elem).remove(); - $$1(getElem('pathpointgrip_container')).find('*').attr('display', 'none'); + const elem = getElem(editorContext_$1.getId()); + $$3(getElem('path_stretch_line')).remove(); + $$3(elem).remove(); + $$3(getElem('pathpointgrip_container')).find('*').attr('display', 'none'); firstCtrl = null; - editorContext_.setDrawnPath(null); - editorContext_.setStarted(false); - } else if (editorContext_.getCurrentMode() === 'pathedit') { + editorContext_$1.setDrawnPath(null); + editorContext_$1.setStarted(false); + } else if (editorContext_$1.getCurrentMode() === 'pathedit') { this.toSelectMode(); } @@ -7600,21 +8873,21 @@ * @param {?(Element|SVGPathElement)} pth * @returns {false|void} */ - resetOrientation: function resetOrientation(pth) { + resetOrientation(pth) { if (isNullish(pth) || pth.nodeName !== 'path') { return false; } - var tlist = getTransformList(pth); - var m = transformListToTransform(tlist).matrix; + const tlist = getTransformList(pth); + const m = transformListToTransform(tlist).matrix; tlist.clear(); pth.removeAttribute('transform'); - var segList = pth.pathSegList; // Opera/win/non-EN throws an error here. + const segList = pth.pathSegList; // Opera/win/non-EN throws an error here. // TODO: Find out why! // Presumed fixed in Opera 10.5, so commented out for now // try { - var len = segList.numberOfItems; // } catch(err) { + const len = segList.numberOfItems; // } catch(err) { // const fixed_d = pathActions.convertPath(pth); // pth.setAttribute('d', fixed_d); // segList = pth.pathSegList; @@ -7622,31 +8895,25 @@ // } // let lastX, lastY; - var _loop = function _loop(i) { - var seg = segList.getItem(i); - var type = seg.pathSegType; + for (let i = 0; i < len; ++i) { + const seg = segList.getItem(i); + const type = seg.pathSegType; if (type === 1) { - return "continue"; + continue; } - var pts = []; - $$1.each(['', 1, 2], function (j, n) { - var x = seg['x' + n], - y = seg['y' + n]; + const pts = []; + $$3.each(['', 1, 2], function (j, n) { + const x = seg['x' + n], + y = seg['y' + n]; if (x !== undefined && y !== undefined) { - var pt = transformPoint(x, y, m); + const pt = transformPoint(x, y, m); pts.splice(pts.length, 0, pt.x, pt.y); } }); replacePathSeg(type, i, pts, pth); - }; - - for (var i = 0; i < len; ++i) { - var _ret = _loop(i); - - if (_ret === "continue") continue; } reorientGrads(pth, m); @@ -7656,8 +8923,8 @@ /** * @returns {void} */ - zoomChange: function zoomChange() { - if (editorContext_.getCurrentMode() === 'pathedit') { + zoomChange() { + if (editorContext_$1.getCurrentMode() === 'pathedit') { path.update(); } }, @@ -7672,9 +8939,9 @@ /** * @returns {module:path.NodePoint} */ - getNodePoint: function getNodePoint() { - var selPt = path.selected_pts.length ? path.selected_pts[0] : 1; - var seg = path.segs[selPt]; + getNodePoint() { + const selPt = path.selected_pts.length ? path.selected_pts[0] : 1; + const seg = path.segs[selPt]; return { x: seg.item.x, y: seg.item.y, @@ -7686,22 +8953,22 @@ * @param {boolean} linkPoints * @returns {void} */ - linkControlPoints: function linkControlPoints(linkPoints) { + linkControlPoints(linkPoints) { setLinkControlPoints(linkPoints); }, /** * @returns {void} */ - clonePathNode: function clonePathNode() { + clonePathNode() { path.storeD(); - var selPts = path.selected_pts; // const {segs} = path; + const selPts = path.selected_pts; // const {segs} = path; - var i = selPts.length; - var nums = []; + let i = selPts.length; + const nums = []; while (i--) { - var pt = selPts[i]; + const pt = selPts[i]; path.addSeg(pt); nums.push(pt + i); nums.push(pt + i + 1); @@ -7714,20 +8981,21 @@ /** * @returns {void} */ - opencloseSubPath: function opencloseSubPath() { - var selPts = path.selected_pts; // Only allow one selected node for now + opencloseSubPath() { + const selPts = path.selected_pts; // Only allow one selected node for now if (selPts.length !== 1) { return; } - var _path = path, - elem = _path.elem; - var list = elem.pathSegList; // const len = list.numberOfItems; + const { + elem + } = path; + const list = elem.pathSegList; // const len = list.numberOfItems; - var index = selPts[0]; - var openPt = null; - var startItem = null; // Check if subpath is already open + const index = selPts[0]; + let openPt = null; + let startItem = null; // Check if subpath is already open path.eachSeg(function (i) { if (this.type === 2 && i <= index) { @@ -7761,8 +9029,8 @@ if (openPt !== false) { // Close this path // Create a line going to the previous "M" - var newseg = elem.createSVGPathSegLinetoAbs(startItem.x, startItem.y); - var closer = elem.createSVGPathSegClosePath(); + const newseg = elem.createSVGPathSegLinetoAbs(startItem.x, startItem.y); + const closer = elem.createSVGPathSegClosePath(); if (openPt === path.segs.length - 1) { list.appendItem(newseg); @@ -7780,7 +9048,7 @@ // M 1,1 L 2,2 L 1,1 z [M 4,4] L 5,5 L(M)6,6 L 5,5 z - var seg = path.segs[index]; + const seg = path.segs[index]; if (seg.mate) { list.removeItem(index); // Removes last "L" @@ -7791,10 +9059,10 @@ return; } - var lastM, zSeg; // Find this sub-path's closing point and remove + let lastM, zSeg; // Find this sub-path's closing point and remove - for (var i = 0; i < list.numberOfItems; i++) { - var item = list.getItem(i); + for (let i = 0; i < list.numberOfItems; i++) { + const item = list.getItem(i); if (item.pathSegType === 2) { // Find the preceding M @@ -7810,13 +9078,13 @@ } } - var num = index - lastM - 1; + let num = index - lastM - 1; while (num--) { insertItemBefore(elem, list.getItem(lastM), zSeg); } - var pt = list.getItem(lastM); // Make this point the new "M" + const pt = list.getItem(lastM); // Make this point the new "M" replacePathSeg(2, lastM, [pt.x, pt.y]); // i = index; // i is local here, so has no effect; what was the intent for this? @@ -7826,26 +9094,26 @@ /** * @returns {void} */ - deletePathNode: function deletePathNode() { + deletePathNode() { if (!pathActions.canDeleteNodes) { return; } path.storeD(); - var selPts = path.selected_pts; - var i = selPts.length; + const selPts = path.selected_pts; + let i = selPts.length; while (i--) { - var pt = selPts[i]; + const pt = selPts[i]; path.deleteSeg(pt); } // Cleanup - var cleanup = function cleanup() { - var segList = path.elem.pathSegList; - var len = segList.numberOfItems; + const cleanup = function () { + const segList = path.elem.pathSegList; + let len = segList.numberOfItems; - var remItems = function remItems(pos, count) { + const remItems = function (pos, count) { while (count--) { segList.removeItem(pos); } @@ -7856,11 +9124,11 @@ } while (len--) { - var item = segList.getItem(len); + const item = segList.getItem(len); if (item.pathSegType === 1) { - var prev = segList.getItem(len - 1); - var nprev = segList.getItem(len - 2); + const prev = segList.getItem(len - 1); + const nprev = segList.getItem(len - 2); if (prev.pathSegType === 2) { remItems(len - 1, 2); @@ -7873,7 +9141,7 @@ } } else if (item.pathSegType === 2) { if (len > 0) { - var prevType = segList.getItem(len - 1).pathSegType; // Path has M M + const prevType = segList.getItem(len - 1).pathSegType; // Path has M M if (prevType === 2) { remItems(len - 1, 1); @@ -7895,7 +9163,7 @@ if (path.elem.pathSegList.numberOfItems <= 1) { pathActions.toSelectMode(path.elem); - editorContext_.canvas.deleteSelectedElements(); + editorContext_$1.canvas.deleteSelectedElements(); return; } @@ -7905,7 +9173,7 @@ if (window.opera) { // Opera repaints incorrectly - var cp = $$1(path.elem); + const cp = $$3(path.elem); cp.attr('d', cp.attr('d')); } @@ -7920,7 +9188,7 @@ * @function module:path.pathActions.smoothPolylineIntoPath * @see module:path~smoothPolylineIntoPath */ - smoothPolylineIntoPath: smoothPolylineIntoPath, + smoothPolylineIntoPath, /* eslint-enable jsdoc/require-returns */ @@ -7928,7 +9196,7 @@ * @param {?Integer} v See {@link https://www.w3.org/TR/SVG/single-page.html#paths-InterfaceSVGPathSeg} * @returns {void} */ - setSegType: function setSegType(v) { + setSegType(v) { path.setSegType(v); }, @@ -7937,8 +9205,8 @@ * @param {Float} newValue * @returns {void} */ - moveNode: function moveNode(attr, newValue) { - var selPts = path.selected_pts; + moveNode(attr, newValue) { + const selPts = path.selected_pts; if (!selPts.length) { return; @@ -7946,8 +9214,8 @@ path.storeD(); // Get first selected point - var seg = path.segs[selPts[0]]; - var diff = { + const seg = path.segs[selPts[0]]; + const diff = { x: 0, y: 0 }; @@ -7960,27 +9228,27 @@ * @param {Element} elem * @returns {void} */ - fixEnd: function fixEnd(elem) { + fixEnd(elem) { // Adds an extra segment if the last seg before a Z doesn't end // at its M point // M0,0 L0,100 L100,100 z - var segList = elem.pathSegList; - var len = segList.numberOfItems; - var lastM; + const segList = elem.pathSegList; + const len = segList.numberOfItems; + let lastM; - for (var i = 0; i < len; ++i) { - var item = segList.getItem(i); + for (let i = 0; i < len; ++i) { + const item = segList.getItem(i); if (item.pathSegType === 2) { lastM = item; } if (item.pathSegType === 1) { - var prev = segList.getItem(i - 1); + const prev = segList.getItem(i - 1); if (prev.x !== lastM.x || prev.y !== lastM.y) { // Add an L segment here - var newseg = elem.createSVGPathSegLinetoAbs(lastM.x, lastM.y); + const newseg = elem.createSVGPathSegLinetoAbs(lastM.x, lastM.y); insertItemBefore(elem, newseg, i); // Can this be done better? pathActions.fixEnd(elem); @@ -7990,7 +9258,7 @@ } if (isWebkit()) { - editorContext_.resetD(elem); + editorContext_$1.resetD(elem); } }, @@ -8002,2036 +9270,45 @@ * @function module:path.pathActions.convertPath * @see module:path.convertPath */ - convertPath: convertPath + convertPath /* eslint-enable jsdoc/require-returns */ } ); }(); // end pathActions - var $$2 = jQueryPluginSVG(jQuery); // String used to encode base64. - - var KEYSTR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; // Much faster than running getBBox() every time - - var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; - var visElemsArr = visElems.split(','); // const hidElems = 'clipPath,defs,desc,feGaussianBlur,filter,linearGradient,marker,mask,metadata,pattern,radialGradient,stop,switch,symbol,title,textPath'; - - var editorContext_$1 = null; - var domdoc_ = null; - var domcontainer_ = null; - var svgroot_ = null; - /** - * Object with the following keys/values. - * @typedef {PlainObject} module:utilities.SVGElementJSON - * @property {string} element - Tag name of the SVG element to create - * @property {PlainObject<string, string>} attr - Has key-value attributes to assign to the new element. An `id` should be set so that {@link module:utilities.EditorContext#addSVGElementFromJson} can later re-identify the element for modification or replacement. - * @property {boolean} [curStyles=false] - Indicates whether current style attributes should be applied first - * @property {module:utilities.SVGElementJSON[]} [children] - Data objects to be added recursively as children - * @property {string} [namespace="http://www.w3.org/2000/svg"] - Indicate a (non-SVG) namespace - */ - - /** - * An object that creates SVG elements for the canvas. - * - * @interface module:utilities.EditorContext - * @property {module:path.pathActions} pathActions - */ - - /** - * @function module:utilities.EditorContext#getSVGContent - * @returns {SVGSVGElement} - */ - - /** - * Create a new SVG element based on the given object keys/values and add it - * to the current layer. - * The element will be run through `cleanupElement` before being returned. - * @function module:utilities.EditorContext#addSVGElementFromJson - * @param {module:utilities.SVGElementJSON} data - * @returns {Element} The new element - */ - - /** - * @function module:utilities.EditorContext#getSelectedElements - * @returns {Element[]} the array with selected DOM elements - */ - - /** - * @function module:utilities.EditorContext#getDOMDocument - * @returns {HTMLDocument} - */ - - /** - * @function module:utilities.EditorContext#getDOMContainer - * @returns {HTMLElement} - */ - - /** - * @function module:utilities.EditorContext#getSVGRoot - * @returns {SVGSVGElement} - */ - - /** - * @function module:utilities.EditorContext#getBaseUnit - * @returns {string} - */ - - /** - * @function module:utilities.EditorContext#getSnappingStep - * @returns {Float|string} - */ - - /** - * @function module:utilities.init - * @param {module:utilities.EditorContext} editorContext - * @returns {void} - */ - - var init$2 = function init(editorContext) { - editorContext_$1 = editorContext; - domdoc_ = editorContext.getDOMDocument(); - domcontainer_ = editorContext.getDOMContainer(); - svgroot_ = editorContext.getSVGRoot(); - }; - /** - * Used to prevent the [Billion laughs attack]{@link https://en.wikipedia.org/wiki/Billion_laughs_attack}. - * @function module:utilities.dropXMLInternalSubset - * @param {string} str String to be processed - * @returns {string} The string with entity declarations in the internal subset removed - * @todo This might be needed in other places `parseFromString` is used even without LGTM flagging - */ - - var dropXMLInternalSubset = function dropXMLInternalSubset(str) { - return str.replace(/(<!DOCTYPE\s+\w*\s*\[).*(\?]>)/, '$1$2'); // return str.replace(/(?<doctypeOpen><!DOCTYPE\s+\w*\s*\[).*(?<doctypeClose>\?\]>)/, '$<doctypeOpen>$<doctypeClose>'); - }; - /** - * Converts characters in a string to XML-friendly entities. - * @function module:utilities.toXml - * @example `&` becomes `&` - * @param {string} str - The string to be converted - * @returns {string} The converted string - */ - - var toXml = function toXml(str) { - // ' is ok in XML, but not HTML - // > does not normally need escaping, though it can if within a CDATA expression (and preceded by "]]") - return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, '''); // Note: `'` is XML only - }; - // public domain. It would be nice if you left this header intact. - // Base64 code from Tyler Akins -- http://rumkin.com - // schiller: Removed string concatenation in favour of Array.join() optimization, - // also precalculate the size of the array needed. - - /** - * Converts a string to base64. - * @function module:utilities.encode64 - * @param {string} input - * @returns {string} Base64 output - */ - - function encode64(input) { - // base64 strings are 4/3 larger than the original string - input = encodeUTF8(input); // convert non-ASCII characters - // input = convertToXMLReferences(input); - - if (window.btoa) { - return window.btoa(input); // Use native if available - } - - var output = new Array(Math.floor((input.length + 2) / 3) * 4); - var i = 0, - p = 0; - - do { - var chr1 = input.charCodeAt(i++); - var chr2 = input.charCodeAt(i++); - var chr3 = input.charCodeAt(i++); - /* eslint-disable no-bitwise */ - - var enc1 = chr1 >> 2; - var enc2 = (chr1 & 3) << 4 | chr2 >> 4; - var enc3 = (chr2 & 15) << 2 | chr3 >> 6; - var enc4 = chr3 & 63; - /* eslint-enable no-bitwise */ - - if (Number.isNaN(chr2)) { - enc3 = 64; - enc4 = 64; - } else if (Number.isNaN(chr3)) { - enc4 = 64; - } - - output[p++] = KEYSTR.charAt(enc1); - output[p++] = KEYSTR.charAt(enc2); - output[p++] = KEYSTR.charAt(enc3); - output[p++] = KEYSTR.charAt(enc4); - } while (i < input.length); - - return output.join(''); - } - /** - * Converts a string from base64. - * @function module:utilities.decode64 - * @param {string} input Base64-encoded input - * @returns {string} Decoded output - */ - - function decode64(input) { - if (window.atob) { - return decodeUTF8(window.atob(input)); - } // remove all characters that are not A-Z, a-z, 0-9, +, /, or = - - - input = input.replace(/[^A-Za-z\d+/=]/g, ''); - var output = ''; - var i = 0; - - do { - var enc1 = KEYSTR.indexOf(input.charAt(i++)); - var enc2 = KEYSTR.indexOf(input.charAt(i++)); - var enc3 = KEYSTR.indexOf(input.charAt(i++)); - var enc4 = KEYSTR.indexOf(input.charAt(i++)); - /* eslint-disable no-bitwise */ - - var chr1 = enc1 << 2 | enc2 >> 4; - var chr2 = (enc2 & 15) << 4 | enc3 >> 2; - var chr3 = (enc3 & 3) << 6 | enc4; - /* eslint-enable no-bitwise */ - - output += String.fromCharCode(chr1); - - if (enc3 !== 64) { - output += String.fromCharCode(chr2); - } - - if (enc4 !== 64) { - output += String.fromCharCode(chr3); - } - } while (i < input.length); - - return decodeUTF8(output); - } - /** - * @function module:utilities.decodeUTF8 - * @param {string} argString - * @returns {string} - */ - - function decodeUTF8(argString) { - return decodeURIComponent(escape(argString)); - } // codedread:does not seem to work with webkit-based browsers on OSX // Brettz9: please test again as function upgraded - - /** - * @function module:utilities.encodeUTF8 - * @param {string} argString - * @returns {string} - */ - - var encodeUTF8 = function encodeUTF8(argString) { - return unescape(encodeURIComponent(argString)); - }; - /** - * Convert dataURL to object URL. - * @function module:utilities.dataURLToObjectURL - * @param {string} dataurl - * @returns {string} object URL or empty string - */ - - var dataURLToObjectURL = function dataURLToObjectURL(dataurl) { - if (typeof Uint8Array === 'undefined' || typeof Blob === 'undefined' || typeof URL === 'undefined' || !URL.createObjectURL) { - return ''; - } - - var arr = dataurl.split(','), - mime = arr[0].match(/:(.*?);/)[1], - bstr = atob(arr[1]); - /* - const [prefix, suffix] = dataurl.split(','), - {groups: {mime}} = prefix.match(/:(?<mime>.*?);/), - bstr = atob(suffix); - */ - - var n = bstr.length; - var u8arr = new Uint8Array(n); - - while (n--) { - u8arr[n] = bstr.charCodeAt(n); - } - - var blob = new Blob([u8arr], { - type: mime - }); - return URL.createObjectURL(blob); - }; - /** - * Get object URL for a blob object. - * @function module:utilities.createObjectURL - * @param {Blob} blob A Blob object or File object - * @returns {string} object URL or empty string - */ - - var createObjectURL = function createObjectURL(blob) { - if (!blob || typeof URL === 'undefined' || !URL.createObjectURL) { - return ''; - } - - return URL.createObjectURL(blob); - }; - /** - * @property {string} blankPageObjectURL - */ - - var blankPageObjectURL = function () { - if (typeof Blob === 'undefined') { - return ''; - } - - var blob = new Blob(['<html><head><title>SVG-edit '], { - type: 'text/html' - }); - return createObjectURL(blob); - }(); - /** - * Cross-browser compatible method of converting a string to an XML tree. - * Found this function [here]{@link http://groups.google.com/group/jquery-dev/browse_thread/thread/c6d11387c580a77f}. - * @function module:utilities.text2xml - * @param {string} sXML - * @throws {Error} - * @returns {XMLDocument} - */ - - var text2xml = function text2xml(sXML) { - if (sXML.includes('` - * - `` - * - `` - * @function module:utilities.getUrlFromAttr - * @param {string} attrVal The attribute value as a string - * @returns {string} String with just the URL, like "someFile.svg#foo" - */ - - var getUrlFromAttr = function getUrlFromAttr(attrVal) { - if (attrVal) { - // url('#somegrad') - if (attrVal.startsWith('url("')) { - return attrVal.substring(5, attrVal.indexOf('"', 6)); - } // url('#somegrad') - - - if (attrVal.startsWith("url('")) { - return attrVal.substring(5, attrVal.indexOf("'", 6)); - } - - if (attrVal.startsWith('url(')) { - return attrVal.substring(4, attrVal.indexOf(')')); - } - } - - return null; - }; - /** - * @function module:utilities.getHref - * @param {Element} elem - * @returns {string} The given element's `xlink:href` value - */ - - var getHref = function getHref(elem) { - // eslint-disable-line import/no-mutable-exports - return elem.getAttributeNS(NS.XLINK, 'href'); - }; - /** - * Sets the given element's `xlink:href` value. - * @function module:utilities.setHref - * @param {Element} elem - * @param {string} val - * @returns {void} - */ - - var setHref = function setHref(elem, val) { - // eslint-disable-line import/no-mutable-exports - elem.setAttributeNS(NS.XLINK, 'xlink:href', val); - }; - /** - * @function module:utilities.findDefs - * @returns {SVGDefsElement} The document's `` element, creating it first if necessary - */ - - var findDefs = function findDefs() { - var svgElement = editorContext_$1.getSVGContent(); - var defs = svgElement.getElementsByTagNameNS(NS.SVG, 'defs'); - - if (defs.length > 0) { - defs = defs[0]; - } else { - defs = svgElement.ownerDocument.createElementNS(NS.SVG, 'defs'); - - if (svgElement.firstChild) { - // first child is a comment, so call nextSibling - svgElement.insertBefore(defs, svgElement.firstChild.nextSibling); // svgElement.firstChild.nextSibling.before(defs); // Not safe - } else { - svgElement.append(defs); - } - } - - return defs; - }; // TODO(codedread): Consider moving the next to functions to bbox.js - - /** - * Get correct BBox for a path in Webkit. - * Converted from code found [here]{@link http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html}. - * @function module:utilities.getPathBBox - * @param {SVGPathElement} path - The path DOM element to get the BBox for - * @returns {module:utilities.BBoxObject} A BBox-like object - */ - - var getPathBBox = function getPathBBox(path) { - var seglist = path.pathSegList; - var tot = seglist.numberOfItems; - var bounds = [[], []]; - var start = seglist.getItem(0); - var P0 = [start.x, start.y]; - - var getCalc = function getCalc(j, P1, P2, P3) { - return function (t) { - return 1 - Math.pow(t, 3) * P0[j] + 3 * 1 - Math.pow(t, 2) * t * P1[j] + 3 * (1 - t) * Math.pow(t, 2) * P2[j] + Math.pow(t, 3) * P3[j]; - }; - }; - - for (var i = 0; i < tot; i++) { - var seg = seglist.getItem(i); - - if (seg.x === undefined) { - continue; - } // Add actual points to limits - - - bounds[0].push(P0[0]); - bounds[1].push(P0[1]); - - if (seg.x1) { - var P1 = [seg.x1, seg.y1], - P2 = [seg.x2, seg.y2], - P3 = [seg.x, seg.y]; - - for (var j = 0; j < 2; j++) { - var calc = getCalc(j, P1, P2, P3); - var b = 6 * P0[j] - 12 * P1[j] + 6 * P2[j]; - var a = -3 * P0[j] + 9 * P1[j] - 9 * P2[j] + 3 * P3[j]; - var c = 3 * P1[j] - 3 * P0[j]; - - if (a === 0) { - if (b === 0) { - continue; - } - - var t = -c / b; - - if (t > 0 && t < 1) { - bounds[j].push(calc(t)); - } - - continue; - } - - var b2ac = Math.pow(b, 2) - 4 * c * a; - - if (b2ac < 0) { - continue; - } - - var t1 = (-b + Math.sqrt(b2ac)) / (2 * a); - - if (t1 > 0 && t1 < 1) { - bounds[j].push(calc(t1)); - } - - var t2 = (-b - Math.sqrt(b2ac)) / (2 * a); - - if (t2 > 0 && t2 < 1) { - bounds[j].push(calc(t2)); - } - } - - P0 = P3; - } else { - bounds[0].push(seg.x); - bounds[1].push(seg.y); - } - } - - var x = Math.min.apply(null, bounds[0]); - var w = Math.max.apply(null, bounds[0]) - x; - var y = Math.min.apply(null, bounds[1]); - var h = Math.max.apply(null, bounds[1]) - y; - return { - x: x, - y: y, - width: w, - height: h - }; - }; - /** - * Get the given/selected element's bounding box object, checking for - * horizontal/vertical lines (see issue 717) - * Note that performance is currently terrible, so some way to improve would - * be great. - * @param {Element} selected - Container or `` DOM element - * @returns {DOMRect} Bounding box object - */ - - function groupBBFix(selected) { - if (supportsHVLineContainerBBox()) { - try { - return selected.getBBox(); - } catch (e) {} - } - - var ref = $$2.data(selected, 'ref'); - var matched = null; - var ret, copy; - - if (ref) { - copy = $$2(ref).children().clone().attr('visibility', 'hidden'); - $$2(svgroot_).append(copy); - matched = copy.filter('line, path'); - } else { - matched = $$2(selected).find('line, path'); - } - - var issue = false; - - if (matched.length) { - matched.each(function () { - var bb = this.getBBox(); - - if (!bb.width || !bb.height) { - issue = true; - } - }); - - if (issue) { - var elems = ref ? copy : $$2(selected).children(); - ret = getStrokedBBox(elems); - } else { - ret = selected.getBBox(); - } - } else { - ret = selected.getBBox(); - } - - if (ref) { - copy.remove(); - } - - return ret; - } - /** - * Get the given/selected element's bounding box object, convert it to be more - * usable when necessary. - * @function module:utilities.getBBox - * @param {Element} elem - Optional DOM element to get the BBox for - * @returns {module:utilities.BBoxObject} Bounding box object - */ - - - var getBBox = function getBBox(elem) { - var selected = elem || editorContext_$1.geSelectedElements()[0]; - - if (elem.nodeType !== 1) { - return null; - } - - var elname = selected.nodeName; - var ret = null; - - switch (elname) { - case 'text': - if (selected.textContent === '') { - selected.textContent = 'a'; // Some character needed for the selector to use. - - ret = selected.getBBox(); - selected.textContent = ''; - } else if (selected.getBBox) { - ret = selected.getBBox(); - } - - break; - - case 'path': - if (!supportsPathBBox()) { - ret = getPathBBox(selected); - } else if (selected.getBBox) { - ret = selected.getBBox(); - } - - break; - - case 'g': - case 'a': - ret = groupBBFix(selected); - break; - - default: - if (elname === 'use') { - ret = groupBBFix(selected); // , true); - } - - if (elname === 'use' || elname === 'foreignObject' && isWebkit()) { - if (!ret) { - ret = selected.getBBox(); - } // This is resolved in later versions of webkit, perhaps we should - // have a featured detection for correct 'use' behavior? - // —————————— - - - if (!isWebkit()) { - var _ret = ret, - x = _ret.x, - y = _ret.y, - width = _ret.width, - height = _ret.height; - var bb = { - width: width, - height: height, - x: x + Number.parseFloat(selected.getAttribute('x') || 0), - y: y + Number.parseFloat(selected.getAttribute('y') || 0) - }; - ret = bb; - } - } else if (visElemsArr.includes(elname)) { - if (selected) { - try { - ret = selected.getBBox(); - } catch (err) { - // tspan (and textPath apparently) have no `getBBox` in Firefox: https://bugzilla.mozilla.org/show_bug.cgi?id=937268 - // Re: Chrome returning bbox for containing text element, see: https://bugs.chromium.org/p/chromium/issues/detail?id=349835 - var extent = selected.getExtentOfChar(0); // pos+dimensions of the first glyph - - var _width = selected.getComputedTextLength(); // width of the tspan - - - ret = { - x: extent.x, - y: extent.y, - width: _width, - height: extent.height - }; - } - } else { - // Check if element is child of a foreignObject - var fo = $$2(selected).closest('foreignObject'); - - if (fo.length) { - if (fo[0].getBBox) { - ret = fo[0].getBBox(); - } - } - } - } - - } - - if (ret) { - ret = bboxToObj(ret); - } // get the bounding box from the DOM (which is in that element's coordinate system) - - - return ret; - }; - /** - * @typedef {GenericArray} module:utilities.PathSegmentArray - * @property {Integer} length 2 - * @property {"M"|"L"|"C"|"Z"} 0 - * @property {Float[]} 1 - */ - - /** - * Create a path 'd' attribute from path segments. - * Each segment is an array of the form: `[singleChar, [x,y, x,y, ...]]` - * @function module:utilities.getPathDFromSegments - * @param {module:utilities.PathSegmentArray[]} pathSegments - An array of path segments to be converted - * @returns {string} The converted path d attribute. - */ - - var getPathDFromSegments = function getPathDFromSegments(pathSegments) { - var d = ''; - $$2.each(pathSegments, function (j, _ref2) { - var _ref3 = _slicedToArray(_ref2, 2), - singleChar = _ref3[0], - pts = _ref3[1]; - - d += singleChar; - - for (var i = 0; i < pts.length; i += 2) { - d += pts[i] + ',' + pts[i + 1] + ' '; - } - }); - return d; - }; - /** - * Make a path 'd' attribute from a simple SVG element shape. - * @function module:utilities.getPathDFromElement - * @param {Element} elem - The element to be converted - * @returns {string} The path d attribute or `undefined` if the element type is unknown. - */ - - var getPathDFromElement = function getPathDFromElement(elem) { - // Possibly the cubed root of 6, but 1.81 works best - var num = 1.81; - var d, a, rx, ry; - - switch (elem.tagName) { - case 'ellipse': - case 'circle': - { - a = $$2(elem).attr(['rx', 'ry', 'cx', 'cy']); - var _a = a, - cx = _a.cx, - cy = _a.cy; - var _a2 = a; - rx = _a2.rx; - ry = _a2.ry; - - if (elem.tagName === 'circle') { - ry = $$2(elem).attr('r'); - rx = ry; - } - - d = getPathDFromSegments([['M', [cx - rx, cy]], ['C', [cx - rx, cy - ry / num, cx - rx / num, cy - ry, cx, cy - ry]], ['C', [cx + rx / num, cy - ry, cx + rx, cy - ry / num, cx + rx, cy]], ['C', [cx + rx, cy + ry / num, cx + rx / num, cy + ry, cx, cy + ry]], ['C', [cx - rx / num, cy + ry, cx - rx, cy + ry / num, cx - rx, cy]], ['Z', []]]); - break; - } - - case 'path': - d = elem.getAttribute('d'); - break; - - case 'line': - a = $$2(elem).attr(['x1', 'y1', 'x2', 'y2']); - d = 'M' + a.x1 + ',' + a.y1 + 'L' + a.x2 + ',' + a.y2; - break; - - case 'polyline': - d = 'M' + elem.getAttribute('points'); - break; - - case 'polygon': - d = 'M' + elem.getAttribute('points') + ' Z'; - break; - - case 'rect': - { - var r = $$2(elem).attr(['rx', 'ry']); - rx = r.rx; - ry = r.ry; - var b = elem.getBBox(); - var x = b.x, - y = b.y, - w = b.width, - h = b.height; - num = 4 - num; // Why? Because! - - if (!rx && !ry) { - // Regular rect - d = getPathDFromSegments([['M', [x, y]], ['L', [x + w, y]], ['L', [x + w, y + h]], ['L', [x, y + h]], ['L', [x, y]], ['Z', []]]); - } else { - d = getPathDFromSegments([['M', [x, y + ry]], ['C', [x, y + ry / num, x + rx / num, y, x + rx, y]], ['L', [x + w - rx, y]], ['C', [x + w - rx / num, y, x + w, y + ry / num, x + w, y + ry]], ['L', [x + w, y + h - ry]], ['C', [x + w, y + h - ry / num, x + w - rx / num, y + h, x + w - rx, y + h]], ['L', [x + rx, y + h]], ['C', [x + rx / num, y + h, x, y + h - ry / num, x, y + h - ry]], ['L', [x, y + ry]], ['Z', []]]); - } - - break; - } - } - - return d; - }; - /** - * Get a set of attributes from an element that is useful for convertToPath. - * @function module:utilities.getExtraAttributesForConvertToPath - * @param {Element} elem - The element to be probed - * @returns {PlainObject<"marker-start"|"marker-end"|"marker-mid"|"filter"|"clip-path", string>} An object with attributes. - */ - - var getExtraAttributesForConvertToPath = function getExtraAttributesForConvertToPath(elem) { - var attrs = {}; // TODO: make this list global so that we can properly maintain it - // TODO: what about @transform, @clip-rule, @fill-rule, etc? - - $$2.each(['marker-start', 'marker-end', 'marker-mid', 'filter', 'clip-path'], function () { - var a = elem.getAttribute(this); - - if (a) { - attrs[this] = a; - } - }); - return attrs; - }; - /** - * Get the BBox of an element-as-path. - * @function module:utilities.getBBoxOfElementAsPath - * @param {Element} elem - The DOM element to be probed - * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson - * @param {module:path.pathActions} pathActions - If a transform exists, `pathActions.resetOrientation()` is used. See: canvas.pathActions. - * @returns {DOMRect|false} The resulting path's bounding box object. - */ - - var getBBoxOfElementAsPath = function getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions) { - var path = addSVGElementFromJson({ - element: 'path', - attr: getExtraAttributesForConvertToPath(elem) - }); - var eltrans = elem.getAttribute('transform'); - - if (eltrans) { - path.setAttribute('transform', eltrans); - } - - var parentNode = elem.parentNode; - - if (elem.nextSibling) { - elem.before(path); - } else { - parentNode.append(path); - } - - var d = getPathDFromElement(elem); - - if (d) { - path.setAttribute('d', d); - } else { - path.remove(); - } // Get the correct BBox of the new path, then discard it - - - pathActions.resetOrientation(path); - var bb = false; - - try { - bb = path.getBBox(); - } catch (e) {// Firefox fails - } - - path.remove(); - return bb; - }; - /** - * Convert selected element to a path. - * @function module:utilities.convertToPath - * @param {Element} elem - The DOM element to be converted - * @param {module:utilities.SVGElementJSON} attrs - Apply attributes to new path. see canvas.convertToPath - * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson - * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. - * @param {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} clearSelection - see [canvas.clearSelection]{@link module:svgcanvas.SvgCanvas#clearSelection} - * @param {module:path.EditorContext#addToSelection} addToSelection - see [canvas.addToSelection]{@link module:svgcanvas.SvgCanvas#addToSelection} - * @param {module:history} hstry - see history module - * @param {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} addCommandToHistory - see [canvas.addCommandToHistory]{@link module:svgcanvas~addCommandToHistory} - * @returns {SVGPathElement|null} The converted path element or null if the DOM element was not recognized. - */ - - var convertToPath = function convertToPath(elem, attrs, addSVGElementFromJson, pathActions, clearSelection, addToSelection, hstry, addCommandToHistory) { - var batchCmd = new hstry.BatchCommand('Convert element to Path'); // Any attribute on the element not covered by the passed-in attributes - - attrs = $$2.extend({}, attrs, getExtraAttributesForConvertToPath(elem)); - var path = addSVGElementFromJson({ - element: 'path', - attr: attrs - }); - var eltrans = elem.getAttribute('transform'); - - if (eltrans) { - path.setAttribute('transform', eltrans); - } - - var id = elem.id; - var parentNode = elem.parentNode; - - if (elem.nextSibling) { - elem.before(path); - } else { - parentNode.append(path); - } - - var d = getPathDFromElement(elem); - - if (d) { - path.setAttribute('d', d); // Replace the current element with the converted one - // Reorient if it has a matrix - - if (eltrans) { - var tlist = getTransformList(path); - - if (hasMatrixTransform(tlist)) { - pathActions.resetOrientation(path); - } - } - - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new hstry.RemoveElementCommand(elem, nextSibling, parent)); - batchCmd.addSubCommand(new hstry.InsertElementCommand(path)); - clearSelection(); - elem.remove(); - path.setAttribute('id', id); - path.removeAttribute('visibility'); - addToSelection([path], true); - addCommandToHistory(batchCmd); - return path; - } // the elem.tagName was not recognized, so no "d" attribute. Remove it, so we've haven't changed anything. - - - path.remove(); - return null; - }; - /** - * Can the bbox be optimized over the native getBBox? The optimized bbox is the same as the native getBBox when - * the rotation angle is a multiple of 90 degrees and there are no complex transforms. - * Getting an optimized bbox can be dramatically slower, so we want to make sure it's worth it. - * - * The best example for this is a circle rotate 45 degrees. The circle doesn't get wider or taller when rotated - * about it's center. - * - * The standard, unoptimized technique gets the native bbox of the circle, rotates the box 45 degrees, uses - * that width and height, and applies any transforms to get the final bbox. This means the calculated bbox - * is much wider than the original circle. If the angle had been 0, 90, 180, etc. both techniques render the - * same bbox. - * - * The optimization is not needed if the rotation is a multiple 90 degrees. The default technique is to call - * getBBox then apply the angle and any transforms. - * - * @param {Float} angle - The rotation angle in degrees - * @param {boolean} hasAMatrixTransform - True if there is a matrix transform - * @returns {boolean} True if the bbox can be optimized. - */ - - function bBoxCanBeOptimizedOverNativeGetBBox(angle, hasAMatrixTransform) { - var angleModulo90 = angle % 90; - var closeTo90 = angleModulo90 < -89.99 || angleModulo90 > 89.99; - var closeTo0 = angleModulo90 > -0.001 && angleModulo90 < 0.001; - return hasAMatrixTransform || !(closeTo0 || closeTo90); - } - /** - * Get bounding box that includes any transforms. - * @function module:utilities.getBBoxWithTransform - * @param {Element} elem - The DOM element to be converted - * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson - * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. - * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object - */ - - - var getBBoxWithTransform = function getBBoxWithTransform(elem, addSVGElementFromJson, pathActions) { - // TODO: Fix issue with rotated groups. Currently they work - // fine in FF, but not in other browsers (same problem mentioned - // in Issue 339 comment #2). - var bb = getBBox(elem); - - if (!bb) { - return null; - } - - var tlist = getTransformList(elem); - var angle = getRotationAngleFromTransformList(tlist); - var hasMatrixXForm = hasMatrixTransform(tlist); - - if (angle || hasMatrixXForm) { - var goodBb = false; - - if (bBoxCanBeOptimizedOverNativeGetBBox(angle, hasMatrixXForm)) { - // Get the BBox from the raw path for these elements - // TODO: why ellipse and not circle - var elemNames = ['ellipse', 'path', 'line', 'polyline', 'polygon']; - - if (elemNames.includes(elem.tagName)) { - goodBb = getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); - bb = goodBb; - } else if (elem.tagName === 'rect') { - // Look for radius - var rx = elem.getAttribute('rx'); - var ry = elem.getAttribute('ry'); - - if (rx || ry) { - goodBb = getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); - bb = goodBb; - } - } - } - - if (!goodBb) { - var _transformListToTrans = transformListToTransform(tlist), - matrix = _transformListToTrans.matrix; - - bb = transformBox(bb.x, bb.y, bb.width, bb.height, matrix).aabox; // Old technique that was exceedingly slow with large documents. - // - // Accurate way to get BBox of rotated element in Firefox: - // Put element in group and get its BBox - // - // Must use clone else FF freaks out - // const clone = elem.cloneNode(true); - // const g = document.createElementNS(NS.SVG, 'g'); - // const parent = elem.parentNode; - // parent.append(g); - // g.append(clone); - // const bb2 = bboxToObj(g.getBBox()); - // g.remove(); - } - } - - return bb; - }; - /** - * @param {Element} elem - * @returns {Float} - * @todo This is problematic with large stroke-width and, for example, a single - * horizontal line. The calculated BBox extends way beyond left and right sides. - */ - - function getStrokeOffsetForBBox(elem) { - var sw = elem.getAttribute('stroke-width'); - return !isNaN(sw) && elem.getAttribute('stroke') !== 'none' ? sw / 2 : 0; - } - /** - * @typedef {PlainObject} BBox - * @property {Integer} x The x value - * @property {Integer} y The y value - * @property {Float} width - * @property {Float} height - */ - - /** - * Get the bounding box for one or more stroked and/or transformed elements. - * @function module:utilities.getStrokedBBox - * @param {Element[]} elems - Array with DOM elements to check - * @param {module:utilities.EditorContext#addSVGElementFromJson} addSVGElementFromJson - Function to add the path element to the current layer. See canvas.addSVGElementFromJson - * @param {module:path.pathActions} pathActions - If a transform exists, pathActions.resetOrientation() is used. See: canvas.pathActions. - * @returns {module:utilities.BBoxObject|module:math.TransformedBox|DOMRect} A single bounding box object - */ - - - var getStrokedBBox = function getStrokedBBox(elems, addSVGElementFromJson, pathActions) { - if (!elems || !elems.length) { - return false; - } - - var fullBb; - $$2.each(elems, function () { - if (fullBb) { - return; - } - - if (!this.parentNode) { - return; - } - - fullBb = getBBoxWithTransform(this, addSVGElementFromJson, pathActions); - }); // This shouldn't ever happen... - - if (fullBb === undefined) { - return null; - } // fullBb doesn't include the stoke, so this does no good! - // if (elems.length == 1) return fullBb; - - - var maxX = fullBb.x + fullBb.width; - var maxY = fullBb.y + fullBb.height; - var minX = fullBb.x; - var minY = fullBb.y; // If only one elem, don't call the potentially slow getBBoxWithTransform method again. - - if (elems.length === 1) { - var offset = getStrokeOffsetForBBox(elems[0]); - minX -= offset; - minY -= offset; - maxX += offset; - maxY += offset; - } else { - $$2.each(elems, function (i, elem) { - var curBb = getBBoxWithTransform(elem, addSVGElementFromJson, pathActions); - - if (curBb) { - var _offset = getStrokeOffsetForBBox(elem); - - minX = Math.min(minX, curBb.x - _offset); - minY = Math.min(minY, curBb.y - _offset); // TODO: The old code had this test for max, but not min. I suspect this test should be for both min and max - - if (elem.nodeType === 1) { - maxX = Math.max(maxX, curBb.x + curBb.width + _offset); - maxY = Math.max(maxY, curBb.y + curBb.height + _offset); - } - } - }); - } - - fullBb.x = minX; - fullBb.y = minY; - fullBb.width = maxX - minX; - fullBb.height = maxY - minY; - return fullBb; - }; - /** - * Get all elements that have a BBox (excludes ``, ``, etc). - * Note that 0-opacity, off-screen etc elements are still considered "visible" - * for this function. - * @function module:utilities.getVisibleElements - * @param {Element} parentElement - The parent DOM element to search within - * @returns {Element[]} All "visible" elements. - */ - - var getVisibleElements = function getVisibleElements(parentElement) { - if (!parentElement) { - parentElement = $$2(editorContext_$1.getSVGContent()).children(); // Prevent layers from being included - } - - var contentElems = []; - $$2(parentElement).children().each(function (i, elem) { - if (elem.getBBox) { - contentElems.push(elem); - } - }); - return contentElems.reverse(); - }; - /** - * Get the bounding box for one or more stroked and/or transformed elements. - * @function module:utilities.getStrokedBBoxDefaultVisible - * @param {Element[]} elems - Array with DOM elements to check - * @returns {module:utilities.BBoxObject} A single bounding box object - */ - - var getStrokedBBoxDefaultVisible = function getStrokedBBoxDefaultVisible(elems) { - if (!elems) { - elems = getVisibleElements(); - } - - return getStrokedBBox(elems, editorContext_$1.addSVGElementFromJson, editorContext_$1.pathActions); - }; - /** - * Get the rotation angle of the given transform list. - * @function module:utilities.getRotationAngleFromTransformList - * @param {SVGTransformList} tlist - List of transforms - * @param {boolean} toRad - When true returns the value in radians rather than degrees - * @returns {Float} The angle in degrees or radians - */ - - var getRotationAngleFromTransformList = function getRotationAngleFromTransformList(tlist, toRad) { - if (!tlist) { - return 0; - } // <svg> elements have no tlist - - - var N = tlist.numberOfItems; - - for (var i = 0; i < N; ++i) { - var xform = tlist.getItem(i); - - if (xform.type === 4) { - return toRad ? xform.angle * Math.PI / 180.0 : xform.angle; - } - } - - return 0.0; - }; - /** - * Get the rotation angle of the given/selected DOM element. - * @function module:utilities.getRotationAngle - * @param {Element} [elem] - DOM element to get the angle for. Default to first of selected elements. - * @param {boolean} [toRad=false] - When true returns the value in radians rather than degrees - * @returns {Float} The angle in degrees or radians - */ - - var getRotationAngle = function getRotationAngle(elem, toRad) { - // eslint-disable-line import/no-mutable-exports - var selected = elem || editorContext_$1.getSelectedElements()[0]; // find the rotation transform (if any) and set it - - var tlist = getTransformList(selected); - return getRotationAngleFromTransformList(tlist, toRad); - }; - /** - * Get the reference element associated with the given attribute value. - * @function module:utilities.getRefElem - * @param {string} attrVal - The attribute value as a string - * @returns {Element} Reference element - */ - - var getRefElem = function getRefElem(attrVal) { - return getElem(getUrlFromAttr(attrVal).substr(1)); - }; - /** - * Get a DOM element by ID within the SVG root element. - * @function module:utilities.getElem - * @param {string} id - String with the element's new ID - * @returns {?Element} - */ - - var getElem = supportsSelectors() ? function (id) { - // querySelector lookup - return svgroot_.querySelector('#' + id); - } : supportsXpath() ? function (id) { - // xpath lookup - return domdoc_.evaluate('svg:svg[@id="svgroot"]//svg:*[@id="' + id + '"]', domcontainer_, function () { - return NS.SVG; - }, 9, null).singleNodeValue; - } : function (id) { - // jQuery lookup: twice as slow as xpath in FF - // eslint-disable-next-line unicorn/no-fn-reference-in-iterator - return $$2(svgroot_).find('[id=' + id + ']')[0]; - }; - /** - * Assigns multiple attributes to an element. - * @function module:utilities.assignAttributes - * @param {Element} elem - DOM element to apply new attribute values to - * @param {PlainObject<string, string>} attrs - Object with attribute keys/values - * @param {Integer} [suspendLength] - Milliseconds to suspend redraw - * @param {boolean} [unitCheck=false] - Boolean to indicate the need to use units.setUnitAttr - * @returns {void} - */ - - var assignAttributes = function assignAttributes(elem, attrs, suspendLength, unitCheck) { - for (var _i = 0, _Object$entries = Object.entries(attrs); _i < _Object$entries.length; _i++) { - var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2), - key = _Object$entries$_i[0], - value = _Object$entries$_i[1]; - - var ns = key.substr(0, 4) === 'xml:' ? NS.XML : key.substr(0, 6) === 'xlink:' ? NS.XLINK : null; - - if (isNullish(value)) { - if (ns) { - elem.removeAttributeNS(ns, key); - } else { - elem.removeAttribute(key); - } - - continue; - } - - if (ns) { - elem.setAttributeNS(ns, key, value); - } else if (!unitCheck) { - elem.setAttribute(key, value); - } else { - setUnitAttr(elem, key, value); - } - } - }; - /** - * Remove unneeded (default) attributes, making resulting SVG smaller. - * @function module:utilities.cleanupElement - * @param {Element} element - DOM element to clean up - * @returns {void} - */ - - var cleanupElement = function cleanupElement(element) { - var defaults = { - 'fill-opacity': 1, - 'stop-opacity': 1, - opacity: 1, - stroke: 'none', - 'stroke-dasharray': 'none', - 'stroke-linejoin': 'miter', - 'stroke-linecap': 'butt', - 'stroke-opacity': 1, - 'stroke-width': 1, - rx: 0, - ry: 0 - }; - - if (element.nodeName === 'ellipse') { - // Ellipse elements require rx and ry attributes - delete defaults.rx; - delete defaults.ry; - } - - Object.entries(defaults).forEach(function (_ref4) { - var _ref5 = _slicedToArray(_ref4, 2), - attr = _ref5[0], - val = _ref5[1]; - - if (element.getAttribute(attr) === String(val)) { - element.removeAttribute(attr); - } - }); - }; - /** - * Round value to for snapping. - * @function module:utilities.snapToGrid - * @param {Float} value - * @returns {Integer} - */ - - var snapToGrid = function snapToGrid(value) { - var unit = editorContext_$1.getBaseUnit(); - var stepSize = editorContext_$1.getSnappingStep(); - - if (unit !== 'px') { - stepSize *= getTypeMap()[unit]; - } - - value = Math.round(value / stepSize) * stepSize; - return value; - }; - /** - * Escapes special characters in a regular expression. - * @function module:utilities.regexEscape - * @param {string} str - * @returns {string} - */ - - var regexEscape = function regexEscape(str) { - // Originally from: http://phpjs.org/functions - return String(str).replace(/[.\\+*?[^\]$(){}=!<>|:-]/g, '\\$&'); - }; - /** - * Prevents default browser click behaviour on the given element. - * @function module:utilities.preventClickDefault - * @param {Element} img - The DOM element to prevent the click on - * @returns {void} - */ - - var preventClickDefault = function preventClickDefault(img) { - $$2(img).click(function (e) { - e.preventDefault(); - }); - }; - /** - * @callback module:utilities.GetNextID - * @returns {string} The ID - */ - - /** - * Create a clone of an element, updating its ID and its children's IDs when needed. - * @function module:utilities.copyElem - * @param {Element} el - DOM element to clone - * @param {module:utilities.GetNextID} getNextId - The getter of the next unique ID. - * @returns {Element} The cloned element - */ - - var copyElem = function copyElem(el, getNextId) { - // manually create a copy of the element - var newEl = document.createElementNS(el.namespaceURI, el.nodeName); - $$2.each(el.attributes, function (i, attr) { - if (attr.localName !== '-moz-math-font-style') { - newEl.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value); - } - }); // set the copied element's new id - - newEl.removeAttribute('id'); - newEl.id = getNextId(); // Opera's "d" value needs to be reset for Opera/Win/non-EN - // Also needed for webkit (else does not keep curved segments on clone) - - if (isWebkit() && el.nodeName === 'path') { - var fixedD = convertPath(el); - newEl.setAttribute('d', fixedD); - } // now create copies of all children - - - $$2.each(el.childNodes, function (i, child) { - switch (child.nodeType) { - case 1: - // element node - newEl.append(copyElem(child, getNextId)); - break; - - case 3: - // text node - newEl.textContent = child.nodeValue; - break; - } - }); - - if ($$2(el).data('gsvg')) { - $$2(newEl).data('gsvg', newEl.firstChild); - } else if ($$2(el).data('symbol')) { - var ref = $$2(el).data('symbol'); - $$2(newEl).data('ref', ref).data('symbol', ref); - } else if (newEl.tagName === 'image') { - preventClickDefault(newEl); - } - - return newEl; - }; - /** - * Whether a value is `null` or `undefined`. - * @param {any} val - * @returns {boolean} - */ - - var isNullish = function isNullish(val) { - return val === null || val === undefined; - }; + var pathModule = /*#__PURE__*/Object.freeze({ + __proto__: null, + setUiStrings: setUiStrings, + setLinkControlPoints: setLinkControlPoints, + get path () { return path; }, + init: init$2, + insertItemBefore: insertItemBefore, + ptObjToArr: ptObjToArr, + getGripPt: getGripPt, + getPointFromGrip: getPointFromGrip, + addPointGrip: addPointGrip, + getGripContainer: getGripContainer, + addCtrlGrip: addCtrlGrip, + getCtrlLine: getCtrlLine, + getPointGrip: getPointGrip, + getControlPoints: getControlPoints, + replacePathSeg: replacePathSeg, + getSegSelector: getSegSelector, + smoothControlPoints: smoothControlPoints, + Segment: Segment, + Path: Path, + getPath_: getPath_, + removePath_: removePath_, + recalcRotatedPath: recalcRotatedPath, + clearData: clearData, + reorientGrads: reorientGrads, + convertPath: convertPath, + pathActions: pathActions + }); /* globals jQuery */ - - /** - * Adds context menu functionality. - * @module contextmenu - * @license Apache-2.0 - * @author Adam Bender - */ - // Dependencies: - // 1) jQuery (for dom injection of context menus) - var $$3 = jQuery; - var contextMenuExtensions = {}; - /** - * @function module:contextmenu.hasCustomHandler - * @param {string} handlerKey - * @returns {boolean} - */ - - var hasCustomHandler = function hasCustomHandler(handlerKey) { - return Boolean(contextMenuExtensions[handlerKey]); - }; - /** - * @function module:contextmenu.getCustomHandler - * @param {string} handlerKey - * @returns {module:contextmenu.MenuItemAction} - */ - - var getCustomHandler = function getCustomHandler(handlerKey) { - return contextMenuExtensions[handlerKey].action; - }; - /** - * @param {module:contextmenu.MenuItem} menuItem - * @returns {void} - */ - - var injectExtendedContextMenuItemIntoDom = function injectExtendedContextMenuItemIntoDom(menuItem) { - if (!Object.keys(contextMenuExtensions).length) { - // all menuItems appear at the bottom of the menu in their own container. - // if this is the first extension menu we need to add the separator. - $$3('#cmenu_canvas').append("<li class='separator'>"); - } - - var shortcut = menuItem.shortcut || ''; - $$3('#cmenu_canvas').append("<li class='disabled'><a href='#" + menuItem.id + "'>" + menuItem.label + "<span class='shortcut'>" + shortcut + '</span></a></li>'); - }; - /** - * @function module:contextmenu.injectExtendedContextMenuItemsIntoDom - * @returns {void} - */ - - - var injectExtendedContextMenuItemsIntoDom = function injectExtendedContextMenuItemsIntoDom() { - Object.values(contextMenuExtensions).forEach(function (menuItem) { - injectExtendedContextMenuItemIntoDom(menuItem); - }); - }; - - /* eslint-disable jsdoc/require-file-overview */ - - /** - * Adapted from {@link https://github.com/uupaa/dynamic-import-polyfill/blob/master/importModule.js}. - * @module importModule - * @license MIT - */ - - /** - * Converts a possible relative URL into an absolute one. - * @param {string} url - * @returns {string} - */ - function toAbsoluteURL(url) { - var a = document.createElement('a'); - a.setAttribute('href', url); // <a href="hoge.html"> - - return a.cloneNode(false).href; // -> "http://example.com/hoge.html" - } - /** - * Add any of the whitelisted attributes to the script tag. - * @param {HTMLScriptElement} script - * @param {PlainObject<string, string>} atts - * @returns {void} - */ - - - function addScriptAtts(script, atts) { - ['id', 'class', 'type'].forEach(function (prop) { - if (prop in atts) { - script[prop] = atts[prop]; - } - }); - } // Additions by Brett - - /** - * @typedef {PlainObject} module:importModule.ImportConfig - * @property {string} global The variable name to set on `window` (when not using the modular version) - * @property {boolean} [returnDefault=false] - */ - - /** - * @function module:importModule.importSetGlobalDefault - * @param {string|GenericArray<any>} url - * @param {module:importModule.ImportConfig} config - * @returns {Promise<any>} The value to which it resolves depends on the export of the targeted module. - */ - - - function importSetGlobalDefault(url, config) { - return importSetGlobal(url, _extends({}, config, { - returnDefault: true - })); - } - /** - * @function module:importModule.importSetGlobal - * @param {string|string[]} url - * @param {module:importModule.ImportConfig} config - * @returns {Promise<ArbitraryModule>} The promise resolves to either an `ArbitraryModule` or - * any other value depends on the export of the targeted module. - */ - - function importSetGlobal(_x, _x2) { - return _importSetGlobal.apply(this, arguments); - } - /** - * - * @author Brett Zamir (other items are from `dynamic-import-polyfill`) - * @param {string|string[]} url - * @param {PlainObject} [atts={}] - * @returns {Promise<void|Error>} Resolves to `undefined` or rejects with an `Error` upon a - * script loading error - */ - - function _importSetGlobal() { - _importSetGlobal = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(url, _ref) { - var glob, returnDefault, modularVersion; - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - glob = _ref.global, returnDefault = _ref.returnDefault; - // Todo: Replace calls to this function with `import()` when supported - modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; - - if (!modularVersion) { - _context.next = 4; - break; - } - - return _context.abrupt("return", importModule(url, undefined, { - returnDefault: returnDefault - })); - - case 4: - _context.next = 6; - return importScript(url); - - case 6: - return _context.abrupt("return", window[glob]); - - case 7: - case "end": - return _context.stop(); - } - } - }, _callee); - })); - return _importSetGlobal.apply(this, arguments); - } - - 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) { - // eslint-disable-line promise/avoid-new - var script = document.createElement('script'); - /** - * - * @returns {void} - */ - - function scriptOnError() { - reject(new Error("Failed to import: ".concat(url))); - destructor(); - } - /** - * - * @returns {void} - */ - - - function scriptOnLoad() { - resolve(); - destructor(); - } - - var destructor = function destructor() { - script.removeEventListener('error', scriptOnError); - script.removeEventListener('load', scriptOnLoad); - script.remove(); - script.src = ''; - }; - - script.defer = 'defer'; - addScriptAtts(script, atts); - script.addEventListener('error', scriptOnError); - script.addEventListener('load', scriptOnLoad); - script.src = url; - document.head.append(script); - }); - } - /** - * - * @param {string|string[]} url - * @param {PlainObject} [atts={}] - * @param {PlainObject} opts - * @param {boolean} [opts.returnDefault=false} = {}] - * @returns {Promise<any>} Resolves to value of loading module or rejects with - * `Error` upon a script loading error. - */ - - function importModule(url) { - var atts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - - var _ref2 = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, - _ref2$returnDefault = _ref2.returnDefault, - returnDefault = _ref2$returnDefault === void 0 ? false : _ref2$returnDefault; - - if (Array.isArray(url)) { - return Promise.all(url.map(function (u) { - return importModule(u, atts); - })); - } - - return new Promise(function (resolve, reject) { - // eslint-disable-line promise/avoid-new - var vector = '$importModule$' + Math.random().toString(32).slice(2); - var script = document.createElement('script'); - /** - * - * @returns {void} - */ - - function scriptOnError() { - reject(new Error("Failed to import: ".concat(url))); - destructor(); - } - /** - * - * @returns {void} - */ - - - function scriptOnLoad() { - resolve(window[vector]); - destructor(); - } - - var destructor = function destructor() { - delete window[vector]; - script.removeEventListener('error', scriptOnError); - script.removeEventListener('load', scriptOnLoad); - script.remove(); - URL.revokeObjectURL(script.src); - script.src = ''; - }; - - addScriptAtts(script, atts); - script.defer = 'defer'; - script.type = 'module'; - script.addEventListener('error', scriptOnError); - script.addEventListener('load', scriptOnLoad); - var absURL = toAbsoluteURL(url); - var loader = "import * as m from '".concat(absURL.replace(/'/g, "\\'"), "'; window.").concat(vector, " = ").concat(returnDefault ? 'm.default || ' : '', "m;"); // export Module - - var blob = new Blob([loader], { - type: 'text/javascript' - }); - script.src = URL.createObjectURL(blob); - document.head.append(script); - }); - } - - /** - * Created by alexey2baranov on 28.01.17. - */ - - /* - An extraction of the deparam method from Ben Alman's jQuery BBQ - http://benalman.com/projects/jquery-bbq-plugin/ - */ - var coerce_types = { - 'true': !0, - 'false': !1, - 'null': null - }; - - function deparam(params, coerce) { - // console.log(params) - var obj = {}; // Iterate over all name=value pairs. - - params.replace(/\+/g, ' ').split('&').forEach(function (v) { - var param = v.split('='); - var key = decodeURIComponent(param[0]), - // If key is more complex than 'foo', like 'a[]' or 'a[b][c]', split it - // into its component parts. - keys = key.split(']['), - keys_last = keys.length - 1; // If the first keys part contains [ and the last ends with ], then [] - // are correctly balanced. - - if (/\[/.test(keys[0]) && /\]$/.test(keys[keys_last])) { - // Remove the trailing ] from the last keys part. - keys[keys_last] = keys[keys_last].replace(/\]$/, ''); // Split first keys part into two parts on the [ and add them back onto - // the beginning of the keys array. - - keys = keys.shift().split('[').concat(keys); - keys_last = keys.length - 1; - } else { - // Basic 'foo' style key. - keys_last = 0; - } // Are we dealing with a name=value pair, or just a name? - - - if (param.length >= 2) { - var val = decodeURIComponent(param.slice(1).join('=')); // Coerce values. - - if (coerce) { - val = val && !isNaN(val) ? +val // number - : val === 'undefined' ? undefined // undefined - : coerce_types[val] !== undefined ? coerce_types[val] // true, false, null - : val; // string - } - - if (keys_last) { - var cur = obj; // Complex key, build deep object structure based on a few rules: - // * The 'cur' pointer starts at the object top-level. - // * [] = array push (n is set to array length), [n] = array if n is - // numeric, otherwise object. - // * If at the last keys part, set the value. - // * For each keys part, if the current level is undefined create an - // object or array based on the type of the next keys part. - // * Move the 'cur' pointer to the next level. - // * Rinse & repeat. - - for (var i = 0; i <= keys_last; i++) { - key = keys[i] === '' ? cur.length : keys[i]; - cur = cur[key] = i < keys_last ? cur[key] || (keys[i + 1] && isNaN(keys[i + 1]) ? {} : []) : val; - } - } else { - // Simple key, even simpler rules, since only scalars and shallow - // arrays are allowed. - if (Array.isArray(obj[key])) { - // val is already an array, so push on the next value. - obj[key].push(val); - } else if (obj[key] !== undefined) { - // val isn't an array, but since a second value has been specified, - // convert val into an array. - obj[key] = [obj[key], val]; - } else { - // val is a scalar. - obj[key] = val; - } - } - } else if (key) { - // No value was defined, so set something meaningful. - obj[key] = coerce ? undefined : ''; - } - }); - return obj; - } - - /** - * @module jQueryPluginDBox - */ - - /** - * @param {external:jQuery} $ - * @param {PlainObject} [strings] - * @param {PlainObject} [strings.ok] - * @param {PlainObject} [strings.cancel] - * @returns {external:jQuery} - */ - function jQueryPluginDBox($) { - var strings = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { - ok: 'Ok', - cancel: 'Cancel' - }; - // This sets up alternative dialog boxes. They mostly work the same way as - // their UI counterparts, expect instead of returning the result, a callback - // needs to be included that returns the result as its first parameter. - // In the future we may want to add additional types of dialog boxes, since - // they should be easy to handle this way. - $('#dialog_container').draggable({ - cancel: '#dialog_content, #dialog_buttons *', - containment: 'window' - }).css('position', 'absolute'); - var box = $('#dialog_box'), - btnHolder = $('#dialog_buttons'), - dialogContent = $('#dialog_content'); - /** - * @typedef {PlainObject} module:jQueryPluginDBox.PromiseResultObject - * @property {string|true} response - * @property {boolean} checked - */ - - /** - * Resolves to `false` (if cancelled), for prompts and selects - * without checkboxes, it resolves to the value of the form control. For other - * types without checkboxes, it resolves to `true`. For checkboxes, it resolves - * to an object with the `response` key containing the same value as the previous - * mentioned (string or `true`) and a `checked` (boolean) property. - * @typedef {Promise<boolean|string|module:jQueryPluginDBox.PromiseResultObject>} module:jQueryPluginDBox.ResultPromise - */ - - /** - * @typedef {PlainObject} module:jQueryPluginDBox.SelectOption - * @property {string} text - * @property {string} value - */ - - /** - * @typedef {PlainObject} module:jQueryPluginDBox.CheckboxInfo - * @property {string} label Label for the checkbox - * @property {string} value Value of the checkbox - * @property {string} tooltip Tooltip on the checkbox label - * @property {boolean} checked Whether the checkbox is checked by default - */ - - /** - * Triggered upon a change of value for the select pull-down. - * @callback module:jQueryPluginDBox.SelectChangeListener - * @returns {void} - */ - - /** - * Creates a dialog of the specified type with a given message - * and any defaults and type-specific metadata. Returns a `Promise` - * which resolves differently depending on whether the dialog - * was cancelled or okayed (with the response and any checked state). - * @param {"alert"|"prompt"|"select"|"process"} type - * @param {string} msg - * @param {string} [defaultVal] - * @param {module:jQueryPluginDBox.SelectOption[]} [opts] - * @param {module:jQueryPluginDBox.SelectChangeListener} [changeListener] - * @param {module:jQueryPluginDBox.CheckboxInfo} [checkbox] - * @returns {jQueryPluginDBox.ResultPromise} - */ - - function dbox(type, msg, defaultVal, opts, changeListener, checkbox) { - dialogContent.html('<p>' + msg.replace(/\n/g, '</p><p>') + '</p>').toggleClass('prompt', type === 'prompt'); - btnHolder.empty(); - var ok = $('<input type="button" data-ok="" value="' + strings.ok + '">').appendTo(btnHolder); - return new Promise(function (resolve, reject) { - // eslint-disable-line promise/avoid-new - if (type !== 'alert') { - $('<input type="button" value="' + strings.cancel + '">').appendTo(btnHolder).click(function () { - box.hide(); - resolve(false); - }); - } - - var ctrl, chkbx; - - if (type === 'prompt') { - ctrl = $('<input type="text">').prependTo(btnHolder); - ctrl.val(defaultVal || ''); - ctrl.bind('keydown', 'return', function () { - ok.click(); - }); - } else if (type === 'select') { - var div = $('<div style="text-align:center;">'); - ctrl = $("<select aria-label=\"".concat(msg, "\">")).appendTo(div); - - if (checkbox) { - var label = $('<label>').text(checkbox.label); - chkbx = $('<input type="checkbox">').appendTo(label); - chkbx.val(checkbox.value); - - if (checkbox.tooltip) { - label.attr('title', checkbox.tooltip); - } - - chkbx.prop('checked', Boolean(checkbox.checked)); - div.append($('<div>').append(label)); - } - - $.each(opts || [], function (opt, val) { - if (_typeof(val) === 'object') { - ctrl.append($('<option>').val(val.value).html(val.text)); - } else { - ctrl.append($('<option>').html(val)); - } - }); - dialogContent.append(div); - - if (defaultVal) { - ctrl.val(defaultVal); - } - - if (changeListener) { - ctrl.bind('change', 'return', changeListener); - } - - ctrl.bind('keydown', 'return', function () { - ok.click(); - }); - } else if (type === 'process') { - ok.hide(); - } - - box.show(); - ok.click(function () { - box.hide(); - var response = type === 'prompt' || type === 'select' ? ctrl.val() : true; - - if (chkbx) { - resolve({ - response: response, - checked: chkbx.prop('checked') - }); - return; - } - - resolve(response); - }).focus(); - - if (type === 'prompt' || type === 'select') { - ctrl.focus(); - } - }); - } - /** - * @param {string} msg Message to alert - * @returns {jQueryPluginDBox.ResultPromise} - */ - - - $.alert = function (msg) { - return dbox('alert', msg); - }; - /** - * @param {string} msg Message for which to ask confirmation - * @returns {jQueryPluginDBox.ResultPromise} - */ - - - $.confirm = function (msg) { - return dbox('confirm', msg); - }; - /** - * @param {string} msg Message to indicate upon cancelable indicator - * @returns {jQueryPluginDBox.ResultPromise} - */ - - - $.process_cancel = function (msg) { - return dbox('process', msg); - }; - /** - * @param {string} msg Message to accompany the prompt - * @param {string} [defaultText=''] The default text to show for the prompt - * @returns {jQueryPluginDBox.ResultPromise} - */ - - - $.prompt = function (msg) { - var defaultText = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; - return dbox('prompt', msg, defaultText); - }; - - $.select = function (msg, opts, changeListener, txt, checkbox) { - return dbox('select', msg, txt, opts, changeListener, checkbox); - }; - - return $; - } - - var $$4 = jQuery; + const $$4 = jQuery; /** * This class encapsulates the concept of a layer in the drawing. It can be constructed with * an existing group element or, with three parameters, will create a new layer group element. @@ -10043,7 +9320,7 @@ * @memberof module:layer */ - var Layer = /*#__PURE__*/function () { + class Layer { /** * @param {string} name - Layer name * @param {SVGGElement|null} group - An existing SVG group element or null. @@ -10053,17 +9330,15 @@ * @param {SVGGElement} [svgElem] - The SVG DOM element. If defined, use this to add * a new layer to the document. */ - function Layer(name, group, svgElem) { - _classCallCheck(this, Layer); - + constructor(name, group, svgElem) { this.name_ = name; this.group_ = svgElem ? null : group; if (svgElem) { // Create a group element with title and add it to the DOM. - var svgdoc = svgElem.ownerDocument; + const svgdoc = svgElem.ownerDocument; this.group_ = svgdoc.createElementNS(NS.SVG, 'g'); - var layerTitle = svgdoc.createElementNS(NS.SVG, 'title'); + const layerTitle = svgdoc.createElementNS(NS.SVG, 'title'); layerTitle.textContent = name; this.group_.append(layerTitle); @@ -10086,187 +9361,162 @@ */ - _createClass(Layer, [{ - key: "getName", - value: function getName() { + getName() { + return this.name_; + } + /** + * Get the group element for this layer. + * @returns {SVGGElement} The layer SVG group + */ + + + getGroup() { + return this.group_; + } + /** + * Active this layer so it takes pointer events. + * @returns {void} + */ + + + activate() { + this.group_.setAttribute('style', 'pointer-events:all'); + } + /** + * Deactive this layer so it does NOT take pointer events. + * @returns {void} + */ + + + deactivate() { + this.group_.setAttribute('style', 'pointer-events:none'); + } + /** + * Set this layer visible or hidden based on 'visible' parameter. + * @param {boolean} visible - If true, make visible; otherwise, hide it. + * @returns {void} + */ + + + setVisible(visible) { + const expected = visible === undefined || visible ? 'inline' : 'none'; + const oldDisplay = this.group_.getAttribute('display'); + + if (oldDisplay !== expected) { + this.group_.setAttribute('display', expected); + } + } + /** + * Is this layer visible? + * @returns {boolean} True if visible. + */ + + + isVisible() { + return this.group_.getAttribute('display') !== 'none'; + } + /** + * Get layer opacity. + * @returns {Float} Opacity value. + */ + + + getOpacity() { + const opacity = this.group_.getAttribute('opacity'); + + if (isNullish(opacity)) { + return 1; + } + + return Number.parseFloat(opacity); + } + /** + * Sets the opacity of this layer. If opacity is not a value between 0.0 and 1.0, + * nothing happens. + * @param {Float} opacity - A float value in the range 0.0-1.0 + * @returns {void} + */ + + + setOpacity(opacity) { + if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) { + this.group_.setAttribute('opacity', opacity); + } + } + /** + * Append children to this layer. + * @param {SVGGElement} children - The children to append to this layer. + * @returns {void} + */ + + + appendChildren(children) { + for (const child of children) { + this.group_.append(child); + } + } + /** + * @returns {SVGTitleElement|null} + */ + + + getTitleElement() { + const len = this.group_.childNodes.length; + + for (let i = 0; i < len; ++i) { + const child = this.group_.childNodes.item(i); + + if (child && child.tagName === 'title') { + return child; + } + } + + return null; + } + /** + * Set the name of this layer. + * @param {string} name - The new name. + * @param {module:history.HistoryRecordingService} hrService - History recording service + * @returns {string|null} The new name if changed; otherwise, null. + */ + + + setName(name, hrService) { + const previousName = this.name_; + name = toXml(name); // now change the underlying title element contents + + const title = this.getTitleElement(); + + if (title) { + $$4(title).empty(); + title.textContent = name; + this.name_ = name; + + if (hrService) { + hrService.changeElement(title, { + '#text': previousName + }); + } + return this.name_; } - /** - * Get the group element for this layer. - * @returns {SVGGElement} The layer SVG group - */ - }, { - key: "getGroup", - value: function getGroup() { - return this.group_; - } - /** - * Active this layer so it takes pointer events. - * @returns {void} - */ + return null; + } + /** + * Remove this layer's group from the DOM. No more functions on group can be called after this. + * @returns {SVGGElement} The layer SVG group that was just removed. + */ - }, { - key: "activate", - value: function activate() { - this.group_.setAttribute('style', 'pointer-events:all'); - } - /** - * Deactive this layer so it does NOT take pointer events. - * @returns {void} - */ - }, { - key: "deactivate", - value: function deactivate() { - this.group_.setAttribute('style', 'pointer-events:none'); - } - /** - * Set this layer visible or hidden based on 'visible' parameter. - * @param {boolean} visible - If true, make visible; otherwise, hide it. - * @returns {void} - */ + removeGroup() { + const group = this.group_; + this.group_.remove(); + this.group_ = undefined; + return group; + } - }, { - key: "setVisible", - value: function setVisible(visible) { - var expected = visible === undefined || visible ? 'inline' : 'none'; - var oldDisplay = this.group_.getAttribute('display'); - - if (oldDisplay !== expected) { - this.group_.setAttribute('display', expected); - } - } - /** - * Is this layer visible? - * @returns {boolean} True if visible. - */ - - }, { - key: "isVisible", - value: function isVisible() { - return this.group_.getAttribute('display') !== 'none'; - } - /** - * Get layer opacity. - * @returns {Float} Opacity value. - */ - - }, { - key: "getOpacity", - value: function getOpacity() { - var opacity = this.group_.getAttribute('opacity'); - - if (isNullish(opacity)) { - return 1; - } - - return Number.parseFloat(opacity); - } - /** - * Sets the opacity of this layer. If opacity is not a value between 0.0 and 1.0, - * nothing happens. - * @param {Float} opacity - A float value in the range 0.0-1.0 - * @returns {void} - */ - - }, { - key: "setOpacity", - value: function setOpacity(opacity) { - if (typeof opacity === 'number' && opacity >= 0.0 && opacity <= 1.0) { - this.group_.setAttribute('opacity', opacity); - } - } - /** - * Append children to this layer. - * @param {SVGGElement} children - The children to append to this layer. - * @returns {void} - */ - - }, { - key: "appendChildren", - value: function appendChildren(children) { - var _iterator = _createForOfIteratorHelper(children), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var child = _step.value; - this.group_.append(child); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); - } - } - /** - * @returns {SVGTitleElement|null} - */ - - }, { - key: "getTitleElement", - value: function getTitleElement() { - var len = this.group_.childNodes.length; - - for (var i = 0; i < len; ++i) { - var child = this.group_.childNodes.item(i); - - if (child && child.tagName === 'title') { - return child; - } - } - - return null; - } - /** - * Set the name of this layer. - * @param {string} name - The new name. - * @param {module:history.HistoryRecordingService} hrService - History recording service - * @returns {string|null} The new name if changed; otherwise, null. - */ - - }, { - key: "setName", - value: function setName(name, hrService) { - var previousName = this.name_; - name = toXml(name); // now change the underlying title element contents - - var title = this.getTitleElement(); - - if (title) { - $$4(title).empty(); - title.textContent = name; - this.name_ = name; - - if (hrService) { - hrService.changeElement(title, { - '#text': previousName - }); - } - - return this.name_; - } - - return null; - } - /** - * Remove this layer's group from the DOM. No more functions on group can be called after this. - * @returns {SVGGElement} The layer SVG group that was just removed. - */ - - }, { - key: "removeGroup", - value: function removeGroup() { - var group = this.group_; - this.group_.remove(); - this.group_ = undefined; - return group; - } - }]); - - return Layer; - }(); + } /** * @property {string} CLASS_NAME - class attribute assigned to all layer groups. */ @@ -10286,7 +9536,7 @@ */ function addLayerClass(elem) { - var classes = elem.getAttribute('class'); + const classes = elem.getAttribute('class'); if (isNullish(classes) || !classes.length) { elem.setAttribute('class', Layer.CLASS_NAME); @@ -10295,6 +9545,12 @@ } } + /** + * HistoryRecordingService component of history. + * @module history + * @license MIT + * @copyright 2016 Flint O'Brien + */ /** * History recording service. * @@ -10328,15 +9584,13 @@ * @memberof module:history */ - var HistoryRecordingService = /*#__PURE__*/function () { + class HistoryRecordingService { /** * @param {history.UndoManager|null} undoManager - The undo manager. * A value of `null` is valid for cases where no history recording is required. * See singleton: {@link module:history.HistoryRecordingService.HistoryRecordingService.NO_HISTORY} */ - function HistoryRecordingService(undoManager) { - _classCallCheck(this, HistoryRecordingService); - + constructor(undoManager) { this.undoManager_ = undoManager; this.currentBatchCommand_ = null; this.batchCommandStack_ = []; @@ -10350,138 +9604,130 @@ */ - _createClass(HistoryRecordingService, [{ - key: "startBatchCommand", - value: function startBatchCommand(text) { - if (!this.undoManager_) { - return this; - } - - this.currentBatchCommand_ = new BatchCommand(text); - this.batchCommandStack_.push(this.currentBatchCommand_); + startBatchCommand(text) { + if (!this.undoManager_) { return this; } - /** - * End a batch command and add it to the history or a parent batch command. - * @returns {module:history.HistoryRecordingService} - */ - }, { - key: "endBatchCommand", - value: function endBatchCommand() { - if (!this.undoManager_) { - return this; - } + this.currentBatchCommand_ = new BatchCommand(text); + this.batchCommandStack_.push(this.currentBatchCommand_); + return this; + } + /** + * End a batch command and add it to the history or a parent batch command. + * @returns {module:history.HistoryRecordingService} + */ - if (this.currentBatchCommand_) { - var batchCommand = this.currentBatchCommand_; - this.batchCommandStack_.pop(); - var len = this.batchCommandStack_.length; - this.currentBatchCommand_ = len ? this.batchCommandStack_[len - 1] : null; - this.addCommand_(batchCommand); - } + endBatchCommand() { + if (!this.undoManager_) { return this; } - /** - * Add a `MoveElementCommand` to the history or current batch command. - * @param {Element} elem - The DOM element that was moved - * @param {Element} oldNextSibling - The element's next sibling before it was moved - * @param {Element} oldParent - The element's parent before it was moved - * @param {string} [text] - An optional string visible to user related to this change - * @returns {module:history.HistoryRecordingService} - */ - }, { - key: "moveElement", - value: function moveElement(elem, oldNextSibling, oldParent, text) { - if (!this.undoManager_) { - return this; - } + if (this.currentBatchCommand_) { + const batchCommand = this.currentBatchCommand_; + this.batchCommandStack_.pop(); + const { + length: len + } = this.batchCommandStack_; + this.currentBatchCommand_ = len ? this.batchCommandStack_[len - 1] : null; + this.addCommand_(batchCommand); + } - this.addCommand_(new MoveElementCommand(elem, oldNextSibling, oldParent, text)); + return this; + } + /** + * Add a `MoveElementCommand` to the history or current batch command. + * @param {Element} elem - The DOM element that was moved + * @param {Element} oldNextSibling - The element's next sibling before it was moved + * @param {Element} oldParent - The element's parent before it was moved + * @param {string} [text] - An optional string visible to user related to this change + * @returns {module:history.HistoryRecordingService} + */ + + + moveElement(elem, oldNextSibling, oldParent, text) { + if (!this.undoManager_) { return this; } - /** - * Add an `InsertElementCommand` to the history or current batch command. - * @param {Element} elem - The DOM element that was added - * @param {string} [text] - An optional string visible to user related to this change - * @returns {module:history.HistoryRecordingService} - */ - }, { - key: "insertElement", - value: function insertElement(elem, text) { - if (!this.undoManager_) { - return this; - } + this.addCommand_(new MoveElementCommand(elem, oldNextSibling, oldParent, text)); + return this; + } + /** + * Add an `InsertElementCommand` to the history or current batch command. + * @param {Element} elem - The DOM element that was added + * @param {string} [text] - An optional string visible to user related to this change + * @returns {module:history.HistoryRecordingService} + */ - this.addCommand_(new InsertElementCommand(elem, text)); + + insertElement(elem, text) { + if (!this.undoManager_) { return this; } - /** - * Add a `RemoveElementCommand` to the history or current batch command. - * @param {Element} elem - The DOM element that was removed - * @param {Element} oldNextSibling - The element's next sibling before it was removed - * @param {Element} oldParent - The element's parent before it was removed - * @param {string} [text] - An optional string visible to user related to this change - * @returns {module:history.HistoryRecordingService} - */ - }, { - key: "removeElement", - value: function removeElement(elem, oldNextSibling, oldParent, text) { - if (!this.undoManager_) { - return this; - } + this.addCommand_(new InsertElementCommand(elem, text)); + return this; + } + /** + * Add a `RemoveElementCommand` to the history or current batch command. + * @param {Element} elem - The DOM element that was removed + * @param {Element} oldNextSibling - The element's next sibling before it was removed + * @param {Element} oldParent - The element's parent before it was removed + * @param {string} [text] - An optional string visible to user related to this change + * @returns {module:history.HistoryRecordingService} + */ - this.addCommand_(new RemoveElementCommand(elem, oldNextSibling, oldParent, text)); + + removeElement(elem, oldNextSibling, oldParent, text) { + if (!this.undoManager_) { return this; } - /** - * Add a `ChangeElementCommand` to the history or current batch command. - * @param {Element} elem - The DOM element that was changed - * @param {module:history.CommandAttributes} attrs - An object with the attributes to be changed and the values they had *before* the change - * @param {string} [text] - An optional string visible to user related to this change - * @returns {module:history.HistoryRecordingService} - */ - }, { - key: "changeElement", - value: function changeElement(elem, attrs, text) { - if (!this.undoManager_) { - return this; - } + this.addCommand_(new RemoveElementCommand(elem, oldNextSibling, oldParent, text)); + return this; + } + /** + * Add a `ChangeElementCommand` to the history or current batch command. + * @param {Element} elem - The DOM element that was changed + * @param {module:history.CommandAttributes} attrs - An object with the attributes to be changed and the values they had *before* the change + * @param {string} [text] - An optional string visible to user related to this change + * @returns {module:history.HistoryRecordingService} + */ - this.addCommand_(new ChangeElementCommand(elem, attrs, text)); + + changeElement(elem, attrs, text) { + if (!this.undoManager_) { return this; } - /** - * Private function to add a command to the history or current batch command. - * @private - * @param {Command} cmd - * @returns {module:history.HistoryRecordingService|void} - */ - }, { - key: "addCommand_", - value: function addCommand_(cmd) { - if (!this.undoManager_) { - return this; - } + this.addCommand_(new ChangeElementCommand(elem, attrs, text)); + return this; + } + /** + * Private function to add a command to the history or current batch command. + * @private + * @param {Command} cmd + * @returns {module:history.HistoryRecordingService|void} + */ - if (this.currentBatchCommand_) { - this.currentBatchCommand_.addSubCommand(cmd); - } else { - this.undoManager_.addCommandToHistory(cmd); - } - return undefined; + addCommand_(cmd) { + if (!this.undoManager_) { + return this; } - }]); - return HistoryRecordingService; - }(); + if (this.currentBatchCommand_) { + this.currentBatchCommand_.addSubCommand(cmd); + } else { + this.undoManager_.addCommandToHistory(cmd); + } + + return undefined; + } + + } /** * @memberof module:history.HistoryRecordingService * @property {module:history.HistoryRecordingService} NO_HISTORY - Singleton that can be passed to functions that record history, but the caller requires that no history be recorded. @@ -10490,16 +9736,73 @@ HistoryRecordingService.NO_HISTORY = new HistoryRecordingService(); - var $$5 = jQuery; - var visElems$1 = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(','); - var RandomizeModes = { + /* globals jQuery */ + + const $$5 = jQueryPluginSVG(jQuery); + /** + * Create a clone of an element, updating its ID and its children's IDs when needed. + * @function module:utilities.copyElem + * @param {Element} el - DOM element to clone + * @param {module:utilities.GetNextID} getNextId - The getter of the next unique ID. + * @returns {Element} The cloned element + */ + + const copyElem = function (el, getNextId) { + // manually create a copy of the element + const newEl = document.createElementNS(el.namespaceURI, el.nodeName); + $$5.each(el.attributes, function (i, attr) { + if (attr.localName !== '-moz-math-font-style') { + newEl.setAttributeNS(attr.namespaceURI, attr.nodeName, attr.value); + } + }); // set the copied element's new id + + newEl.removeAttribute('id'); + newEl.id = getNextId(); // Opera's "d" value needs to be reset for Opera/Win/non-EN + // Also needed for webkit (else does not keep curved segments on clone) + + if (isWebkit() && el.nodeName === 'path') { + const fixedD = convertPath(el); + newEl.setAttribute('d', fixedD); + } // now create copies of all children + + + $$5.each(el.childNodes, function (i, child) { + switch (child.nodeType) { + case 1: + // element node + newEl.append(copyElem(child, getNextId)); + break; + + case 3: + // text node + newEl.textContent = child.nodeValue; + break; + } + }); + + if ($$5(el).data('gsvg')) { + $$5(newEl).data('gsvg', newEl.firstChild); + } else if ($$5(el).data('symbol')) { + const ref = $$5(el).data('symbol'); + $$5(newEl).data('ref', ref).data('symbol', ref); + } else if (newEl.tagName === 'image') { + preventClickDefault(newEl); + } + + return newEl; + }; + + /* globals jQuery */ + const $$6 = jQuery; + const visElems$1 = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'.split(','); + const RandomizeModes = { LET_DOCUMENT_DECIDE: 0, ALWAYS_RANDOMIZE: 1, NEVER_RANDOMIZE: 2 }; - var randIds = RandomizeModes.LET_DOCUMENT_DECIDE; // Array with current disabled elements (for in-group editing) + let randIds = RandomizeModes.LET_DOCUMENT_DECIDE; // Array with current disabled elements (for in-group editing) - var disabledElems = []; + let disabledElems = []; /** * Get a HistoryRecordingService. * @param {module:history.HistoryRecordingService} [hrService] - if exists, return it instead of creating a new service. @@ -10517,8 +9820,8 @@ function findLayerNameInGroup(group) { - return $$5('title', group).text() || (isOpera() && group.querySelectorAll // Hack for Opera 10.60 - ? $$5(group.querySelectorAll('title')).text() : ''); + return $$6('title', group).text() || (isOpera() && group.querySelectorAll // Hack for Opera 10.60 + ? $$6(group.querySelectorAll('title')).text() : ''); } /** * Given a set of names, return a new unique name. @@ -10528,7 +9831,7 @@ function getNewLayerName(existingLayerNames) { - var i = 1; // TODO(codedread): What about internationalization of "Layer"? + let i = 1; // TODO(codedread): What about internationalization of "Layer"? while (existingLayerNames.includes('Layer ' + i)) { i++; @@ -10541,7 +9844,7 @@ */ - var Drawing = /*#__PURE__*/function () { + class Drawing { /** * @param {SVGSVGElement} svgElem - The SVG DOM Element that this JS object * encapsulates. If the svgElem has a se:nonce attribute on it, then @@ -10549,9 +9852,7 @@ * @param {string} [optIdPrefix=svg_] - The ID prefix to use. * @throws {Error} If not initialized with an SVG element */ - function Drawing(svgElem, optIdPrefix) { - _classCallCheck(this, Drawing); - + constructor(svgElem, optIdPrefix) { if (!svgElem || !svgElem.tagName || !svgElem.namespaceURI || svgElem.tagName !== 'svg' || svgElem.namespaceURI !== NS.SVG) { throw new Error('Error: svgedit.draw.Drawing instance initialized without a <svg> element'); } @@ -10610,7 +9911,7 @@ */ this.nonce_ = ''; - var n = this.svgElem_.getAttributeNS(NS.SE, 'nonce'); // If already set in the DOM, use the nonce throughout the document + const n = this.svgElem_.getAttributeNS(NS.SE, 'nonce'); // If already set in the DOM, use the nonce throughout the document // else, if randomizeIds(true) has been called, create and set the nonce. if (n && randIds !== RandomizeModes.NEVER_RANDOMIZE) { @@ -10625,644 +9926,608 @@ */ - _createClass(Drawing, [{ - key: "getElem_", - value: function getElem_(id) { - if (this.svgElem_.querySelector) { - // querySelector lookup - return this.svgElem_.querySelector('#' + id); - } // jQuery lookup: twice as slow as xpath in FF - // eslint-disable-next-line unicorn/no-fn-reference-in-iterator + getElem_(id) { + if (this.svgElem_.querySelector) { + // querySelector lookup + return this.svgElem_.querySelector('#' + id); + } // jQuery lookup: twice as slow as xpath in FF + // eslint-disable-next-line unicorn/no-fn-reference-in-iterator - return $$5(this.svgElem_).find('[id=' + id + ']')[0]; - } - /** - * @returns {SVGSVGElement} - */ - - }, { - key: "getSvgElem", - value: function getSvgElem() { - return this.svgElem_; - } - /** - * @returns {!(string|Integer)} The previously set nonce - */ - - }, { - key: "getNonce", - value: function getNonce() { - return this.nonce_; - } - /** - * @param {!(string|Integer)} n The nonce to set - * @returns {void} - */ - - }, { - key: "setNonce", - value: function setNonce(n) { - this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE); - this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n); - this.nonce_ = n; - } - /** - * Clears any previously set nonce. - * @returns {void} - */ - - }, { - key: "clearNonce", - value: function clearNonce() { - // We deliberately leave any se:nonce attributes alone, - // we just don't use it to randomize ids. - this.nonce_ = ''; - } - /** - * Returns the latest object id as a string. - * @returns {string} The latest object Id. - */ - - }, { - key: "getId", - value: function getId() { - return this.nonce_ ? this.idPrefix + this.nonce_ + '_' + this.obj_num : this.idPrefix + this.obj_num; - } - /** - * Returns the next object Id as a string. - * @returns {string} The next object Id to use. - */ - - }, { - key: "getNextId", - value: function getNextId() { - var oldObjNum = this.obj_num; - var restoreOldObjNum = false; // If there are any released numbers in the release stack, - // use the last one instead of the next obj_num. - // We need to temporarily use obj_num as that is what getId() depends on. - - if (this.releasedNums.length > 0) { - this.obj_num = this.releasedNums.pop(); - restoreOldObjNum = true; - } else { - // If we are not using a released id, then increment the obj_num. - this.obj_num++; - } // Ensure the ID does not exist. + return $$6(this.svgElem_).find('[id=' + id + ']')[0]; + } + /** + * @returns {SVGSVGElement} + */ - var id = this.getId(); - - while (this.getElem_(id)) { - if (restoreOldObjNum) { - this.obj_num = oldObjNum; - restoreOldObjNum = false; - } - - this.obj_num++; - id = this.getId(); - } // Restore the old object number if required. + getSvgElem() { + return this.svgElem_; + } + /** + * @returns {!(string|Integer)} The previously set nonce + */ + getNonce() { + return this.nonce_; + } + /** + * @param {!(string|Integer)} n The nonce to set + * @returns {void} + */ + + + setNonce(n) { + this.svgElem_.setAttributeNS(NS.XMLNS, 'xmlns:se', NS.SE); + this.svgElem_.setAttributeNS(NS.SE, 'se:nonce', n); + this.nonce_ = n; + } + /** + * Clears any previously set nonce. + * @returns {void} + */ + + + clearNonce() { + // We deliberately leave any se:nonce attributes alone, + // we just don't use it to randomize ids. + this.nonce_ = ''; + } + /** + * Returns the latest object id as a string. + * @returns {string} The latest object Id. + */ + + + getId() { + return this.nonce_ ? this.idPrefix + this.nonce_ + '_' + this.obj_num : this.idPrefix + this.obj_num; + } + /** + * Returns the next object Id as a string. + * @returns {string} The next object Id to use. + */ + + + getNextId() { + const oldObjNum = this.obj_num; + let restoreOldObjNum = false; // If there are any released numbers in the release stack, + // use the last one instead of the next obj_num. + // We need to temporarily use obj_num as that is what getId() depends on. + + if (this.releasedNums.length > 0) { + this.obj_num = this.releasedNums.pop(); + restoreOldObjNum = true; + } else { + // If we are not using a released id, then increment the obj_num. + this.obj_num++; + } // Ensure the ID does not exist. + + + let id = this.getId(); + + while (this.getElem_(id)) { if (restoreOldObjNum) { this.obj_num = oldObjNum; + restoreOldObjNum = false; } - return id; + this.obj_num++; + id = this.getId(); + } // Restore the old object number if required. + + + if (restoreOldObjNum) { + this.obj_num = oldObjNum; } - /** - * Releases the object Id, letting it be used as the next id in getNextId(). - * This method DOES NOT remove any elements from the DOM, it is expected - * that client code will do this. - * @param {string} id - The id to release. - * @returns {boolean} True if the id was valid to be released, false otherwise. - */ - }, { - key: "releaseId", - value: function releaseId(id) { - // confirm if this is a valid id for this Document, else return false - var front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : ''); - - if (typeof id !== 'string' || !id.startsWith(front)) { - return false; - } // extract the obj_num of this id + return id; + } + /** + * Releases the object Id, letting it be used as the next id in getNextId(). + * This method DOES NOT remove any elements from the DOM, it is expected + * that client code will do this. + * @param {string} id - The id to release. + * @returns {boolean} True if the id was valid to be released, false otherwise. + */ - var num = Number.parseInt(id.substr(front.length)); // if we didn't get a positive number or we already released this number - // then return false. - - if (typeof num !== 'number' || num <= 0 || this.releasedNums.includes(num)) { - return false; - } // push the released number into the released queue - - - this.releasedNums.push(num); - return true; - } - /** - * Returns the number of layers in the current drawing. - * @returns {Integer} The number of layers in the current drawing. - */ - - }, { - key: "getNumLayers", - value: function getNumLayers() { - return this.all_layers.length; - } - /** - * Check if layer with given name already exists. - * @param {string} name - The layer name to check - * @returns {boolean} - */ - - }, { - key: "hasLayer", - value: function hasLayer(name) { - return this.layer_map[name] !== undefined; - } - /** - * Returns the name of the ith layer. If the index is out of range, an empty string is returned. - * @param {Integer} i - The zero-based index of the layer you are querying. - * @returns {string} The name of the ith layer (or the empty string if none found) - */ - - }, { - key: "getLayerName", - value: function getLayerName(i) { - return i >= 0 && i < this.getNumLayers() ? this.all_layers[i].getName() : ''; - } - /** - * @returns {SVGGElement|null} The SVGGElement representing the current layer. - */ - - }, { - key: "getCurrentLayer", - value: function getCurrentLayer() { - return this.current_layer ? this.current_layer.getGroup() : null; - } - /** - * Get a layer by name. - * @param {string} name - * @returns {SVGGElement} The SVGGElement representing the named layer or null. - */ - - }, { - key: "getLayerByName", - value: function getLayerByName(name) { - var layer = this.layer_map[name]; - return layer ? layer.getGroup() : null; - } - /** - * Returns the name of the currently selected layer. If an error occurs, an empty string - * is returned. - * @returns {string} The name of the currently active layer (or the empty string if none found). - */ - - }, { - key: "getCurrentLayerName", - value: function getCurrentLayerName() { - return this.current_layer ? this.current_layer.getName() : ''; - } - /** - * Set the current layer's name. - * @param {string} name - The new name. - * @param {module:history.HistoryRecordingService} hrService - History recording service - * @returns {string|null} The new name if changed; otherwise, null. - */ - - }, { - key: "setCurrentLayerName", - value: function setCurrentLayerName(name, hrService) { - var finalName = null; - - if (this.current_layer) { - var oldName = this.current_layer.getName(); - finalName = this.current_layer.setName(name, hrService); - - if (finalName) { - delete this.layer_map[oldName]; - this.layer_map[finalName] = this.current_layer; - } - } - - return finalName; - } - /** - * Set the current layer's position. - * @param {Integer} newpos - The zero-based index of the new position of the layer. Range should be 0 to layers-1 - * @returns {{title: SVGGElement, previousName: string}|null} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null. - */ - - }, { - key: "setCurrentLayerPosition", - value: function setCurrentLayerPosition(newpos) { - var layerCount = this.getNumLayers(); - - if (!this.current_layer || newpos < 0 || newpos >= layerCount) { - return null; - } - - var oldpos; - - for (oldpos = 0; oldpos < layerCount; ++oldpos) { - if (this.all_layers[oldpos] === this.current_layer) { - break; - } - } // some unknown error condition (current_layer not in all_layers) - - - if (oldpos === layerCount) { - return null; - } - - if (oldpos !== newpos) { - // if our new position is below us, we need to insert before the node after newpos - var currentGroup = this.current_layer.getGroup(); - var oldNextSibling = currentGroup.nextSibling; - var refGroup = null; - - if (newpos > oldpos) { - if (newpos < layerCount - 1) { - refGroup = this.all_layers[newpos + 1].getGroup(); - } // if our new position is above us, we need to insert before the node at newpos - - } else { - refGroup = this.all_layers[newpos].getGroup(); - } - - this.svgElem_.insertBefore(currentGroup, refGroup); // Ok to replace with `refGroup.before(currentGroup);`? - - this.identifyLayers(); - this.setCurrentLayer(this.getLayerName(newpos)); - return { - currentGroup: currentGroup, - oldNextSibling: oldNextSibling - }; - } - - return null; - } - /** - * @param {module:history.HistoryRecordingService} hrService - * @returns {void} - */ - - }, { - key: "mergeLayer", - value: function mergeLayer(hrService) { - var currentGroup = this.current_layer.getGroup(); - var prevGroup = $$5(currentGroup).prev()[0]; - - if (!prevGroup) { - return; - } - - hrService.startBatchCommand('Merge Layer'); - var layerNextSibling = currentGroup.nextSibling; - hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_); - - while (currentGroup.firstChild) { - var child = currentGroup.firstChild; - - if (child.localName === 'title') { - hrService.removeElement(child, child.nextSibling, currentGroup); - child.remove(); - continue; - } - - var oldNextSibling = child.nextSibling; - prevGroup.append(child); - hrService.moveElement(child, oldNextSibling, currentGroup); - } // Remove current layer's group - - - this.current_layer.removeGroup(); // Remove the current layer and set the previous layer as the new current layer - - var index = this.all_layers.indexOf(this.current_layer); - - if (index > 0) { - var _name = this.current_layer.getName(); - - this.current_layer = this.all_layers[index - 1]; - this.all_layers.splice(index, 1); - delete this.layer_map[_name]; - } - - hrService.endBatchCommand(); - } - /** - * @param {module:history.HistoryRecordingService} hrService - * @returns {void} - */ - - }, { - key: "mergeAllLayers", - value: function mergeAllLayers(hrService) { - // Set the current layer to the last layer. - this.current_layer = this.all_layers[this.all_layers.length - 1]; - hrService.startBatchCommand('Merge all Layers'); - - while (this.all_layers.length > 1) { - this.mergeLayer(hrService); - } - - hrService.endBatchCommand(); - } - /** - * Sets the current layer. If the name is not a valid layer name, then this - * function returns `false`. Otherwise it returns `true`. This is not an - * undo-able action. - * @param {string} name - The name of the layer you want to switch to. - * @returns {boolean} `true` if the current layer was switched, otherwise `false` - */ - - }, { - key: "setCurrentLayer", - value: function setCurrentLayer(name) { - var layer = this.layer_map[name]; - - if (layer) { - if (this.current_layer) { - this.current_layer.deactivate(); - } - - this.current_layer = layer; - this.current_layer.activate(); - return true; - } + releaseId(id) { + // confirm if this is a valid id for this Document, else return false + const front = this.idPrefix + (this.nonce_ ? this.nonce_ + '_' : ''); + if (typeof id !== 'string' || !id.startsWith(front)) { return false; - } - /** - * Deletes the current layer from the drawing and then clears the selection. - * This function then calls the 'changed' handler. This is an undoable action. - * @todo Does this actually call the 'changed' handler? - * @returns {SVGGElement} The SVGGElement of the layer removed or null. - */ + } // extract the obj_num of this id - }, { - key: "deleteCurrentLayer", - value: function deleteCurrentLayer() { - if (this.current_layer && this.getNumLayers() > 1) { - var oldLayerGroup = this.current_layer.removeGroup(); - this.identifyLayers(); - return oldLayerGroup; + + const num = Number.parseInt(id.substr(front.length)); // if we didn't get a positive number or we already released this number + // then return false. + + if (typeof num !== 'number' || num <= 0 || this.releasedNums.includes(num)) { + return false; + } // push the released number into the released queue + + + this.releasedNums.push(num); + return true; + } + /** + * Returns the number of layers in the current drawing. + * @returns {Integer} The number of layers in the current drawing. + */ + + + getNumLayers() { + return this.all_layers.length; + } + /** + * Check if layer with given name already exists. + * @param {string} name - The layer name to check + * @returns {boolean} + */ + + + hasLayer(name) { + return this.layer_map[name] !== undefined; + } + /** + * Returns the name of the ith layer. If the index is out of range, an empty string is returned. + * @param {Integer} i - The zero-based index of the layer you are querying. + * @returns {string} The name of the ith layer (or the empty string if none found) + */ + + + getLayerName(i) { + return i >= 0 && i < this.getNumLayers() ? this.all_layers[i].getName() : ''; + } + /** + * @returns {SVGGElement|null} The SVGGElement representing the current layer. + */ + + + getCurrentLayer() { + return this.current_layer ? this.current_layer.getGroup() : null; + } + /** + * Get a layer by name. + * @param {string} name + * @returns {SVGGElement} The SVGGElement representing the named layer or null. + */ + + + getLayerByName(name) { + const layer = this.layer_map[name]; + return layer ? layer.getGroup() : null; + } + /** + * Returns the name of the currently selected layer. If an error occurs, an empty string + * is returned. + * @returns {string} The name of the currently active layer (or the empty string if none found). + */ + + + getCurrentLayerName() { + return this.current_layer ? this.current_layer.getName() : ''; + } + /** + * Set the current layer's name. + * @param {string} name - The new name. + * @param {module:history.HistoryRecordingService} hrService - History recording service + * @returns {string|null} The new name if changed; otherwise, null. + */ + + + setCurrentLayerName(name, hrService) { + let finalName = null; + + if (this.current_layer) { + const oldName = this.current_layer.getName(); + finalName = this.current_layer.setName(name, hrService); + + if (finalName) { + delete this.layer_map[oldName]; + this.layer_map[finalName] = this.current_layer; } + } + return finalName; + } + /** + * Set the current layer's position. + * @param {Integer} newpos - The zero-based index of the new position of the layer. Range should be 0 to layers-1 + * @returns {{title: SVGGElement, previousName: string}|null} If the name was changed, returns {title:SVGGElement, previousName:string}; otherwise null. + */ + + + setCurrentLayerPosition(newpos) { + const layerCount = this.getNumLayers(); + + if (!this.current_layer || newpos < 0 || newpos >= layerCount) { return null; } - /** - * Updates layer system and sets the current layer to the - * top-most layer (last `<g>` child of this drawing). - * @returns {void} - */ - }, { - key: "identifyLayers", - value: function identifyLayers() { - this.all_layers = []; - this.layer_map = {}; - var numchildren = this.svgElem_.childNodes.length; // loop through all children of SVG element + let oldpos; - var orphans = [], - layernames = []; - var layer = null; - var childgroups = false; - - for (var i = 0; i < numchildren; ++i) { - var child = this.svgElem_.childNodes.item(i); // for each g, find its layer name - - if (child && child.nodeType === 1) { - if (child.tagName === 'g') { - childgroups = true; - - var _name2 = findLayerNameInGroup(child); - - if (_name2) { - layernames.push(_name2); - layer = new Layer(_name2, child); - this.all_layers.push(layer); - this.layer_map[_name2] = layer; - } else { - // if group did not have a name, it is an orphan - orphans.push(child); - } - } else if (visElems$1.includes(child.nodeName)) { - // Child is "visible" (i.e. not a <title> or <defs> element), so it is an orphan - orphans.push(child); - } - } - } // If orphans or no layers found, create a new layer and add all the orphans to it + for (oldpos = 0; oldpos < layerCount; ++oldpos) { + if (this.all_layers[oldpos] === this.current_layer) { + break; + } + } // some unknown error condition (current_layer not in all_layers) - if (orphans.length > 0 || !childgroups) { - layer = new Layer(getNewLayerName(layernames), null, this.svgElem_); - layer.appendChildren(orphans); - this.all_layers.push(layer); - this.layer_map[name] = layer; + if (oldpos === layerCount) { + return null; + } + + if (oldpos !== newpos) { + // if our new position is below us, we need to insert before the node after newpos + const currentGroup = this.current_layer.getGroup(); + const oldNextSibling = currentGroup.nextSibling; + let refGroup = null; + + if (newpos > oldpos) { + if (newpos < layerCount - 1) { + refGroup = this.all_layers[newpos + 1].getGroup(); + } // if our new position is above us, we need to insert before the node at newpos + } else { - layer.activate(); + refGroup = this.all_layers[newpos].getGroup(); } - this.current_layer = layer; - } - /** - * Creates a new top-level layer in the drawing with the given name and - * makes it the current layer. - * @param {string} name - The given name. If the layer name exists, a new name will be generated. - * @param {module:history.HistoryRecordingService} hrService - History recording service - * @returns {SVGGElement} The SVGGElement of the new layer, which is - * also the current layer of this drawing. - */ + this.svgElem_.insertBefore(currentGroup, refGroup); // Ok to replace with `refGroup.before(currentGroup);`? - }, { - key: "createLayer", - value: function createLayer(name, hrService) { + this.identifyLayers(); + this.setCurrentLayer(this.getLayerName(newpos)); + return { + currentGroup, + oldNextSibling + }; + } + + return null; + } + /** + * @param {module:history.HistoryRecordingService} hrService + * @returns {void} + */ + + + mergeLayer(hrService) { + const currentGroup = this.current_layer.getGroup(); + const prevGroup = $$6(currentGroup).prev()[0]; + + if (!prevGroup) { + return; + } + + hrService.startBatchCommand('Merge Layer'); + const layerNextSibling = currentGroup.nextSibling; + hrService.removeElement(currentGroup, layerNextSibling, this.svgElem_); + + while (currentGroup.firstChild) { + const child = currentGroup.firstChild; + + if (child.localName === 'title') { + hrService.removeElement(child, child.nextSibling, currentGroup); + child.remove(); + continue; + } + + const oldNextSibling = child.nextSibling; + prevGroup.append(child); + hrService.moveElement(child, oldNextSibling, currentGroup); + } // Remove current layer's group + + + this.current_layer.removeGroup(); // Remove the current layer and set the previous layer as the new current layer + + const index = this.all_layers.indexOf(this.current_layer); + + if (index > 0) { + const name = this.current_layer.getName(); + this.current_layer = this.all_layers[index - 1]; + this.all_layers.splice(index, 1); + delete this.layer_map[name]; + } + + hrService.endBatchCommand(); + } + /** + * @param {module:history.HistoryRecordingService} hrService + * @returns {void} + */ + + + mergeAllLayers(hrService) { + // Set the current layer to the last layer. + this.current_layer = this.all_layers[this.all_layers.length - 1]; + hrService.startBatchCommand('Merge all Layers'); + + while (this.all_layers.length > 1) { + this.mergeLayer(hrService); + } + + hrService.endBatchCommand(); + } + /** + * Sets the current layer. If the name is not a valid layer name, then this + * function returns `false`. Otherwise it returns `true`. This is not an + * undo-able action. + * @param {string} name - The name of the layer you want to switch to. + * @returns {boolean} `true` if the current layer was switched, otherwise `false` + */ + + + setCurrentLayer(name) { + const layer = this.layer_map[name]; + + if (layer) { if (this.current_layer) { this.current_layer.deactivate(); - } // Check for duplicate name. - - - if (name === undefined || name === null || name === '' || this.layer_map[name]) { - name = getNewLayerName(Object.keys(this.layer_map)); - } // Crate new layer and add to DOM as last layer - - - var layer = new Layer(name, null, this.svgElem_); // Like to assume hrService exists, but this is backwards compatible with old version of createLayer. - - if (hrService) { - hrService.startBatchCommand('Create Layer'); - hrService.insertElement(layer.getGroup()); - hrService.endBatchCommand(); } + this.current_layer = layer; + this.current_layer.activate(); + return true; + } + + return false; + } + /** + * Deletes the current layer from the drawing and then clears the selection. + * This function then calls the 'changed' handler. This is an undoable action. + * @todo Does this actually call the 'changed' handler? + * @returns {SVGGElement} The SVGGElement of the layer removed or null. + */ + + + deleteCurrentLayer() { + if (this.current_layer && this.getNumLayers() > 1) { + const oldLayerGroup = this.current_layer.removeGroup(); + this.identifyLayers(); + return oldLayerGroup; + } + + return null; + } + /** + * Updates layer system and sets the current layer to the + * top-most layer (last `<g>` child of this drawing). + * @returns {void} + */ + + + identifyLayers() { + this.all_layers = []; + this.layer_map = {}; + const numchildren = this.svgElem_.childNodes.length; // loop through all children of SVG element + + const orphans = [], + layernames = []; + let layer = null; + let childgroups = false; + + for (let i = 0; i < numchildren; ++i) { + const child = this.svgElem_.childNodes.item(i); // for each g, find its layer name + + if (child && child.nodeType === 1) { + if (child.tagName === 'g') { + childgroups = true; + const name = findLayerNameInGroup(child); + + if (name) { + layernames.push(name); + layer = new Layer(name, child); + this.all_layers.push(layer); + this.layer_map[name] = layer; + } else { + // if group did not have a name, it is an orphan + orphans.push(child); + } + } else if (visElems$1.includes(child.nodeName)) { + // Child is "visible" (i.e. not a <title> or <defs> element), so it is an orphan + orphans.push(child); + } + } + } // If orphans or no layers found, create a new layer and add all the orphans to it + + + if (orphans.length > 0 || !childgroups) { + layer = new Layer(getNewLayerName(layernames), null, this.svgElem_); + layer.appendChildren(orphans); this.all_layers.push(layer); this.layer_map[name] = layer; - this.current_layer = layer; - return layer.getGroup(); + } else { + layer.activate(); } - /** - * Creates a copy of the current layer with the given name and makes it the current layer. - * @param {string} name - The given name. If the layer name exists, a new name will be generated. - * @param {module:history.HistoryRecordingService} hrService - History recording service - * @returns {SVGGElement} The SVGGElement of the new layer, which is - * also the current layer of this drawing. - */ - }, { - key: "cloneLayer", - value: function cloneLayer(name, hrService) { - var _this = this; - - if (!this.current_layer) { - return null; - } - - this.current_layer.deactivate(); // Check for duplicate name. - - if (name === undefined || name === null || name === '' || this.layer_map[name]) { - name = getNewLayerName(Object.keys(this.layer_map)); - } // Create new group and add to DOM just after current_layer + this.current_layer = layer; + } + /** + * Creates a new top-level layer in the drawing with the given name and + * makes it the current layer. + * @param {string} name - The given name. If the layer name exists, a new name will be generated. + * @param {module:history.HistoryRecordingService} hrService - History recording service + * @returns {SVGGElement} The SVGGElement of the new layer, which is + * also the current layer of this drawing. + */ - var currentGroup = this.current_layer.getGroup(); - var layer = new Layer(name, currentGroup, this.svgElem_); - var group = layer.getGroup(); // Clone children - - var children = _toConsumableArray(currentGroup.childNodes); - - children.forEach(function (child) { - if (child.localName === 'title') { - return; - } - - group.append(_this.copyElem(child)); - }); - - if (hrService) { - hrService.startBatchCommand('Duplicate Layer'); - hrService.insertElement(group); - hrService.endBatchCommand(); - } // Update layer containers and current_layer. + createLayer(name, hrService) { + if (this.current_layer) { + this.current_layer.deactivate(); + } // Check for duplicate name. - var index = this.all_layers.indexOf(this.current_layer); + if (name === undefined || name === null || name === '' || this.layer_map[name]) { + name = getNewLayerName(Object.keys(this.layer_map)); + } // Crate new layer and add to DOM as last layer - if (index >= 0) { - this.all_layers.splice(index + 1, 0, layer); - } else { - this.all_layers.push(layer); - } - this.layer_map[name] = layer; - this.current_layer = layer; - return group; + const layer = new Layer(name, null, this.svgElem_); // Like to assume hrService exists, but this is backwards compatible with old version of createLayer. + + if (hrService) { + hrService.startBatchCommand('Create Layer'); + hrService.insertElement(layer.getGroup()); + hrService.endBatchCommand(); } - /** - * Returns whether the layer is visible. If the layer name is not valid, - * then this function returns `false`. - * @param {string} layerName - The name of the layer which you want to query. - * @returns {boolean} The visibility state of the layer, or `false` if the layer name was invalid. - */ - }, { - key: "getLayerVisibility", - value: function getLayerVisibility(layerName) { - var layer = this.layer_map[layerName]; - return layer ? layer.isVisible() : false; + this.all_layers.push(layer); + this.layer_map[name] = layer; + this.current_layer = layer; + return layer.getGroup(); + } + /** + * Creates a copy of the current layer with the given name and makes it the current layer. + * @param {string} name - The given name. If the layer name exists, a new name will be generated. + * @param {module:history.HistoryRecordingService} hrService - History recording service + * @returns {SVGGElement} The SVGGElement of the new layer, which is + * also the current layer of this drawing. + */ + + + cloneLayer(name, hrService) { + if (!this.current_layer) { + return null; } - /** - * Sets the visibility of the layer. If the layer name is not valid, this - * function returns `null`, otherwise it returns the `SVGElement` representing - * the layer. This is an undo-able action. - * @param {string} layerName - The name of the layer to change the visibility - * @param {boolean} bVisible - Whether the layer should be visible - * @returns {?SVGGElement} The SVGGElement representing the layer if the - * `layerName` was valid, otherwise `null`. - */ - }, { - key: "setLayerVisibility", - value: function setLayerVisibility(layerName, bVisible) { - if (typeof bVisible !== 'boolean') { - return null; - } + this.current_layer.deactivate(); // Check for duplicate name. - var layer = this.layer_map[layerName]; + if (name === undefined || name === null || name === '' || this.layer_map[name]) { + name = getNewLayerName(Object.keys(this.layer_map)); + } // Create new group and add to DOM just after current_layer - if (!layer) { - return null; - } - layer.setVisible(bVisible); - return layer.getGroup(); - } - /** - * Returns the opacity of the given layer. If the input name is not a layer, `null` is returned. - * @param {string} layerName - name of the layer on which to get the opacity - * @returns {?Float} The opacity value of the given layer. This will be a value between 0.0 and 1.0, or `null` - * if `layerName` is not a valid layer - */ + const currentGroup = this.current_layer.getGroup(); + const layer = new Layer(name, currentGroup, this.svgElem_); + const group = layer.getGroup(); // Clone children - }, { - key: "getLayerOpacity", - value: function getLayerOpacity(layerName) { - var layer = this.layer_map[layerName]; - - if (!layer) { - return null; - } - - return layer.getOpacity(); - } - /** - * Sets the opacity of the given layer. If the input name is not a layer, - * nothing happens. If opacity is not a value between 0.0 and 1.0, then - * nothing happens. - * NOTE: this function exists solely to apply a highlighting/de-emphasis - * effect to a layer. When it is possible for a user to affect the opacity - * of a layer, we will need to allow this function to produce an undo-able - * action. - * @param {string} layerName - Name of the layer on which to set the opacity - * @param {Float} opacity - A float value in the range 0.0-1.0 - * @returns {void} - */ - - }, { - key: "setLayerOpacity", - value: function setLayerOpacity(layerName, opacity) { - if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) { + const children = [...currentGroup.childNodes]; + children.forEach(child => { + if (child.localName === 'title') { return; } - var layer = this.layer_map[layerName]; + group.append(this.copyElem(child)); + }); - if (layer) { - layer.setOpacity(opacity); - } + if (hrService) { + hrService.startBatchCommand('Duplicate Layer'); + hrService.insertElement(group); + hrService.endBatchCommand(); + } // Update layer containers and current_layer. + + + const index = this.all_layers.indexOf(this.current_layer); + + if (index >= 0) { + this.all_layers.splice(index + 1, 0, layer); + } else { + this.all_layers.push(layer); } - /** - * Create a clone of an element, updating its ID and its children's IDs when needed. - * @param {Element} el - DOM element to clone - * @returns {Element} - */ - }, { - key: "copyElem", - value: function copyElem$1(el) { - var that = this; + this.layer_map[name] = layer; + this.current_layer = layer; + return group; + } + /** + * Returns whether the layer is visible. If the layer name is not valid, + * then this function returns `false`. + * @param {string} layerName - The name of the layer which you want to query. + * @returns {boolean} The visibility state of the layer, or `false` if the layer name was invalid. + */ - var getNextIdClosure = function getNextIdClosure() { - return that.getNextId(); - }; - return copyElem(el, getNextIdClosure); + getLayerVisibility(layerName) { + const layer = this.layer_map[layerName]; + return layer ? layer.isVisible() : false; + } + /** + * Sets the visibility of the layer. If the layer name is not valid, this + * function returns `null`, otherwise it returns the `SVGElement` representing + * the layer. This is an undo-able action. + * @param {string} layerName - The name of the layer to change the visibility + * @param {boolean} bVisible - Whether the layer should be visible + * @returns {?SVGGElement} The SVGGElement representing the layer if the + * `layerName` was valid, otherwise `null`. + */ + + + setLayerVisibility(layerName, bVisible) { + if (typeof bVisible !== 'boolean') { + return null; } - }]); - return Drawing; - }(); + const layer = this.layer_map[layerName]; + + if (!layer) { + return null; + } + + layer.setVisible(bVisible); + return layer.getGroup(); + } + /** + * Returns the opacity of the given layer. If the input name is not a layer, `null` is returned. + * @param {string} layerName - name of the layer on which to get the opacity + * @returns {?Float} The opacity value of the given layer. This will be a value between 0.0 and 1.0, or `null` + * if `layerName` is not a valid layer + */ + + + getLayerOpacity(layerName) { + const layer = this.layer_map[layerName]; + + if (!layer) { + return null; + } + + return layer.getOpacity(); + } + /** + * Sets the opacity of the given layer. If the input name is not a layer, + * nothing happens. If opacity is not a value between 0.0 and 1.0, then + * nothing happens. + * NOTE: this function exists solely to apply a highlighting/de-emphasis + * effect to a layer. When it is possible for a user to affect the opacity + * of a layer, we will need to allow this function to produce an undo-able + * action. + * @param {string} layerName - Name of the layer on which to set the opacity + * @param {Float} opacity - A float value in the range 0.0-1.0 + * @returns {void} + */ + + + setLayerOpacity(layerName, opacity) { + if (typeof opacity !== 'number' || opacity < 0.0 || opacity > 1.0) { + return; + } + + const layer = this.layer_map[layerName]; + + if (layer) { + layer.setOpacity(opacity); + } + } + /** + * Create a clone of an element, updating its ID and its children's IDs when needed. + * @param {Element} el - DOM element to clone + * @returns {Element} + */ + + + copyElem(el) { + const that = this; + + const getNextIdClosure = function () { + return that.getNextId(); + }; + + return copyElem(el, getNextIdClosure); + } + + } /** * Called to ensure that drawings will or will not have randomized ids. * The currentDrawing will have its nonce set if it doesn't already. @@ -11272,7 +10537,7 @@ * @returns {void} */ - var randomizeIds = function randomizeIds(enableRandomization, currentDrawing) { + const randomizeIds = function (enableRandomization, currentDrawing) { randIds = enableRandomization === false ? RandomizeModes.NEVER_RANDOMIZE : RandomizeModes.ALWAYS_RANDOMIZE; if (randIds === RandomizeModes.ALWAYS_RANDOMIZE && !currentDrawing.getNonce()) { @@ -11351,14 +10616,14 @@ * @returns {void} */ - var canvas_; + let canvas_; /** * @function module:draw.init * @param {module:draw.DrawCanvasInit} canvas * @returns {void} */ - var init$3 = function init(canvas) { + const init$3 = function (canvas) { canvas_ = canvas; }; /** @@ -11367,7 +10632,7 @@ * @returns {void} */ - var identifyLayers = function identifyLayers() { + const identifyLayers = function () { leaveContext(); canvas_.getCurrentDrawing().identifyLayers(); }; @@ -11382,8 +10647,8 @@ * @returns {void} */ - var createLayer = function createLayer(name, hrService) { - var newLayer = canvas_.getCurrentDrawing().createLayer(name, historyRecordingService(hrService)); + const createLayer = function (name, hrService) { + const newLayer = canvas_.getCurrentDrawing().createLayer(name, historyRecordingService(hrService)); canvas_.clearSelection(); canvas_.call('changed', [newLayer]); }; @@ -11398,9 +10663,9 @@ * @returns {void} */ - var cloneLayer = function cloneLayer(name, hrService) { + const cloneLayer = function (name, hrService) { // Clone the current layer and make the cloned layer the new current layer - var newLayer = canvas_.getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService)); + const newLayer = canvas_.getCurrentDrawing().cloneLayer(name, historyRecordingService(hrService)); canvas_.clearSelection(); leaveContext(); canvas_.call('changed', [newLayer]); @@ -11413,15 +10678,16 @@ * @returns {boolean} `true` if an old layer group was found to delete */ - var deleteCurrentLayer = function deleteCurrentLayer() { - var currentLayer = canvas_.getCurrentDrawing().getCurrentLayer(); - var _currentLayer = currentLayer, - nextSibling = _currentLayer.nextSibling; - var parent = currentLayer.parentNode; + const deleteCurrentLayer = function () { + let currentLayer = canvas_.getCurrentDrawing().getCurrentLayer(); + const { + nextSibling + } = currentLayer; + const parent = currentLayer.parentNode; currentLayer = canvas_.getCurrentDrawing().deleteCurrentLayer(); if (currentLayer) { - var batchCmd = new BatchCommand('Delete Layer'); // store in our Undo History + const batchCmd = new BatchCommand('Delete Layer'); // store in our Undo History batchCmd.addSubCommand(new RemoveElementCommand(currentLayer, nextSibling, parent)); canvas_.addCommandToHistory(batchCmd); @@ -11440,8 +10706,8 @@ * @returns {boolean} true if the current layer was switched, otherwise false */ - var setCurrentLayer = function setCurrentLayer(name) { - var result = canvas_.getCurrentDrawing().setCurrentLayer(toXml(name)); + const setCurrentLayer = function (name) { + const result = canvas_.getCurrentDrawing().setCurrentLayer(toXml(name)); if (result) { canvas_.clearSelection(); @@ -11459,12 +10725,12 @@ * @returns {boolean} Whether the rename succeeded */ - var renameCurrentLayer = function renameCurrentLayer(newName) { - var drawing = canvas_.getCurrentDrawing(); - var layer = drawing.getCurrentLayer(); + const renameCurrentLayer = function (newName) { + const drawing = canvas_.getCurrentDrawing(); + const layer = drawing.getCurrentLayer(); if (layer) { - var result = drawing.setCurrentLayerName(newName, historyRecordingService()); + const result = drawing.setCurrentLayerName(newName, historyRecordingService()); if (result) { canvas_.call('changed', [layer]); @@ -11484,9 +10750,9 @@ * @returns {boolean} `true` if the current layer position was changed, `false` otherwise. */ - var setCurrentLayerPosition = function setCurrentLayerPosition(newPos) { - var drawing = canvas_.getCurrentDrawing(); - var result = drawing.setCurrentLayerPosition(newPos); + const setCurrentLayerPosition = function (newPos) { + const drawing = canvas_.getCurrentDrawing(); + const result = drawing.setCurrentLayerPosition(newPos); if (result) { canvas_.addCommandToHistory(new MoveElementCommand(result.currentGroup, result.oldNextSibling, canvas_.getSVGContent())); @@ -11504,13 +10770,13 @@ * @returns {boolean} true if the layer's visibility was set, false otherwise */ - var setLayerVisibility = function setLayerVisibility(layerName, bVisible) { - var drawing = canvas_.getCurrentDrawing(); - var prevVisibility = drawing.getLayerVisibility(layerName); - var layer = drawing.setLayerVisibility(layerName, bVisible); + const setLayerVisibility = function (layerName, bVisible) { + const drawing = canvas_.getCurrentDrawing(); + const prevVisibility = drawing.getLayerVisibility(layerName); + const layer = drawing.setLayerVisibility(layerName, bVisible); if (layer) { - var oldDisplay = prevVisibility ? 'inline' : 'none'; + const oldDisplay = prevVisibility ? 'inline' : 'none'; canvas_.addCommandToHistory(new ChangeElementCommand(layer, { display: oldDisplay }, 'Layer Visibility')); @@ -11534,30 +10800,30 @@ * @returns {boolean} Whether the selected elements were moved to the layer. */ - var moveSelectedToLayer = function moveSelectedToLayer(layerName) { + const moveSelectedToLayer = function (layerName) { // find the layer - var drawing = canvas_.getCurrentDrawing(); - var layer = drawing.getLayerByName(layerName); + const drawing = canvas_.getCurrentDrawing(); + const layer = drawing.getLayerByName(layerName); if (!layer) { return false; } - var batchCmd = new BatchCommand('Move Elements to Layer'); // loop for each selected element and move it + const batchCmd = new BatchCommand('Move Elements to Layer'); // loop for each selected element and move it - var selElems = canvas_.getSelectedElements(); - var i = selElems.length; + const selElems = canvas_.getSelectedElements(); + let i = selElems.length; while (i--) { - var elem = selElems[i]; + const elem = selElems[i]; if (!elem) { continue; } - var oldNextSibling = elem.nextSibling; // TODO: this is pretty brittle! + const oldNextSibling = elem.nextSibling; // TODO: this is pretty brittle! - var oldLayer = elem.parentNode; + const oldLayer = elem.parentNode; layer.append(elem); batchCmd.addSubCommand(new MoveElementCommand(elem, oldNextSibling, oldLayer)); } @@ -11571,7 +10837,7 @@ * @returns {void} */ - var mergeLayer = function mergeLayer(hrService) { + const mergeLayer = function (hrService) { canvas_.getCurrentDrawing().mergeLayer(historyRecordingService(hrService)); canvas_.clearSelection(); leaveContext(); @@ -11583,7 +10849,7 @@ * @returns {void} */ - var mergeAllLayers = function mergeAllLayers(hrService) { + const mergeAllLayers = function (hrService) { canvas_.getCurrentDrawing().mergeAllLayers(historyRecordingService(hrService)); canvas_.clearSelection(); leaveContext(); @@ -11597,13 +10863,13 @@ * @returns {void} */ - var leaveContext = function leaveContext() { - var len = disabledElems.length; + const leaveContext = function () { + const len = disabledElems.length; if (len) { - for (var i = 0; i < len; i++) { - var elem = disabledElems[i]; - var orig = canvas_.elData(elem, 'orig_opac'); + for (let i = 0; i < len; i++) { + const elem = disabledElems[i]; + const orig = canvas_.elData(elem, 'orig_opac'); if (orig !== 1) { elem.setAttribute('opacity', orig); @@ -11629,7 +10895,7 @@ * @returns {void} */ - var setContext = function setContext(elem) { + const setContext = function (elem) { leaveContext(); if (typeof elem === 'string') { @@ -11639,8 +10905,8 @@ canvas_.setCurrentGroup(elem); // Disable other elements - $$5(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function () { - var opac = this.getAttribute('opacity') || 1; // Store the original's opacity + $$6(elem).parentsUntil('#svgcontent').andSelf().siblings().each(function () { + const opac = this.getAttribute('opacity') || 1; // Store the original's opacity canvas_.elData(this, 'orig_opac', opac); this.setAttribute('opacity', opac * 0.33); @@ -11651,7 +10917,14 @@ canvas_.call('contextset', canvas_.getCurrentGroup()); }; - var REVERSE_NS = getReverseNS(); // Todo: Split out into core attributes, presentation attributes, etc. so consistent + /** + * Tools for SVG sanitization. + * @module sanitize + * @license MIT + * + * @copyright 2010 Alexis Deveria, 2010 Jeff Schiller + */ + const REVERSE_NS = getReverseNS(); // Todo: Split out into core attributes, presentation attributes, etc. so consistent /** * This defines which elements and attributes that we support (or at least @@ -11659,7 +10932,7 @@ * @type {PlainObject} */ - var svgWhiteList_ = { + const svgWhiteList_ = { // SVG Elements a: ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'xlink:href', 'xlink:title'], circle: ['class', 'clip-path', 'clip-rule', 'cx', 'cy', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'id', 'mask', 'opacity', 'r', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform'], @@ -11687,7 +10960,7 @@ rect: ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'height', 'id', 'mask', 'opacity', 'requiredFeatures', 'rx', 'ry', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'width', 'x', 'y'], stop: ['class', 'id', 'offset', 'requiredFeatures', 'stop-color', 'stop-opacity', 'style', 'systemLanguage'], svg: ['class', 'clip-path', 'clip-rule', 'filter', 'id', 'height', 'mask', 'preserveAspectRatio', 'requiredFeatures', 'style', 'systemLanguage', 'viewBox', 'width', 'x', 'xmlns', 'xmlns:se', 'xmlns:xlink', 'y'], - "switch": ['class', 'id', 'requiredFeatures', 'systemLanguage'], + switch: ['class', 'id', 'requiredFeatures', 'systemLanguage'], symbol: ['class', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'opacity', 'preserveAspectRatio', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'transform', 'viewBox'], text: ['class', 'clip-path', 'clip-rule', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'font-family', 'font-size', 'font-style', 'font-weight', 'id', 'mask', 'opacity', 'requiredFeatures', 'stroke', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'style', 'systemLanguage', 'text-anchor', 'transform', 'x', 'xml:space', 'y'], textPath: ['class', 'id', 'method', 'requiredFeatures', 'spacing', 'startOffset', 'style', 'systemLanguage', 'transform', 'xlink:href'], @@ -11728,20 +11001,12 @@ semantics: [] }; // Produce a Namespace-aware version of svgWhitelist - var svgWhiteListNS_ = {}; - Object.entries(svgWhiteList_).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - elt = _ref2[0], - atts = _ref2[1]; - - var attNS = {}; - Object.entries(atts).forEach(function (_ref3) { - var _ref4 = _slicedToArray(_ref3, 2), - i = _ref4[0], - att = _ref4[1]; - + const svgWhiteListNS_ = {}; + Object.entries(svgWhiteList_).forEach(function ([elt, atts]) { + const attNS = {}; + Object.entries(atts).forEach(function ([i, att]) { if (att.includes(':')) { - var v = att.split(':'); + const v = att.split(':'); attNS[v[1]] = NS[v[0].toUpperCase()]; } else { attNS[att] = att === 'xmlns' ? NS.XMLNS : null; @@ -11757,7 +11022,7 @@ * @returns {void} */ - var sanitizeSvg = function sanitizeSvg(node) { + const sanitizeSvg = function (node) { // Cleanup text nodes if (node.nodeType === 3) { // 3 === TEXT_NODE @@ -11776,27 +11041,27 @@ return; } - var doc = node.ownerDocument; - var parent = node.parentNode; // can parent ever be null here? I think the root node's parent is the document... + const doc = node.ownerDocument; + const parent = node.parentNode; // can parent ever be null here? I think the root node's parent is the document... if (!doc || !parent) { return; } - var allowedAttrs = svgWhiteList_[node.nodeName]; - var allowedAttrsNS = svgWhiteListNS_[node.nodeName]; // if this element is supported, sanitize it + const allowedAttrs = svgWhiteList_[node.nodeName]; + const allowedAttrsNS = svgWhiteListNS_[node.nodeName]; // if this element is supported, sanitize it if (typeof allowedAttrs !== 'undefined') { - var seAttrs = []; - var i = node.attributes.length; + const seAttrs = []; + let i = node.attributes.length; while (i--) { // if the attribute is not in our whitelist, then remove it // could use jQuery's inArray(), but I don't know if that's any better - var attr = node.attributes.item(i); - var attrName = attr.nodeName; - var attrLocalName = attr.localName; - var attrNsURI = attr.namespaceURI; // Check that an attribute with the correct localName in the correct namespace is on + const attr = node.attributes.item(i); + const attrName = attr.nodeName; + const attrLocalName = attr.localName; + const attrNsURI = attr.namespaceURI; // Check that an attribute with the correct localName in the correct namespace is on // our whitelist or is a namespace declaration for one of our allowed namespaces if (!({}.hasOwnProperty.call(allowedAttrsNS, attrLocalName) && attrNsURI === allowedAttrsNS[attrLocalName] && attrNsURI !== NS.XMLNS) && !(attrNsURI === NS.XMLNS && REVERSE_NS[attr.value])) { @@ -11817,7 +11082,7 @@ case 'gradientTransform': case 'patternTransform': { - var val = attr.value.replace(/(\d)-/g, '$1 -'); // const val = attr.value.replace(/(?<digit>\d)-/g, '$<digit> -'); + const val = attr.value.replace(/(\d)-/g, '$1 -'); // const val = attr.value.replace(/(?<digit>\d)-/g, '$<digit> -'); node.setAttribute(attrName, val); break; @@ -11827,19 +11092,13 @@ if (attrName === 'style') { - var props = attr.value.split(';'); - var p = props.length; + const props = attr.value.split(';'); + let p = props.length; while (p--) { - var _props$p$split = props[p].split(':'), - _props$p$split2 = _slicedToArray(_props$p$split, 2), - name = _props$p$split2[0], - _val = _props$p$split2[1]; - - var styleAttrName = (name || '').trim(); - - var styleAttrVal = (_val || '').trim(); // Now check that this attribute is supported - + const [name, val] = props[p].split(':'); + const styleAttrName = (name || '').trim(); + const styleAttrVal = (val || '').trim(); // Now check that this attribute is supported if (allowedAttrs.includes(styleAttrName)) { node.setAttribute(styleAttrName, styleAttrVal); @@ -11850,16 +11109,12 @@ } } - Object.values(seAttrs).forEach(function (_ref5) { - var _ref6 = _slicedToArray(_ref5, 2), - att = _ref6[0], - val = _ref6[1]; - + Object.values(seAttrs).forEach(([att, val]) => { node.setAttributeNS(NS.SE, att, val); }); // for some elements that have a xlink:href, ensure the URI refers to a local element // (but not for links) - var href = getHref(node); + const href = getHref(node); if (href && ['filter', 'linearGradient', 'pattern', 'radialGradient', 'textPath', 'use'].includes(node.nodeName)) { // TODO: we simply check if the first character is a #, is this bullet-proof? @@ -11879,7 +11134,7 @@ Object.values(['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke'], function (attr) { - var val = node.getAttribute(attr); + let val = node.getAttribute(attr); if (val) { val = getUrlFromAttr(val); // simply check for first character being a '#' @@ -11900,7 +11155,7 @@ } else { // remove all children from this node and insert them before this node // TODO: in the case of animation elements this will hardly ever be correct - var children = []; + const children = []; while (node.hasChildNodes()) { children.push(parent.insertBefore(node.firstChild, node)); @@ -11909,17 +11164,18 @@ node.remove(); // call sanitizeSvg on each of those children - var _i = children.length; + let i = children.length; - while (_i--) { - sanitizeSvg(children[_i]); + while (i--) { + sanitizeSvg(children[i]); } } }; - var $$6 = jQuery; // this is how we map paths to our preferred relative segment types + /* globals jQuery */ + const $$7 = jQuery; // this is how we map paths to our preferred relative segment types - var pathMap$1 = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; + const pathMap$1 = [0, 'z', 'M', 'm', 'L', 'l', 'C', 'c', 'Q', 'q', 'A', 'a', 'H', 'h', 'V', 'v', 'S', 's', 'T', 't']; /** * @interface module:coords.EditorContext */ @@ -11939,14 +11195,14 @@ * @returns {SVGSVGElement} */ - var editorContext_$2 = null; + let editorContext_$2 = null; /** * @function module:coords.init * @param {module:svgcanvas.SvgCanvas#event:pointsAdded} editorContext * @returns {void} */ - var init$4 = function init(editorContext) { + const init$4 = function (editorContext) { editorContext_$2 = editorContext; }; /** @@ -11955,53 +11211,49 @@ * @type {module:path.EditorContext#remapElement} */ - var remapElement = function remapElement(selected, changes, m) { - var remap = function remap(x, y) { + const remapElement = function (selected, changes, m) { + const remap = function (x, y) { return transformPoint(x, y, m); }, - scalew = function scalew(w) { + scalew = function (w) { return m.a * w; }, - scaleh = function scaleh(h) { + scaleh = function (h) { return m.d * h; }, - doSnapping = editorContext_$2.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg', - finishUp = function finishUp() { + doSnapping = editorContext_$2.getGridSnapping() && selected.parentNode.parentNode.localName === 'svg', + finishUp = function () { if (doSnapping) { - Object.entries(changes).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - o = _ref2[0], - value = _ref2[1]; - + Object.entries(changes).forEach(([o, value]) => { changes[o] = snapToGrid(value); }); } assignAttributes(selected, changes, 1000, true); }, - box = getBBox(selected); + box = getBBox(selected); - for (var i = 0; i < 2; i++) { - var type = i === 0 ? 'fill' : 'stroke'; - var attrVal = selected.getAttribute(type); + for (let i = 0; i < 2; i++) { + const type = i === 0 ? 'fill' : 'stroke'; + const attrVal = selected.getAttribute(type); if (attrVal && attrVal.startsWith('url(')) { if (m.a < 0 || m.d < 0) { - var grad = getRefElem(attrVal); - var newgrad = grad.cloneNode(true); + const grad = getRefElem(attrVal); + const newgrad = grad.cloneNode(true); if (m.a < 0) { // flip x - var x1 = newgrad.getAttribute('x1'); - var x2 = newgrad.getAttribute('x2'); + const x1 = newgrad.getAttribute('x1'); + const x2 = newgrad.getAttribute('x2'); newgrad.setAttribute('x1', -(x1 - 1)); newgrad.setAttribute('x2', -(x2 - 1)); } if (m.d < 0) { // flip y - var y1 = newgrad.getAttribute('y1'); - var y2 = newgrad.getAttribute('y2'); + const y1 = newgrad.getAttribute('y1'); + const y2 = newgrad.getAttribute('y2'); newgrad.setAttribute('y1', -(y1 - 1)); newgrad.setAttribute('y2', -(y2 - 1)); } @@ -12017,21 +11269,21 @@ } } - var elName = selected.tagName; + const elName = selected.tagName; if (elName === 'g' || elName === 'text' || elName === 'tspan' || elName === 'use') { // if it was a translate, then just update x,y if (m.a === 1 && m.b === 0 && m.c === 0 && m.d === 1 && (m.e !== 0 || m.f !== 0)) { // [T][M] = [M][T'] // therefore [T'] = [M_inv][T][M] - var existing = transformListToTransform(selected).matrix, - tNew = matrixMultiply(existing.inverse(), m, existing); + const existing = transformListToTransform(selected).matrix, + tNew = matrixMultiply(existing.inverse(), m, existing); changes.x = Number.parseFloat(changes.x) + tNew.e; changes.y = Number.parseFloat(changes.y) + tNew.f; } else { // we just absorb all matrices into the element and don't do any remapping - var chlist = getTransformList(selected); - var mt = editorContext_$2.getSVGRoot().createSVGTransform(); + const chlist = getTransformList(selected); + const mt = editorContext_$2.getSVGRoot().createSVGTransform(); mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m)); chlist.clear(); chlist.appendItem(mt); @@ -12048,17 +11300,13 @@ // Allow images to be inverted (give them matrix when flipped) if (elName === 'image' && (m.a < 0 || m.d < 0)) { // Convert to matrix - var _chlist = getTransformList(selected); - - var _mt = editorContext_$2.getSVGRoot().createSVGTransform(); - - _mt.setMatrix(matrixMultiply(transformListToTransform(_chlist).matrix, m)); - - _chlist.clear(); - - _chlist.appendItem(_mt); + const chlist = getTransformList(selected); + const mt = editorContext_$2.getSVGRoot().createSVGTransform(); + mt.setMatrix(matrixMultiply(transformListToTransform(chlist).matrix, m)); + chlist.clear(); + chlist.appendItem(mt); } else { - var pt1 = remap(changes.x, changes.y); + const pt1 = remap(changes.x, changes.y); changes.width = scalew(changes.width); changes.height = scaleh(changes.height); changes.x = pt1.x + Math.min(0, changes.width); @@ -12073,7 +11321,7 @@ case 'ellipse': { - var c = remap(changes.cx, changes.cy); + const c = remap(changes.cx, changes.cy); changes.cx = c.x; changes.cy = c.y; changes.rx = scalew(changes.rx); @@ -12086,14 +11334,13 @@ case 'circle': { - var _c = remap(changes.cx, changes.cy); + const c = remap(changes.cx, changes.cy); + changes.cx = c.x; + changes.cy = c.y; // take the minimum of the new selected box's dimensions for the new circle radius - changes.cx = _c.x; - changes.cy = _c.y; // take the minimum of the new selected box's dimensions for the new circle radius - - var tbox = transformBox(box.x, box.y, box.width, box.height, m); - var w = tbox.tr.x - tbox.tl.x, - h = tbox.bl.y - tbox.tl.y; + const tbox = transformBox(box.x, box.y, box.width, box.height, m); + const w = tbox.tr.x - tbox.tl.x, + h = tbox.bl.y - tbox.tl.y; changes.r = Math.min(w / 2, h / 2); if (changes.r) { @@ -12106,11 +11353,10 @@ case 'line': { - var _pt = remap(changes.x1, changes.y1); - - var pt2 = remap(changes.x2, changes.y2); - changes.x1 = _pt.x; - changes.y1 = _pt.y; + const pt1 = remap(changes.x1, changes.y1); + const pt2 = remap(changes.x2, changes.y2); + changes.x1 = pt1.x; + changes.y1 = pt1.y; changes.x2 = pt2.x; changes.y2 = pt2.y; } @@ -12126,7 +11372,7 @@ case 'g': { - var gsvg = $$6(selected).data('gsvg'); + const gsvg = $$7(selected).data('gsvg'); if (gsvg) { assignAttributes(gsvg, changes, 1000, true); @@ -12138,25 +11384,24 @@ case 'polyline': case 'polygon': { - var len = changes.points.length; + const len = changes.points.length; - for (var _i = 0; _i < len; ++_i) { - var pt = changes.points[_i]; - - var _remap = remap(pt.x, pt.y), - x = _remap.x, - y = _remap.y; - - changes.points[_i].x = x; - changes.points[_i].y = y; + for (let i = 0; i < len; ++i) { + const pt = changes.points[i]; + const { + x, + y + } = remap(pt.x, pt.y); + changes.points[i].x = x; + changes.points[i].y = y; } // const len = changes.points.length; - var pstr = ''; + let pstr = ''; - for (var _i2 = 0; _i2 < len; ++_i2) { - var _pt2 = changes.points[_i2]; - pstr += _pt2.x + ',' + _pt2.y + ' '; + for (let i = 0; i < len; ++i) { + const pt = changes.points[i]; + pstr += pt.x + ',' + pt.y + ' '; } selected.setAttribute('points', pstr); @@ -12165,13 +11410,13 @@ case 'path': { - var segList = selected.pathSegList; - var _len = segList.numberOfItems; + const segList = selected.pathSegList; + let len = segList.numberOfItems; changes.d = []; - for (var _i3 = 0; _i3 < _len; ++_i3) { - var seg = segList.getItem(_i3); - changes.d[_i3] = { + for (let i = 0; i < len; ++i) { + const seg = segList.getItem(i); + changes.d[i] = { type: seg.pathSegType, x: seg.x, y: seg.y, @@ -12187,72 +11432,73 @@ }; } - _len = changes.d.length; - var firstseg = changes.d[0], - currentpt = remap(firstseg.x, firstseg.y); + len = changes.d.length; + const firstseg = changes.d[0], + currentpt = remap(firstseg.x, firstseg.y); changes.d[0].x = currentpt.x; changes.d[0].y = currentpt.y; - for (var _i4 = 1; _i4 < _len; ++_i4) { - var _seg = changes.d[_i4]; - var _type = _seg.type; // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 + for (let i = 1; i < len; ++i) { + const seg = changes.d[i]; + const { + type + } = seg; // if absolute or first segment, we want to remap x, y, x1, y1, x2, y2 // if relative, we want to scalew, scaleh - if (_type % 2 === 0) { + if (type % 2 === 0) { // absolute - var thisx = _seg.x !== undefined ? _seg.x : currentpt.x, - // for V commands - thisy = _seg.y !== undefined ? _seg.y : currentpt.y; // for H commands + const thisx = seg.x !== undefined ? seg.x : currentpt.x, + // for V commands + thisy = seg.y !== undefined ? seg.y : currentpt.y; // for H commands - var _pt3 = remap(thisx, thisy); - - var _pt4 = remap(_seg.x1, _seg.y1); - - var _pt5 = remap(_seg.x2, _seg.y2); - - _seg.x = _pt3.x; - _seg.y = _pt3.y; - _seg.x1 = _pt4.x; - _seg.y1 = _pt4.y; - _seg.x2 = _pt5.x; - _seg.y2 = _pt5.y; - _seg.r1 = scalew(_seg.r1); - _seg.r2 = scaleh(_seg.r2); + const pt = remap(thisx, thisy); + const pt1 = remap(seg.x1, seg.y1); + const pt2 = remap(seg.x2, seg.y2); + seg.x = pt.x; + seg.y = pt.y; + seg.x1 = pt1.x; + seg.y1 = pt1.y; + seg.x2 = pt2.x; + seg.y2 = pt2.y; + seg.r1 = scalew(seg.r1); + seg.r2 = scaleh(seg.r2); } else { // relative - _seg.x = scalew(_seg.x); - _seg.y = scaleh(_seg.y); - _seg.x1 = scalew(_seg.x1); - _seg.y1 = scaleh(_seg.y1); - _seg.x2 = scalew(_seg.x2); - _seg.y2 = scaleh(_seg.y2); - _seg.r1 = scalew(_seg.r1); - _seg.r2 = scaleh(_seg.r2); + seg.x = scalew(seg.x); + seg.y = scaleh(seg.y); + seg.x1 = scalew(seg.x1); + seg.y1 = scaleh(seg.y1); + seg.x2 = scalew(seg.x2); + seg.y2 = scaleh(seg.y2); + seg.r1 = scalew(seg.r1); + seg.r2 = scaleh(seg.r2); } } // for each segment - var dstr = ''; - _len = changes.d.length; + let dstr = ''; + len = changes.d.length; - for (var _i5 = 0; _i5 < _len; ++_i5) { - var _seg2 = changes.d[_i5]; - var _type2 = _seg2.type; - dstr += pathMap$1[_type2]; + for (let i = 0; i < len; ++i) { + const seg = changes.d[i]; + const { + type + } = seg; + dstr += pathMap$1[type]; - switch (_type2) { + switch (type) { case 13: // relative horizontal line (h) case 12: // absolute horizontal line (H) - dstr += _seg2.x + ' '; + dstr += seg.x + ' '; break; case 15: // relative vertical line (v) case 14: // absolute vertical line (V) - dstr += _seg2.y + ' '; + dstr += seg.y + ' '; break; case 3: // relative move (m) @@ -12267,35 +11513,35 @@ case 18: // absolute smooth quad (T) - dstr += _seg2.x + ',' + _seg2.y + ' '; + dstr += seg.x + ',' + seg.y + ' '; break; case 7: // relative cubic (c) case 6: // absolute cubic (C) - dstr += _seg2.x1 + ',' + _seg2.y1 + ' ' + _seg2.x2 + ',' + _seg2.y2 + ' ' + _seg2.x + ',' + _seg2.y + ' '; + dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' '; break; case 9: // relative quad (q) case 8: // absolute quad (Q) - dstr += _seg2.x1 + ',' + _seg2.y1 + ' ' + _seg2.x + ',' + _seg2.y + ' '; + dstr += seg.x1 + ',' + seg.y1 + ' ' + seg.x + ',' + seg.y + ' '; break; case 11: // relative elliptical arc (a) case 10: // absolute elliptical arc (A) - dstr += _seg2.r1 + ',' + _seg2.r2 + ' ' + _seg2.angle + ' ' + Number(_seg2.largeArcFlag) + ' ' + Number(_seg2.sweepFlag) + ' ' + _seg2.x + ',' + _seg2.y + ' '; + dstr += seg.r1 + ',' + seg.r2 + ' ' + seg.angle + ' ' + Number(seg.largeArcFlag) + ' ' + Number(seg.sweepFlag) + ' ' + seg.x + ',' + seg.y + ' '; break; case 17: // relative smooth cubic (s) case 16: // absolute smooth cubic (S) - dstr += _seg2.x2 + ',' + _seg2.y2 + ' ' + _seg2.x + ',' + _seg2.y + ' '; + dstr += seg.x2 + ',' + seg.y2 + ' ' + seg.x + ',' + seg.y + ' '; break; } } @@ -12307,8 +11553,8 @@ }; /* globals jQuery */ - var $$7 = jQueryPluginSVG(jQuery); - var context_; + const $$8 = jQueryPluginSVG(jQuery); + let context_; /** * @interface module:recalculate.EditorContext */ @@ -12335,7 +11581,7 @@ * @returns {void} */ - var init$5 = function init(editorContext) { + const init$5 = function (editorContext) { context_ = editorContext; }; /** @@ -12347,10 +11593,10 @@ * @returns {void} */ - var updateClipPath = function updateClipPath(attr, tx, ty) { - var path = getRefElem(attr).firstChild; - var cpXform = getTransformList(path); - var newxlate = context_.getSVGRoot().createSVGTransform(); + const updateClipPath = function (attr, tx, ty) { + const path = getRefElem(attr).firstChild; + const cpXform = getTransformList(path); + const newxlate = context_.getSVGRoot().createSVGTransform(); newxlate.setTranslate(tx, ty); cpXform.appendItem(newxlate); // Update clipPath's dimensions @@ -12363,7 +11609,7 @@ * @returns {Command} Undo command object with the resulting change */ - var recalculateDimensions = function recalculateDimensions(selected) { + const recalculateDimensions = function (selected) { if (isNullish(selected)) { return null; } // Firefox Issue - 1081 @@ -12373,15 +11619,15 @@ return null; } - var svgroot = context_.getSVGRoot(); - var tlist = getTransformList(selected); // remove any unnecessary transforms + const svgroot = context_.getSVGRoot(); + const tlist = getTransformList(selected); // remove any unnecessary transforms if (tlist && tlist.numberOfItems > 0) { - var k = tlist.numberOfItems; - var noi = k; + let k = tlist.numberOfItems; + const noi = k; while (k--) { - var xform = tlist.getItem(k); + const xform = tlist.getItem(k); if (xform.type === 0) { tlist.removeItem(k); // remove identity matrices @@ -12424,35 +11670,35 @@ if (tlist) { - var mxs = []; - var _k = tlist.numberOfItems; + let mxs = []; + let k = tlist.numberOfItems; - while (_k--) { - var _xform = tlist.getItem(_k); + while (k--) { + const xform = tlist.getItem(k); - if (_xform.type === 1) { - mxs.push([_xform.matrix, _k]); + if (xform.type === 1) { + mxs.push([xform.matrix, k]); } else if (mxs.length) { mxs = []; } } if (mxs.length === 2) { - var mNew = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])); + const mNew = svgroot.createSVGTransformFromMatrix(matrixMultiply(mxs[1][0], mxs[0][0])); tlist.removeItem(mxs[0][1]); tlist.removeItem(mxs[1][1]); tlist.insertItemBefore(mNew, mxs[1][1]); } // combine matrix + translate - _k = tlist.numberOfItems; + k = tlist.numberOfItems; - if (_k >= 2 && tlist.getItem(_k - 2).type === 1 && tlist.getItem(_k - 1).type === 2) { - var mt = svgroot.createSVGTransform(); - var m = matrixMultiply(tlist.getItem(_k - 2).matrix, tlist.getItem(_k - 1).matrix); + if (k >= 2 && tlist.getItem(k - 2).type === 1 && tlist.getItem(k - 1).type === 2) { + const mt = svgroot.createSVGTransform(); + const m = matrixMultiply(tlist.getItem(k - 2).matrix, tlist.getItem(k - 1).matrix); mt.setMatrix(m); - tlist.removeItem(_k - 2); - tlist.removeItem(_k - 2); + tlist.removeItem(k - 2); + tlist.removeItem(k - 2); tlist.appendItem(mt); } } // If it still has a single [M] or [R][M], return null too (prevents BatchCommand from being returned). @@ -12474,13 +11720,13 @@ } // Grouped SVG element - var gsvg = $$7(selected).data('gsvg'); // we know we have some transforms, so set up return variable + const gsvg = $$8(selected).data('gsvg'); // we know we have some transforms, so set up return variable - var batchCmd = new BatchCommand('Transform'); // store initial values that will be affected by reducing the transform list + const batchCmd = new BatchCommand('Transform'); // store initial values that will be affected by reducing the transform list - var changes = {}; - var initial = null; - var attrs = []; + let changes = {}; + let initial = null; + let attrs = []; switch (selected.tagName) { case 'line': @@ -12512,12 +11758,12 @@ { initial = {}; initial.points = selected.getAttribute('points'); - var list = selected.points; - var len = list.numberOfItems; + const list = selected.points; + const len = list.numberOfItems; changes.points = new Array(len); - for (var i = 0; i < len; ++i) { - var pt = list.getItem(i); + for (let i = 0; i < len; ++i) { + const pt = list.getItem(i); changes.points[i] = { x: pt.x, y: pt.y @@ -12536,33 +11782,33 @@ if (attrs.length) { - changes = $$7(selected).attr(attrs); - $$7.each(changes, function (attr, val) { + changes = $$8(selected).attr(attrs); + $$8.each(changes, function (attr, val) { changes[attr] = convertToNum(attr, val); }); } else if (gsvg) { // GSVG exception changes = { - x: $$7(gsvg).attr('x') || 0, - y: $$7(gsvg).attr('y') || 0 + x: $$8(gsvg).attr('x') || 0, + y: $$8(gsvg).attr('y') || 0 }; } // if we haven't created an initial array in polygon/polyline/path, then // make a copy of initial values and include the transform if (isNullish(initial)) { - initial = $$7.extend(true, {}, changes); - $$7.each(initial, function (attr, val) { + initial = $$8.extend(true, {}, changes); + $$8.each(initial, function (attr, val) { initial[attr] = convertToNum(attr, val); }); } // save the start transform value too initial.transform = context_.getStartTransform() || ''; - var oldcenter, newcenter; // if it's a regular group, we have special processing to flatten transforms + let oldcenter, newcenter; // if it's a regular group, we have special processing to flatten transforms if (selected.tagName === 'g' && !gsvg || selected.tagName === 'a') { - var box = getBBox(selected); + const box = getBBox(selected); oldcenter = { x: box.x + box.width / 2, y: box.y + box.height / 2 @@ -12570,11 +11816,11 @@ newcenter = transformPoint(box.x + box.width / 2, box.y + box.height / 2, transformListToTransform(tlist).matrix); // let m = svgroot.createSVGMatrix(); // temporarily strip off the rotate and save the old center - var gangle = getRotationAngle(selected); + const gangle = getRotationAngle(selected); if (gangle) { - var a = gangle * Math.PI / 180; - var s; + const a = gangle * Math.PI / 180; + let s; if (Math.abs(a) > 1.0e-10) { s = Math.sin(a) / (1 - Math.cos(a)); @@ -12583,56 +11829,56 @@ s = 2 / a; } - for (var _i = 0; _i < tlist.numberOfItems; ++_i) { - var _xform2 = tlist.getItem(_i); + for (let i = 0; i < tlist.numberOfItems; ++i) { + const xform = tlist.getItem(i); - if (_xform2.type === 4) { + if (xform.type === 4) { // extract old center through mystical arts - var rm = _xform2.matrix; + const rm = xform.matrix; oldcenter.y = (s * rm.e + rm.f) / 2; oldcenter.x = (rm.e - s * rm.f) / 2; - tlist.removeItem(_i); + tlist.removeItem(i); break; } } } - var N = tlist.numberOfItems; - var tx = 0, + const N = tlist.numberOfItems; + let tx = 0, ty = 0, operation = 0; - var firstM; + let firstM; if (N) { firstM = tlist.getItem(0).matrix; } - var oldStartTransform; // first, if it was a scale then the second-last transform will be it + let oldStartTransform; // first, if it was a scale then the second-last transform will be it if (N >= 3 && tlist.getItem(N - 2).type === 3 && tlist.getItem(N - 3).type === 2 && tlist.getItem(N - 1).type === 2) { operation = 3; // scale // if the children are unrotated, pass the scale down directly // otherwise pass the equivalent matrix() down directly - var tm = tlist.getItem(N - 3).matrix, - sm = tlist.getItem(N - 2).matrix, - tmn = tlist.getItem(N - 1).matrix; - var children = selected.childNodes; - var c = children.length; + const tm = tlist.getItem(N - 3).matrix, + sm = tlist.getItem(N - 2).matrix, + tmn = tlist.getItem(N - 1).matrix; + const children = selected.childNodes; + let c = children.length; while (c--) { - var child = children.item(c); + const child = children.item(c); tx = 0; ty = 0; if (child.nodeType === 1) { - var childTlist = getTransformList(child); // some children might not have a transform (<metadata>, <defs>, etc) + const childTlist = getTransformList(child); // some children might not have a transform (<metadata>, <defs>, etc) if (!childTlist) { continue; } - var _m = transformListToTransform(childTlist).matrix; // Convert a matrix to a scale if applicable + const m = transformListToTransform(childTlist).matrix; // Convert a matrix to a scale if applicable // if (hasMatrixTransform(childTlist) && childTlist.numberOfItems == 1) { // if (m.b==0 && m.c==0 && m.e==0 && m.f==0) { // childTlist.removeItem(0); @@ -12648,14 +11894,14 @@ // } // } - var angle = getRotationAngle(child); + const angle = getRotationAngle(child); oldStartTransform = context_.getStartTransform(); // const childxforms = []; context_.setStartTransform(child.getAttribute('transform')); if (angle || hasMatrixTransform(childTlist)) { - var e2t = svgroot.createSVGTransform(); - e2t.setMatrix(matrixMultiply(tm, sm, tmn, _m)); + const e2t = svgroot.createSVGTransform(); + e2t.setMatrix(matrixMultiply(tm, sm, tmn, m)); childTlist.clear(); childTlist.appendItem(e2t); // childxforms.push(e2t); // if not rotated or skewed, push the [T][S][-T] down to the child @@ -12666,17 +11912,17 @@ // (only bringing [-T] to the right of [M]) // [T][S][-T][M] = [T][S][M][-T2] // [-T2] = [M_inv][-T][M] - var t2n = matrixMultiply(_m.inverse(), tmn, _m); // [T2] is always negative translation of [-T2] + const t2n = matrixMultiply(m.inverse(), tmn, m); // [T2] is always negative translation of [-T2] - var t2 = svgroot.createSVGMatrix(); + const t2 = svgroot.createSVGMatrix(); t2.e = -t2n.e; t2.f = -t2n.f; // [T][S][-T][M] = [M][T2][S2][-T2] // [S2] = [T2_inv][M_inv][T][S][-T][M][-T2_inv] - var s2 = matrixMultiply(t2.inverse(), _m.inverse(), tm, sm, tmn, _m, t2n.inverse()); - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); + const s2 = matrixMultiply(t2.inverse(), m.inverse(), tm, sm, tmn, m, t2n.inverse()); + const translateOrigin = svgroot.createSVGTransform(), + scale = svgroot.createSVGTransform(), + translateBack = svgroot.createSVGTransform(); translateOrigin.setTranslate(t2n.e, t2n.f); scale.setScale(s2.a, s2.d); translateBack.setTranslate(t2.e, t2.f); @@ -12719,40 +11965,37 @@ } else if (N >= 3 && tlist.getItem(N - 1).type === 1) { operation = 3; // scale - var _m2 = transformListToTransform(tlist).matrix; - - var _e2t = svgroot.createSVGTransform(); - - _e2t.setMatrix(_m2); - + const m = transformListToTransform(tlist).matrix; + const e2t = svgroot.createSVGTransform(); + e2t.setMatrix(m); tlist.clear(); - tlist.appendItem(_e2t); // next, check if the first transform was a translate + tlist.appendItem(e2t); // next, check if the first transform was a translate // if we had [ T1 ] [ M ] we want to transform this into [ M ] [ T2 ] // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] } else if ((N === 1 || N > 1 && tlist.getItem(1).type !== 3) && tlist.getItem(0).type === 2) { operation = 2; // translate - var T_M = transformListToTransform(tlist).matrix; + const T_M = transformListToTransform(tlist).matrix; tlist.removeItem(0); - var mInv = transformListToTransform(tlist).matrix.inverse(); - var M2 = matrixMultiply(mInv, T_M); + const mInv = transformListToTransform(tlist).matrix.inverse(); + const M2 = matrixMultiply(mInv, T_M); tx = M2.e; ty = M2.f; if (tx !== 0 || ty !== 0) { // we pass the translates down to the individual children - var _children = selected.childNodes; - var _c = _children.length; - var clipPathsDone = []; + const children = selected.childNodes; + let c = children.length; + const clipPathsDone = []; - while (_c--) { - var _child = _children.item(_c); + while (c--) { + const child = children.item(c); - if (_child.nodeType === 1) { + if (child.nodeType === 1) { // Check if child has clip-path - if (_child.getAttribute('clip-path')) { + if (child.getAttribute('clip-path')) { // tx, ty - var attr = _child.getAttribute('clip-path'); + const attr = child.getAttribute('clip-path'); if (!clipPathsDone.includes(attr)) { updateClipPath(attr, tx, ty); @@ -12761,34 +12004,32 @@ } oldStartTransform = context_.getStartTransform(); - context_.setStartTransform(_child.getAttribute('transform')); + context_.setStartTransform(child.getAttribute('transform')); + const childTlist = getTransformList(child); // some children might not have a transform (<metadata>, <defs>, etc) - var _childTlist = getTransformList(_child); // some children might not have a transform (<metadata>, <defs>, etc) - - - if (_childTlist) { - var newxlate = svgroot.createSVGTransform(); + if (childTlist) { + const newxlate = svgroot.createSVGTransform(); newxlate.setTranslate(tx, ty); - if (_childTlist.numberOfItems) { - _childTlist.insertItemBefore(newxlate, 0); + if (childTlist.numberOfItems) { + childTlist.insertItemBefore(newxlate, 0); } else { - _childTlist.appendItem(newxlate); + childTlist.appendItem(newxlate); } - batchCmd.addSubCommand(recalculateDimensions(_child)); // If any <use> have this group as a parent and are + batchCmd.addSubCommand(recalculateDimensions(child)); // If any <use> have this group as a parent and are // referencing this child, then impose a reverse translate on it // so that when it won't get double-translated - var uses = selected.getElementsByTagNameNS(NS.SVG, 'use'); - var href = '#' + _child.id; - var u = uses.length; + const uses = selected.getElementsByTagNameNS(NS.SVG, 'use'); + const href = '#' + child.id; + let u = uses.length; while (u--) { - var useElem = uses.item(u); + const useElem = uses.item(u); if (href === getHref(useElem)) { - var usexlate = svgroot.createSVGTransform(); + const usexlate = svgroot.createSVGTransform(); usexlate.setTranslate(-tx, -ty); getTransformList(useElem).insertItemBefore(usexlate, 0); batchCmd.addSubCommand(recalculateDimensions(useElem)); @@ -12806,41 +12047,36 @@ } else if (N === 1 && tlist.getItem(0).type === 1 && !gangle) { operation = 1; - var _m3 = tlist.getItem(0).matrix, - _children2 = selected.childNodes; - var _c2 = _children2.length; + const m = tlist.getItem(0).matrix, + children = selected.childNodes; + let c = children.length; - while (_c2--) { - var _child2 = _children2.item(_c2); + while (c--) { + const child = children.item(c); - if (_child2.nodeType === 1) { + if (child.nodeType === 1) { oldStartTransform = context_.getStartTransform(); - context_.setStartTransform(_child2.getAttribute('transform')); + context_.setStartTransform(child.getAttribute('transform')); + const childTlist = getTransformList(child); - var _childTlist2 = getTransformList(_child2); - - if (!_childTlist2) { + if (!childTlist) { continue; } - var em = matrixMultiply(_m3, transformListToTransform(_childTlist2).matrix); - var e2m = svgroot.createSVGTransform(); + const em = matrixMultiply(m, transformListToTransform(childTlist).matrix); + const e2m = svgroot.createSVGTransform(); e2m.setMatrix(em); - - _childTlist2.clear(); - - _childTlist2.appendItem(e2m, 0); - - batchCmd.addSubCommand(recalculateDimensions(_child2)); + childTlist.clear(); + childTlist.appendItem(e2m, 0); + batchCmd.addSubCommand(recalculateDimensions(child)); context_.setStartTransform(oldStartTransform); // Convert stroke // TODO: Find out if this should actually happen somewhere else - var sw = _child2.getAttribute('stroke-width'); + const sw = child.getAttribute('stroke-width'); - if (_child2.getAttribute('stroke') !== 'none' && !isNaN(sw)) { - var avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; - - _child2.setAttribute('stroke-width', sw * avg); + if (child.getAttribute('stroke') !== 'none' && !isNaN(sw)) { + const avg = (Math.abs(em.a) + Math.abs(em.d)) / 2; + child.setAttribute('stroke-width', sw * avg); } } } @@ -12848,7 +12084,7 @@ tlist.clear(); // else it was just a rotate } else { if (gangle) { - var newRot = svgroot.createSVGTransform(); + const newRot = svgroot.createSVGTransform(); newRot.setRotate(gangle, newcenter.x, newcenter.y); if (tlist.numberOfItems) { @@ -12872,59 +12108,52 @@ x: oldcenter.x + firstM.e, y: oldcenter.y + firstM.f }; - - var _newRot = svgroot.createSVGTransform(); - - _newRot.setRotate(gangle, newcenter.x, newcenter.y); + const newRot = svgroot.createSVGTransform(); + newRot.setRotate(gangle, newcenter.x, newcenter.y); if (tlist.numberOfItems) { - tlist.insertItemBefore(_newRot, 0); + tlist.insertItemBefore(newRot, 0); } else { - tlist.appendItem(_newRot); + tlist.appendItem(newRot); } } // if it was a resize } else if (operation === 3) { - var _m4 = transformListToTransform(tlist).matrix; - var roldt = svgroot.createSVGTransform(); + const m = transformListToTransform(tlist).matrix; + const roldt = svgroot.createSVGTransform(); roldt.setRotate(gangle, oldcenter.x, oldcenter.y); - var rold = roldt.matrix; - var rnew = svgroot.createSVGTransform(); + const rold = roldt.matrix; + const rnew = svgroot.createSVGTransform(); rnew.setRotate(gangle, newcenter.x, newcenter.y); - - var rnewInv = rnew.matrix.inverse(), - _mInv = _m4.inverse(), - extrat = matrixMultiply(_mInv, rnewInv, rold, _m4); - + const rnewInv = rnew.matrix.inverse(), + mInv = m.inverse(), + extrat = matrixMultiply(mInv, rnewInv, rold, m); tx = extrat.e; ty = extrat.f; if (tx !== 0 || ty !== 0) { // now push this transform down to the children // we pass the translates down to the individual children - var _children3 = selected.childNodes; - var _c3 = _children3.length; + const children = selected.childNodes; + let c = children.length; - while (_c3--) { - var _child3 = _children3.item(_c3); + while (c--) { + const child = children.item(c); - if (_child3.nodeType === 1) { + if (child.nodeType === 1) { oldStartTransform = context_.getStartTransform(); - context_.setStartTransform(_child3.getAttribute('transform')); + context_.setStartTransform(child.getAttribute('transform')); + const childTlist = getTransformList(child); + const newxlate = svgroot.createSVGTransform(); + newxlate.setTranslate(tx, ty); - var _childTlist3 = getTransformList(_child3); - - var _newxlate = svgroot.createSVGTransform(); - - _newxlate.setTranslate(tx, ty); - - if (_childTlist3.numberOfItems) { - _childTlist3.insertItemBefore(_newxlate, 0); + if (childTlist.numberOfItems) { + childTlist.insertItemBefore(newxlate, 0); } else { - _childTlist3.appendItem(_newxlate); + childTlist.appendItem(newxlate); } - batchCmd.addSubCommand(recalculateDimensions(_child3)); + batchCmd.addSubCommand(recalculateDimensions(child)); context_.setStartTransform(oldStartTransform); } } @@ -12941,68 +12170,63 @@ } else { // TODO: box might be null for some elements (<metadata> etc), need to handle this - var _box = getBBox(selected); // Paths (and possbly other shapes) will have no BBox while still in <defs>, + const box = getBBox(selected); // Paths (and possbly other shapes) will have no BBox while still in <defs>, // but we still may need to recalculate them (see issue 595). // TODO: Figure out how to get BBox from these elements in case they // have a rotation transform - - if (!_box && selected.tagName !== 'path') return null; - - var _m5; // = svgroot.createSVGMatrix(); + if (!box && selected.tagName !== 'path') return null; + let m; // = svgroot.createSVGMatrix(); // temporarily strip off the rotate and save the old center + const angle = getRotationAngle(selected); - var _angle = getRotationAngle(selected); - - if (_angle) { + if (angle) { oldcenter = { - x: _box.x + _box.width / 2, - y: _box.y + _box.height / 2 + x: box.x + box.width / 2, + y: box.y + box.height / 2 }; - newcenter = transformPoint(_box.x + _box.width / 2, _box.y + _box.height / 2, transformListToTransform(tlist).matrix); + newcenter = transformPoint(box.x + box.width / 2, box.y + box.height / 2, transformListToTransform(tlist).matrix); + const a = angle * Math.PI / 180; + const s = Math.abs(a) > 1.0e-10 ? Math.sin(a) / (1 - Math.cos(a)) // TODO: This blows up if the angle is exactly 0! + : 2 / a; - var _a = _angle * Math.PI / 180; + for (let i = 0; i < tlist.numberOfItems; ++i) { + const xform = tlist.getItem(i); - var _s = Math.abs(_a) > 1.0e-10 ? Math.sin(_a) / (1 - Math.cos(_a)) // TODO: This blows up if the angle is exactly 0! - : 2 / _a; - - for (var _i2 = 0; _i2 < tlist.numberOfItems; ++_i2) { - var _xform3 = tlist.getItem(_i2); - - if (_xform3.type === 4) { + if (xform.type === 4) { // extract old center through mystical arts - var _rm = _xform3.matrix; - oldcenter.y = (_s * _rm.e + _rm.f) / 2; - oldcenter.x = (_rm.e - _s * _rm.f) / 2; - tlist.removeItem(_i2); + const rm = xform.matrix; + oldcenter.y = (s * rm.e + rm.f) / 2; + oldcenter.x = (rm.e - s * rm.f) / 2; + tlist.removeItem(i); break; } } } // 2 = translate, 3 = scale, 4 = rotate, 1 = matrix imposition - var _operation = 0; - var _N = tlist.numberOfItems; // Check if it has a gradient with userSpaceOnUse, in which case + let operation = 0; + const N = tlist.numberOfItems; // Check if it has a gradient with userSpaceOnUse, in which case // adjust it by recalculating the matrix transform. // TODO: Make this work in Webkit using transformlist.SVGTransformList if (!isWebkit()) { - var fill = selected.getAttribute('fill'); + const fill = selected.getAttribute('fill'); if (fill && fill.startsWith('url(')) { - var paint = getRefElem(fill); - var type = 'pattern'; + const paint = getRefElem(fill); + let type = 'pattern'; if (paint.tagName !== type) type = 'gradient'; - var attrVal = paint.getAttribute(type + 'Units'); + const attrVal = paint.getAttribute(type + 'Units'); if (attrVal === 'userSpaceOnUse') { // Update the userSpaceOnUse element - _m5 = transformListToTransform(tlist).matrix; - var gtlist = getTransformList(paint); - var gmatrix = transformListToTransform(gtlist).matrix; - _m5 = matrixMultiply(_m5, gmatrix); - var mStr = 'matrix(' + [_m5.a, _m5.b, _m5.c, _m5.d, _m5.e, _m5.f].join(',') + ')'; + m = transformListToTransform(tlist).matrix; + const gtlist = getTransformList(paint); + const gmatrix = transformListToTransform(gtlist).matrix; + m = matrixMultiply(m, gmatrix); + const mStr = 'matrix(' + [m.a, m.b, m.c, m.d, m.e, m.f].join(',') + ')'; paint.setAttribute(type + 'Transform', mStr); } } @@ -13012,49 +12236,46 @@ // [T][S][T] and push it down to the element - if (_N >= 3 && tlist.getItem(_N - 2).type === 3 && tlist.getItem(_N - 3).type === 2 && tlist.getItem(_N - 1).type === 2) { + if (N >= 3 && tlist.getItem(N - 2).type === 3 && tlist.getItem(N - 3).type === 2 && tlist.getItem(N - 1).type === 2) { // Removed this so a <use> with a given [T][S][T] would convert to a matrix. // Is that bad? // && selected.nodeName != 'use' - _operation = 3; // scale + operation = 3; // scale - _m5 = transformListToTransform(tlist, _N - 3, _N - 1).matrix; - tlist.removeItem(_N - 1); - tlist.removeItem(_N - 2); - tlist.removeItem(_N - 3); // if we had [T][S][-T][M], then this was a skewed element being resized + m = transformListToTransform(tlist, N - 3, N - 1).matrix; + tlist.removeItem(N - 1); + tlist.removeItem(N - 2); + tlist.removeItem(N - 3); // if we had [T][S][-T][M], then this was a skewed element being resized // Thus, we simply combine it all into one matrix - } else if (_N === 4 && tlist.getItem(_N - 1).type === 1) { - _operation = 3; // scale - - _m5 = transformListToTransform(tlist).matrix; - - var _e2t2 = svgroot.createSVGTransform(); - - _e2t2.setMatrix(_m5); + } else if (N === 4 && tlist.getItem(N - 1).type === 1) { + operation = 3; // scale + m = transformListToTransform(tlist).matrix; + const e2t = svgroot.createSVGTransform(); + e2t.setMatrix(m); tlist.clear(); - tlist.appendItem(_e2t2); // reset the matrix so that the element is not re-mapped + tlist.appendItem(e2t); // reset the matrix so that the element is not re-mapped - _m5 = svgroot.createSVGMatrix(); // if we had [R][T][S][-T][M], then this was a rotated matrix-element + m = svgroot.createSVGMatrix(); // if we had [R][T][S][-T][M], then this was a rotated matrix-element // if we had [T1][M] we want to transform this into [M][T2] // therefore [ T2 ] = [ M_inv ] [ T1 ] [ M ] and we can push [T2] // down to the element - } else if ((_N === 1 || _N > 1 && tlist.getItem(1).type !== 3) && tlist.getItem(0).type === 2) { - _operation = 2; // translate + } else if ((N === 1 || N > 1 && tlist.getItem(1).type !== 3) && tlist.getItem(0).type === 2) { + operation = 2; // translate - var oldxlate = tlist.getItem(0).matrix, - meq = transformListToTransform(tlist, 1).matrix, - meqInv = meq.inverse(); - _m5 = matrixMultiply(meqInv, oldxlate, meq); + const oldxlate = tlist.getItem(0).matrix, + meq = transformListToTransform(tlist, 1).matrix, + meqInv = meq.inverse(); + m = matrixMultiply(meqInv, oldxlate, meq); tlist.removeItem(0); // else if this child now has a matrix imposition (from a parent group) // we might be able to simplify - } else if (_N === 1 && tlist.getItem(0).type === 1 && !_angle) { + } else if (N === 1 && tlist.getItem(0).type === 1 && !angle) { // Remap all point-based elements - _m5 = transformListToTransform(tlist).matrix; + m = transformListToTransform(tlist).matrix; switch (selected.tagName) { case 'line': - changes = $$7(selected).attr(['x1', 'y1', 'x2', 'y2']); + changes = $$8(selected).attr(['x1', 'y1', 'x2', 'y2']); // Fallthrough case 'polyline': @@ -13062,16 +12283,15 @@ changes.points = selected.getAttribute('points'); if (changes.points) { - var _list = selected.points; - var _len = _list.numberOfItems; - changes.points = new Array(_len); + const list = selected.points; + const len = list.numberOfItems; + changes.points = new Array(len); - for (var _i3 = 0; _i3 < _len; ++_i3) { - var _pt = _list.getItem(_i3); - - changes.points[_i3] = { - x: _pt.x, - y: _pt.y + for (let i = 0; i < len; ++i) { + const pt = list.getItem(i); + changes.points[i] = { + x: pt.x, + y: pt.y }; } } @@ -13080,7 +12300,7 @@ case 'path': changes.d = selected.getAttribute('d'); - _operation = 1; + operation = 1; tlist.clear(); break; } // if it was a rotation, put the rotate back and return without a command @@ -13088,15 +12308,14 @@ } else { // operation = 4; // rotation - if (_angle) { - var _newRot2 = svgroot.createSVGTransform(); - - _newRot2.setRotate(_angle, newcenter.x, newcenter.y); + if (angle) { + const newRot = svgroot.createSVGTransform(); + newRot.setRotate(angle, newcenter.x, newcenter.y); if (tlist.numberOfItems) { - tlist.insertItemBefore(_newRot2, 0); + tlist.insertItemBefore(newRot, 0); } else { - tlist.appendItem(_newRot2); + tlist.appendItem(newRot); } } @@ -13108,29 +12327,28 @@ } // if it was a translate or resize, we need to remap the element and absorb the xform - if (_operation === 1 || _operation === 2 || _operation === 3) { - remapElement(selected, changes, _m5); + if (operation === 1 || operation === 2 || operation === 3) { + remapElement(selected, changes, m); } // if we are remapping // if it was a translate, put back the rotate at the new center - if (_operation === 2) { - if (_angle) { + if (operation === 2) { + if (angle) { if (!hasMatrixTransform(tlist)) { newcenter = { - x: oldcenter.x + _m5.e, - y: oldcenter.y + _m5.f + x: oldcenter.x + m.e, + y: oldcenter.y + m.f }; } - var _newRot3 = svgroot.createSVGTransform(); - - _newRot3.setRotate(_angle, newcenter.x, newcenter.y); + const newRot = svgroot.createSVGTransform(); + newRot.setRotate(angle, newcenter.x, newcenter.y); if (tlist.numberOfItems) { - tlist.insertItemBefore(_newRot3, 0); + tlist.insertItemBefore(newRot, 0); } else { - tlist.appendItem(_newRot3); + tlist.appendItem(newRot); } } // We have special processing for tspans: Tspans are not transformable // but they can have x,y coordinates (sigh). Thus, if this was a translate, @@ -13138,18 +12356,18 @@ if (selected.tagName === 'text') { - var _children4 = selected.childNodes; - var _c4 = _children4.length; + const children = selected.childNodes; + let c = children.length; - while (_c4--) { - var _child4 = _children4.item(_c4); + while (c--) { + const child = children.item(c); - if (_child4.tagName === 'tspan') { - var tspanChanges = { - x: $$7(_child4).attr('x') || 0, - y: $$7(_child4).attr('y') || 0 + if (child.tagName === 'tspan') { + const tspanChanges = { + x: $$8(child).attr('x') || 0, + y: $$8(child).attr('y') || 0 }; - remapElement(_child4, tspanChanges, _m5); + remapElement(child, tspanChanges, m); } } } // [Rold][M][T][S][-T] became [Rold][M] @@ -13157,33 +12375,25 @@ // translation required to re-center it // Therefore, [Tr] = [M_inv][Rnew_inv][Rold][M] - } else if (_operation === 3 && _angle) { - var _transformListToTrans = transformListToTransform(tlist), - matrix = _transformListToTrans.matrix; + } else if (operation === 3 && angle) { + const { + matrix + } = transformListToTransform(tlist); + const roldt = svgroot.createSVGTransform(); + roldt.setRotate(angle, oldcenter.x, oldcenter.y); + const rold = roldt.matrix; + const rnew = svgroot.createSVGTransform(); + rnew.setRotate(angle, newcenter.x, newcenter.y); + const rnewInv = rnew.matrix.inverse(); + const mInv = matrix.inverse(); + const extrat = matrixMultiply(mInv, rnewInv, rold, matrix); + remapElement(selected, changes, extrat); - var _roldt = svgroot.createSVGTransform(); - - _roldt.setRotate(_angle, oldcenter.x, oldcenter.y); - - var _rold = _roldt.matrix; - - var _rnew = svgroot.createSVGTransform(); - - _rnew.setRotate(_angle, newcenter.x, newcenter.y); - - var _rnewInv = _rnew.matrix.inverse(); - - var _mInv2 = matrix.inverse(); - - var _extrat = matrixMultiply(_mInv2, _rnewInv, _rold, matrix); - - remapElement(selected, changes, _extrat); - - if (_angle) { + if (angle) { if (tlist.numberOfItems) { - tlist.insertItemBefore(_rnew, 0); + tlist.insertItemBefore(rnew, 0); } else { - tlist.appendItem(_rnew); + tlist.appendItem(rnew); } } } @@ -13199,25 +12409,24 @@ return batchCmd; }; - var $$8 = jQuery; - var svgFactory_; - var config_; - var selectorManager_; // A Singleton + /* globals jQuery */ + const $$9 = jQuery; + let svgFactory_; + let config_; + let selectorManager_; // A Singleton - var gripRadius = isTouch() ? 10 : 4; + const gripRadius = isTouch() ? 10 : 4; /** * Private class for DOM element selection boxes. */ - var Selector = /*#__PURE__*/function () { + class Selector { /** * @param {Integer} id - Internally identify the selector * @param {Element} elem - DOM element associated with this selector * @param {module:utilities.BBoxObject} [bbox] - Optional bbox to use for initialization (prevents duplicate `getBBox` call). */ - function Selector(id, elem, bbox) { - _classCallCheck(this, Selector); - + constructor(id, elem, bbox) { // this is the selector's unique number this.id = id; // this holds a reference to the element for which this selector is being used @@ -13265,204 +12474,199 @@ */ - _createClass(Selector, [{ - key: "reset", - value: function reset(e, bbox) { - this.locked = true; - this.selectedElement = e; - this.resize(bbox); - this.selectorGroup.setAttribute('display', 'inline'); + reset(e, bbox) { + this.locked = true; + this.selectedElement = e; + this.resize(bbox); + this.selectorGroup.setAttribute('display', 'inline'); + } + /** + * Show the resize grips of this selector. + * @param {boolean} show - Indicates whether grips should be shown or not + * @returns {void} + */ + + + showGrips(show) { + const bShow = show ? 'inline' : 'none'; + selectorManager_.selectorGripsGroup.setAttribute('display', bShow); + const elem = this.selectedElement; + this.hasGrips = show; + + if (elem && show) { + this.selectorGroup.append(selectorManager_.selectorGripsGroup); + Selector.updateGripCursors(getRotationAngle(elem)); } - /** - * Show the resize grips of this selector. - * @param {boolean} show - Indicates whether grips should be shown or not - * @returns {void} - */ + } + /** + * Updates the selector to match the element's size. + * @param {module:utilities.BBoxObject} [bbox] - BBox to use for resize (prevents duplicate getBBox call). + * @returns {void} + */ - }, { - key: "showGrips", - value: function showGrips(show) { - var bShow = show ? 'inline' : 'none'; - selectorManager_.selectorGripsGroup.setAttribute('display', bShow); - var elem = this.selectedElement; - this.hasGrips = show; - if (elem && show) { - this.selectorGroup.append(selectorManager_.selectorGripsGroup); - Selector.updateGripCursors(getRotationAngle(elem)); - } - } - /** - * Updates the selector to match the element's size. - * @param {module:utilities.BBoxObject} [bbox] - BBox to use for resize (prevents duplicate getBBox call). - * @returns {void} - */ - - }, { - key: "resize", - value: function resize(bbox) { - var selectedBox = this.selectorRect, + resize(bbox) { + const selectedBox = this.selectorRect, mgr = selectorManager_, selectedGrips = mgr.selectorGrips, selected = this.selectedElement, sw = selected.getAttribute('stroke-width'), currentZoom = svgFactory_.getCurrentZoom(); - var offset = 1 / currentZoom; + let offset = 1 / currentZoom; - if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) { - offset += sw / 2; + if (selected.getAttribute('stroke') !== 'none' && !isNaN(sw)) { + offset += sw / 2; + } + + const { + tagName + } = selected; + + if (tagName === 'text') { + offset += 2 / currentZoom; + } // loop and transform our bounding box until we reach our first rotation + + + const tlist = getTransformList(selected); + const m = transformListToTransform(tlist).matrix; // This should probably be handled somewhere else, but for now + // it keeps the selection box correctly positioned when zoomed + + m.e *= currentZoom; + m.f *= currentZoom; + + if (!bbox) { + bbox = getBBox(selected); + } // TODO: getBBox (previous line) already knows to call getStrokedBBox when tagName === 'g'. Remove this? + // TODO: getBBox doesn't exclude 'gsvg' and calls getStrokedBBox for any 'g'. Should getBBox be updated? + + + if (tagName === 'g' && !$$9.data(selected, 'gsvg')) { + // The bbox for a group does not include stroke vals, so we + // get the bbox based on its children. + const strokedBbox = getStrokedBBox([selected.childNodes]); + + if (strokedBbox) { + bbox = strokedBbox; } - - var tagName = selected.tagName; - - if (tagName === 'text') { - offset += 2 / currentZoom; - } // loop and transform our bounding box until we reach our first rotation + } // apply the transforms - var tlist = getTransformList(selected); - var m = transformListToTransform(tlist).matrix; // This should probably be handled somewhere else, but for now - // it keeps the selection box correctly positioned when zoomed - - m.e *= currentZoom; - m.f *= currentZoom; - - if (!bbox) { - bbox = getBBox(selected); - } // TODO: getBBox (previous line) already knows to call getStrokedBBox when tagName === 'g'. Remove this? - // TODO: getBBox doesn't exclude 'gsvg' and calls getStrokedBBox for any 'g'. Should getBBox be updated? - - - if (tagName === 'g' && !$$8.data(selected, 'gsvg')) { - // The bbox for a group does not include stroke vals, so we - // get the bbox based on its children. - var strokedBbox = getStrokedBBox([selected.childNodes]); - - if (strokedBbox) { - bbox = strokedBbox; - } - } // apply the transforms - - - var l = bbox.x, + const l = bbox.x, t = bbox.y, w = bbox.width, h = bbox.height; // bbox = {x: l, y: t, width: w, height: h}; // Not in use - // we need to handle temporary transforms too - // if skewed, get its transformed box, then find its axis-aligned bbox - // * + // we need to handle temporary transforms too + // if skewed, get its transformed box, then find its axis-aligned bbox + // * - offset *= currentZoom; - var nbox = transformBox(l * currentZoom, t * currentZoom, w * currentZoom, h * currentZoom, m), - aabox = nbox.aabox; - var nbax = aabox.x - offset, - nbay = aabox.y - offset, - nbaw = aabox.width + offset * 2, - nbah = aabox.height + offset * 2; // now if the shape is rotated, un-rotate it + offset *= currentZoom; + const nbox = transformBox(l * currentZoom, t * currentZoom, w * currentZoom, h * currentZoom, m), + { + aabox + } = nbox; + let nbax = aabox.x - offset, + nbay = aabox.y - offset, + nbaw = aabox.width + offset * 2, + nbah = aabox.height + offset * 2; // now if the shape is rotated, un-rotate it - var cx = nbax + nbaw / 2, + const cx = nbax + nbaw / 2, cy = nbay + nbah / 2; - var angle = getRotationAngle(selected); + const angle = getRotationAngle(selected); - if (angle) { - var rot = svgFactory_.svgRoot().createSVGTransform(); - rot.setRotate(-angle, cx, cy); - var rotm = rot.matrix; - nbox.tl = transformPoint(nbox.tl.x, nbox.tl.y, rotm); - nbox.tr = transformPoint(nbox.tr.x, nbox.tr.y, rotm); - nbox.bl = transformPoint(nbox.bl.x, nbox.bl.y, rotm); - nbox.br = transformPoint(nbox.br.x, nbox.br.y, rotm); // calculate the axis-aligned bbox + if (angle) { + const rot = svgFactory_.svgRoot().createSVGTransform(); + rot.setRotate(-angle, cx, cy); + const rotm = rot.matrix; + nbox.tl = transformPoint(nbox.tl.x, nbox.tl.y, rotm); + nbox.tr = transformPoint(nbox.tr.x, nbox.tr.y, rotm); + nbox.bl = transformPoint(nbox.bl.x, nbox.bl.y, rotm); + nbox.br = transformPoint(nbox.br.x, nbox.br.y, rotm); // calculate the axis-aligned bbox - var tl = nbox.tl; - var minx = tl.x, - miny = tl.y, - maxx = tl.x, - maxy = tl.y; - var min = Math.min, - max = Math.max; - minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x))) - offset; - miny = min(miny, min(nbox.tr.y, min(nbox.bl.y, nbox.br.y))) - offset; - maxx = max(maxx, max(nbox.tr.x, max(nbox.bl.x, nbox.br.x))) + offset; - maxy = max(maxy, max(nbox.tr.y, max(nbox.bl.y, nbox.br.y))) + offset; - nbax = minx; - nbay = miny; - nbaw = maxx - minx; - nbah = maxy - miny; - } - - var dstr = 'M' + nbax + ',' + nbay + ' L' + (nbax + nbaw) + ',' + nbay + ' ' + (nbax + nbaw) + ',' + (nbay + nbah) + ' ' + nbax + ',' + (nbay + nbah) + 'z'; - selectedBox.setAttribute('d', dstr); - var xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : ''; - this.selectorGroup.setAttribute('transform', xform); // TODO(codedread): Is this needed? - // if (selected === selectedElements[0]) { - - this.gripCoords = { - nw: [nbax, nbay], - ne: [nbax + nbaw, nbay], - sw: [nbax, nbay + nbah], - se: [nbax + nbaw, nbay + nbah], - n: [nbax + nbaw / 2, nbay], - w: [nbax, nbay + nbah / 2], - e: [nbax + nbaw, nbay + nbah / 2], - s: [nbax + nbaw / 2, nbay + nbah] - }; - Object.entries(this.gripCoords).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - dir = _ref2[0], - coords = _ref2[1]; - - selectedGrips[dir].setAttribute('cx', coords[0]); - selectedGrips[dir].setAttribute('cy', coords[1]); - }); // we want to go 20 pixels in the negative transformed y direction, ignoring scale - - mgr.rotateGripConnector.setAttribute('x1', nbax + nbaw / 2); - mgr.rotateGripConnector.setAttribute('y1', nbay); - mgr.rotateGripConnector.setAttribute('x2', nbax + nbaw / 2); - mgr.rotateGripConnector.setAttribute('y2', nbay - gripRadius * 5); - mgr.rotateGrip.setAttribute('cx', nbax + nbaw / 2); - mgr.rotateGrip.setAttribute('cy', nbay - gripRadius * 5); // } - } // STATIC methods - - /** - * Updates cursors for corner grips on rotation so arrows point the right way. - * @param {Float} angle - Current rotation angle in degrees - * @returns {void} - */ - - }], [{ - key: "updateGripCursors", - value: function updateGripCursors(angle) { - var dirArr = Object.keys(selectorManager_.selectorGrips); - var steps = Math.round(angle / 45); - - if (steps < 0) { - steps += 8; - } - - while (steps > 0) { - dirArr.push(dirArr.shift()); - steps--; - } - - Object.values(selectorManager_.selectorGrips).forEach(function (gripElement, i) { - gripElement.setAttribute('style', 'cursor:' + dirArr[i] + '-resize'); - }); + const { + tl + } = nbox; + let minx = tl.x, + miny = tl.y, + maxx = tl.x, + maxy = tl.y; + const { + min, + max + } = Math; + minx = min(minx, min(nbox.tr.x, min(nbox.bl.x, nbox.br.x))) - offset; + miny = min(miny, min(nbox.tr.y, min(nbox.bl.y, nbox.br.y))) - offset; + maxx = max(maxx, max(nbox.tr.x, max(nbox.bl.x, nbox.br.x))) + offset; + maxy = max(maxy, max(nbox.tr.y, max(nbox.bl.y, nbox.br.y))) + offset; + nbax = minx; + nbay = miny; + nbaw = maxx - minx; + nbah = maxy - miny; } - }]); - return Selector; - }(); + const dstr = 'M' + nbax + ',' + nbay + ' L' + (nbax + nbaw) + ',' + nbay + ' ' + (nbax + nbaw) + ',' + (nbay + nbah) + ' ' + nbax + ',' + (nbay + nbah) + 'z'; + selectedBox.setAttribute('d', dstr); + const xform = angle ? 'rotate(' + [angle, cx, cy].join(',') + ')' : ''; + this.selectorGroup.setAttribute('transform', xform); // TODO(codedread): Is this needed? + // if (selected === selectedElements[0]) { + + this.gripCoords = { + nw: [nbax, nbay], + ne: [nbax + nbaw, nbay], + sw: [nbax, nbay + nbah], + se: [nbax + nbaw, nbay + nbah], + n: [nbax + nbaw / 2, nbay], + w: [nbax, nbay + nbah / 2], + e: [nbax + nbaw, nbay + nbah / 2], + s: [nbax + nbaw / 2, nbay + nbah] + }; + Object.entries(this.gripCoords).forEach(([dir, coords]) => { + selectedGrips[dir].setAttribute('cx', coords[0]); + selectedGrips[dir].setAttribute('cy', coords[1]); + }); // we want to go 20 pixels in the negative transformed y direction, ignoring scale + + mgr.rotateGripConnector.setAttribute('x1', nbax + nbaw / 2); + mgr.rotateGripConnector.setAttribute('y1', nbay); + mgr.rotateGripConnector.setAttribute('x2', nbax + nbaw / 2); + mgr.rotateGripConnector.setAttribute('y2', nbay - gripRadius * 5); + mgr.rotateGrip.setAttribute('cx', nbax + nbaw / 2); + mgr.rotateGrip.setAttribute('cy', nbay - gripRadius * 5); // } + } // STATIC methods + + /** + * Updates cursors for corner grips on rotation so arrows point the right way. + * @param {Float} angle - Current rotation angle in degrees + * @returns {void} + */ + + + static updateGripCursors(angle) { + const dirArr = Object.keys(selectorManager_.selectorGrips); + let steps = Math.round(angle / 45); + + if (steps < 0) { + steps += 8; + } + + while (steps > 0) { + dirArr.push(dirArr.shift()); + steps--; + } + + Object.values(selectorManager_.selectorGrips).forEach((gripElement, i) => { + gripElement.setAttribute('style', 'cursor:' + dirArr[i] + '-resize'); + }); + } + + } /** * Manage all selector objects (selection boxes). */ - var SelectorManager = /*#__PURE__*/function () { + class SelectorManager { /** * Sets up properties and calls `initGroup`. */ - function SelectorManager() { - _classCallCheck(this, SelectorManager); - + constructor() { // this will hold the <g> element that contains all selector rects/grips this.selectorParentGroup = null; // this is a special rect that is used for multi-select @@ -13493,219 +12697,207 @@ */ - _createClass(SelectorManager, [{ - key: "initGroup", - value: function initGroup() { - var _this = this; - - // remove old selector parent group if it existed - if (this.selectorParentGroup && this.selectorParentGroup.parentNode) { - this.selectorParentGroup.remove(); - } // create parent selector group and add it to svgroot + initGroup() { + // remove old selector parent group if it existed + if (this.selectorParentGroup && this.selectorParentGroup.parentNode) { + this.selectorParentGroup.remove(); + } // create parent selector group and add it to svgroot - this.selectorParentGroup = svgFactory_.createSVGElement({ - element: 'g', - attr: { - id: 'selectorParentGroup' - } - }); - this.selectorGripsGroup = svgFactory_.createSVGElement({ - element: 'g', - attr: { - display: 'none' - } - }); - this.selectorParentGroup.append(this.selectorGripsGroup); - svgFactory_.svgRoot().append(this.selectorParentGroup); - this.selectorMap = {}; - this.selectors = []; - this.rubberBandBox = null; // add the corner grips + this.selectorParentGroup = svgFactory_.createSVGElement({ + element: 'g', + attr: { + id: 'selectorParentGroup' + } + }); + this.selectorGripsGroup = svgFactory_.createSVGElement({ + element: 'g', + attr: { + display: 'none' + } + }); + this.selectorParentGroup.append(this.selectorGripsGroup); + svgFactory_.svgRoot().append(this.selectorParentGroup); + this.selectorMap = {}; + this.selectors = []; + this.rubberBandBox = null; // add the corner grips - Object.keys(this.selectorGrips).forEach(function (dir) { - var grip = svgFactory_.createSVGElement({ - element: 'circle', - attr: { - id: 'selectorGrip_resize_' + dir, - fill: '#22C', - r: gripRadius, - style: 'cursor:' + dir + '-resize', - // This expands the mouse-able area of the grips making them - // easier to grab with the mouse. - // This works in Opera and WebKit, but does not work in Firefox - // see https://bugzilla.mozilla.org/show_bug.cgi?id=500174 - 'stroke-width': 2, - 'pointer-events': 'all' - } - }); - $$8.data(grip, 'dir', dir); - $$8.data(grip, 'type', 'resize'); - _this.selectorGrips[dir] = _this.selectorGripsGroup.appendChild(grip); - }); // add rotator elems - - this.rotateGripConnector = this.selectorGripsGroup.appendChild(svgFactory_.createSVGElement({ - element: 'line', - attr: { - id: 'selectorGrip_rotateconnector', - stroke: '#22C', - 'stroke-width': '1' - } - })); - this.rotateGrip = this.selectorGripsGroup.appendChild(svgFactory_.createSVGElement({ + Object.keys(this.selectorGrips).forEach(dir => { + const grip = svgFactory_.createSVGElement({ element: 'circle', attr: { - id: 'selectorGrip_rotate', - fill: 'lime', + id: 'selectorGrip_resize_' + dir, + fill: '#22C', r: gripRadius, - stroke: '#22C', + style: 'cursor:' + dir + '-resize', + // This expands the mouse-able area of the grips making them + // easier to grab with the mouse. + // This works in Opera and WebKit, but does not work in Firefox + // see https://bugzilla.mozilla.org/show_bug.cgi?id=500174 'stroke-width': 2, - style: 'cursor:url(' + config_.imgPath + 'rotate.png) 12 12, auto;' - } - })); - $$8.data(this.rotateGrip, 'type', 'rotate'); - - if ($$8('#canvasBackground').length) { - return; - } - - var _config_$dimensions = _slicedToArray(config_.dimensions, 2), - width = _config_$dimensions[0], - height = _config_$dimensions[1]; - - var canvasbg = svgFactory_.createSVGElement({ - element: 'svg', - attr: { - id: 'canvasBackground', - width: width, - height: height, - x: 0, - y: 0, - overflow: isWebkit() ? 'none' : 'visible', - // Chrome 7 has a problem with this when zooming out - style: 'pointer-events:none' + 'pointer-events': 'all' } }); - var rect = svgFactory_.createSVGElement({ - element: 'rect', - attr: { - width: '100%', - height: '100%', - x: 0, - y: 0, - 'stroke-width': 1, - stroke: '#000', - fill: '#FFF', - style: 'pointer-events:none' - } - }); // Both Firefox and WebKit are too slow with this filter region (especially at higher - // zoom levels) and Opera has at least one bug - // if (!isOpera()) rect.setAttribute('filter', 'url(#canvashadow)'); + $$9.data(grip, 'dir', dir); + $$9.data(grip, 'type', 'resize'); + this.selectorGrips[dir] = this.selectorGripsGroup.appendChild(grip); + }); // add rotator elems - canvasbg.append(rect); - svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent()); // Ok to replace above with `svgFactory_.svgContent().before(canvasbg);`? + this.rotateGripConnector = this.selectorGripsGroup.appendChild(svgFactory_.createSVGElement({ + element: 'line', + attr: { + id: 'selectorGrip_rotateconnector', + stroke: '#22C', + 'stroke-width': '1' + } + })); + this.rotateGrip = this.selectorGripsGroup.appendChild(svgFactory_.createSVGElement({ + element: 'circle', + attr: { + id: 'selectorGrip_rotate', + fill: 'lime', + r: gripRadius, + stroke: '#22C', + 'stroke-width': 2, + style: 'cursor:url(' + config_.imgPath + 'rotate.png) 12 12, auto;' + } + })); + $$9.data(this.rotateGrip, 'type', 'rotate'); + + if ($$9('#canvasBackground').length) { + return; } - /** - * - * @param {Element} elem - DOM element to get the selector for - * @param {module:utilities.BBoxObject} [bbox] - Optional bbox to use for reset (prevents duplicate getBBox call). - * @returns {Selector} The selector based on the given element - */ - }, { - key: "requestSelector", - value: function requestSelector(elem, bbox) { - if (isNullish(elem)) { - return null; + const [width, height] = config_.dimensions; + const canvasbg = svgFactory_.createSVGElement({ + element: 'svg', + attr: { + id: 'canvasBackground', + width, + height, + x: 0, + y: 0, + overflow: isWebkit() ? 'none' : 'visible', + // Chrome 7 has a problem with this when zooming out + style: 'pointer-events:none' } - - var N = this.selectors.length; // If we've already acquired one for this element, return it. - - if (_typeof(this.selectorMap[elem.id]) === 'object') { - this.selectorMap[elem.id].locked = true; - return this.selectorMap[elem.id]; + }); + const rect = svgFactory_.createSVGElement({ + element: 'rect', + attr: { + width: '100%', + height: '100%', + x: 0, + y: 0, + 'stroke-width': 1, + stroke: '#000', + fill: '#FFF', + style: 'pointer-events:none' } + }); // Both Firefox and WebKit are too slow with this filter region (especially at higher + // zoom levels) and Opera has at least one bug + // if (!isOpera()) rect.setAttribute('filter', 'url(#canvashadow)'); - for (var i = 0; i < N; ++i) { - if (this.selectors[i] && !this.selectors[i].locked) { - this.selectors[i].locked = true; - this.selectors[i].reset(elem, bbox); - this.selectorMap[elem.id] = this.selectors[i]; - return this.selectors[i]; - } - } // if we reached here, no available selectors were found, we create one + canvasbg.append(rect); + svgFactory_.svgRoot().insertBefore(canvasbg, svgFactory_.svgContent()); // Ok to replace above with `svgFactory_.svgContent().before(canvasbg);`? + } + /** + * + * @param {Element} elem - DOM element to get the selector for + * @param {module:utilities.BBoxObject} [bbox] - Optional bbox to use for reset (prevents duplicate getBBox call). + * @returns {Selector} The selector based on the given element + */ - this.selectors[N] = new Selector(N, elem, bbox); - this.selectorParentGroup.append(this.selectors[N].selectorGroup); - this.selectorMap[elem.id] = this.selectors[N]; - return this.selectors[N]; + requestSelector(elem, bbox) { + if (isNullish(elem)) { + return null; } - /** - * Removes the selector of the given element (hides selection box). - * - * @param {Element} elem - DOM element to remove the selector for - * @returns {void} - */ - }, { - key: "releaseSelector", - value: function releaseSelector(elem) { - if (isNullish(elem)) { - return; + const N = this.selectors.length; // If we've already acquired one for this element, return it. + + if (typeof this.selectorMap[elem.id] === 'object') { + this.selectorMap[elem.id].locked = true; + return this.selectorMap[elem.id]; + } + + for (let i = 0; i < N; ++i) { + if (this.selectors[i] && !this.selectors[i].locked) { + this.selectors[i].locked = true; + this.selectors[i].reset(elem, bbox); + this.selectorMap[elem.id] = this.selectors[i]; + return this.selectors[i]; } + } // if we reached here, no available selectors were found, we create one - var N = this.selectors.length, + + this.selectors[N] = new Selector(N, elem, bbox); + this.selectorParentGroup.append(this.selectors[N].selectorGroup); + this.selectorMap[elem.id] = this.selectors[N]; + return this.selectors[N]; + } + /** + * Removes the selector of the given element (hides selection box). + * + * @param {Element} elem - DOM element to remove the selector for + * @returns {void} + */ + + + releaseSelector(elem) { + if (isNullish(elem)) { + return; + } + + const N = this.selectors.length, sel = this.selectorMap[elem.id]; - if (!sel.locked) { - // TODO(codedread): Ensure this exists in this module. - console.log('WARNING! selector was released but was already unlocked'); // eslint-disable-line no-console + if (!sel.locked) { + // TODO(codedread): Ensure this exists in this module. + console.log('WARNING! selector was released but was already unlocked'); // eslint-disable-line no-console + } + + for (let i = 0; i < N; ++i) { + if (this.selectors[i] && this.selectors[i] === sel) { + delete this.selectorMap[elem.id]; + sel.locked = false; + sel.selectedElement = null; + sel.showGrips(false); // remove from DOM and store reference in JS but only if it exists in the DOM + + try { + sel.selectorGroup.setAttribute('display', 'none'); + } catch (e) {} + + break; } + } + } + /** + * @returns {SVGRectElement} The rubberBandBox DOM element. This is the rectangle drawn by + * the user for selecting/zooming + */ - for (var i = 0; i < N; ++i) { - if (this.selectors[i] && this.selectors[i] === sel) { - delete this.selectorMap[elem.id]; - sel.locked = false; - sel.selectedElement = null; - sel.showGrips(false); // remove from DOM and store reference in JS but only if it exists in the DOM - try { - sel.selectorGroup.setAttribute('display', 'none'); - } catch (e) {} - - break; + getRubberBandBox() { + if (!this.rubberBandBox) { + this.rubberBandBox = this.selectorParentGroup.appendChild(svgFactory_.createSVGElement({ + element: 'rect', + attr: { + id: 'selectorRubberBand', + fill: '#22C', + 'fill-opacity': 0.15, + stroke: '#22C', + 'stroke-width': 0.5, + display: 'none', + style: 'pointer-events:none' } - } + })); } - /** - * @returns {SVGRectElement} The rubberBandBox DOM element. This is the rectangle drawn by - * the user for selecting/zooming - */ - }, { - key: "getRubberBandBox", - value: function getRubberBandBox() { - if (!this.rubberBandBox) { - this.rubberBandBox = this.selectorParentGroup.appendChild(svgFactory_.createSVGElement({ - element: 'rect', - attr: { - id: 'selectorRubberBand', - fill: '#22C', - 'fill-opacity': 0.15, - stroke: '#22C', - 'stroke-width': 0.5, - display: 'none', - style: 'pointer-events:none' - } - })); - } + return this.rubberBandBox; + } - return this.rubberBandBox; - } - }]); - - return SelectorManager; - }(); + } /** * An object that creates SVG elements for the canvas. * @@ -13754,7 +12946,7 @@ * @returns {void} */ - var init$6 = function init(config, svgFactory) { + const init$6 = function (config, svgFactory) { config_ = config; svgFactory_ = svgFactory; selectorManager_ = new SelectorManager(); @@ -13764,18 +12956,19 @@ * @returns {module:select.SelectorManager} The SelectorManager instance. */ - var getSelectorManager = function getSelectorManager() { - return selectorManager_; - }; + const getSelectorManager = () => selectorManager_; - var $$9 = jQueryPluginSVG(jQuery); - var MoveElementCommand$1 = MoveElementCommand, - InsertElementCommand$1 = InsertElementCommand, - RemoveElementCommand$1 = RemoveElementCommand, - ChangeElementCommand$1 = ChangeElementCommand, - BatchCommand$1 = BatchCommand, - UndoManager$1 = UndoManager, - HistoryEventTypes$1 = HistoryEventTypes; + /* eslint-disable indent, unicorn/no-fn-reference-in-iterator */ + let $$a = jQueryPluginSVG(jQuery); + const { + MoveElementCommand: MoveElementCommand$1, + InsertElementCommand: InsertElementCommand$1, + RemoveElementCommand: RemoveElementCommand$1, + ChangeElementCommand: ChangeElementCommand$1, + BatchCommand: BatchCommand$1, + UndoManager: UndoManager$1, + HistoryEventTypes: HistoryEventTypes$1 + } = hstry; if (!window.console) { window.console = {}; @@ -13829,1865 +13022,1856 @@ */ - var SvgCanvas = - /** - * @param {HTMLElement} container - The container HTML element that should hold the SVG root element - * @param {module:SVGEditor.curConfig} config - An object that contains configuration data - */ - function SvgCanvas(container, config) { - _classCallCheck(this, SvgCanvas); - - // Alias Namespace constants - // Default configuration options - var curConfig = { - show_outside_canvas: true, - selectNew: true, - dimensions: [640, 480] - }; // Update config with new one if given - - if (config) { - $$9.extend(curConfig, config); - } // Array with width/height of canvas - - - var dimensions = curConfig.dimensions; - var canvas = this; // eslint-disable-line consistent-this - // "document" element associated with the container (same as window.document using default svg-editor.js) - // NOTE: This is not actually a SVG document, but an HTML document. - - var svgdoc = container.ownerDocument; // This is a container for the document being edited, not the document itself. - + class SvgCanvas { /** - * @name module:svgcanvas~svgroot - * @type {SVGSVGElement} - */ - - var svgroot = svgdoc.importNode(text2xml('<svg id="svgroot" xmlns="' + NS.SVG + '" xlinkns="' + NS.XLINK + '" ' + 'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' + '<defs>' + '<filter id="canvashadow" filterUnits="objectBoundingBox">' + '<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>' + '<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>' + '<feMerge>' + '<feMergeNode in="offsetBlur"/>' + '<feMergeNode in="SourceGraphic"/>' + '</feMerge>' + '</filter>' + '</defs>' + '</svg>').documentElement, true); - container.append(svgroot); - /** - * The actual element that represents the final output SVG element. - * @name module:svgcanvas~svgcontent - * @type {SVGSVGElement} - */ - - var svgcontent = svgdoc.createElementNS(NS.SVG, 'svg'); - /** - * This function resets the svgcontent element while keeping it in the DOM. - * @function module:svgcanvas.SvgCanvas#clearSvgContentElement - * @returns {void} + * @param {HTMLElement} container - The container HTML element that should hold the SVG root element + * @param {module:SVGEditor.curConfig} config - An object that contains configuration data */ + constructor(container, config) { + // Alias Namespace constants + // Default configuration options + const curConfig = { + show_outside_canvas: true, + selectNew: true, + dimensions: [640, 480] + }; // Update config with new one if given - var clearSvgContentElement = canvas.clearSvgContentElement = function () { - $$9(svgcontent).empty(); // TODO: Clear out all other attributes first? - - $$9(svgcontent).attr({ - id: 'svgcontent', - width: dimensions[0], - height: dimensions[1], - x: dimensions[0], - y: dimensions[1], - overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden', - xmlns: NS.SVG, - 'xmlns:se': NS.SE, - 'xmlns:xlink': NS.XLINK - }).appendTo(svgroot); // TODO: make this string optional and set by the client - - var comment = svgdoc.createComment(' Created with SVG-edit - https://github.com/SVG-Edit/svgedit'); - svgcontent.append(comment); - }; - - clearSvgContentElement(); // Prefix string for element IDs - - var idprefix = 'svg_'; - /** - * Changes the ID prefix to the given value. - * @function module:svgcanvas.SvgCanvas#setIdPrefix - * @param {string} p - String with the new prefix - * @returns {void} - */ - - canvas.setIdPrefix = function (p) { - idprefix = p; - }; - /** - * Current `draw.Drawing` object. - * @type {module:draw.Drawing} - * @name module:svgcanvas.SvgCanvas#current_drawing_ - */ + if (config) { + $$a.extend(curConfig, config); + } // Array with width/height of canvas - canvas.current_drawing_ = new Drawing(svgcontent, idprefix); - /** - * Returns the current Drawing. - * @name module:svgcanvas.SvgCanvas#getCurrentDrawing - * @type {module:draw.DrawCanvasInit#getCurrentDrawing} - */ + const { + dimensions + } = curConfig; + const canvas = this; // eslint-disable-line consistent-this + // "document" element associated with the container (same as window.document using default svg-editor.js) + // NOTE: This is not actually a SVG document, but an HTML document. - var getCurrentDrawing = canvas.getCurrentDrawing = function () { - return canvas.current_drawing_; - }; - /** - * Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). - * @type {Float} - */ + const svgdoc = container.ownerDocument; // This is a container for the document being edited, not the document itself. - - var currentZoom = 1; // pointer to current group (for in-group editing) - - var currentGroup = null; // Object containing data for the currently selected styles - - var allProperties = { - shape: { - fill: (curConfig.initFill.color === 'none' ? '' : '#') + curConfig.initFill.color, - fill_paint: null, - fill_opacity: curConfig.initFill.opacity, - stroke: '#' + curConfig.initStroke.color, - stroke_paint: null, - stroke_opacity: curConfig.initStroke.opacity, - stroke_width: curConfig.initStroke.width, - stroke_dasharray: 'none', - stroke_linejoin: 'miter', - stroke_linecap: 'butt', - opacity: curConfig.initOpacity - } - }; - allProperties.text = $$9.extend(true, {}, allProperties.shape); - $$9.extend(allProperties.text, { - fill: '#000000', - stroke_width: curConfig.text && curConfig.text.stroke_width, - font_size: curConfig.text && curConfig.text.font_size, - font_family: curConfig.text && curConfig.text.font_family - }); // Current shape style properties - - var curShape = allProperties.shape; // Array with all the currently selected elements - // default size of 1 until it needs to grow bigger - - var selectedElements = []; - /** - * @typedef {PlainObject} module:svgcanvas.SVGAsJSON - * @property {string} element - * @property {PlainObject<string, string>} attr - * @property {module:svgcanvas.SVGAsJSON[]} children - */ - - /** - * @function module:svgcanvas.SvgCanvas#getContentElem - * @param {Text|Element} data - * @returns {module:svgcanvas.SVGAsJSON} - */ - - var getJsonFromSvgElement = this.getJsonFromSvgElement = function (data) { - // Text node - if (data.nodeType === 3) return data.nodeValue; - var retval = { - element: data.tagName, - // namespace: nsMap[data.namespaceURI], - attr: {}, - children: [] - }; // Iterate attributes - - for (var i = 0, attr; attr = data.attributes[i]; i++) { - retval.attr[attr.name] = attr.value; - } // Iterate children - - - for (var _i = 0, node; node = data.childNodes[_i]; _i++) { - retval.children[_i] = getJsonFromSvgElement(node); - } - - return retval; - }; - /** - * This should really be an intersection implementing all rather than a union. - * @name module:svgcanvas.SvgCanvas#addSVGElementFromJson - * @type {module:utilities.EditorContext#addSVGElementFromJson|module:path.EditorContext#addSVGElementFromJson} - */ - - - var addSVGElementFromJson = this.addSVGElementFromJson = function (data) { - if (typeof data === 'string') return svgdoc.createTextNode(data); - var shape = getElem(data.attr.id); // if shape is a path but we need to create a rect/ellipse, then remove the path - - var currentLayer = getCurrentDrawing().getCurrentLayer(); - - if (shape && data.element !== shape.tagName) { - shape.remove(); - shape = null; - } - - if (!shape) { - var ns = data.namespace || NS.SVG; - shape = svgdoc.createElementNS(ns, data.element); - - if (currentLayer) { - (currentGroup || currentLayer).append(shape); - } - } - - if (data.curStyles) { - assignAttributes(shape, { - fill: curShape.fill, - stroke: curShape.stroke, - 'stroke-width': curShape.stroke_width, - 'stroke-dasharray': curShape.stroke_dasharray, - 'stroke-linejoin': curShape.stroke_linejoin, - 'stroke-linecap': curShape.stroke_linecap, - 'stroke-opacity': curShape.stroke_opacity, - 'fill-opacity': curShape.fill_opacity, - opacity: curShape.opacity / 2, - style: 'pointer-events:inherit' - }); - } - - assignAttributes(shape, data.attr); - cleanupElement(shape); // Children - - if (data.children) { - data.children.forEach(function (child) { - shape.append(addSVGElementFromJson(child)); - }); - } - - return shape; - }; - - canvas.getTransformList = getTransformList; - canvas.matrixMultiply = matrixMultiply; - canvas.hasMatrixTransform = hasMatrixTransform; - canvas.transformListToTransform = transformListToTransform; - /** - * @type {module:utilities.EditorContext#getBaseUnit} - */ - - var getBaseUnit = function getBaseUnit() { - return curConfig.baseUnit; - }; - /** - * Initialize from units.js. - * Send in an object implementing the ElementContainer interface (see units.js). - */ - - - init( - /** - * @implements {module:units.ElementContainer} - */ - { - getBaseUnit: getBaseUnit, - getElement: getElem, - getHeight: function getHeight() { - return svgcontent.getAttribute('height') / currentZoom; - }, - getWidth: function getWidth() { - return svgcontent.getAttribute('width') / currentZoom; - }, - getRoundDigits: function getRoundDigits() { - return saveOptions.round_digits; - } - }); - canvas.convertToNum = convertToNum; - /** - * This should really be an intersection implementing all rather than a union. - * @type {module:draw.DrawCanvasInit#getSVGContent|module:utilities.EditorContext#getSVGContent} - */ - - var getSVGContent = function getSVGContent() { - return svgcontent; - }; - /** - * Should really be an intersection with all needing to apply rather than a union. - * @name module:svgcanvas.SvgCanvas#getSelectedElements - * @type {module:utilities.EditorContext#getSelectedElements|module:draw.DrawCanvasInit#getSelectedElements|module:path.EditorContext#getSelectedElements} - */ - - - var getSelectedElements = this.getSelectedElems = function () { - return selectedElements; - }; - - var pathActions$1 = pathActions; - /** - * This should actually be an intersection as all interfaces should be met. - * @type {module:utilities.EditorContext#getSVGRoot|module:recalculate.EditorContext#getSVGRoot|module:coords.EditorContext#getSVGRoot|module:path.EditorContext#getSVGRoot} - */ - - var getSVGRoot = function getSVGRoot() { - return svgroot; - }; - - init$2( - /** - * @implements {module:utilities.EditorContext} - */ - { - pathActions: pathActions$1, - // Ok since not modifying - getSVGContent: getSVGContent, - addSVGElementFromJson: addSVGElementFromJson, - getSelectedElements: getSelectedElements, - getDOMDocument: function getDOMDocument() { - return svgdoc; - }, - getDOMContainer: function getDOMContainer() { - return container; - }, - getSVGRoot: getSVGRoot, - // TODO: replace this mostly with a way to get the current drawing. - getBaseUnit: getBaseUnit, - getSnappingStep: function getSnappingStep() { - return curConfig.snappingStep; - } - }); - canvas.findDefs = findDefs; - canvas.getUrlFromAttr = getUrlFromAttr; - canvas.getHref = getHref; - canvas.setHref = setHref; - /* const getBBox = */ - - canvas.getBBox = getBBox; - canvas.getRotationAngle = getRotationAngle; - canvas.getElem = getElem; - canvas.getRefElem = getRefElem; - canvas.assignAttributes = assignAttributes; - this.cleanupElement = cleanupElement; - /** - * This should actually be an intersection not a union as all should apply. - * @type {module:coords.EditorContext#getGridSnapping|module:path.EditorContext#getGridSnapping} - */ - - var getGridSnapping = function getGridSnapping() { - return curConfig.gridSnapping; - }; - - init$4( - /** - * @implements {module:coords.EditorContext} - */ - { - getDrawing: function getDrawing() { - return getCurrentDrawing(); - }, - getSVGRoot: getSVGRoot, - getGridSnapping: getGridSnapping - }); - this.remapElement = remapElement; - init$5( - /** - * @implements {module:recalculate.EditorContext} - */ - { - getSVGRoot: getSVGRoot, - getStartTransform: function getStartTransform() { - return startTransform; - }, - setStartTransform: function setStartTransform(transform) { - startTransform = transform; - } - }); - this.recalculateDimensions = recalculateDimensions; // import from sanitize.js - - var nsMap = getReverseNS(); - canvas.sanitizeSvg = sanitizeSvg; - /** - * @name undoMgr - * @memberof module:svgcanvas.SvgCanvas# - * @type {module:history.HistoryEventHandler} - */ - - var undoMgr = canvas.undoMgr = new UndoManager$1({ /** - * @param {string} eventType One of the HistoryEvent types - * @param {module:history.HistoryCommand} cmd Fulfills the HistoryCommand interface - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} + * @name module:svgcanvas~svgroot + * @type {SVGSVGElement} */ - handleHistoryEvent: function handleHistoryEvent(eventType, cmd) { - var EventTypes = HistoryEventTypes$1; // TODO: handle setBlurOffsets. - if (eventType === EventTypes.BEFORE_UNAPPLY || eventType === EventTypes.BEFORE_APPLY) { - canvas.clearSelection(); - } else if (eventType === EventTypes.AFTER_APPLY || eventType === EventTypes.AFTER_UNAPPLY) { - var elems = cmd.elements(); - canvas.pathActions.clear(); - call('changed', elems); - var cmdType = cmd.type(); - var isApply = eventType === EventTypes.AFTER_APPLY; + const svgroot = svgdoc.importNode(text2xml('<svg id="svgroot" xmlns="' + NS.SVG + '" xlinkns="' + NS.XLINK + '" ' + 'width="' + dimensions[0] + '" height="' + dimensions[1] + '" x="' + dimensions[0] + '" y="' + dimensions[1] + '" overflow="visible">' + '<defs>' + '<filter id="canvashadow" filterUnits="objectBoundingBox">' + '<feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>' + '<feOffset in="blur" dx="5" dy="5" result="offsetBlur"/>' + '<feMerge>' + '<feMergeNode in="offsetBlur"/>' + '<feMergeNode in="SourceGraphic"/>' + '</feMerge>' + '</filter>' + '</defs>' + '</svg>').documentElement, true); + container.append(svgroot); + /** + * The actual element that represents the final output SVG element. + * @name module:svgcanvas~svgcontent + * @type {SVGSVGElement} + */ - if (cmdType === MoveElementCommand$1.type()) { - var parent = isApply ? cmd.newParent : cmd.oldParent; + let svgcontent = svgdoc.createElementNS(NS.SVG, 'svg'); + /** + * This function resets the svgcontent element while keeping it in the DOM. + * @function module:svgcanvas.SvgCanvas#clearSvgContentElement + * @returns {void} + */ - if (parent === svgcontent) { - identifyLayers(); - } - } else if (cmdType === InsertElementCommand$1.type() || cmdType === RemoveElementCommand$1.type()) { - if (cmd.parent === svgcontent) { - identifyLayers(); - } + const clearSvgContentElement = canvas.clearSvgContentElement = function () { + $$a(svgcontent).empty(); // TODO: Clear out all other attributes first? - if (cmdType === InsertElementCommand$1.type()) { - if (isApply) { + $$a(svgcontent).attr({ + id: 'svgcontent', + width: dimensions[0], + height: dimensions[1], + x: dimensions[0], + y: dimensions[1], + overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden', + xmlns: NS.SVG, + 'xmlns:se': NS.SE, + 'xmlns:xlink': NS.XLINK + }).appendTo(svgroot); // TODO: make this string optional and set by the client + + const comment = svgdoc.createComment(' Created with SVG-edit - https://github.com/SVG-Edit/svgedit'); + svgcontent.append(comment); + }; + + clearSvgContentElement(); // Prefix string for element IDs + + let idprefix = 'svg_'; + /** + * Changes the ID prefix to the given value. + * @function module:svgcanvas.SvgCanvas#setIdPrefix + * @param {string} p - String with the new prefix + * @returns {void} + */ + + canvas.setIdPrefix = function (p) { + idprefix = p; + }; + /** + * Current `draw.Drawing` object. + * @type {module:draw.Drawing} + * @name module:svgcanvas.SvgCanvas#current_drawing_ + */ + + + canvas.current_drawing_ = new Drawing(svgcontent, idprefix); + /** + * Returns the current Drawing. + * @name module:svgcanvas.SvgCanvas#getCurrentDrawing + * @type {module:draw.DrawCanvasInit#getCurrentDrawing} + */ + + const getCurrentDrawing = canvas.getCurrentDrawing = function () { + return canvas.current_drawing_; + }; + /** + * Float displaying the current zoom level (1 = 100%, .5 = 50%, etc.). + * @type {Float} + */ + + + let currentZoom = 1; // pointer to current group (for in-group editing) + + let currentGroup = null; // Object containing data for the currently selected styles + + const allProperties = { + shape: { + fill: (curConfig.initFill.color === 'none' ? '' : '#') + curConfig.initFill.color, + fill_paint: null, + fill_opacity: curConfig.initFill.opacity, + stroke: '#' + curConfig.initStroke.color, + stroke_paint: null, + stroke_opacity: curConfig.initStroke.opacity, + stroke_width: curConfig.initStroke.width, + stroke_dasharray: 'none', + stroke_linejoin: 'miter', + stroke_linecap: 'butt', + opacity: curConfig.initOpacity + } + }; + allProperties.text = $$a.extend(true, {}, allProperties.shape); + $$a.extend(allProperties.text, { + fill: '#000000', + stroke_width: curConfig.text && curConfig.text.stroke_width, + font_size: curConfig.text && curConfig.text.font_size, + font_family: curConfig.text && curConfig.text.font_family + }); // Current shape style properties + + const curShape = allProperties.shape; // Array with all the currently selected elements + // default size of 1 until it needs to grow bigger + + let selectedElements = []; + /** + * @typedef {PlainObject} module:svgcanvas.SVGAsJSON + * @property {string} element + * @property {PlainObject<string, string>} attr + * @property {module:svgcanvas.SVGAsJSON[]} children + */ + + /** + * @function module:svgcanvas.SvgCanvas#getContentElem + * @param {Text|Element} data + * @returns {module:svgcanvas.SVGAsJSON} + */ + + const getJsonFromSvgElement = this.getJsonFromSvgElement = function (data) { + // Text node + if (data.nodeType === 3) return data.nodeValue; + const retval = { + element: data.tagName, + // namespace: nsMap[data.namespaceURI], + attr: {}, + children: [] + }; // Iterate attributes + + for (let i = 0, attr; attr = data.attributes[i]; i++) { + retval.attr[attr.name] = attr.value; + } // Iterate children + + + for (let i = 0, node; node = data.childNodes[i]; i++) { + retval.children[i] = getJsonFromSvgElement(node); + } + + return retval; + }; + /** + * This should really be an intersection implementing all rather than a union. + * @name module:svgcanvas.SvgCanvas#addSVGElementFromJson + * @type {module:utilities.EditorContext#addSVGElementFromJson|module:path.EditorContext#addSVGElementFromJson} + */ + + + const addSVGElementFromJson = this.addSVGElementFromJson = function (data) { + if (typeof data === 'string') return svgdoc.createTextNode(data); + let shape = getElem(data.attr.id); // if shape is a path but we need to create a rect/ellipse, then remove the path + + const currentLayer = getCurrentDrawing().getCurrentLayer(); + + if (shape && data.element !== shape.tagName) { + shape.remove(); + shape = null; + } + + if (!shape) { + const ns = data.namespace || NS.SVG; + shape = svgdoc.createElementNS(ns, data.element); + + if (currentLayer) { + (currentGroup || currentLayer).append(shape); + } + } + + if (data.curStyles) { + assignAttributes(shape, { + fill: curShape.fill, + stroke: curShape.stroke, + 'stroke-width': curShape.stroke_width, + 'stroke-dasharray': curShape.stroke_dasharray, + 'stroke-linejoin': curShape.stroke_linejoin, + 'stroke-linecap': curShape.stroke_linecap, + 'stroke-opacity': curShape.stroke_opacity, + 'fill-opacity': curShape.fill_opacity, + opacity: curShape.opacity / 2, + style: 'pointer-events:inherit' + }); + } + + assignAttributes(shape, data.attr); + cleanupElement(shape); // Children + + if (data.children) { + data.children.forEach(child => { + shape.append(addSVGElementFromJson(child)); + }); + } + + return shape; + }; + + canvas.getTransformList = getTransformList; + canvas.matrixMultiply = matrixMultiply; + canvas.hasMatrixTransform = hasMatrixTransform; + canvas.transformListToTransform = transformListToTransform; + /** + * @type {module:utilities.EditorContext#getBaseUnit} + */ + + const getBaseUnit = () => { + return curConfig.baseUnit; + }; + /** + * Initialize from units.js. + * Send in an object implementing the ElementContainer interface (see units.js). + */ + + + init( + /** + * @implements {module:units.ElementContainer} + */ + { + getBaseUnit, + getElement: getElem, + + getHeight() { + return svgcontent.getAttribute('height') / currentZoom; + }, + + getWidth() { + return svgcontent.getAttribute('width') / currentZoom; + }, + + getRoundDigits() { + return saveOptions.round_digits; + } + + }); + canvas.convertToNum = convertToNum; + /** + * This should really be an intersection implementing all rather than a union. + * @type {module:draw.DrawCanvasInit#getSVGContent|module:utilities.EditorContext#getSVGContent} + */ + + const getSVGContent = () => { + return svgcontent; + }; + /** + * Should really be an intersection with all needing to apply rather than a union. + * @name module:svgcanvas.SvgCanvas#getSelectedElements + * @type {module:utilities.EditorContext#getSelectedElements|module:draw.DrawCanvasInit#getSelectedElements|module:path.EditorContext#getSelectedElements} + */ + + + const getSelectedElements = this.getSelectedElems = function () { + return selectedElements; + }; + + const { + pathActions + } = pathModule; + /** + * This should actually be an intersection as all interfaces should be met. + * @type {module:utilities.EditorContext#getSVGRoot|module:recalculate.EditorContext#getSVGRoot|module:coords.EditorContext#getSVGRoot|module:path.EditorContext#getSVGRoot} + */ + + const getSVGRoot = () => svgroot; + + init$1( + /** + * @implements {module:utilities.EditorContext} + */ + { + pathActions, + // Ok since not modifying + getSVGContent, + addSVGElementFromJson, + getSelectedElements, + + getDOMDocument() { + return svgdoc; + }, + + getDOMContainer() { + return container; + }, + + getSVGRoot, + // TODO: replace this mostly with a way to get the current drawing. + getBaseUnit, + + getSnappingStep() { + return curConfig.snappingStep; + } + + }); + canvas.findDefs = findDefs; + canvas.getUrlFromAttr = getUrlFromAttr; + canvas.getHref = getHref; + canvas.setHref = setHref; + /* const getBBox = */ + + canvas.getBBox = getBBox; + canvas.getRotationAngle = getRotationAngle; + canvas.getElem = getElem; + canvas.getRefElem = getRefElem; + canvas.assignAttributes = assignAttributes; + this.cleanupElement = cleanupElement; + /** + * This should actually be an intersection not a union as all should apply. + * @type {module:coords.EditorContext#getGridSnapping|module:path.EditorContext#getGridSnapping} + */ + + const getGridSnapping = () => { + return curConfig.gridSnapping; + }; + + init$4( + /** + * @implements {module:coords.EditorContext} + */ + { + getDrawing() { + return getCurrentDrawing(); + }, + + getSVGRoot, + getGridSnapping + }); + this.remapElement = remapElement; + init$5( + /** + * @implements {module:recalculate.EditorContext} + */ + { + getSVGRoot, + + getStartTransform() { + return startTransform; + }, + + setStartTransform(transform) { + startTransform = transform; + } + + }); + this.recalculateDimensions = recalculateDimensions; // import from sanitize.js + + const nsMap = getReverseNS(); + canvas.sanitizeSvg = sanitizeSvg; + /** + * @name undoMgr + * @memberof module:svgcanvas.SvgCanvas# + * @type {module:history.HistoryEventHandler} + */ + + const undoMgr = canvas.undoMgr = new UndoManager$1({ + /** + * @param {string} eventType One of the HistoryEvent types + * @param {module:history.HistoryCommand} cmd Fulfills the HistoryCommand interface + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + handleHistoryEvent(eventType, cmd) { + const EventTypes = HistoryEventTypes$1; // TODO: handle setBlurOffsets. + + if (eventType === EventTypes.BEFORE_UNAPPLY || eventType === EventTypes.BEFORE_APPLY) { + canvas.clearSelection(); + } else if (eventType === EventTypes.AFTER_APPLY || eventType === EventTypes.AFTER_UNAPPLY) { + const elems = cmd.elements(); + canvas.pathActions.clear(); + call('changed', elems); + const cmdType = cmd.type(); + const isApply = eventType === EventTypes.AFTER_APPLY; + + if (cmdType === 'MoveElementCommand') { + const parent = isApply ? cmd.newParent : cmd.oldParent; + + if (parent === svgcontent) { + identifyLayers(); + } + } else if (cmdType === 'InsertElementCommand' || cmdType === 'RemoveElementCommand') { + if (cmd.parent === svgcontent) { + identifyLayers(); + } + + if (cmdType === 'InsertElementCommand') { + if (isApply) { + restoreRefElems(cmd.elem); + } + } else if (!isApply) { restoreRefElems(cmd.elem); } - } else if (!isApply) { - restoreRefElems(cmd.elem); + + if (cmd.elem && cmd.elem.tagName === 'use') { + setUseData(cmd.elem); + } + } else if (cmdType === 'ChangeElementCommand') { + // if we are changing layer names, re-identify all layers + if (cmd.elem.tagName === 'title' && cmd.elem.parentNode.parentNode === svgcontent) { + identifyLayers(); + } + + const values = isApply ? cmd.newValues : cmd.oldValues; // If stdDeviation was changed, update the blur. + + if (values.stdDeviation) { + canvas.setBlurOffsets(cmd.elem.parentNode, values.stdDeviation); + } // This is resolved in later versions of webkit, perhaps we should + // have a featured detection for correct 'use' behavior? + // —————————— + // Remove & Re-add hack for Webkit (issue 775) + // if (cmd.elem.tagName === 'use' && isWebkit()) { + // const {elem} = cmd; + // if (!elem.getAttribute('x') && !elem.getAttribute('y')) { + // const parent = elem.parentNode; + // const sib = elem.nextSibling; + // elem.remove(); + // parent.insertBefore(elem, sib); + // // Ok to replace above with this? `sib.before(elem);` + // } + // } + } - - if (cmd.elem && cmd.elem.tagName === 'use') { - setUseData(cmd.elem); - } - } else if (cmdType === ChangeElementCommand$1.type()) { - // if we are changing layer names, re-identify all layers - if (cmd.elem.tagName === 'title' && cmd.elem.parentNode.parentNode === svgcontent) { - identifyLayers(); - } - - var values = isApply ? cmd.newValues : cmd.oldValues; // If stdDeviation was changed, update the blur. - - if (values.stdDeviation) { - canvas.setBlurOffsets(cmd.elem.parentNode, values.stdDeviation); - } // This is resolved in later versions of webkit, perhaps we should - // have a featured detection for correct 'use' behavior? - // —————————— - // Remove & Re-add hack for Webkit (issue 775) - // if (cmd.elem.tagName === 'use' && isWebkit()) { - // const {elem} = cmd; - // if (!elem.getAttribute('x') && !elem.getAttribute('y')) { - // const parent = elem.parentNode; - // const sib = elem.nextSibling; - // elem.remove(); - // parent.insertBefore(elem, sib); - // // Ok to replace above with this? `sib.before(elem);` - // } - // } - } } - } - }); - /** - * This should really be an intersection applying to all types rather than a union. - * @name module:svgcanvas~addCommandToHistory - * @type {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} - */ - var addCommandToHistory = function addCommandToHistory(cmd) { - canvas.undoMgr.addCommandToHistory(cmd); - }; - /** - * This should really be an intersection applying to all types rather than a union. - * @name module:svgcanvas.SvgCanvas#getZoom - * @type {module:path.EditorContext#getCurrentZoom|module:select.SVGFactory#getCurrentZoom} - */ - - - var getCurrentZoom = this.getZoom = function () { - return currentZoom; - }; - /** - * This method rounds the incoming value to the nearest value based on the `currentZoom` - * @name module:svgcanvas.SvgCanvas#round - * @type {module:path.EditorContext#round} - */ - - - var round = this.round = function (val) { - return Number.parseInt(val * currentZoom) / currentZoom; - }; - - init$6(curConfig, - /** - * Export to select.js. - * @implements {module:select.SVGFactory} - */ - { - createSVGElement: function createSVGElement(jsonMap) { - return canvas.addSVGElementFromJson(jsonMap); - }, - svgRoot: function svgRoot() { - return svgroot; - }, - svgContent: function svgContent() { - return svgcontent; - }, - getCurrentZoom: getCurrentZoom - }); - /** - * This object manages selectors for us. - * @name module:svgcanvas.SvgCanvas#selectorManager - * @type {module:select.SelectorManager} - */ - - var selectorManager = this.selectorManager = getSelectorManager(); - /** - * @name module:svgcanvas.SvgCanvas#getNextId - * @type {module:path.EditorContext#getNextId} - */ - - var getNextId = canvas.getNextId = function () { - return getCurrentDrawing().getNextId(); - }; - /** - * @name module:svgcanvas.SvgCanvas#getId - * @type {module:path.EditorContext#getId} - */ - - - var getId = canvas.getId = function () { - return getCurrentDrawing().getId(); - }; - /** - * The "implements" should really be an intersection applying to all types rather than a union. - * @name module:svgcanvas.SvgCanvas#call - * @type {module:draw.DrawCanvasInit#call|module:path.EditorContext#call} - */ - - - var call = function call(ev, arg) { - if (events[ev]) { - return events[ev](window, arg); - } - - return undefined; - }; - /** - * Clears the selection. The 'selected' handler is then optionally called. - * This should really be an intersection applying to all types rather than a union. - * @name module:svgcanvas.SvgCanvas#clearSelection - * @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} - * @fires module:svgcanvas.SvgCanvas#event:selected - */ - - - var clearSelection = this.clearSelection = function (noCall) { - selectedElements.forEach(function (elem) { - if (isNullish(elem)) { - return; - } - - selectorManager.releaseSelector(elem); }); - selectedElements = []; - - if (!noCall) { - call('selected', selectedElements); - } - }; - /** - * Adds a list of elements to the selection. The 'selected' handler is then called. - * @name module:svgcanvas.SvgCanvas#addToSelection - * @type {module:path.EditorContext#addToSelection} - * @fires module:svgcanvas.SvgCanvas#event:selected - */ - - - var addToSelection = this.addToSelection = function (elemsToAdd, showGrips) { - if (!elemsToAdd.length) { - return; - } // find the first null in our selectedElements array - - - var j = 0; - - while (j < selectedElements.length) { - if (isNullish(selectedElements[j])) { - break; - } - - ++j; - } // now add each element consecutively - - - var i = elemsToAdd.length; - - while (i--) { - var elem = elemsToAdd[i]; - - if (!elem) { - continue; - } - - var bbox = getBBox(elem); - - if (!bbox) { - continue; - } - - if (elem.tagName === 'a' && elem.childNodes.length === 1) { - // Make "a" element's child be the selected element - elem = elem.firstChild; - } // if it's not already there, add it - - - if (!selectedElements.includes(elem)) { - selectedElements[j] = elem; // only the first selectedBBoxes element is ever used in the codebase these days - // if (j === 0) selectedBBoxes[0] = utilsGetBBox(elem); - - j++; - var sel = selectorManager.requestSelector(elem, bbox); - - if (selectedElements.length > 1) { - sel.showGrips(false); - } - } - } - - if (!selectedElements.length) { - return; - } - - call('selected', selectedElements); - - if (selectedElements.length === 1) { - selectorManager.requestSelector(selectedElements[0]).showGrips(showGrips); - } // make sure the elements are in the correct order - // See: https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - - - selectedElements.sort(function (a, b) { - if (a && b && a.compareDocumentPosition) { - return 3 - (b.compareDocumentPosition(a) & 6); // eslint-disable-line no-bitwise - } - - if (isNullish(a)) { - return 1; - } - - return 0; - }); // Make sure first elements are not null - - while (isNullish(selectedElements[0])) { - selectedElements.shift(0); - } - }; - /** - * @type {module:path.EditorContext#getOpacity} - */ - - - var getOpacity = function getOpacity() { - return curShape.opacity; - }; - /** - * @name module:svgcanvas.SvgCanvas#getMouseTarget - * @type {module:path.EditorContext#getMouseTarget} - */ - - - var getMouseTarget = this.getMouseTarget = function (evt) { - if (isNullish(evt)) { - return null; - } - - var mouseTarget = evt.target; // if it was a <use>, Opera and WebKit return the SVGElementInstance - - if (mouseTarget.correspondingUseElement) { - mouseTarget = mouseTarget.correspondingUseElement; - } // for foreign content, go up until we find the foreignObject - // WebKit browsers set the mouse target to the svgcanvas div - - - if ([NS.MATH, NS.HTML].includes(mouseTarget.namespaceURI) && mouseTarget.id !== 'svgcanvas') { - while (mouseTarget.nodeName !== 'foreignObject') { - mouseTarget = mouseTarget.parentNode; - - if (!mouseTarget) { - return svgroot; - } - } - } // Get the desired mouseTarget with jQuery selector-fu - // If it's root-like, select the root - - - var currentLayer = getCurrentDrawing().getCurrentLayer(); - - if ([svgroot, container, svgcontent, currentLayer].includes(mouseTarget)) { - return svgroot; - } - - var $target = $$9(mouseTarget); // If it's a selection grip, return the grip parent - - if ($target.closest('#selectorParentGroup').length) { - // While we could instead have just returned mouseTarget, - // this makes it easier to indentify as being a selector grip - return selectorManager.selectorParentGroup; - } - - while (mouseTarget.parentNode !== (currentGroup || currentLayer)) { - mouseTarget = mouseTarget.parentNode; - } // - // // go up until we hit a child of a layer - // while (mouseTarget.parentNode.parentNode.tagName == 'g') { - // mouseTarget = mouseTarget.parentNode; - // } - // Webkit bubbles the mouse event all the way up to the div, so we - // set the mouseTarget to the svgroot like the other browsers - // if (mouseTarget.nodeName.toLowerCase() == 'div') { - // mouseTarget = svgroot; - // } - - - return mouseTarget; - }; - /** - * @namespace {module:path.pathActions} pathActions - * @memberof module:svgcanvas.SvgCanvas# - * @see module:path.pathActions - */ - - - canvas.pathActions = pathActions$1; - /** - * @type {module:path.EditorContext#resetD} - */ - - function resetD(p) { - p.setAttribute('d', pathActions$1.convertPath(p)); - } - - init$1( - /** - * @implements {module:path.EditorContext} - */ - { - selectorManager: selectorManager, - // Ok since not changing - canvas: canvas, - // Ok since not changing - call: call, - resetD: resetD, - round: round, - clearSelection: clearSelection, - addToSelection: addToSelection, - addCommandToHistory: addCommandToHistory, - remapElement: remapElement, - addSVGElementFromJson: addSVGElementFromJson, - getGridSnapping: getGridSnapping, - getOpacity: getOpacity, - getSelectedElements: getSelectedElements, - getContainer: function getContainer() { - return container; - }, - setStarted: function setStarted(s) { - started = s; - }, - getRubberBox: function getRubberBox() { - return rubberBox; - }, - setRubberBox: function setRubberBox(rb) { - rubberBox = rb; - return rubberBox; - }, - /** - * @param {PlainObject} ptsInfo - * @param {boolean} ptsInfo.closedSubpath - * @param {SVGCircleElement[]} ptsInfo.grips - * @fires module:svgcanvas.SvgCanvas#event:pointsAdded - * @fires module:svgcanvas.SvgCanvas#event:selected - * @returns {void} - */ - addPtsToSelection: function addPtsToSelection(_ref) { - var closedSubpath = _ref.closedSubpath, - grips = _ref.grips; - // TODO: Correct this: - pathActions$1.canDeleteNodes = true; - pathActions$1.closed_subpath = closedSubpath; - call('pointsAdded', { - closedSubpath: closedSubpath, - grips: grips - }); - call('selected', grips); - }, + * This should really be an intersection applying to all types rather than a union. + * @name module:svgcanvas~addCommandToHistory + * @type {module:path.EditorContext#addCommandToHistory|module:draw.DrawCanvasInit#addCommandToHistory} + */ - /** - * @param {PlainObject} changes - * @param {ChangeElementCommand} changes.cmd - * @param {SVGPathElement} changes.elem - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - endChanges: function endChanges(_ref2) { - var cmd = _ref2.cmd, - elem = _ref2.elem; - addCommandToHistory(cmd); - call('changed', [elem]); - }, - getCurrentZoom: getCurrentZoom, - getId: getId, - getNextId: getNextId, - getMouseTarget: getMouseTarget, - getCurrentMode: function getCurrentMode() { - return currentMode; - }, - setCurrentMode: function setCurrentMode(cm) { - currentMode = cm; - return currentMode; - }, - getDrawnPath: function getDrawnPath() { - return drawnPath; - }, - setDrawnPath: function setDrawnPath(dp) { - drawnPath = dp; - return drawnPath; - }, - getSVGRoot: getSVGRoot - }); // Interface strings, usually for title elements - - var uiStrings = {}; - var visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; - var refAttrs = ['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke']; - var elData = $$9.data; // Animation element to change the opacity of any newly created element - - var opacAni = document.createElementNS(NS.SVG, 'animate'); - $$9(opacAni).attr({ - attributeName: 'opacity', - begin: 'indefinite', - dur: 1, - fill: 'freeze' - }).appendTo(svgroot); - - var restoreRefElems = function restoreRefElems(elem) { - // Look for missing reference elements, restore any found - var attrs = $$9(elem).attr(refAttrs); - Object.values(attrs).forEach(function (val) { - if (val && val.startsWith('url(')) { - var id = getUrlFromAttr(val).substr(1); - var ref = getElem(id); - - if (!ref) { - findDefs().append(removedElements[id]); - delete removedElements[id]; - } - } - }); - var childs = elem.getElementsByTagName('*'); - - if (childs.length) { - for (var i = 0, l = childs.length; i < l; i++) { - restoreRefElems(childs[i]); - } - } - }; // (function () { - // TODO For Issue 208: this is a start on a thumbnail - // const svgthumb = svgdoc.createElementNS(NS.SVG, 'use'); - // svgthumb.setAttribute('width', '100'); - // svgthumb.setAttribute('height', '100'); - // setHref(svgthumb, '#svgcontent'); - // svgroot.append(svgthumb); - // }()); - - /** - * @typedef {PlainObject} module:svgcanvas.SaveOptions - * @property {boolean} apply - * @property {"embed"} [image] - * @property {Integer} round_digits - */ - // Object to contain image data for raster images that were found encodable - - - var encodableImages = {}, - // Object with save options - - /** - * @type {module:svgcanvas.SaveOptions} - */ - saveOptions = { - round_digits: 5 - }, - // Object with IDs for imported files, to see if one was already added - importIds = {}, - // Current text style properties - curText = allProperties.text, - // Object to contain all included extensions - extensions = {}, - // Map of deleted reference elements - removedElements = {}; - var // String with image URL of last loadable image - lastGoodImgUrl = curConfig.imgPath + 'logo.png', - // Boolean indicating whether or not a draw action has been started - started = false, - // String with an element's initial transform attribute value - startTransform = null, - // String indicating the current editor mode - currentMode = 'select', - // String with the current direction in which an element is being resized - currentResizeMode = 'none', - // Current general properties - curProperties = curShape, - // Array with selected elements' Bounding box object - // selectedBBoxes = new Array(1), - // The DOM element that was just selected - justSelected = null, - // DOM element for selection rectangle drawn by the user - rubberBox = null, - // Array of current BBoxes, used in getIntersectionList(). - curBBoxes = [], - // Canvas point for the most recent right click - lastClickPoint = null; - - this.runExtension = function (name, action, vars) { - return this.runExtensions(action, vars, false, function (n) { - return n === name; - }); - }; - /** - * @typedef {module:svgcanvas.ExtensionMouseDownStatus|module:svgcanvas.ExtensionMouseUpStatus|module:svgcanvas.ExtensionIDsUpdatedStatus|module:locale.ExtensionLocaleData[]|void} module:svgcanvas.ExtensionStatus - * @tutorial ExtensionDocs - */ - - /** - * @callback module:svgcanvas.ExtensionVarBuilder - * @param {string} name The name of the extension - * @returns {module:svgcanvas.SvgCanvas#event:ext_addLangData} - */ - - /** - * @callback module:svgcanvas.ExtensionNameFilter - * @param {string} name - * @returns {boolean} - */ - - /** - * @todo Consider: Should this return an array by default, so extension results aren't overwritten? - * @todo Would be easier to document if passing in object with key of action and vars as value; could then define an interface which tied both together - * @function module:svgcanvas.SvgCanvas#runExtensions - * @param {"mouseDown"|"mouseMove"|"mouseUp"|"zoomChanged"|"IDsUpdated"|"canvasUpdated"|"toolButtonStateUpdate"|"selectedChanged"|"elementTransition"|"elementChanged"|"langReady"|"langChanged"|"addLangData"|"onNewDocument"|"workareaResized"} action - * @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown|module:svgcanvas.SvgCanvas#event:ext_mouseMove|module:svgcanvas.SvgCanvas#event:ext_mouseUp|module:svgcanvas.SvgCanvas#event:ext_zoomChanged|module:svgcanvas.SvgCanvas#event:ext_IDsUpdated|module:svgcanvas.SvgCanvas#event:ext_canvasUpdated|module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate|module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementTransition|module:svgcanvas.SvgCanvas#event:ext_elementChanged|module:svgcanvas.SvgCanvas#event:ext_langReady|module:svgcanvas.SvgCanvas#event:ext_langChanged|module:svgcanvas.SvgCanvas#event:ext_addLangData|module:svgcanvas.SvgCanvas#event:ext_onNewDocument|module:svgcanvas.SvgCanvas#event:ext_workareaResized|module:svgcanvas.ExtensionVarBuilder} [vars] - * @param {boolean} [returnArray] - * @param {module:svgcanvas.ExtensionNameFilter} nameFilter - * @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. - */ - - - var runExtensions = this.runExtensions = function (action, vars, returnArray, nameFilter) { - var result = returnArray ? [] : false; - $$9.each(extensions, function (name, ext) { - if (nameFilter && !nameFilter(name)) { - return; - } - - if (ext && action in ext) { - if (typeof vars === 'function') { - vars = vars(name); // ext, action - } - - if (returnArray) { - result.push(ext[action](vars)); - } else { - result = ext[action](vars); - } - } - }); - return result; - }; - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionMouseDownStatus - * @property {boolean} started Indicates that creating/editing has started - */ - - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionMouseUpStatus - * @property {boolean} keep Indicates if the current element should be kept - * @property {boolean} started Indicates if editing should still be considered as "started" - * @property {Element} element The element being affected - */ - - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionIDsUpdatedStatus - * @property {string[]} remove Contains string IDs (used by `ext-connector.js`) - */ - - /** - * @interface module:svgcanvas.ExtensionInitResponse - * @property {module:SVGEditor.ContextTool[]|PlainObject<string, module:SVGEditor.ContextTool>} [context_tools] - * @property {module:SVGEditor.Button[]|PlainObject<Integer, module:SVGEditor.Button>} [buttons] - * @property {string} [svgicons] The location of a local SVG or SVGz file - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#mouseDown - * @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown} arg - * @returns {void|module:svgcanvas.ExtensionMouseDownStatus} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#mouseMove - * @param {module:svgcanvas.SvgCanvas#event:ext_mouseMove} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#mouseUp - * @param {module:svgcanvas.SvgCanvas#event:ext_mouseUp} arg - * @returns {module:svgcanvas.ExtensionMouseUpStatus} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#zoomChanged - * @param {module:svgcanvas.SvgCanvas#event:ext_zoomChanged} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#IDsUpdated - * @param {module:svgcanvas.SvgCanvas#event:ext_IDsUpdated} arg - * @returns {module:svgcanvas.ExtensionIDsUpdatedStatus} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#canvasUpdated - * @param {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#toolButtonStateUpdate - * @param {module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#selectedChanged - * @param {module:svgcanvas.SvgCanvas#event:ext_selectedChanged} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#elementTransition - * @param {module:svgcanvas.SvgCanvas#event:ext_elementTransition} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#elementChanged - * @param {module:svgcanvas.SvgCanvas#event:ext_elementChanged} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#langReady - * @param {module:svgcanvas.SvgCanvas#event:ext_langReady} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#langChanged - * @param {module:svgcanvas.SvgCanvas#event:ext_langChanged} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#addLangData - * @param {module:svgcanvas.SvgCanvas#event:ext_addLangData} arg - * @returns {Promise<module:locale.ExtensionLocaleData>} Resolves to {@link module:locale.ExtensionLocaleData} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#onNewDocument - * @param {module:svgcanvas.SvgCanvas#event:ext_onNewDocument} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#workareaResized - * @param {module:svgcanvas.SvgCanvas#event:ext_workareaResized} arg - * @returns {void} - */ - - /** - * @function module:svgcanvas.ExtensionInitResponse#callback - * @this module:SVGEditor - * @param {module:svgcanvas.SvgCanvas#event:ext_callback} arg - * @returns {void} - */ - - /** - * @callback module:svgcanvas.ExtensionInitCallback - * @this module:SVGEditor - * @param {module:svgcanvas.ExtensionArgumentObject} arg - * @returns {Promise<module:svgcanvas.ExtensionInitResponse|void>} Resolves to [ExtensionInitResponse]{@link module:svgcanvas.ExtensionInitResponse} or `undefined` - */ - - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionInitArgs - * @property {external:jQuery} $ - * @property {module:SVGEditor~ImportLocale} importLocale - */ - - /** - * Add an extension to the editor. - * @function module:svgcanvas.SvgCanvas#addExtension - * @param {string} name - String with the ID of the extension. Used internally; no need for i18n. - * @param {module:svgcanvas.ExtensionInitCallback} [extInitFunc] - Function supplied by the extension with its data - * @param {module:svgcanvas.ExtensionInitArgs} initArgs - * @fires module:svgcanvas.SvgCanvas#event:extension_added - * @throws {TypeError|Error} `TypeError` if `extInitFunc` is not a function, `Error` - * if extension of supplied name already exists - * @returns {Promise<void>} Resolves to `undefined` - */ - - - this.addExtension = /*#__PURE__*/function () { - var _ref4 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(name, extInitFunc, _ref3) { - var jq, importLocale, argObj, extObj; - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - jq = _ref3.$, importLocale = _ref3.importLocale; - - if (!(typeof extInitFunc !== 'function')) { - _context.next = 3; - break; - } - - throw new TypeError('Function argument expected for `svgcanvas.addExtension`'); - - case 3: - if (!(name in extensions)) { - _context.next = 5; - break; - } - - throw new Error('Cannot add extension "' + name + '", an extension by that name already exists.'); - - case 5: - // Provide private vars/funcs here. Is there a better way to do this? - - /** - * @typedef {module:svgcanvas.PrivateMethods} module:svgcanvas.ExtensionArgumentObject - * @property {SVGSVGElement} svgroot See {@link module:svgcanvas~svgroot} - * @property {SVGSVGElement} svgcontent See {@link module:svgcanvas~svgcontent} - * @property {!(string|Integer)} nonce See {@link module:draw.Drawing#getNonce} - * @property {module:select.SelectorManager} selectorManager - * @property {module:SVGEditor~ImportLocale} importLocale - */ - - /** - * @type {module:svgcanvas.ExtensionArgumentObject} - * @see {@link module:svgcanvas.PrivateMethods} source for the other methods/properties - */ - argObj = $$9.extend(canvas.getPrivateMethods(), { - $: jq, - importLocale: importLocale, - svgroot: svgroot, - svgcontent: svgcontent, - nonce: getCurrentDrawing().getNonce(), - selectorManager: selectorManager - }); - _context.next = 8; - return extInitFunc(argObj); - - case 8: - extObj = _context.sent; - - if (extObj) { - extObj.name = name; - } - - extensions[name] = extObj; - return _context.abrupt("return", call('extension_added', extObj)); - - case 12: - case "end": - return _context.stop(); - } - } - }, _callee); - })); - - return function (_x, _x2, _x3) { - return _ref4.apply(this, arguments); + const addCommandToHistory = function (cmd) { + canvas.undoMgr.addCommandToHistory(cmd); }; - }(); - /** - * This method sends back an array or a NodeList full of elements that - * intersect the multi-select rubber-band-box on the currentLayer only. - * - * We brute-force `getIntersectionList` for browsers that do not support it (Firefox). - * - * Reference: - * Firefox does not implement `getIntersectionList()`, see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=501421}. - * @function module:svgcanvas.SvgCanvas#getIntersectionList - * @param {SVGRect} rect - * @returns {Element[]|NodeList} Bbox elements - */ + /** + * This should really be an intersection applying to all types rather than a union. + * @name module:svgcanvas.SvgCanvas#getZoom + * @type {module:path.EditorContext#getCurrentZoom|module:select.SVGFactory#getCurrentZoom} + */ - var getIntersectionList = this.getIntersectionList = function (rect) { - if (isNullish(rubberBox)) { - return null; - } + const getCurrentZoom = this.getZoom = function () { + return currentZoom; + }; + /** + * This method rounds the incoming value to the nearest value based on the `currentZoom` + * @name module:svgcanvas.SvgCanvas#round + * @type {module:path.EditorContext#round} + */ - var parent = currentGroup || getCurrentDrawing().getCurrentLayer(); - var rubberBBox; - if (!rect) { - rubberBBox = rubberBox.getBBox(); - var bb = svgcontent.createSVGRect(); - ['x', 'y', 'width', 'height', 'top', 'right', 'bottom', 'left'].forEach(function (o) { - bb[o] = rubberBBox[o] / currentZoom; + const round = this.round = function (val) { + return Number.parseInt(val * currentZoom) / currentZoom; + }; + + init$6(curConfig, + /** + * Export to select.js. + * @implements {module:select.SVGFactory} + */ + { + createSVGElement(jsonMap) { + return canvas.addSVGElementFromJson(jsonMap); + }, + + svgRoot() { + return svgroot; + }, + + svgContent() { + return svgcontent; + }, + + getCurrentZoom + }); + /** + * This object manages selectors for us. + * @name module:svgcanvas.SvgCanvas#selectorManager + * @type {module:select.SelectorManager} + */ + + const selectorManager = this.selectorManager = getSelectorManager(); + /** + * @name module:svgcanvas.SvgCanvas#getNextId + * @type {module:path.EditorContext#getNextId} + */ + + const getNextId = canvas.getNextId = function () { + return getCurrentDrawing().getNextId(); + }; + /** + * @name module:svgcanvas.SvgCanvas#getId + * @type {module:path.EditorContext#getId} + */ + + + const getId = canvas.getId = function () { + return getCurrentDrawing().getId(); + }; + /** + * The "implements" should really be an intersection applying to all types rather than a union. + * @name module:svgcanvas.SvgCanvas#call + * @type {module:draw.DrawCanvasInit#call|module:path.EditorContext#call} + */ + + + const call = function (ev, arg) { + if (events[ev]) { + return events[ev](window, arg); + } + + return undefined; + }; + /** + * Clears the selection. The 'selected' handler is then optionally called. + * This should really be an intersection applying to all types rather than a union. + * @name module:svgcanvas.SvgCanvas#clearSelection + * @type {module:draw.DrawCanvasInit#clearSelection|module:path.EditorContext#clearSelection} + * @fires module:svgcanvas.SvgCanvas#event:selected + */ + + + const clearSelection = this.clearSelection = function (noCall) { + selectedElements.forEach(elem => { + if (isNullish(elem)) { + return; + } + + selectorManager.releaseSelector(elem); }); - rubberBBox = bb; - } else { - rubberBBox = svgcontent.createSVGRect(); - rubberBBox.x = rect.x; - rubberBBox.y = rect.y; - rubberBBox.width = rect.width; - rubberBBox.height = rect.height; - } + selectedElements = []; - var resultList = null; - - if (!isIE()) { - if (typeof svgroot.getIntersectionList === 'function') { - // Offset the bbox of the rubber box by the offset of the svgcontent element. - rubberBBox.x += Number.parseInt(svgcontent.getAttribute('x')); - rubberBBox.y += Number.parseInt(svgcontent.getAttribute('y')); - resultList = svgroot.getIntersectionList(rubberBBox, parent); + if (!noCall) { + call('selected', selectedElements); } - } + }; + /** + * Adds a list of elements to the selection. The 'selected' handler is then called. + * @name module:svgcanvas.SvgCanvas#addToSelection + * @type {module:path.EditorContext#addToSelection} + * @fires module:svgcanvas.SvgCanvas#event:selected + */ - if (isNullish(resultList) || typeof resultList.item !== 'function') { - resultList = []; - if (!curBBoxes.length) { - // Cache all bboxes - curBBoxes = getVisibleElementsAndBBoxes(parent); - } + const addToSelection = this.addToSelection = function (elemsToAdd, showGrips) { + if (!elemsToAdd.length) { + return; + } // find the first null in our selectedElements array - var i = curBBoxes.length; + + let j = 0; + + while (j < selectedElements.length) { + if (isNullish(selectedElements[j])) { + break; + } + + ++j; + } // now add each element consecutively + + + let i = elemsToAdd.length; while (i--) { - if (!rubberBBox.width) { + let elem = elemsToAdd[i]; + + if (!elem) { continue; } - if (rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { - resultList.push(curBBoxes[i].elem); + const bbox = getBBox(elem); + + if (!bbox) { + continue; + } + + if (elem.tagName === 'a' && elem.childNodes.length === 1) { + // Make "a" element's child be the selected element + elem = elem.firstChild; + } // if it's not already there, add it + + + if (!selectedElements.includes(elem)) { + selectedElements[j] = elem; // only the first selectedBBoxes element is ever used in the codebase these days + // if (j === 0) selectedBBoxes[0] = utilsGetBBox(elem); + + j++; + const sel = selectorManager.requestSelector(elem, bbox); + + if (selectedElements.length > 1) { + sel.showGrips(false); + } } } - } // addToSelection expects an array, but it's ok to pass a NodeList - // because using square-bracket notation is allowed: - // https://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html - - return resultList; - }; - - this.getStrokedBBox = getStrokedBBoxDefaultVisible; - this.getVisibleElements = getVisibleElements; - /** - * @typedef {PlainObject} ElementAndBBox - * @property {Element} elem - The element - * @property {module:utilities.BBoxObject} bbox - The element's BBox as retrieved from `getStrokedBBoxDefaultVisible` - */ - - /** - * Get all elements that have a BBox (excludes `<defs>`, `<title>`, etc). - * Note that 0-opacity, off-screen etc elements are still considered "visible" - * for this function. - * @function module:svgcanvas.SvgCanvas#getVisibleElementsAndBBoxes - * @param {Element} parent - The parent DOM element to search within - * @returns {ElementAndBBox[]} An array with objects that include: - */ - - var getVisibleElementsAndBBoxes = this.getVisibleElementsAndBBoxes = function (parent) { - if (!parent) { - parent = $$9(svgcontent).children(); // Prevent layers from being included - } - - var contentElems = []; - $$9(parent).children().each(function (i, elem) { - if (elem.getBBox) { - contentElems.push({ - elem: elem, - bbox: getStrokedBBoxDefaultVisible([elem]) - }); + if (!selectedElements.length) { + return; } - }); - return contentElems.reverse(); - }; - /** - * Wrap an SVG element into a group element, mark the group as 'gsvg'. - * @function module:svgcanvas.SvgCanvas#groupSvgElem - * @param {Element} elem - SVG element to wrap - * @returns {void} - */ + call('selected', selectedElements); - var groupSvgElem = this.groupSvgElem = function (elem) { - var g = document.createElementNS(NS.SVG, 'g'); - elem.replaceWith(g); - $$9(g).append(elem).data('gsvg', elem)[0].id = getNextId(); - }; // Set scope for these functions - // Object to contain editor event names and callback functions + if (selectedElements.length === 1) { + selectorManager.requestSelector(selectedElements[0]).showGrips(showGrips); + } // make sure the elements are in the correct order + // See: https://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-compareDocumentPosition - var events = {}; - canvas.call = call; - /** - * Array of what was changed (elements, layers). - * @event module:svgcanvas.SvgCanvas#event:changed - * @type {Element[]} - */ - - /** - * Array of selected elements. - * @event module:svgcanvas.SvgCanvas#event:selected - * @type {Element[]} - */ - - /** - * Array of selected elements. - * @event module:svgcanvas.SvgCanvas#event:transition - * @type {Element[]} - */ - - /** - * The Element is always `SVGGElement`? - * If not `null`, will be the set current group element. - * @event module:svgcanvas.SvgCanvas#event:contextset - * @type {null|Element} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:pointsAdded - * @type {PlainObject} - * @property {boolean} closedSubpath - * @property {SVGCircleElement[]} grips Grips elements - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:zoomed - * @type {PlainObject} - * @property {Float} x - * @property {Float} y - * @property {Float} width - * @property {Float} height - * @property {0.5|2} factor - * @see module:SVGEditor.BBoxObjectWithFactor - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:updateCanvas - * @type {PlainObject} - * @property {false} center - * @property {module:math.XYObject} newCtr - */ - - /** - * @typedef {PlainObject} module:svgcanvas.ExtensionInitResponsePlusName - * @implements {module:svgcanvas.ExtensionInitResponse} - * @property {string} name The extension's resolved ID (whether explicit or based on file name) - */ - - /** - * Generalized extension object response of - * [`init()`]{@link module:svgcanvas.ExtensionInitCallback} - * along with the name of the extension. - * @event module:svgcanvas.SvgCanvas#event:extension_added - * @type {module:svgcanvas.ExtensionInitResponsePlusName|void} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:extensions_added - * @type {void} - */ - - /** - * @typedef {PlainObject} module:svgcanvas.Message - * @property {any} data The data - * @property {string} origin The origin - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:message - * @type {module:svgcanvas.Message} - */ - - /** - * SVG canvas converted to string. - * @event module:svgcanvas.SvgCanvas#event:saved - * @type {string} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:setnonce - * @type {!(string|Integer)} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:unsetnonce - * @type {void} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:zoomDone - * @type {void} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:cleared - * @type {void} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:exported - * @type {module:svgcanvas.ImageExportedResults} - */ - - /** - * @event module:svgcanvas.SvgCanvas#event:exportedPDF - * @type {module:svgcanvas.PDFExportedResults} - */ - - /** - * Creating a cover-all class until {@link https://github.com/jsdoc3/jsdoc/issues/1545} may be supported. - * `undefined` may be returned by {@link module:svgcanvas.SvgCanvas#event:extension_added} if the extension's `init` returns `undefined` It is also the type for the following events "zoomDone", "unsetnonce", "cleared", and "extensions_added". - * @event module:svgcanvas.SvgCanvas#event:GenericCanvasEvent - * @type {module:svgcanvas.SvgCanvas#event:selected|module:svgcanvas.SvgCanvas#event:changed|module:svgcanvas.SvgCanvas#event:contextset|module:svgcanvas.SvgCanvas#event:pointsAdded|module:svgcanvas.SvgCanvas#event:extension_added|module:svgcanvas.SvgCanvas#event:extensions_added|module:svgcanvas.SvgCanvas#event:message|module:svgcanvas.SvgCanvas#event:transition|module:svgcanvas.SvgCanvas#event:zoomed|module:svgcanvas.SvgCanvas#event:updateCanvas|module:svgcanvas.SvgCanvas#event:saved|module:svgcanvas.SvgCanvas#event:exported|module:svgcanvas.SvgCanvas#event:exportedPDF|module:svgcanvas.SvgCanvas#event:setnonce|module:svgcanvas.SvgCanvas#event:unsetnonce|void} - */ - - /** - * The promise return, if present, resolves to `undefined` - * (`extension_added`, `exported`, `saved`). - * @typedef {Promise<void>|void} module:svgcanvas.EventHandlerReturn - */ - - /** - * @callback module:svgcanvas.EventHandler - * @param {external:Window} win - * @param {module:svgcanvas.SvgCanvas#event:GenericCanvasEvent} arg - * @listens module:svgcanvas.SvgCanvas#event:GenericCanvasEvent - * @returns {module:svgcanvas.EventHandlerReturn} - */ - - /** - * Attaches a callback function to an event. - * @function module:svgcanvas.SvgCanvas#bind - * @param {"changed"|"contextset"|"selected"|"pointsAdded"|"extension_added"|"extensions_added"|"message"|"transition"|"zoomed"|"updateCanvas"|"zoomDone"|"saved"|"exported"|"exportedPDF"|"setnonce"|"unsetnonce"|"cleared"} ev - String indicating the name of the event - * @param {module:svgcanvas.EventHandler} f - The callback function to bind to the event - * @returns {module:svgcanvas.EventHandler} The previous event - */ - - canvas.bind = function (ev, f) { - var old = events[ev]; - events[ev] = f; - return old; - }; - /** - * Runs the SVG Document through the sanitizer and then updates its paths. - * @function module:svgcanvas.SvgCanvas#prepareSvg - * @param {XMLDocument} newDoc - The SVG DOM document - * @returns {void} - */ - - - this.prepareSvg = function (newDoc) { - this.sanitizeSvg(newDoc.documentElement); // convert paths into absolute commands - - var paths = _toConsumableArray(newDoc.getElementsByTagNameNS(NS.SVG, 'path')); - - paths.forEach(function (path) { - path.setAttribute('d', pathActions$1.convertPath(path)); - pathActions$1.fixEnd(path); - }); - }; - /** - * Hack for Firefox bugs where text element features aren't updated or get - * messed up. See issue 136 and issue 137. - * This function clones the element and re-selects it. - * @function module:svgcanvas~ffClone - * @todo Test for this bug on load and add it to "support" object instead of - * browser sniffing - * @param {Element} elem - The (text) DOM element to clone - * @returns {Element} Cloned element - */ - - - var ffClone = function ffClone(elem) { - if (!isGecko()) { - return elem; - } - - var clone = elem.cloneNode(true); - elem.before(clone); - elem.remove(); - selectorManager.releaseSelector(elem); - selectedElements[0] = clone; - selectorManager.requestSelector(clone).showGrips(true); - return clone; - }; // `this.each` is deprecated, if any extension used this it can be recreated by doing this: - // * @example $(canvas.getRootElem()).children().each(...) - // * @function module:svgcanvas.SvgCanvas#each - // this.each = function (cb) { - // $(svgroot).children().each(cb); - // }; - - /** - * Removes any old rotations if present, prepends a new rotation at the - * transformed center. - * @function module:svgcanvas.SvgCanvas#setRotationAngle - * @param {string|Float} val - The new rotation angle in degrees - * @param {boolean} preventUndo - Indicates whether the action should be undoable or not - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.setRotationAngle = function (val, preventUndo) { - // ensure val is the proper type - val = Number.parseFloat(val); - var elem = selectedElements[0]; - var oldTransform = elem.getAttribute('transform'); - var bbox = getBBox(elem); - var cx = bbox.x + bbox.width / 2, - cy = bbox.y + bbox.height / 2; - var tlist = getTransformList(elem); // only remove the real rotational transform if present (i.e. at index=0) - - if (tlist.numberOfItems > 0) { - var xform = tlist.getItem(0); - - if (xform.type === 4) { - tlist.removeItem(0); - } - } // find Rnc and insert it - - - if (val !== 0) { - var center = transformPoint(cx, cy, transformListToTransform(tlist).matrix); - var Rnc = svgroot.createSVGTransform(); - Rnc.setRotate(val, center.x, center.y); - - if (tlist.numberOfItems) { - tlist.insertItemBefore(Rnc, 0); - } else { - tlist.appendItem(Rnc); - } - } else if (tlist.numberOfItems === 0) { - elem.removeAttribute('transform'); - } - - if (!preventUndo) { - // we need to undo it, then redo it so it can be undo-able! :) - // TODO: figure out how to make changes to transform list undo-able cross-browser? - var newTransform = elem.getAttribute('transform'); - elem.setAttribute('transform', oldTransform); - changeSelectedAttribute('transform', newTransform, selectedElements); - call('changed', selectedElements); - } // const pointGripContainer = getElem('pathpointgrip_container'); - // if (elem.nodeName === 'path' && pointGripContainer) { - // pathActions.setPointContainerTransform(elem.getAttribute('transform')); - // } - - - var selector = selectorManager.requestSelector(selectedElements[0]); - selector.resize(); - Selector.updateGripCursors(val); - }; - /** - * Runs `recalculateDimensions` on the selected elements, - * adding the changes to a single batch command. - * @function module:svgcanvas.SvgCanvas#recalculateAllSelectedDimensions - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - var recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function () { - var text = currentResizeMode === 'none' ? 'position' : 'size'; - var batchCmd = new BatchCommand$1(text); - var i = selectedElements.length; - - while (i--) { - var elem = selectedElements[i]; // if (getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) { continue; } - - var cmd = recalculateDimensions(elem); - - if (cmd) { - batchCmd.addSubCommand(cmd); - } - } - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - call('changed', selectedElements); - } - }; - /** - * Debug tool to easily see the current matrix in the browser's console. - * @function module:svgcanvas~logMatrix - * @param {SVGMatrix} m The matrix - * @returns {void} - */ - - - var logMatrix = function logMatrix(m) { - console.log([m.a, m.b, m.c, m.d, m.e, m.f]); // eslint-disable-line no-console - }; // Root Current Transformation Matrix in user units - - - var rootSctm = null; - /** - * Group: Selection. - */ - // TODO: do we need to worry about selectedBBoxes here? - - /** - * Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. - * @function module:svgcanvas.SvgCanvas#selectOnly - * @param {Element[]} elems - an array of DOM elements to be selected - * @param {boolean} showGrips - Indicates whether the resize grips should be shown - * @returns {void} - */ - - var selectOnly = this.selectOnly = function (elems, showGrips) { - clearSelection(true); - addToSelection(elems, showGrips); - }; // TODO: could use slice here to make this faster? - // TODO: should the 'selected' handler - - /** - * Removes elements from the selection. - * @function module:svgcanvas.SvgCanvas#removeFromSelection - * @param {Element[]} elemsToRemove - An array of elements to remove from selection - * @returns {void} - */ - - /* const removeFromSelection = */ - - - this.removeFromSelection = function (elemsToRemove) { - if (isNullish(selectedElements[0])) { - return; - } - - if (!elemsToRemove.length) { - return; - } // find every element and remove it from our array copy - - - var newSelectedItems = [], - len = selectedElements.length; - - for (var i = 0; i < len; ++i) { - var elem = selectedElements[i]; - - if (elem) { - // keep the item - if (!elemsToRemove.includes(elem)) { - newSelectedItems.push(elem); - } else { - // remove the item and its selector - selectorManager.releaseSelector(elem); + selectedElements.sort(function (a, b) { + if (a && b && a.compareDocumentPosition) { + return 3 - (b.compareDocumentPosition(a) & 6); // eslint-disable-line no-bitwise } + + if (isNullish(a)) { + return 1; + } + + return 0; + }); // Make sure first elements are not null + + while (isNullish(selectedElements[0])) { + selectedElements.shift(0); } - } // the copy becomes the master now - - - selectedElements = newSelectedItems; - }; - /** - * Clears the selection, then adds all elements in the current layer to the selection. - * @function module:svgcanvas.SvgCanvas#selectAllInCurrentLayer - * @returns {void} - */ - - - this.selectAllInCurrentLayer = function () { - var currentLayer = getCurrentDrawing().getCurrentLayer(); - - if (currentLayer) { - currentMode = 'select'; - selectOnly($$9(currentGroup || currentLayer).children()); - } - }; - - var drawnPath = null; // Mouse events - - (function () { - var freehand = { - minx: null, - miny: null, - maxx: null, - maxy: null - }; - var THRESHOLD_DIST = 0.8, - STEP_COUNT = 10; - var dAttr = null, - startX = null, - startY = null, - rStartX = null, - rStartY = null, - initBbox = {}, - sumDistance = 0, - controllPoint2 = { - x: 0, - y: 0 - }, - controllPoint1 = { - x: 0, - y: 0 - }, - start = { - x: 0, - y: 0 - }, - end = { - x: 0, - y: 0 - }, - bSpline = { - x: 0, - y: 0 - }, - nextPos = { - x: 0, - y: 0 - }, - parameter, - nextParameter; - - var getBsplinePoint = function getBsplinePoint(t) { - var spline = { - x: 0, - y: 0 - }, - p0 = controllPoint2, - p1 = controllPoint1, - p2 = start, - p3 = end, - S = 1.0 / 6.0, - t2 = t * t, - t3 = t2 * t; - var m = [[-1, 3, -3, 1], [3, -6, 3, 0], [-3, 0, 3, 0], [1, 4, 1, 0]]; - spline.x = S * ((p0.x * m[0][0] + p1.x * m[0][1] + p2.x * m[0][2] + p3.x * m[0][3]) * t3 + (p0.x * m[1][0] + p1.x * m[1][1] + p2.x * m[1][2] + p3.x * m[1][3]) * t2 + (p0.x * m[2][0] + p1.x * m[2][1] + p2.x * m[2][2] + p3.x * m[2][3]) * t + (p0.x * m[3][0] + p1.x * m[3][1] + p2.x * m[3][2] + p3.x * m[3][3])); - spline.y = S * ((p0.y * m[0][0] + p1.y * m[0][1] + p2.y * m[0][2] + p3.y * m[0][3]) * t3 + (p0.y * m[1][0] + p1.y * m[1][1] + p2.y * m[1][2] + p3.y * m[1][3]) * t2 + (p0.y * m[2][0] + p1.y * m[2][1] + p2.y * m[2][2] + p3.y * m[2][3]) * t + (p0.y * m[3][0] + p1.y * m[3][1] + p2.y * m[3][2] + p3.y * m[3][3])); - return { - x: spline.x, - y: spline.y - }; }; /** - * Follows these conditions: - * - When we are in a create mode, the element is added to the canvas but the - * action is not recorded until mousing up. - * - When we are in select mode, select the element, remember the position - * and do nothing else. - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseDown + * @type {module:path.EditorContext#getOpacity} + */ + + + const getOpacity = function () { + return curShape.opacity; + }; + /** + * @name module:svgcanvas.SvgCanvas#getMouseTarget + * @type {module:path.EditorContext#getMouseTarget} + */ + + + const getMouseTarget = this.getMouseTarget = function (evt) { + if (isNullish(evt)) { + return null; + } + + let mouseTarget = evt.target; // if it was a <use>, Opera and WebKit return the SVGElementInstance + + if (mouseTarget.correspondingUseElement) { + mouseTarget = mouseTarget.correspondingUseElement; + } // for foreign content, go up until we find the foreignObject + // WebKit browsers set the mouse target to the svgcanvas div + + + if ([NS.MATH, NS.HTML].includes(mouseTarget.namespaceURI) && mouseTarget.id !== 'svgcanvas') { + while (mouseTarget.nodeName !== 'foreignObject') { + mouseTarget = mouseTarget.parentNode; + + if (!mouseTarget) { + return svgroot; + } + } + } // Get the desired mouseTarget with jQuery selector-fu + // If it's root-like, select the root + + + const currentLayer = getCurrentDrawing().getCurrentLayer(); + + if ([svgroot, container, svgcontent, currentLayer].includes(mouseTarget)) { + return svgroot; + } + + const $target = $$a(mouseTarget); // If it's a selection grip, return the grip parent + + if ($target.closest('#selectorParentGroup').length) { + // While we could instead have just returned mouseTarget, + // this makes it easier to indentify as being a selector grip + return selectorManager.selectorParentGroup; + } + + while (mouseTarget.parentNode !== (currentGroup || currentLayer)) { + mouseTarget = mouseTarget.parentNode; + } // + // // go up until we hit a child of a layer + // while (mouseTarget.parentNode.parentNode.tagName == 'g') { + // mouseTarget = mouseTarget.parentNode; + // } + // Webkit bubbles the mouse event all the way up to the div, so we + // set the mouseTarget to the svgroot like the other browsers + // if (mouseTarget.nodeName.toLowerCase() == 'div') { + // mouseTarget = svgroot; + // } + + + return mouseTarget; + }; + /** + * @namespace {module:path.pathActions} pathActions + * @memberof module:svgcanvas.SvgCanvas# + * @see module:path.pathActions + */ + + + canvas.pathActions = pathActions; + /** + * @type {module:path.EditorContext#resetD} + */ + + function resetD(p) { + p.setAttribute('d', pathActions.convertPath(p)); + } + + init$2( + /** + * @implements {module:path.EditorContext} + */ + { + selectorManager, + // Ok since not changing + canvas, + // Ok since not changing + call, + resetD, + round, + clearSelection, + addToSelection, + addCommandToHistory, + remapElement, + addSVGElementFromJson, + getGridSnapping, + getOpacity, + getSelectedElements, + + getContainer() { + return container; + }, + + setStarted(s) { + started = s; + }, + + getRubberBox() { + return rubberBox; + }, + + setRubberBox(rb) { + rubberBox = rb; + return rubberBox; + }, + + /** + * @param {PlainObject} ptsInfo + * @param {boolean} ptsInfo.closedSubpath + * @param {SVGCircleElement[]} ptsInfo.grips + * @fires module:svgcanvas.SvgCanvas#event:pointsAdded + * @fires module:svgcanvas.SvgCanvas#event:selected + * @returns {void} + */ + addPtsToSelection({ + closedSubpath, + grips + }) { + // TODO: Correct this: + pathActions.canDeleteNodes = true; + pathActions.closed_subpath = closedSubpath; + call('pointsAdded', { + closedSubpath, + grips + }); + call('selected', grips); + }, + + /** + * @param {PlainObject} changes + * @param {ChangeElementCommand} changes.cmd + * @param {SVGPathElement} changes.elem + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + endChanges({ + cmd, + elem + }) { + addCommandToHistory(cmd); + call('changed', [elem]); + }, + + getCurrentZoom, + getId, + getNextId, + getMouseTarget, + + getCurrentMode() { + return currentMode; + }, + + setCurrentMode(cm) { + currentMode = cm; + return currentMode; + }, + + getDrawnPath() { + return drawnPath; + }, + + setDrawnPath(dp) { + drawnPath = dp; + return drawnPath; + }, + + getSVGRoot + }); // Interface strings, usually for title elements + + const uiStrings = {}; + const visElems = 'a,circle,ellipse,foreignObject,g,image,line,path,polygon,polyline,rect,svg,text,tspan,use'; + const refAttrs = ['clip-path', 'fill', 'filter', 'marker-end', 'marker-mid', 'marker-start', 'mask', 'stroke']; + const elData = $$a.data; // Animation element to change the opacity of any newly created element + + const opacAni = document.createElementNS(NS.SVG, 'animate'); + $$a(opacAni).attr({ + attributeName: 'opacity', + begin: 'indefinite', + dur: 1, + fill: 'freeze' + }).appendTo(svgroot); + + const restoreRefElems = function (elem) { + // Look for missing reference elements, restore any found + const attrs = $$a(elem).attr(refAttrs); + Object.values(attrs).forEach(val => { + if (val && val.startsWith('url(')) { + const id = getUrlFromAttr(val).substr(1); + const ref = getElem(id); + + if (!ref) { + findDefs().append(removedElements[id]); + delete removedElements[id]; + } + } + }); + const childs = elem.getElementsByTagName('*'); + + if (childs.length) { + for (let i = 0, l = childs.length; i < l; i++) { + restoreRefElems(childs[i]); + } + } + }; // (function () { + // TODO For Issue 208: this is a start on a thumbnail + // const svgthumb = svgdoc.createElementNS(NS.SVG, 'use'); + // svgthumb.setAttribute('width', '100'); + // svgthumb.setAttribute('height', '100'); + // setHref(svgthumb, '#svgcontent'); + // svgroot.append(svgthumb); + // }()); + + /** + * @typedef {PlainObject} module:svgcanvas.SaveOptions + * @property {boolean} apply + * @property {"embed"} [image] + * @property {Integer} round_digits + */ + // Object to contain image data for raster images that were found encodable + + + const encodableImages = {}, + // Object with save options + + /** + * @type {module:svgcanvas.SaveOptions} + */ + saveOptions = { + round_digits: 5 + }, + // Object with IDs for imported files, to see if one was already added + importIds = {}, + // Current text style properties + curText = allProperties.text, + // Object to contain all included extensions + extensions = {}, + // Map of deleted reference elements + removedElements = {}; + let // String with image URL of last loadable image + lastGoodImgUrl = curConfig.imgPath + 'logo.png', + // Boolean indicating whether or not a draw action has been started + started = false, + // String with an element's initial transform attribute value + startTransform = null, + // String indicating the current editor mode + currentMode = 'select', + // String with the current direction in which an element is being resized + currentResizeMode = 'none', + // Current general properties + curProperties = curShape, + // Array with selected elements' Bounding box object + // selectedBBoxes = new Array(1), + // The DOM element that was just selected + justSelected = null, + // DOM element for selection rectangle drawn by the user + rubberBox = null, + // Array of current BBoxes, used in getIntersectionList(). + curBBoxes = [], + // Canvas point for the most recent right click + lastClickPoint = null; + + this.runExtension = function (name, action, vars) { + return this.runExtensions(action, vars, false, n => n === name); + }; + /** + * @typedef {module:svgcanvas.ExtensionMouseDownStatus|module:svgcanvas.ExtensionMouseUpStatus|module:svgcanvas.ExtensionIDsUpdatedStatus|module:locale.ExtensionLocaleData[]|void} module:svgcanvas.ExtensionStatus + * @tutorial ExtensionDocs + */ + + /** + * @callback module:svgcanvas.ExtensionVarBuilder + * @param {string} name The name of the extension + * @returns {module:svgcanvas.SvgCanvas#event:ext_addLangData} + */ + + /** + * @callback module:svgcanvas.ExtensionNameFilter + * @param {string} name + * @returns {boolean} + */ + + /** + * @todo Consider: Should this return an array by default, so extension results aren't overwritten? + * @todo Would be easier to document if passing in object with key of action and vars as value; could then define an interface which tied both together + * @function module:svgcanvas.SvgCanvas#runExtensions + * @param {"mouseDown"|"mouseMove"|"mouseUp"|"zoomChanged"|"IDsUpdated"|"canvasUpdated"|"toolButtonStateUpdate"|"selectedChanged"|"elementTransition"|"elementChanged"|"langReady"|"langChanged"|"addLangData"|"onNewDocument"|"workareaResized"} action + * @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown|module:svgcanvas.SvgCanvas#event:ext_mouseMove|module:svgcanvas.SvgCanvas#event:ext_mouseUp|module:svgcanvas.SvgCanvas#event:ext_zoomChanged|module:svgcanvas.SvgCanvas#event:ext_IDsUpdated|module:svgcanvas.SvgCanvas#event:ext_canvasUpdated|module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate|module:svgcanvas.SvgCanvas#event:ext_selectedChanged|module:svgcanvas.SvgCanvas#event:ext_elementTransition|module:svgcanvas.SvgCanvas#event:ext_elementChanged|module:svgcanvas.SvgCanvas#event:ext_langReady|module:svgcanvas.SvgCanvas#event:ext_langChanged|module:svgcanvas.SvgCanvas#event:ext_addLangData|module:svgcanvas.SvgCanvas#event:ext_onNewDocument|module:svgcanvas.SvgCanvas#event:ext_workareaResized|module:svgcanvas.ExtensionVarBuilder} [vars] + * @param {boolean} [returnArray] + * @param {module:svgcanvas.ExtensionNameFilter} nameFilter + * @returns {GenericArray<module:svgcanvas.ExtensionStatus>|module:svgcanvas.ExtensionStatus|false} See {@tutorial ExtensionDocs} on the ExtensionStatus. + */ + + + const runExtensions = this.runExtensions = function (action, vars, returnArray, nameFilter) { + let result = returnArray ? [] : false; + $$a.each(extensions, function (name, ext) { + if (nameFilter && !nameFilter(name)) { + return; + } + + if (ext && action in ext) { + if (typeof vars === 'function') { + vars = vars(name); // ext, action + } + + if (returnArray) { + result.push(ext[action](vars)); + } else { + result = ext[action](vars); + } + } + }); + return result; + }; + /** + * @typedef {PlainObject} module:svgcanvas.ExtensionMouseDownStatus + * @property {boolean} started Indicates that creating/editing has started + */ + + /** + * @typedef {PlainObject} module:svgcanvas.ExtensionMouseUpStatus + * @property {boolean} keep Indicates if the current element should be kept + * @property {boolean} started Indicates if editing should still be considered as "started" + * @property {Element} element The element being affected + */ + + /** + * @typedef {PlainObject} module:svgcanvas.ExtensionIDsUpdatedStatus + * @property {string[]} remove Contains string IDs (used by `ext-connector.js`) + */ + + /** + * @interface module:svgcanvas.ExtensionInitResponse + * @property {module:SVGEditor.ContextTool[]|PlainObject<string, module:SVGEditor.ContextTool>} [context_tools] + * @property {module:SVGEditor.Button[]|PlainObject<Integer, module:SVGEditor.Button>} [buttons] + * @property {string} [svgicons] The location of a local SVG or SVGz file + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#mouseDown + * @param {module:svgcanvas.SvgCanvas#event:ext_mouseDown} arg + * @returns {void|module:svgcanvas.ExtensionMouseDownStatus} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#mouseMove + * @param {module:svgcanvas.SvgCanvas#event:ext_mouseMove} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#mouseUp + * @param {module:svgcanvas.SvgCanvas#event:ext_mouseUp} arg + * @returns {module:svgcanvas.ExtensionMouseUpStatus} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#zoomChanged + * @param {module:svgcanvas.SvgCanvas#event:ext_zoomChanged} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#IDsUpdated + * @param {module:svgcanvas.SvgCanvas#event:ext_IDsUpdated} arg + * @returns {module:svgcanvas.ExtensionIDsUpdatedStatus} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#canvasUpdated + * @param {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#toolButtonStateUpdate + * @param {module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#selectedChanged + * @param {module:svgcanvas.SvgCanvas#event:ext_selectedChanged} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#elementTransition + * @param {module:svgcanvas.SvgCanvas#event:ext_elementTransition} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#elementChanged + * @param {module:svgcanvas.SvgCanvas#event:ext_elementChanged} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#langReady + * @param {module:svgcanvas.SvgCanvas#event:ext_langReady} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#langChanged + * @param {module:svgcanvas.SvgCanvas#event:ext_langChanged} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#addLangData + * @param {module:svgcanvas.SvgCanvas#event:ext_addLangData} arg + * @returns {Promise<module:locale.ExtensionLocaleData>} Resolves to {@link module:locale.ExtensionLocaleData} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#onNewDocument + * @param {module:svgcanvas.SvgCanvas#event:ext_onNewDocument} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#workareaResized + * @param {module:svgcanvas.SvgCanvas#event:ext_workareaResized} arg + * @returns {void} + */ + + /** + * @function module:svgcanvas.ExtensionInitResponse#callback + * @this module:SVGEditor + * @param {module:svgcanvas.SvgCanvas#event:ext_callback} arg + * @returns {void} + */ + + /** + * @callback module:svgcanvas.ExtensionInitCallback + * @this module:SVGEditor + * @param {module:svgcanvas.ExtensionArgumentObject} arg + * @returns {Promise<module:svgcanvas.ExtensionInitResponse|void>} Resolves to [ExtensionInitResponse]{@link module:svgcanvas.ExtensionInitResponse} or `undefined` + */ + + /** + * @typedef {PlainObject} module:svgcanvas.ExtensionInitArgs + * @property {external:jQuery} $ + * @property {module:SVGEditor~ImportLocale} importLocale + */ + + /** + * Add an extension to the editor. + * @function module:svgcanvas.SvgCanvas#addExtension + * @param {string} name - String with the ID of the extension. Used internally; no need for i18n. + * @param {module:svgcanvas.ExtensionInitCallback} [extInitFunc] - Function supplied by the extension with its data + * @param {module:svgcanvas.ExtensionInitArgs} initArgs + * @fires module:svgcanvas.SvgCanvas#event:extension_added + * @throws {TypeError|Error} `TypeError` if `extInitFunc` is not a function, `Error` + * if extension of supplied name already exists + * @returns {Promise<void>} Resolves to `undefined` + */ + + + this.addExtension = async function (name, extInitFunc, { + $: jq, + importLocale + }) { + if (typeof extInitFunc !== 'function') { + throw new TypeError('Function argument expected for `svgcanvas.addExtension`'); + } + + if (name in extensions) { + throw new Error('Cannot add extension "' + name + '", an extension by that name already exists.'); + } // Provide private vars/funcs here. Is there a better way to do this? + + /** + * @typedef {module:svgcanvas.PrivateMethods} module:svgcanvas.ExtensionArgumentObject + * @property {SVGSVGElement} svgroot See {@link module:svgcanvas~svgroot} + * @property {SVGSVGElement} svgcontent See {@link module:svgcanvas~svgcontent} + * @property {!(string|Integer)} nonce See {@link module:draw.Drawing#getNonce} + * @property {module:select.SelectorManager} selectorManager + * @property {module:SVGEditor~ImportLocale} importLocale + */ + + /** + * @type {module:svgcanvas.ExtensionArgumentObject} + * @see {@link module:svgcanvas.PrivateMethods} source for the other methods/properties + */ + + + const argObj = $$a.extend(canvas.getPrivateMethods(), { + $: jq, + importLocale, + svgroot, + svgcontent, + nonce: getCurrentDrawing().getNonce(), + selectorManager + }); + const extObj = await extInitFunc(argObj); + + if (extObj) { + extObj.name = name; + } + + extensions[name] = extObj; + return call('extension_added', extObj); + }; + /** + * This method sends back an array or a NodeList full of elements that + * intersect the multi-select rubber-band-box on the currentLayer only. + * + * We brute-force `getIntersectionList` for browsers that do not support it (Firefox). + * + * Reference: + * Firefox does not implement `getIntersectionList()`, see {@link https://bugzilla.mozilla.org/show_bug.cgi?id=501421}. + * @function module:svgcanvas.SvgCanvas#getIntersectionList + * @param {SVGRect} rect + * @returns {Element[]|NodeList} Bbox elements + */ + + + const getIntersectionList = this.getIntersectionList = function (rect) { + if (isNullish(rubberBox)) { + return null; + } + + const parent = currentGroup || getCurrentDrawing().getCurrentLayer(); + let rubberBBox; + + if (!rect) { + rubberBBox = rubberBox.getBBox(); + const bb = svgcontent.createSVGRect(); + ['x', 'y', 'width', 'height', 'top', 'right', 'bottom', 'left'].forEach(o => { + bb[o] = rubberBBox[o] / currentZoom; + }); + rubberBBox = bb; + } else { + rubberBBox = svgcontent.createSVGRect(); + rubberBBox.x = rect.x; + rubberBBox.y = rect.y; + rubberBBox.width = rect.width; + rubberBBox.height = rect.height; + } + + let resultList = null; + + if (!isIE()) { + if (typeof svgroot.getIntersectionList === 'function') { + // Offset the bbox of the rubber box by the offset of the svgcontent element. + rubberBBox.x += Number.parseInt(svgcontent.getAttribute('x')); + rubberBBox.y += Number.parseInt(svgcontent.getAttribute('y')); + resultList = svgroot.getIntersectionList(rubberBBox, parent); + } + } + + if (isNullish(resultList) || typeof resultList.item !== 'function') { + resultList = []; + + if (!curBBoxes.length) { + // Cache all bboxes + curBBoxes = getVisibleElementsAndBBoxes(parent); + } + + let i = curBBoxes.length; + + while (i--) { + if (!rubberBBox.width) { + continue; + } + + if (rectsIntersect(rubberBBox, curBBoxes[i].bbox)) { + resultList.push(curBBoxes[i].elem); + } + } + } // addToSelection expects an array, but it's ok to pass a NodeList + // because using square-bracket notation is allowed: + // https://www.w3.org/TR/DOM-Level-2-Core/ecma-script-binding.html + + + return resultList; + }; + + this.getStrokedBBox = getStrokedBBoxDefaultVisible; + this.getVisibleElements = getVisibleElements; + /** + * @typedef {PlainObject} ElementAndBBox + * @property {Element} elem - The element + * @property {module:utilities.BBoxObject} bbox - The element's BBox as retrieved from `getStrokedBBoxDefaultVisible` + */ + + /** + * Get all elements that have a BBox (excludes `<defs>`, `<title>`, etc). + * Note that 0-opacity, off-screen etc elements are still considered "visible" + * for this function. + * @function module:svgcanvas.SvgCanvas#getVisibleElementsAndBBoxes + * @param {Element} parent - The parent DOM element to search within + * @returns {ElementAndBBox[]} An array with objects that include: + */ + + const getVisibleElementsAndBBoxes = this.getVisibleElementsAndBBoxes = function (parent) { + if (!parent) { + parent = $$a(svgcontent).children(); // Prevent layers from being included + } + + const contentElems = []; + $$a(parent).children().each(function (i, elem) { + if (elem.getBBox) { + contentElems.push({ + elem, + bbox: getStrokedBBoxDefaultVisible([elem]) + }); + } + }); + return contentElems.reverse(); + }; + /** + * Wrap an SVG element into a group element, mark the group as 'gsvg'. + * @function module:svgcanvas.SvgCanvas#groupSvgElem + * @param {Element} elem - SVG element to wrap + * @returns {void} + */ + + + const groupSvgElem = this.groupSvgElem = function (elem) { + const g = document.createElementNS(NS.SVG, 'g'); + elem.replaceWith(g); + $$a(g).append(elem).data('gsvg', elem)[0].id = getNextId(); + }; // Set scope for these functions + // Object to contain editor event names and callback functions + + + const events = {}; + canvas.call = call; + /** + * Array of what was changed (elements, layers). + * @event module:svgcanvas.SvgCanvas#event:changed + * @type {Element[]} + */ + + /** + * Array of selected elements. + * @event module:svgcanvas.SvgCanvas#event:selected + * @type {Element[]} + */ + + /** + * Array of selected elements. + * @event module:svgcanvas.SvgCanvas#event:transition + * @type {Element[]} + */ + + /** + * The Element is always `SVGGElement`? + * If not `null`, will be the set current group element. + * @event module:svgcanvas.SvgCanvas#event:contextset + * @type {null|Element} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:pointsAdded + * @type {PlainObject} + * @property {boolean} closedSubpath + * @property {SVGCircleElement[]} grips Grips elements + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:zoomed + * @type {PlainObject} + * @property {Float} x + * @property {Float} y + * @property {Float} width + * @property {Float} height + * @property {0.5|2} factor + * @see module:SVGEditor.BBoxObjectWithFactor + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:updateCanvas + * @type {PlainObject} + * @property {false} center + * @property {module:math.XYObject} newCtr + */ + + /** + * @typedef {PlainObject} module:svgcanvas.ExtensionInitResponsePlusName + * @implements {module:svgcanvas.ExtensionInitResponse} + * @property {string} name The extension's resolved ID (whether explicit or based on file name) + */ + + /** + * Generalized extension object response of + * [`init()`]{@link module:svgcanvas.ExtensionInitCallback} + * along with the name of the extension. + * @event module:svgcanvas.SvgCanvas#event:extension_added + * @type {module:svgcanvas.ExtensionInitResponsePlusName|void} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:extensions_added + * @type {void} + */ + + /** + * @typedef {PlainObject} module:svgcanvas.Message + * @property {any} data The data + * @property {string} origin The origin + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:message + * @type {module:svgcanvas.Message} + */ + + /** + * SVG canvas converted to string. + * @event module:svgcanvas.SvgCanvas#event:saved + * @type {string} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:setnonce + * @type {!(string|Integer)} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:unsetnonce + * @type {void} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:zoomDone + * @type {void} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:cleared + * @type {void} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:exported + * @type {module:svgcanvas.ImageExportedResults} + */ + + /** + * @event module:svgcanvas.SvgCanvas#event:exportedPDF + * @type {module:svgcanvas.PDFExportedResults} + */ + + /** + * Creating a cover-all class until {@link https://github.com/jsdoc3/jsdoc/issues/1545} may be supported. + * `undefined` may be returned by {@link module:svgcanvas.SvgCanvas#event:extension_added} if the extension's `init` returns `undefined` It is also the type for the following events "zoomDone", "unsetnonce", "cleared", and "extensions_added". + * @event module:svgcanvas.SvgCanvas#event:GenericCanvasEvent + * @type {module:svgcanvas.SvgCanvas#event:selected|module:svgcanvas.SvgCanvas#event:changed|module:svgcanvas.SvgCanvas#event:contextset|module:svgcanvas.SvgCanvas#event:pointsAdded|module:svgcanvas.SvgCanvas#event:extension_added|module:svgcanvas.SvgCanvas#event:extensions_added|module:svgcanvas.SvgCanvas#event:message|module:svgcanvas.SvgCanvas#event:transition|module:svgcanvas.SvgCanvas#event:zoomed|module:svgcanvas.SvgCanvas#event:updateCanvas|module:svgcanvas.SvgCanvas#event:saved|module:svgcanvas.SvgCanvas#event:exported|module:svgcanvas.SvgCanvas#event:exportedPDF|module:svgcanvas.SvgCanvas#event:setnonce|module:svgcanvas.SvgCanvas#event:unsetnonce|void} + */ + + /** + * The promise return, if present, resolves to `undefined` + * (`extension_added`, `exported`, `saved`). + * @typedef {Promise<void>|void} module:svgcanvas.EventHandlerReturn + */ + + /** + * @callback module:svgcanvas.EventHandler + * @param {external:Window} win + * @param {module:svgcanvas.SvgCanvas#event:GenericCanvasEvent} arg + * @listens module:svgcanvas.SvgCanvas#event:GenericCanvasEvent + * @returns {module:svgcanvas.EventHandlerReturn} + */ + + /** + * Attaches a callback function to an event. + * @function module:svgcanvas.SvgCanvas#bind + * @param {"changed"|"contextset"|"selected"|"pointsAdded"|"extension_added"|"extensions_added"|"message"|"transition"|"zoomed"|"updateCanvas"|"zoomDone"|"saved"|"exported"|"exportedPDF"|"setnonce"|"unsetnonce"|"cleared"} ev - String indicating the name of the event + * @param {module:svgcanvas.EventHandler} f - The callback function to bind to the event + * @returns {module:svgcanvas.EventHandler} The previous event + */ + + canvas.bind = function (ev, f) { + const old = events[ev]; + events[ev] = f; + return old; + }; + /** + * Runs the SVG Document through the sanitizer and then updates its paths. + * @function module:svgcanvas.SvgCanvas#prepareSvg + * @param {XMLDocument} newDoc - The SVG DOM document + * @returns {void} + */ + + + this.prepareSvg = function (newDoc) { + this.sanitizeSvg(newDoc.documentElement); // convert paths into absolute commands + + const paths = [...newDoc.getElementsByTagNameNS(NS.SVG, 'path')]; + paths.forEach(path => { + path.setAttribute('d', pathActions.convertPath(path)); + pathActions.fixEnd(path); + }); + }; + /** + * Hack for Firefox bugs where text element features aren't updated or get + * messed up. See issue 136 and issue 137. + * This function clones the element and re-selects it. + * @function module:svgcanvas~ffClone + * @todo Test for this bug on load and add it to "support" object instead of + * browser sniffing + * @param {Element} elem - The (text) DOM element to clone + * @returns {Element} Cloned element + */ + + + const ffClone = function (elem) { + if (!isGecko()) { + return elem; + } + + const clone = elem.cloneNode(true); + elem.before(clone); + elem.remove(); + selectorManager.releaseSelector(elem); + selectedElements[0] = clone; + selectorManager.requestSelector(clone).showGrips(true); + return clone; + }; // `this.each` is deprecated, if any extension used this it can be recreated by doing this: + // * @example $(canvas.getRootElem()).children().each(...) + // * @function module:svgcanvas.SvgCanvas#each + // this.each = function (cb) { + // $(svgroot).children().each(cb); + // }; + + /** + * Removes any old rotations if present, prepends a new rotation at the + * transformed center. + * @function module:svgcanvas.SvgCanvas#setRotationAngle + * @param {string|Float} val - The new rotation angle in degrees + * @param {boolean} preventUndo - Indicates whether the action should be undoable or not + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.setRotationAngle = function (val, preventUndo) { + // ensure val is the proper type + val = Number.parseFloat(val); + const elem = selectedElements[0]; + const oldTransform = elem.getAttribute('transform'); + const bbox = getBBox(elem); + const cx = bbox.x + bbox.width / 2, + cy = bbox.y + bbox.height / 2; + const tlist = getTransformList(elem); // only remove the real rotational transform if present (i.e. at index=0) + + if (tlist.numberOfItems > 0) { + const xform = tlist.getItem(0); + + if (xform.type === 4) { + tlist.removeItem(0); + } + } // find Rnc and insert it + + + if (val !== 0) { + const center = transformPoint(cx, cy, transformListToTransform(tlist).matrix); + const Rnc = svgroot.createSVGTransform(); + Rnc.setRotate(val, center.x, center.y); + + if (tlist.numberOfItems) { + tlist.insertItemBefore(Rnc, 0); + } else { + tlist.appendItem(Rnc); + } + } else if (tlist.numberOfItems === 0) { + elem.removeAttribute('transform'); + } + + if (!preventUndo) { + // we need to undo it, then redo it so it can be undo-able! :) + // TODO: figure out how to make changes to transform list undo-able cross-browser? + const newTransform = elem.getAttribute('transform'); + elem.setAttribute('transform', oldTransform); + changeSelectedAttribute('transform', newTransform, selectedElements); + call('changed', selectedElements); + } // const pointGripContainer = getElem('pathpointgrip_container'); + // if (elem.nodeName === 'path' && pointGripContainer) { + // pathActions.setPointContainerTransform(elem.getAttribute('transform')); + // } + + + const selector = selectorManager.requestSelector(selectedElements[0]); + selector.resize(); + Selector.updateGripCursors(val); + }; + /** + * Runs `recalculateDimensions` on the selected elements, + * adding the changes to a single batch command. + * @function module:svgcanvas.SvgCanvas#recalculateAllSelectedDimensions + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + const recalculateAllSelectedDimensions = this.recalculateAllSelectedDimensions = function () { + const text = currentResizeMode === 'none' ? 'position' : 'size'; + const batchCmd = new BatchCommand$1(text); + let i = selectedElements.length; + + while (i--) { + const elem = selectedElements[i]; // if (getRotationAngle(elem) && !hasMatrixTransform(getTransformList(elem))) { continue; } + + const cmd = recalculateDimensions(elem); + + if (cmd) { + batchCmd.addSubCommand(cmd); + } + } + + if (!batchCmd.isEmpty()) { + addCommandToHistory(batchCmd); + call('changed', selectedElements); + } + }; + /** + * Debug tool to easily see the current matrix in the browser's console. + * @function module:svgcanvas~logMatrix + * @param {SVGMatrix} m The matrix * @returns {void} */ - var mouseDown = function mouseDown(evt) { - if (canvas.spaceKey || evt.button === 1) { + const logMatrix = function (m) { + console.log([m.a, m.b, m.c, m.d, m.e, m.f]); // eslint-disable-line no-console + }; // Root Current Transformation Matrix in user units + + + let rootSctm = null; + /** + * Group: Selection. + */ + // TODO: do we need to worry about selectedBBoxes here? + + /** + * Selects only the given elements, shortcut for `clearSelection(); addToSelection()`. + * @function module:svgcanvas.SvgCanvas#selectOnly + * @param {Element[]} elems - an array of DOM elements to be selected + * @param {boolean} showGrips - Indicates whether the resize grips should be shown + * @returns {void} + */ + + const selectOnly = this.selectOnly = function (elems, showGrips) { + clearSelection(true); + addToSelection(elems, showGrips); + }; // TODO: could use slice here to make this faster? + // TODO: should the 'selected' handler + + /** + * Removes elements from the selection. + * @function module:svgcanvas.SvgCanvas#removeFromSelection + * @param {Element[]} elemsToRemove - An array of elements to remove from selection + * @returns {void} + */ + + /* const removeFromSelection = */ + + + this.removeFromSelection = function (elemsToRemove) { + if (isNullish(selectedElements[0])) { return; } - var rightClick = evt.button === 2; + if (!elemsToRemove.length) { + return; + } // find every element and remove it from our array copy - if (evt.altKey) { - // duplicate when dragging - canvas.cloneSelectedElements(0, 0); - } - rootSctm = $$9('#svgcontent g')[0].getScreenCTM().inverse(); - var pt = transformPoint(evt.pageX, evt.pageY, rootSctm), - mouseX = pt.x * currentZoom, - mouseY = pt.y * currentZoom; - evt.preventDefault(); + const newSelectedItems = [], + len = selectedElements.length; - if (rightClick) { + for (let i = 0; i < len; ++i) { + const elem = selectedElements[i]; + + if (elem) { + // keep the item + if (!elemsToRemove.includes(elem)) { + newSelectedItems.push(elem); + } else { + // remove the item and its selector + selectorManager.releaseSelector(elem); + } + } + } // the copy becomes the master now + + + selectedElements = newSelectedItems; + }; + /** + * Clears the selection, then adds all elements in the current layer to the selection. + * @function module:svgcanvas.SvgCanvas#selectAllInCurrentLayer + * @returns {void} + */ + + + this.selectAllInCurrentLayer = function () { + const currentLayer = getCurrentDrawing().getCurrentLayer(); + + if (currentLayer) { currentMode = 'select'; - lastClickPoint = pt; - } // This would seem to be unnecessary... - // if (!['select', 'resize'].includes(currentMode)) { - // setGradient(); - // } + selectOnly($$a(currentGroup || currentLayer).children()); + } + }; + + let drawnPath = null; // Mouse events + + (function () { + const freehand = { + minx: null, + miny: null, + maxx: null, + maxy: null + }; + const THRESHOLD_DIST = 0.8, + STEP_COUNT = 10; + let dAttr = null, + startX = null, + startY = null, + rStartX = null, + rStartY = null, + initBbox = {}, + sumDistance = 0, + controllPoint2 = { + x: 0, + y: 0 + }, + controllPoint1 = { + x: 0, + y: 0 + }, + start = { + x: 0, + y: 0 + }, + end = { + x: 0, + y: 0 + }, + bSpline = { + x: 0, + y: 0 + }, + nextPos = { + x: 0, + y: 0 + }, + parameter, + nextParameter; + + const getBsplinePoint = function (t) { + const spline = { + x: 0, + y: 0 + }, + p0 = controllPoint2, + p1 = controllPoint1, + p2 = start, + p3 = end, + S = 1.0 / 6.0, + t2 = t * t, + t3 = t2 * t; + const m = [[-1, 3, -3, 1], [3, -6, 3, 0], [-3, 0, 3, 0], [1, 4, 1, 0]]; + spline.x = S * ((p0.x * m[0][0] + p1.x * m[0][1] + p2.x * m[0][2] + p3.x * m[0][3]) * t3 + (p0.x * m[1][0] + p1.x * m[1][1] + p2.x * m[1][2] + p3.x * m[1][3]) * t2 + (p0.x * m[2][0] + p1.x * m[2][1] + p2.x * m[2][2] + p3.x * m[2][3]) * t + (p0.x * m[3][0] + p1.x * m[3][1] + p2.x * m[3][2] + p3.x * m[3][3])); + spline.y = S * ((p0.y * m[0][0] + p1.y * m[0][1] + p2.y * m[0][2] + p3.y * m[0][3]) * t3 + (p0.y * m[1][0] + p1.y * m[1][1] + p2.y * m[1][2] + p3.y * m[1][3]) * t2 + (p0.y * m[2][0] + p1.y * m[2][1] + p2.y * m[2][2] + p3.y * m[2][3]) * t + (p0.y * m[3][0] + p1.y * m[3][1] + p2.y * m[3][2] + p3.y * m[3][3])); + return { + x: spline.x, + y: spline.y + }; + }; + /** + * Follows these conditions: + * - When we are in a create mode, the element is added to the canvas but the + * action is not recorded until mousing up. + * - When we are in select mode, select the element, remember the position + * and do nothing else. + * @param {MouseEvent} evt + * @fires module:svgcanvas.SvgCanvas#event:ext_mouseDown + * @returns {void} + */ - var x = mouseX / currentZoom, - y = mouseY / currentZoom; - var mouseTarget = getMouseTarget(evt); - - if (mouseTarget.tagName === 'a' && mouseTarget.childNodes.length === 1) { - mouseTarget = mouseTarget.firstChild; - } // realX/y ignores grid-snap value - - - var realX = x; - rStartX = startX = x; - var realY = y; - rStartY = startY = y; - - if (curConfig.gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - startX = snapToGrid(startX); - startY = snapToGrid(startY); - } // if it is a selector grip, then it must be a single element selected, - // set the mouseTarget to that and update the mode to rotate/resize - - - if (mouseTarget === selectorManager.selectorParentGroup && !isNullish(selectedElements[0])) { - var grip = evt.target; - var griptype = elData(grip, 'type'); // rotating - - if (griptype === 'rotate') { - currentMode = 'rotate'; // resizing - } else if (griptype === 'resize') { - currentMode = 'resize'; - currentResizeMode = elData(grip, 'dir'); + const mouseDown = function (evt) { + if (canvas.spaceKey || evt.button === 1) { + return; } - mouseTarget = selectedElements[0]; - } + const rightClick = evt.button === 2; - startTransform = mouseTarget.getAttribute('transform'); - var tlist = getTransformList(mouseTarget); + if (evt.altKey) { + // duplicate when dragging + canvas.cloneSelectedElements(0, 0); + } - switch (currentMode) { - case 'select': - started = true; - currentResizeMode = 'none'; + rootSctm = $$a('#svgcontent g')[0].getScreenCTM().inverse(); + const pt = transformPoint(evt.pageX, evt.pageY, rootSctm), + mouseX = pt.x * currentZoom, + mouseY = pt.y * currentZoom; + evt.preventDefault(); - if (rightClick) { - started = false; + if (rightClick) { + currentMode = 'select'; + lastClickPoint = pt; + } // This would seem to be unnecessary... + // if (!['select', 'resize'].includes(currentMode)) { + // setGradient(); + // } + + + let x = mouseX / currentZoom, + y = mouseY / currentZoom; + let mouseTarget = getMouseTarget(evt); + + if (mouseTarget.tagName === 'a' && mouseTarget.childNodes.length === 1) { + mouseTarget = mouseTarget.firstChild; + } // realX/y ignores grid-snap value + + + const realX = x; + rStartX = startX = x; + const realY = y; + rStartY = startY = y; + + if (curConfig.gridSnapping) { + x = snapToGrid(x); + y = snapToGrid(y); + startX = snapToGrid(startX); + startY = snapToGrid(startY); + } // if it is a selector grip, then it must be a single element selected, + // set the mouseTarget to that and update the mode to rotate/resize + + + if (mouseTarget === selectorManager.selectorParentGroup && !isNullish(selectedElements[0])) { + const grip = evt.target; + const griptype = elData(grip, 'type'); // rotating + + if (griptype === 'rotate') { + currentMode = 'rotate'; // resizing + } else if (griptype === 'resize') { + currentMode = 'resize'; + currentResizeMode = elData(grip, 'dir'); } - if (mouseTarget !== svgroot) { - // if this element is not yet selected, clear selection and select it - if (!selectedElements.includes(mouseTarget)) { - // only clear selection if shift is not pressed (otherwise, add - // element to selection) - if (!evt.shiftKey) { - // No need to do the call here as it will be done on addToSelection - clearSelection(true); - } + mouseTarget = selectedElements[0]; + } - addToSelection([mouseTarget]); - justSelected = mouseTarget; - pathActions$1.clear(); - } // else if it's a path, go into pathedit mode in mouseup + startTransform = mouseTarget.getAttribute('transform'); + const tlist = getTransformList(mouseTarget); + + switch (currentMode) { + case 'select': + started = true; + currentResizeMode = 'none'; + + if (rightClick) { + started = false; + } + + if (mouseTarget !== svgroot) { + // if this element is not yet selected, clear selection and select it + if (!selectedElements.includes(mouseTarget)) { + // only clear selection if shift is not pressed (otherwise, add + // element to selection) + if (!evt.shiftKey) { + // No need to do the call here as it will be done on addToSelection + clearSelection(true); + } + + addToSelection([mouseTarget]); + justSelected = mouseTarget; + pathActions.clear(); + } // else if it's a path, go into pathedit mode in mouseup - if (!rightClick) { - // insert a dummy transform so if the element(s) are moved it will have - // a transform to use for its translate - var _iterator = _createForOfIteratorHelper(selectedElements), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var selectedElement = _step.value; - + if (!rightClick) { + // insert a dummy transform so if the element(s) are moved it will have + // a transform to use for its translate + for (const selectedElement of selectedElements) { if (isNullish(selectedElement)) { continue; } - var slist = getTransformList(selectedElement); + const slist = getTransformList(selectedElement); if (slist.numberOfItems) { slist.insertItemBefore(svgroot.createSVGTransform(), 0); @@ -15695,792 +14879,588 @@ slist.appendItem(svgroot.createSVGTransform()); } } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); } + } else if (!rightClick) { + clearSelection(); + currentMode = 'multiselect'; + + if (isNullish(rubberBox)) { + rubberBox = selectorManager.getRubberBandBox(); + } + + rStartX *= currentZoom; + rStartY *= currentZoom; // console.log('p',[evt.pageX, evt.pageY]); + // console.log('c',[evt.clientX, evt.clientY]); + // console.log('o',[evt.offsetX, evt.offsetY]); + // console.log('s',[startX, startY]); + + assignAttributes(rubberBox, { + x: rStartX, + y: rStartY, + width: 0, + height: 0, + display: 'inline' + }); } - } else if (!rightClick) { - clearSelection(); - currentMode = 'multiselect'; + + break; + + case 'zoom': + started = true; if (isNullish(rubberBox)) { rubberBox = selectorManager.getRubberBandBox(); } - rStartX *= currentZoom; - rStartY *= currentZoom; // console.log('p',[evt.pageX, evt.pageY]); - // console.log('c',[evt.clientX, evt.clientY]); - // console.log('o',[evt.offsetX, evt.offsetY]); - // console.log('s',[startX, startY]); - assignAttributes(rubberBox, { - x: rStartX, - y: rStartY, + x: realX * currentZoom, + y: realX * currentZoom, width: 0, height: 0, display: 'inline' }); - } + break; - break; + case 'resize': + { + started = true; + startX = x; + startY = y; // Getting the BBox from the selection box, since we know we + // want to orient around it - case 'zoom': - started = true; + initBbox = getBBox($$a('#selectedBox0')[0]); + const bb = {}; + $$a.each(initBbox, function (key, val) { + bb[key] = val / currentZoom; + }); + initBbox = bb; // append three dummy transforms to the tlist so that + // we can translate,scale,translate in mousemove - if (isNullish(rubberBox)) { - rubberBox = selectorManager.getRubberBandBox(); - } + const pos = getRotationAngle(mouseTarget) ? 1 : 0; - assignAttributes(rubberBox, { - x: realX * currentZoom, - y: realX * currentZoom, - width: 0, - height: 0, - display: 'inline' - }); - break; + if (hasMatrixTransform(tlist)) { + tlist.insertItemBefore(svgroot.createSVGTransform(), pos); + tlist.insertItemBefore(svgroot.createSVGTransform(), pos); + tlist.insertItemBefore(svgroot.createSVGTransform(), pos); + } else { + tlist.appendItem(svgroot.createSVGTransform()); + tlist.appendItem(svgroot.createSVGTransform()); + tlist.appendItem(svgroot.createSVGTransform()); - case 'resize': - { - started = true; - startX = x; - startY = y; // Getting the BBox from the selection box, since we know we - // want to orient around it - - initBbox = getBBox($$9('#selectedBox0')[0]); - var bb = {}; - $$9.each(initBbox, function (key, val) { - bb[key] = val / currentZoom; - }); - initBbox = bb; // append three dummy transforms to the tlist so that - // we can translate,scale,translate in mousemove - - var pos = getRotationAngle(mouseTarget) ? 1 : 0; - - if (hasMatrixTransform(tlist)) { - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - tlist.insertItemBefore(svgroot.createSVGTransform(), pos); - } else { - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - tlist.appendItem(svgroot.createSVGTransform()); - - if (supportsNonScalingStroke()) { - // Handle crash for newer Chrome and Safari 6 (Mobile and Desktop): - // https://code.google.com/p/svg-edit/issues/detail?id=904 - // Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 - // TODO: Remove this workaround once vendor fixes the issue - var iswebkit = isWebkit(); - var delayedStroke; - - if (iswebkit) { - delayedStroke = function delayedStroke(ele) { - var stroke_ = ele.getAttribute('stroke'); - ele.removeAttribute('stroke'); // Re-apply stroke after delay. Anything higher than 1 seems to cause flicker - - if (stroke_ !== null) setTimeout(function () { - ele.setAttribute('stroke', stroke_); - }, 0); - }; - } - - mouseTarget.style.vectorEffect = 'non-scaling-stroke'; - - if (iswebkit) { - delayedStroke(mouseTarget); - } - - var all = mouseTarget.getElementsByTagName('*'), - len = all.length; - - for (var i = 0; i < len; i++) { - if (!all[i].style) { - // mathML - continue; - } - - all[i].style.vectorEffect = 'non-scaling-stroke'; + if (supportsNonScalingStroke()) { + // Handle crash for newer Chrome and Safari 6 (Mobile and Desktop): + // https://code.google.com/p/svg-edit/issues/detail?id=904 + // Chromium issue: https://code.google.com/p/chromium/issues/detail?id=114625 + // TODO: Remove this workaround once vendor fixes the issue + const iswebkit = isWebkit(); + let delayedStroke; if (iswebkit) { - delayedStroke(all[i]); + delayedStroke = function (ele) { + const stroke_ = ele.getAttribute('stroke'); + ele.removeAttribute('stroke'); // Re-apply stroke after delay. Anything higher than 1 seems to cause flicker + + if (stroke_ !== null) setTimeout(function () { + ele.setAttribute('stroke', stroke_); + }, 0); + }; + } + + mouseTarget.style.vectorEffect = 'non-scaling-stroke'; + + if (iswebkit) { + delayedStroke(mouseTarget); + } + + const all = mouseTarget.getElementsByTagName('*'), + len = all.length; + + for (let i = 0; i < len; i++) { + if (!all[i].style) { + // mathML + continue; + } + + all[i].style.vectorEffect = 'non-scaling-stroke'; + + if (iswebkit) { + delayedStroke(all[i]); + } } } } + + break; } - break; - } - - case 'fhellipse': - case 'fhrect': - case 'fhpath': - start.x = realX; - start.y = realY; - controllPoint1 = { - x: 0, - y: 0 - }; - controllPoint2 = { - x: 0, - y: 0 - }; - started = true; - dAttr = realX + ',' + realY + ' '; // Commented out as doing nothing now: - // strokeW = parseFloat(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - - addSVGElementFromJson({ - element: 'polyline', - curStyles: true, - attr: { - points: dAttr, - id: getNextId(), - fill: 'none', - opacity: curShape.opacity / 2, - 'stroke-linecap': 'round', - style: 'pointer-events:none' - } - }); - freehand.minx = realX; - freehand.maxx = realX; - freehand.miny = realY; - freehand.maxy = realY; - break; - - case 'image': - { + case 'fhellipse': + case 'fhrect': + case 'fhpath': + start.x = realX; + start.y = realY; + controllPoint1 = { + x: 0, + y: 0 + }; + controllPoint2 = { + x: 0, + y: 0 + }; started = true; - var newImage = addSVGElementFromJson({ - element: 'image', - attr: { - x: x, - y: y, - width: 0, - height: 0, - id: getNextId(), - opacity: curShape.opacity / 2, - style: 'pointer-events:inherit' - } - }); - setHref(newImage, lastGoodImgUrl); - preventClickDefault(newImage); - break; - } + dAttr = realX + ',' + realY + ' '; // Commented out as doing nothing now: + // strokeW = parseFloat(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; - case 'square': // TODO: once we create the rect, we lose information that this was a square - // (for resizing purposes this could be important) - // Fallthrough - - case 'rect': - started = true; - startX = x; - startY = y; - addSVGElementFromJson({ - element: 'rect', - curStyles: true, - attr: { - x: x, - y: y, - width: 0, - height: 0, - id: getNextId(), - opacity: curShape.opacity / 2 - } - }); - break; - - case 'line': - { - started = true; - var strokeW = Number(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; addSVGElementFromJson({ - element: 'line', + element: 'polyline', curStyles: true, attr: { - x1: x, - y1: y, - x2: x, - y2: y, + points: dAttr, id: getNextId(), - stroke: curShape.stroke, - 'stroke-width': strokeW, - 'stroke-dasharray': curShape.stroke_dasharray, - 'stroke-linejoin': curShape.stroke_linejoin, - 'stroke-linecap': curShape.stroke_linecap, - 'stroke-opacity': curShape.stroke_opacity, fill: 'none', opacity: curShape.opacity / 2, + 'stroke-linecap': 'round', style: 'pointer-events:none' } }); + freehand.minx = realX; + freehand.maxx = realX; + freehand.miny = realY; + freehand.maxy = realY; break; - } - case 'circle': - started = true; - addSVGElementFromJson({ - element: 'circle', - curStyles: true, - attr: { - cx: x, - cy: y, - r: 0, - id: getNextId(), - opacity: curShape.opacity / 2 + case 'image': + { + started = true; + const newImage = addSVGElementFromJson({ + element: 'image', + attr: { + x, + y, + width: 0, + height: 0, + id: getNextId(), + opacity: curShape.opacity / 2, + style: 'pointer-events:inherit' + } + }); + setHref(newImage, lastGoodImgUrl); + preventClickDefault(newImage); + break; } - }); - break; - case 'ellipse': - started = true; - addSVGElementFromJson({ - element: 'ellipse', - curStyles: true, - attr: { - cx: x, - cy: y, - rx: 0, - ry: 0, - id: getNextId(), - opacity: curShape.opacity / 2 + case 'square': // TODO: once we create the rect, we lose information that this was a square + // (for resizing purposes this could be important) + // Fallthrough + + case 'rect': + started = true; + startX = x; + startY = y; + addSVGElementFromJson({ + element: 'rect', + curStyles: true, + attr: { + x, + y, + width: 0, + height: 0, + id: getNextId(), + opacity: curShape.opacity / 2 + } + }); + break; + + case 'line': + { + started = true; + const strokeW = Number(curShape.stroke_width) === 0 ? 1 : curShape.stroke_width; + addSVGElementFromJson({ + element: 'line', + curStyles: true, + attr: { + x1: x, + y1: y, + x2: x, + y2: y, + id: getNextId(), + stroke: curShape.stroke, + 'stroke-width': strokeW, + 'stroke-dasharray': curShape.stroke_dasharray, + 'stroke-linejoin': curShape.stroke_linejoin, + 'stroke-linecap': curShape.stroke_linecap, + 'stroke-opacity': curShape.stroke_opacity, + fill: 'none', + opacity: curShape.opacity / 2, + style: 'pointer-events:none' + } + }); + break; } - }); - break; - case 'text': - started = true; - /* const newText = */ + case 'circle': + started = true; + addSVGElementFromJson({ + element: 'circle', + curStyles: true, + attr: { + cx: x, + cy: y, + r: 0, + id: getNextId(), + opacity: curShape.opacity / 2 + } + }); + break; - addSVGElementFromJson({ - element: 'text', - curStyles: true, - attr: { - x: x, - y: y, - id: getNextId(), - fill: curText.fill, - 'stroke-width': curText.stroke_width, - 'font-size': curText.font_size, - 'font-family': curText.font_family, - 'text-anchor': 'middle', - 'xml:space': 'preserve', - opacity: curShape.opacity - } - }); // newText.textContent = 'text'; + case 'ellipse': + started = true; + addSVGElementFromJson({ + element: 'ellipse', + curStyles: true, + attr: { + cx: x, + cy: y, + rx: 0, + ry: 0, + id: getNextId(), + opacity: curShape.opacity / 2 + } + }); + break; - break; + case 'text': + started = true; + /* const newText = */ - case 'path': // Fall through + addSVGElementFromJson({ + element: 'text', + curStyles: true, + attr: { + x, + y, + id: getNextId(), + fill: curText.fill, + 'stroke-width': curText.stroke_width, + 'font-size': curText.font_size, + 'font-family': curText.font_family, + 'text-anchor': 'middle', + 'xml:space': 'preserve', + opacity: curShape.opacity + } + }); // newText.textContent = 'text'; - case 'pathedit': - startX *= currentZoom; - startY *= currentZoom; - pathActions$1.mouseDown(evt, mouseTarget, startX, startY); - started = true; - break; + break; - case 'textedit': - startX *= currentZoom; - startY *= currentZoom; - textActions.mouseDown(evt, mouseTarget, startX, startY); - started = true; - break; + case 'path': // Fall through - case 'rotate': - started = true; // we are starting an undoable change (a drag-rotation) + case 'pathedit': + startX *= currentZoom; + startY *= currentZoom; + pathActions.mouseDown(evt, mouseTarget, startX, startY); + started = true; + break; - canvas.undoMgr.beginUndoableChange('transform', selectedElements); - break; - } - /** - * The main (left) mouse button is held down on the canvas area. - * @event module:svgcanvas.SvgCanvas#event:ext_mouseDown - * @type {PlainObject} - * @property {MouseEvent} event The event object - * @property {Float} start_x x coordinate on canvas - * @property {Float} start_y y coordinate on canvas - * @property {Element[]} selectedElements An array of the selected Elements - */ + case 'textedit': + startX *= currentZoom; + startY *= currentZoom; + textActions.mouseDown(evt, mouseTarget, startX, startY); + started = true; + break; + case 'rotate': + started = true; // we are starting an undoable change (a drag-rotation) - var extResult = runExtensions('mouseDown', - /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseDown} */ - { - event: evt, - start_x: startX, - start_y: startY, - selectedElements: selectedElements - }, true); - $$9.each(extResult, function (i, r) { - if (r && r.started) { - started = true; + canvas.undoMgr.beginUndoableChange('transform', selectedElements); + break; } - }); - }; // in this function we do not record any state changes yet (but we do update - // any elements that are still being created, moved or resized on the canvas) - - /** - * - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:transition - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseMove - * @returns {void} - */ + /** + * The main (left) mouse button is held down on the canvas area. + * @event module:svgcanvas.SvgCanvas#event:ext_mouseDown + * @type {PlainObject} + * @property {MouseEvent} event The event object + * @property {Float} start_x x coordinate on canvas + * @property {Float} start_y y coordinate on canvas + * @property {Element[]} selectedElements An array of the selected Elements + */ - var mouseMove = function mouseMove(evt) { - if (!started) { - return; - } + const extResult = runExtensions('mouseDown', + /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseDown} */ + { + event: evt, + start_x: startX, + start_y: startY, + selectedElements + }, true); + $$a.each(extResult, function (i, r) { + if (r && r.started) { + started = true; + } + }); + }; // in this function we do not record any state changes yet (but we do update + // any elements that are still being created, moved or resized on the canvas) - if (evt.button === 1 || canvas.spaceKey) { - return; - } + /** + * + * @param {MouseEvent} evt + * @fires module:svgcanvas.SvgCanvas#event:transition + * @fires module:svgcanvas.SvgCanvas#event:ext_mouseMove + * @returns {void} + */ - var i, - xya, - c, - cx, - cy, - dx, - dy, - len, - angle, - box, - selected = selectedElements[0]; - var pt = transformPoint(evt.pageX, evt.pageY, rootSctm), - mouseX = pt.x * currentZoom, - mouseY = pt.y * currentZoom, - shape = getElem(getId()); - var realX = mouseX / currentZoom; - var x = realX; - var realY = mouseY / currentZoom; - var y = realY; - if (curConfig.gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - } + const mouseMove = function (evt) { + if (!started) { + return; + } - evt.preventDefault(); - var tlist; + if (evt.button === 1 || canvas.spaceKey) { + return; + } - switch (currentMode) { - case 'select': - { - // we temporarily use a translate on the element(s) being dragged - // this transform is removed upon mousing up and the element is - // relocated to the new location - if (selectedElements[0] !== null) { + let i, + xya, + c, + cx, + cy, + dx, + dy, + len, + angle, + box, + selected = selectedElements[0]; + const pt = transformPoint(evt.pageX, evt.pageY, rootSctm), + mouseX = pt.x * currentZoom, + mouseY = pt.y * currentZoom, + shape = getElem(getId()); + let realX = mouseX / currentZoom; + let x = realX; + let realY = mouseY / currentZoom; + let y = realY; + + if (curConfig.gridSnapping) { + x = snapToGrid(x); + y = snapToGrid(y); + } + + evt.preventDefault(); + let tlist; + + switch (currentMode) { + case 'select': + { + // we temporarily use a translate on the element(s) being dragged + // this transform is removed upon mousing up and the element is + // relocated to the new location + if (selectedElements[0] !== null) { + dx = x - startX; + dy = y - startY; + + if (curConfig.gridSnapping) { + dx = snapToGrid(dx); + dy = snapToGrid(dy); + } + /* + // Commenting out as currently has no effect + if (evt.shiftKey) { + xya = snapToAngle(startX, startY, x, y); + ({x, y} = xya); + } + */ + + + if (dx !== 0 || dy !== 0) { + len = selectedElements.length; + + for (i = 0; i < len; ++i) { + selected = selectedElements[i]; + + if (isNullish(selected)) { + break; + } // if (i === 0) { + // const box = utilsGetBBox(selected); + // selectedBBoxes[i].x = box.x + dx; + // selectedBBoxes[i].y = box.y + dy; + // } + // update the dummy transform in our transform list + // to be a translate + + + const xform = svgroot.createSVGTransform(); + tlist = getTransformList(selected); // Note that if Webkit and there's no ID for this + // element, the dummy transform may have gotten lost. + // This results in unexpected behaviour + + xform.setTranslate(dx, dy); + + if (tlist.numberOfItems) { + tlist.replaceItem(xform, 0); + } else { + tlist.appendItem(xform); + } // update our internal bbox that we're tracking while dragging + + + selectorManager.requestSelector(selected).resize(); + } + + call('transition', selectedElements); + } + } + + break; + } + + case 'multiselect': + { + realX *= currentZoom; + realY *= currentZoom; + assignAttributes(rubberBox, { + x: Math.min(rStartX, realX), + y: Math.min(rStartY, realY), + width: Math.abs(realX - rStartX), + height: Math.abs(realY - rStartY) + }); // for each selected: + // - if newList contains selected, do nothing + // - if newList doesn't contain selected, remove it from selected + // - for any newList that was not in selectedElements, add it to selected + + const elemsToRemove = selectedElements.slice(), + elemsToAdd = [], + newList = getIntersectionList(); // For every element in the intersection, add if not present in selectedElements. + + len = newList.length; + + for (i = 0; i < len; ++i) { + const intElem = newList[i]; // Found an element that was not selected before, so we should add it. + + if (!selectedElements.includes(intElem)) { + elemsToAdd.push(intElem); + } // Found an element that was already selected, so we shouldn't remove it. + + + const foundInd = elemsToRemove.indexOf(intElem); + + if (foundInd !== -1) { + elemsToRemove.splice(foundInd, 1); + } + } + + if (elemsToRemove.length > 0) { + canvas.removeFromSelection(elemsToRemove); + } + + if (elemsToAdd.length > 0) { + canvas.addToSelection(elemsToAdd); + } + + break; + } + + case 'resize': + { + // we track the resize bounding box and translate/scale the selected element + // while the mouse is down, when mouse goes up, we use this to recalculate + // the shape's coordinates + tlist = getTransformList(selected); + const hasMatrix = hasMatrixTransform(tlist); + box = hasMatrix ? initBbox : getBBox(selected); + let left = box.x, + top = box.y, + { + width, + height + } = box; dx = x - startX; dy = y - startY; if (curConfig.gridSnapping) { dx = snapToGrid(dx); dy = snapToGrid(dy); + height = snapToGrid(height); + width = snapToGrid(width); + } // if rotated, adjust the dx,dy values + + + angle = getRotationAngle(selected); + + if (angle) { + const r = Math.sqrt(dx * dx + dy * dy), + theta = Math.atan2(dy, dx) - angle * Math.PI / 180.0; + dx = r * Math.cos(theta); + dy = r * Math.sin(theta); + } // if not stretching in y direction, set dy to 0 + // if not stretching in x direction, set dx to 0 + + + if (!currentResizeMode.includes('n') && !currentResizeMode.includes('s')) { + dy = 0; } - /* - // Commenting out as currently has no effect + + if (!currentResizeMode.includes('e') && !currentResizeMode.includes('w')) { + dx = 0; + } + + let // ts = null, + tx = 0, + ty = 0, + sy = height ? (height + dy) / height : 1, + sx = width ? (width + dx) / width : 1; // if we are dragging on the north side, then adjust the scale factor and ty + + if (currentResizeMode.includes('n')) { + sy = height ? (height - dy) / height : 1; + ty = height; + } // if we dragging on the east side, then adjust the scale factor and tx + + + if (currentResizeMode.includes('w')) { + sx = width ? (width - dx) / width : 1; + tx = width; + } // update the transform list with translate,scale,translate + + + const translateOrigin = svgroot.createSVGTransform(), + scale = svgroot.createSVGTransform(), + translateBack = svgroot.createSVGTransform(); + + if (curConfig.gridSnapping) { + left = snapToGrid(left); + tx = snapToGrid(tx); + top = snapToGrid(top); + ty = snapToGrid(ty); + } + + translateOrigin.setTranslate(-(left + tx), -(top + ty)); + if (evt.shiftKey) { - xya = snapToAngle(startX, startY, x, y); - ({x, y} = xya); - } - */ - - - if (dx !== 0 || dy !== 0) { - len = selectedElements.length; - - for (i = 0; i < len; ++i) { - selected = selectedElements[i]; - - if (isNullish(selected)) { - break; - } // if (i === 0) { - // const box = utilsGetBBox(selected); - // selectedBBoxes[i].x = box.x + dx; - // selectedBBoxes[i].y = box.y + dy; - // } - // update the dummy transform in our transform list - // to be a translate - - - var xform = svgroot.createSVGTransform(); - tlist = getTransformList(selected); // Note that if Webkit and there's no ID for this - // element, the dummy transform may have gotten lost. - // This results in unexpected behaviour - - xform.setTranslate(dx, dy); - - if (tlist.numberOfItems) { - tlist.replaceItem(xform, 0); - } else { - tlist.appendItem(xform); - } // update our internal bbox that we're tracking while dragging - - - selectorManager.requestSelector(selected).resize(); - } - - call('transition', selectedElements); - } - } - - break; - } - - case 'multiselect': - { - realX *= currentZoom; - realY *= currentZoom; - assignAttributes(rubberBox, { - x: Math.min(rStartX, realX), - y: Math.min(rStartY, realY), - width: Math.abs(realX - rStartX), - height: Math.abs(realY - rStartY) - }); // for each selected: - // - if newList contains selected, do nothing - // - if newList doesn't contain selected, remove it from selected - // - for any newList that was not in selectedElements, add it to selected - - var elemsToRemove = selectedElements.slice(), - elemsToAdd = [], - newList = getIntersectionList(); // For every element in the intersection, add if not present in selectedElements. - - len = newList.length; - - for (i = 0; i < len; ++i) { - var intElem = newList[i]; // Found an element that was not selected before, so we should add it. - - if (!selectedElements.includes(intElem)) { - elemsToAdd.push(intElem); - } // Found an element that was already selected, so we shouldn't remove it. - - - var foundInd = elemsToRemove.indexOf(intElem); - - if (foundInd !== -1) { - elemsToRemove.splice(foundInd, 1); - } - } - - if (elemsToRemove.length > 0) { - canvas.removeFromSelection(elemsToRemove); - } - - if (elemsToAdd.length > 0) { - canvas.addToSelection(elemsToAdd); - } - - break; - } - - case 'resize': - { - // we track the resize bounding box and translate/scale the selected element - // while the mouse is down, when mouse goes up, we use this to recalculate - // the shape's coordinates - tlist = getTransformList(selected); - var hasMatrix = hasMatrixTransform(tlist); - box = hasMatrix ? initBbox : getBBox(selected); - var left = box.x, - top = box.y, - _box = box, - width = _box.width, - height = _box.height; - dx = x - startX; - dy = y - startY; - - if (curConfig.gridSnapping) { - dx = snapToGrid(dx); - dy = snapToGrid(dy); - height = snapToGrid(height); - width = snapToGrid(width); - } // if rotated, adjust the dx,dy values - - - angle = getRotationAngle(selected); - - if (angle) { - var r = Math.sqrt(dx * dx + dy * dy), - theta = Math.atan2(dy, dx) - angle * Math.PI / 180.0; - dx = r * Math.cos(theta); - dy = r * Math.sin(theta); - } // if not stretching in y direction, set dy to 0 - // if not stretching in x direction, set dx to 0 - - - if (!currentResizeMode.includes('n') && !currentResizeMode.includes('s')) { - dy = 0; - } - - if (!currentResizeMode.includes('e') && !currentResizeMode.includes('w')) { - dx = 0; - } - - var // ts = null, - tx = 0, - ty = 0, - sy = height ? (height + dy) / height : 1, - sx = width ? (width + dx) / width : 1; // if we are dragging on the north side, then adjust the scale factor and ty - - if (currentResizeMode.includes('n')) { - sy = height ? (height - dy) / height : 1; - ty = height; - } // if we dragging on the east side, then adjust the scale factor and tx - - - if (currentResizeMode.includes('w')) { - sx = width ? (width - dx) / width : 1; - tx = width; - } // update the transform list with translate,scale,translate - - - var translateOrigin = svgroot.createSVGTransform(), - scale = svgroot.createSVGTransform(), - translateBack = svgroot.createSVGTransform(); - - if (curConfig.gridSnapping) { - left = snapToGrid(left); - tx = snapToGrid(tx); - top = snapToGrid(top); - ty = snapToGrid(ty); - } - - translateOrigin.setTranslate(-(left + tx), -(top + ty)); - - if (evt.shiftKey) { - if (sx === 1) { - sx = sy; - } else { - sy = sx; - } - } - - scale.setScale(sx, sy); - translateBack.setTranslate(left + tx, top + ty); - - if (hasMatrix) { - var diff = angle ? 1 : 0; - tlist.replaceItem(translateOrigin, 2 + diff); - tlist.replaceItem(scale, 1 + diff); - tlist.replaceItem(translateBack, Number(diff)); - } else { - var N = tlist.numberOfItems; - tlist.replaceItem(translateBack, N - 3); - tlist.replaceItem(scale, N - 2); - tlist.replaceItem(translateOrigin, N - 1); - } - - selectorManager.requestSelector(selected).resize(); - call('transition', selectedElements); - break; - } - - case 'zoom': - { - realX *= currentZoom; - realY *= currentZoom; - assignAttributes(rubberBox, { - x: Math.min(rStartX * currentZoom, realX), - y: Math.min(rStartY * currentZoom, realY), - width: Math.abs(realX - rStartX * currentZoom), - height: Math.abs(realY - rStartY * currentZoom) - }); - break; - } - - case 'text': - { - assignAttributes(shape, { - x: x, - y: y - }); - break; - } - - case 'line': - { - if (curConfig.gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - } - - var x2 = x; - var y2 = y; - - if (evt.shiftKey) { - xya = snapToAngle(startX, startY, x2, y2); - x2 = xya.x; - y2 = xya.y; - } - - shape.setAttribute('x2', x2); - shape.setAttribute('y2', y2); - break; - } - - case 'foreignObject': // fall through - - case 'square': // fall through - - case 'rect': // fall through - - case 'image': - { - var square = currentMode === 'square' || evt.shiftKey; - var w = Math.abs(x - startX), - h = Math.abs(y - startY); - var newX, newY; - - if (square) { - w = h = Math.max(w, h); - newX = startX < x ? startX : startX - w; - newY = startY < y ? startY : startY - h; - } else { - newX = Math.min(startX, x); - newY = Math.min(startY, y); - } - - if (curConfig.gridSnapping) { - w = snapToGrid(w); - h = snapToGrid(h); - newX = snapToGrid(newX); - newY = snapToGrid(newY); - } - - assignAttributes(shape, { - width: w, - height: h, - x: newX, - y: newY - }); - break; - } - - case 'circle': - { - c = $$9(shape).attr(['cx', 'cy']); - var _c = c; - cx = _c.cx; - cy = _c.cy; - var rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); - - if (curConfig.gridSnapping) { - rad = snapToGrid(rad); - } - - shape.setAttribute('r', rad); - break; - } - - case 'ellipse': - { - c = $$9(shape).attr(['cx', 'cy']); - var _c2 = c; - cx = _c2.cx; - cy = _c2.cy; - - if (curConfig.gridSnapping) { - x = snapToGrid(x); - cx = snapToGrid(cx); - y = snapToGrid(y); - cy = snapToGrid(cy); - } - - shape.setAttribute('rx', Math.abs(x - cx)); - var ry = Math.abs(evt.shiftKey ? x - cx : y - cy); - shape.setAttribute('ry', ry); - break; - } - - case 'fhellipse': - case 'fhrect': - { - freehand.minx = Math.min(realX, freehand.minx); - freehand.maxx = Math.max(realX, freehand.maxx); - freehand.miny = Math.min(realY, freehand.miny); - freehand.maxy = Math.max(realY, freehand.maxy); - } - // Fallthrough - - case 'fhpath': - { - // dAttr += + realX + ',' + realY + ' '; - // shape.setAttribute('points', dAttr); - end.x = realX; - end.y = realY; - - if (controllPoint2.x && controllPoint2.y) { - for (i = 0; i < STEP_COUNT - 1; i++) { - parameter = i / STEP_COUNT; - nextParameter = (i + 1) / STEP_COUNT; - bSpline = getBsplinePoint(nextParameter); - nextPos = bSpline; - bSpline = getBsplinePoint(parameter); - sumDistance += Math.sqrt((nextPos.x - bSpline.x) * (nextPos.x - bSpline.x) + (nextPos.y - bSpline.y) * (nextPos.y - bSpline.y)); - - if (sumDistance > THRESHOLD_DIST) { - sumDistance -= THRESHOLD_DIST; // Faster than completely re-writing the points attribute. - - var point = svgcontent.createSVGPoint(); - point.x = bSpline.x; - point.y = bSpline.y; - shape.points.appendItem(point); + if (sx === 1) { + sx = sy; + } else { + sy = sx; } } - } - controllPoint2 = { - x: controllPoint1.x, - y: controllPoint1.y - }; - controllPoint1 = { - x: start.x, - y: start.y - }; - start = { - x: end.x, - y: end.y - }; - break; // update path stretch line coordinates - } + scale.setScale(sx, sy); + translateBack.setTranslate(left + tx, top + ty); - case 'path': // fall through - - case 'pathedit': - { - x *= currentZoom; - y *= currentZoom; - - if (curConfig.gridSnapping) { - x = snapToGrid(x); - y = snapToGrid(y); - startX = snapToGrid(startX); - startY = snapToGrid(startY); - } - - if (evt.shiftKey) { - var path$1 = path; - var x1, y1; - - if (path$1) { - x1 = path$1.dragging ? path$1.dragging[0] : startX; - y1 = path$1.dragging ? path$1.dragging[1] : startY; + if (hasMatrix) { + const diff = angle ? 1 : 0; + tlist.replaceItem(translateOrigin, 2 + diff); + tlist.replaceItem(scale, 1 + diff); + tlist.replaceItem(translateBack, Number(diff)); } else { - x1 = startX; - y1 = startY; + const N = tlist.numberOfItems; + tlist.replaceItem(translateBack, N - 3); + tlist.replaceItem(scale, N - 2); + tlist.replaceItem(translateOrigin, N - 1); } - xya = snapToAngle(x1, y1, x, y); - var _xya = xya; - x = _xya.x; - y = _xya.y; + selectorManager.requestSelector(selected).resize(); + call('transition', selectedElements); + break; } - if (rubberBox && rubberBox.getAttribute('display') !== 'none') { + case 'zoom': + { realX *= currentZoom; realY *= currentZoom; assignAttributes(rubberBox, { @@ -16489,1962 +15469,2119 @@ width: Math.abs(realX - rStartX * currentZoom), height: Math.abs(realY - rStartY * currentZoom) }); + break; } - pathActions$1.mouseMove(x, y); - break; - } - - case 'textedit': - { - x *= currentZoom; - y *= currentZoom; // if (rubberBox && rubberBox.getAttribute('display') !== 'none') { - // assignAttributes(rubberBox, { - // x: Math.min(startX, x), - // y: Math.min(startY, y), - // width: Math.abs(x - startX), - // height: Math.abs(y - startY) - // }, 100); - // } - - textActions.mouseMove(mouseX, mouseY); - break; - } - - case 'rotate': - { - box = getBBox(selected); - cx = box.x + box.width / 2; - cy = box.y + box.height / 2; - var m = getMatrix(selected), - center = transformPoint(cx, cy, m); - cx = center.x; - cy = center.y; - angle = (Math.atan2(cy - y, cx - x) * (180 / Math.PI) - 90) % 360; - - if (curConfig.gridSnapping) { - angle = snapToGrid(angle); + case 'text': + { + assignAttributes(shape, { + x, + y + }); + break; } - if (evt.shiftKey) { - // restrict rotations to nice angles (WRS) - var snap = 45; - angle = Math.round(angle / snap) * snap; + case 'line': + { + if (curConfig.gridSnapping) { + x = snapToGrid(x); + y = snapToGrid(y); + } + + let x2 = x; + let y2 = y; + + if (evt.shiftKey) { + xya = snapToAngle(startX, startY, x2, y2); + x2 = xya.x; + y2 = xya.y; + } + + shape.setAttribute('x2', x2); + shape.setAttribute('y2', y2); + break; } - canvas.setRotationAngle(angle < -180 ? 360 + angle : angle, true); - call('transition', selectedElements); - break; - } - } - /** - * The mouse has moved on the canvas area. - * @event module:svgcanvas.SvgCanvas#event:ext_mouseMove - * @type {PlainObject} - * @property {MouseEvent} event The event object - * @property {Float} mouse_x x coordinate on canvas - * @property {Float} mouse_y y coordinate on canvas - * @property {Element} selected Refers to the first selected element - */ + case 'foreignObject': // fall through + case 'square': // fall through - runExtensions('mouseMove', - /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ - { - event: evt, - mouse_x: mouseX, - mouse_y: mouseY, - selected: selected - }); - }; // mouseMove() - // - in create mode, the element's opacity is set properly, we create an InsertElementCommand - // and store it on the Undo stack - // - in move/resize mode, the element's attributes which were affected by the move/resize are - // identified, a ChangeElementCommand is created and stored on the stack for those attrs - // this is done in when we recalculate the selected dimensions() + case 'rect': // fall through - /** - * - * @param {MouseEvent} evt - * @fires module:svgcanvas.SvgCanvas#event:zoomed - * @fires module:svgcanvas.SvgCanvas#event:changed - * @fires module:svgcanvas.SvgCanvas#event:ext_mouseUp - * @returns {void} - */ + case 'image': + { + const square = currentMode === 'square' || evt.shiftKey; + let w = Math.abs(x - startX), + h = Math.abs(y - startY); + let newX, newY; - - var mouseUp = function mouseUp(evt) { - if (evt.button === 2) { - return; - } - - var tempJustSelected = justSelected; - justSelected = null; - - if (!started) { - return; - } - - var pt = transformPoint(evt.pageX, evt.pageY, rootSctm), - mouseX = pt.x * currentZoom, - mouseY = pt.y * currentZoom, - x = mouseX / currentZoom, - y = mouseY / currentZoom; - var element = getElem(getId()); - var keep = false; - var realX = x; - var realY = y; // TODO: Make true when in multi-unit mode - - started = false; - var attrs, t; - - switch (currentMode) { - // intentionally fall-through to select here - case 'resize': - case 'multiselect': - if (!isNullish(rubberBox)) { - rubberBox.setAttribute('display', 'none'); - curBBoxes = []; - } - - currentMode = 'select'; - // Fallthrough - - case 'select': - if (!isNullish(selectedElements[0])) { - // if we only have one selected element - if (isNullish(selectedElements[1])) { - // set our current stroke/fill properties to the element's - var selected = selectedElements[0]; - - switch (selected.tagName) { - case 'g': - case 'use': - case 'image': - case 'foreignObject': - break; - - default: - curProperties.fill = selected.getAttribute('fill'); - curProperties.fill_opacity = selected.getAttribute('fill-opacity'); - curProperties.stroke = selected.getAttribute('stroke'); - curProperties.stroke_opacity = selected.getAttribute('stroke-opacity'); - curProperties.stroke_width = selected.getAttribute('stroke-width'); - curProperties.stroke_dasharray = selected.getAttribute('stroke-dasharray'); - curProperties.stroke_linejoin = selected.getAttribute('stroke-linejoin'); - curProperties.stroke_linecap = selected.getAttribute('stroke-linecap'); + if (square) { + w = h = Math.max(w, h); + newX = startX < x ? startX : startX - w; + newY = startY < y ? startY : startY - h; + } else { + newX = Math.min(startX, x); + newY = Math.min(startY, y); } - if (selected.tagName === 'text') { - curText.font_size = selected.getAttribute('font-size'); - curText.font_family = selected.getAttribute('font-family'); + if (curConfig.gridSnapping) { + w = snapToGrid(w); + h = snapToGrid(h); + newX = snapToGrid(newX); + newY = snapToGrid(newY); } - selectorManager.requestSelector(selected).showGrips(true); // This shouldn't be necessary as it was done on mouseDown... - // call('selected', [selected]); - } // always recalculate dimensions to strip off stray identity transforms + assignAttributes(shape, { + width: w, + height: h, + x: newX, + y: newY + }); + break; + } + case 'circle': + { + c = $$a(shape).attr(['cx', 'cy']); + ({ + cx, + cy + } = c); + let rad = Math.sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy)); - recalculateAllSelectedDimensions(); // if it was being dragged/resized + if (curConfig.gridSnapping) { + rad = snapToGrid(rad); + } - if (realX !== rStartX || realY !== rStartY) { - var len = selectedElements.length; + shape.setAttribute('r', rad); + break; + } - for (var i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { - break; - } + case 'ellipse': + { + c = $$a(shape).attr(['cx', 'cy']); + ({ + cx, + cy + } = c); - if (!selectedElements[i].firstChild) { - // Not needed for groups (incorrectly resizes elems), possibly not needed at all? - selectorManager.requestSelector(selectedElements[i]).resize(); - } - } // no change in position/size, so maybe we should move to pathedit + if (curConfig.gridSnapping) { + x = snapToGrid(x); + cx = snapToGrid(cx); + y = snapToGrid(y); + cy = snapToGrid(cy); + } - } else { - t = evt.target; + shape.setAttribute('rx', Math.abs(x - cx)); + const ry = Math.abs(evt.shiftKey ? x - cx : y - cy); + shape.setAttribute('ry', ry); + break; + } - if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { - pathActions$1.select(selectedElements[0]); // if it was a path - // else, if it was selected and this is a shift-click, remove it from selection - } else if (evt.shiftKey) { - if (tempJustSelected !== t) { - canvas.removeFromSelection([t]); + case 'fhellipse': + case 'fhrect': + { + freehand.minx = Math.min(realX, freehand.minx); + freehand.maxx = Math.max(realX, freehand.maxx); + freehand.miny = Math.min(realY, freehand.miny); + freehand.maxy = Math.max(realY, freehand.maxy); + } + // Fallthrough + + case 'fhpath': + { + // dAttr += + realX + ',' + realY + ' '; + // shape.setAttribute('points', dAttr); + end.x = realX; + end.y = realY; + + if (controllPoint2.x && controllPoint2.y) { + for (i = 0; i < STEP_COUNT - 1; i++) { + parameter = i / STEP_COUNT; + nextParameter = (i + 1) / STEP_COUNT; + bSpline = getBsplinePoint(nextParameter); + nextPos = bSpline; + bSpline = getBsplinePoint(parameter); + sumDistance += Math.sqrt((nextPos.x - bSpline.x) * (nextPos.x - bSpline.x) + (nextPos.y - bSpline.y) * (nextPos.y - bSpline.y)); + + if (sumDistance > THRESHOLD_DIST) { + sumDistance -= THRESHOLD_DIST; // Faster than completely re-writing the points attribute. + + const point = svgcontent.createSVGPoint(); + point.x = bSpline.x; + point.y = bSpline.y; + shape.points.appendItem(point); + } } } - } // no change in mouse position - // Remove non-scaling stroke + controllPoint2 = { + x: controllPoint1.x, + y: controllPoint1.y + }; + controllPoint1 = { + x: start.x, + y: start.y + }; + start = { + x: end.x, + y: end.y + }; + break; // update path stretch line coordinates + } - if (supportsNonScalingStroke()) { - var elem = selectedElements[0]; + case 'path': // fall through - if (elem) { - elem.removeAttribute('style'); - walkTree(elem, function (el) { - el.removeAttribute('style'); + case 'pathedit': + { + x *= currentZoom; + y *= currentZoom; + + if (curConfig.gridSnapping) { + x = snapToGrid(x); + y = snapToGrid(y); + startX = snapToGrid(startX); + startY = snapToGrid(startY); + } + + if (evt.shiftKey) { + const { + path + } = pathModule; + let x1, y1; + + if (path) { + x1 = path.dragging ? path.dragging[0] : startX; + y1 = path.dragging ? path.dragging[1] : startY; + } else { + x1 = startX; + y1 = startY; + } + + xya = snapToAngle(x1, y1, x, y); + ({ + x, + y + } = xya); + } + + if (rubberBox && rubberBox.getAttribute('display') !== 'none') { + realX *= currentZoom; + realY *= currentZoom; + assignAttributes(rubberBox, { + x: Math.min(rStartX * currentZoom, realX), + y: Math.min(rStartY * currentZoom, realY), + width: Math.abs(realX - rStartX * currentZoom), + height: Math.abs(realY - rStartY * currentZoom) }); } + + pathActions.mouseMove(x, y); + break; } - } + case 'textedit': + { + x *= currentZoom; + y *= currentZoom; // if (rubberBox && rubberBox.getAttribute('display') !== 'none') { + // assignAttributes(rubberBox, { + // x: Math.min(startX, x), + // y: Math.min(startY, y), + // width: Math.abs(x - startX), + // height: Math.abs(y - startY) + // }, 100); + // } + + textActions.mouseMove(mouseX, mouseY); + break; + } + + case 'rotate': + { + box = getBBox(selected); + cx = box.x + box.width / 2; + cy = box.y + box.height / 2; + const m = getMatrix(selected), + center = transformPoint(cx, cy, m); + cx = center.x; + cy = center.y; + angle = (Math.atan2(cy - y, cx - x) * (180 / Math.PI) - 90) % 360; + + if (curConfig.gridSnapping) { + angle = snapToGrid(angle); + } + + if (evt.shiftKey) { + // restrict rotations to nice angles (WRS) + const snap = 45; + angle = Math.round(angle / snap) * snap; + } + + canvas.setRotationAngle(angle < -180 ? 360 + angle : angle, true); + call('transition', selectedElements); + break; + } + } + /** + * The mouse has moved on the canvas area. + * @event module:svgcanvas.SvgCanvas#event:ext_mouseMove + * @type {PlainObject} + * @property {MouseEvent} event The event object + * @property {Float} mouse_x x coordinate on canvas + * @property {Float} mouse_y y coordinate on canvas + * @property {Element} selected Refers to the first selected element + */ + + + runExtensions('mouseMove', + /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseMove} */ + { + event: evt, + mouse_x: mouseX, + mouse_y: mouseY, + selected + }); + }; // mouseMove() + // - in create mode, the element's opacity is set properly, we create an InsertElementCommand + // and store it on the Undo stack + // - in move/resize mode, the element's attributes which were affected by the move/resize are + // identified, a ChangeElementCommand is created and stored on the stack for those attrs + // this is done in when we recalculate the selected dimensions() + + /** + * + * @param {MouseEvent} evt + * @fires module:svgcanvas.SvgCanvas#event:zoomed + * @fires module:svgcanvas.SvgCanvas#event:changed + * @fires module:svgcanvas.SvgCanvas#event:ext_mouseUp + * @returns {void} + */ + + + const mouseUp = function (evt) { + if (evt.button === 2) { return; + } - case 'zoom': - { + const tempJustSelected = justSelected; + justSelected = null; + + if (!started) { + return; + } + + const pt = transformPoint(evt.pageX, evt.pageY, rootSctm), + mouseX = pt.x * currentZoom, + mouseY = pt.y * currentZoom, + x = mouseX / currentZoom, + y = mouseY / currentZoom; + let element = getElem(getId()); + let keep = false; + const realX = x; + const realY = y; // TODO: Make true when in multi-unit mode + + started = false; + let attrs, t; + + switch (currentMode) { + // intentionally fall-through to select here + case 'resize': + case 'multiselect': if (!isNullish(rubberBox)) { rubberBox.setAttribute('display', 'none'); + curBBoxes = []; + } + + currentMode = 'select'; + // Fallthrough + + case 'select': + if (!isNullish(selectedElements[0])) { + // if we only have one selected element + if (isNullish(selectedElements[1])) { + // set our current stroke/fill properties to the element's + const selected = selectedElements[0]; + + switch (selected.tagName) { + case 'g': + case 'use': + case 'image': + case 'foreignObject': + break; + + default: + curProperties.fill = selected.getAttribute('fill'); + curProperties.fill_opacity = selected.getAttribute('fill-opacity'); + curProperties.stroke = selected.getAttribute('stroke'); + curProperties.stroke_opacity = selected.getAttribute('stroke-opacity'); + curProperties.stroke_width = selected.getAttribute('stroke-width'); + curProperties.stroke_dasharray = selected.getAttribute('stroke-dasharray'); + curProperties.stroke_linejoin = selected.getAttribute('stroke-linejoin'); + curProperties.stroke_linecap = selected.getAttribute('stroke-linecap'); + } + + if (selected.tagName === 'text') { + curText.font_size = selected.getAttribute('font-size'); + curText.font_family = selected.getAttribute('font-family'); + } + + selectorManager.requestSelector(selected).showGrips(true); // This shouldn't be necessary as it was done on mouseDown... + // call('selected', [selected]); + } // always recalculate dimensions to strip off stray identity transforms + + + recalculateAllSelectedDimensions(); // if it was being dragged/resized + + if (realX !== rStartX || realY !== rStartY) { + const len = selectedElements.length; + + for (let i = 0; i < len; ++i) { + if (isNullish(selectedElements[i])) { + break; + } + + if (!selectedElements[i].firstChild) { + // Not needed for groups (incorrectly resizes elems), possibly not needed at all? + selectorManager.requestSelector(selectedElements[i]).resize(); + } + } // no change in position/size, so maybe we should move to pathedit + + } else { + t = evt.target; + + if (selectedElements[0].nodeName === 'path' && isNullish(selectedElements[1])) { + pathActions.select(selectedElements[0]); // if it was a path + // else, if it was selected and this is a shift-click, remove it from selection + } else if (evt.shiftKey) { + if (tempJustSelected !== t) { + canvas.removeFromSelection([t]); + } + } + } // no change in mouse position + // Remove non-scaling stroke + + + if (supportsNonScalingStroke()) { + const elem = selectedElements[0]; + + if (elem) { + elem.removeAttribute('style'); + walkTree(elem, function (el) { + el.removeAttribute('style'); + }); + } + } } - var factor = evt.shiftKey ? 0.5 : 2; - call('zoomed', { - x: Math.min(rStartX, realX), - y: Math.min(rStartY, realY), - width: Math.abs(realX - rStartX), - height: Math.abs(realY - rStartY), - factor: factor - }); return; - } - case 'fhpath': - { - // Check that the path contains at least 2 points; a degenerate one-point path - // causes problems. - // Webkit ignores how we set the points attribute with commas and uses space - // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 - sumDistance = 0; - controllPoint2 = { - x: 0, - y: 0 - }; - controllPoint1 = { - x: 0, - y: 0 - }; - start = { - x: 0, - y: 0 - }; - end = { - x: 0, - y: 0 - }; - var coords = element.getAttribute('points'); - var commaIndex = coords.indexOf(','); + case 'zoom': + { + if (!isNullish(rubberBox)) { + rubberBox.setAttribute('display', 'none'); + } - if (commaIndex >= 0) { - keep = coords.includes(',', commaIndex + 1); - } else { - keep = coords.includes(' ', coords.indexOf(' ') + 1); + const factor = evt.shiftKey ? 0.5 : 2; + call('zoomed', { + x: Math.min(rStartX, realX), + y: Math.min(rStartY, realY), + width: Math.abs(realX - rStartX), + height: Math.abs(realY - rStartY), + factor + }); + return; } - if (keep) { - element = pathActions$1.smoothPolylineIntoPath(element); + case 'fhpath': + { + // Check that the path contains at least 2 points; a degenerate one-point path + // causes problems. + // Webkit ignores how we set the points attribute with commas and uses space + // to separate all coordinates, see https://bugs.webkit.org/show_bug.cgi?id=29870 + sumDistance = 0; + controllPoint2 = { + x: 0, + y: 0 + }; + controllPoint1 = { + x: 0, + y: 0 + }; + start = { + x: 0, + y: 0 + }; + end = { + x: 0, + y: 0 + }; + const coords = element.getAttribute('points'); + const commaIndex = coords.indexOf(','); + + if (commaIndex >= 0) { + keep = coords.includes(',', commaIndex + 1); + } else { + keep = coords.includes(' ', coords.indexOf(' ') + 1); + } + + if (keep) { + element = pathActions.smoothPolylineIntoPath(element); + } + + break; + } + + case 'line': + attrs = $$a(element).attr(['x1', 'x2', 'y1', 'y2']); + keep = attrs.x1 !== attrs.x2 || attrs.y1 !== attrs.y2; + break; + + case 'foreignObject': + case 'square': + case 'rect': + case 'image': + attrs = $$a(element).attr(['width', 'height']); // Image should be kept regardless of size (use inherit dimensions later) + + keep = attrs.width || attrs.height || currentMode === 'image'; + break; + + case 'circle': + keep = element.getAttribute('r') !== '0'; + break; + + case 'ellipse': + attrs = $$a(element).attr(['rx', 'ry']); + keep = attrs.rx || attrs.ry; + break; + + case 'fhellipse': + if (freehand.maxx - freehand.minx > 0 && freehand.maxy - freehand.miny > 0) { + element = addSVGElementFromJson({ + element: 'ellipse', + curStyles: true, + attr: { + cx: (freehand.minx + freehand.maxx) / 2, + cy: (freehand.miny + freehand.maxy) / 2, + rx: (freehand.maxx - freehand.minx) / 2, + ry: (freehand.maxy - freehand.miny) / 2, + id: getId() + } + }); + call('changed', [element]); + keep = true; } break; - } - case 'line': - attrs = $$9(element).attr(['x1', 'x2', 'y1', 'y2']); - keep = attrs.x1 !== attrs.x2 || attrs.y1 !== attrs.y2; - break; + case 'fhrect': + if (freehand.maxx - freehand.minx > 0 && freehand.maxy - freehand.miny > 0) { + element = addSVGElementFromJson({ + element: 'rect', + curStyles: true, + attr: { + x: freehand.minx, + y: freehand.miny, + width: freehand.maxx - freehand.minx, + height: freehand.maxy - freehand.miny, + id: getId() + } + }); + call('changed', [element]); + keep = true; + } - case 'foreignObject': - case 'square': - case 'rect': - case 'image': - attrs = $$9(element).attr(['width', 'height']); // Image should be kept regardless of size (use inherit dimensions later) - - keep = attrs.width || attrs.height || currentMode === 'image'; - break; - - case 'circle': - keep = element.getAttribute('r') !== '0'; - break; - - case 'ellipse': - attrs = $$9(element).attr(['rx', 'ry']); - keep = attrs.rx || attrs.ry; - break; - - case 'fhellipse': - if (freehand.maxx - freehand.minx > 0 && freehand.maxy - freehand.miny > 0) { - element = addSVGElementFromJson({ - element: 'ellipse', - curStyles: true, - attr: { - cx: (freehand.minx + freehand.maxx) / 2, - cy: (freehand.miny + freehand.maxy) / 2, - rx: (freehand.maxx - freehand.minx) / 2, - ry: (freehand.maxy - freehand.miny) / 2, - id: getId() - } - }); - call('changed', [element]); - keep = true; - } - - break; - - case 'fhrect': - if (freehand.maxx - freehand.minx > 0 && freehand.maxy - freehand.miny > 0) { - element = addSVGElementFromJson({ - element: 'rect', - curStyles: true, - attr: { - x: freehand.minx, - y: freehand.miny, - width: freehand.maxx - freehand.minx, - height: freehand.maxy - freehand.miny, - id: getId() - } - }); - call('changed', [element]); - keep = true; - } - - break; - - case 'text': - keep = true; - selectOnly([element]); - textActions.start(element); - break; - - case 'path': - { - // set element to null here so that it is not removed nor finalized - element = null; // continue to be set to true so that mouseMove happens - - started = true; - var res = pathActions$1.mouseUp(evt, element, mouseX, mouseY); - element = res.element; - keep = res.keep; break; - } - case 'pathedit': - keep = true; - element = null; - pathActions$1.mouseUp(evt); - break; + case 'text': + keep = true; + selectOnly([element]); + textActions.start(element); + break; - case 'textedit': - keep = false; - element = null; - textActions.mouseUp(evt, mouseX, mouseY); - break; + case 'path': + { + // set element to null here so that it is not removed nor finalized + element = null; // continue to be set to true so that mouseMove happens - case 'rotate': - { + started = true; + const res = pathActions.mouseUp(evt, element, mouseX, mouseY); + ({ + element + } = res); + ({ + keep + } = res); + break; + } + + case 'pathedit': keep = true; element = null; - currentMode = 'select'; - var batchCmd = canvas.undoMgr.finishUndoableChange(); - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } // perform recalculation to weed out any stray identity transforms that might get stuck - - - recalculateAllSelectedDimensions(); - call('changed', selectedElements); + pathActions.mouseUp(evt); break; + + case 'textedit': + keep = false; + element = null; + textActions.mouseUp(evt, mouseX, mouseY); + break; + + case 'rotate': + { + keep = true; + element = null; + currentMode = 'select'; + const batchCmd = canvas.undoMgr.finishUndoableChange(); + + if (!batchCmd.isEmpty()) { + addCommandToHistory(batchCmd); + } // perform recalculation to weed out any stray identity transforms that might get stuck + + + recalculateAllSelectedDimensions(); + call('changed', selectedElements); + break; + } + } + /** + * The main (left) mouse button is released (anywhere). + * @event module:svgcanvas.SvgCanvas#event:ext_mouseUp + * @type {PlainObject} + * @property {MouseEvent} event The event object + * @property {Float} mouse_x x coordinate on canvas + * @property {Float} mouse_y y coordinate on canvas + */ + + + const extResult = runExtensions('mouseUp', + /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseUp} */ + { + event: evt, + mouse_x: mouseX, + mouse_y: mouseY + }, true); + $$a.each(extResult, function (i, r) { + if (r) { + keep = r.keep || keep; + ({ + element + } = r); + started = r.started || started; } + }); + + if (!keep && !isNullish(element)) { + getCurrentDrawing().releaseId(getId()); + element.remove(); + element = null; + t = evt.target; // if this element is in a group, go up until we reach the top-level group + // just below the layer groups + // TODO: once we implement links, we also would have to check for <a> elements + + while (t && t.parentNode && t.parentNode.parentNode && t.parentNode.parentNode.tagName === 'g') { + t = t.parentNode; + } // if we are not in the middle of creating a path, and we've clicked on some shape, + // then go to Select mode. + // WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> + + + if ((currentMode !== 'path' || !drawnPath) && t && t.parentNode && t.parentNode.id !== 'selectorParentGroup' && t.id !== 'svgcanvas' && t.id !== 'svgroot') { + // switch into "select" mode if we've clicked on an element + canvas.setMode('select'); + selectOnly([t], true); + } + } else if (!isNullish(element)) { + /** + * @name module:svgcanvas.SvgCanvas#addedNew + * @type {boolean} + */ + canvas.addedNew = true; + + let aniDur = 0.2; + let cAni; + + if (opacAni.beginElement && Number.parseFloat(element.getAttribute('opacity')) !== curShape.opacity) { + cAni = $$a(opacAni).clone().attr({ + to: curShape.opacity, + dur: aniDur + }).appendTo(element); + + try { + // Fails in FF4 on foreignObject + cAni[0].beginElement(); + } catch (e) {} + } else { + aniDur = 0; + } // Ideally this would be done on the endEvent of the animation, + // but that doesn't seem to be supported in Webkit + + + setTimeout(function () { + if (cAni) { + cAni.remove(); + } + + element.setAttribute('opacity', curShape.opacity); + element.setAttribute('style', 'pointer-events:inherit'); + cleanupElement(element); + + if (currentMode === 'path') { + pathActions.toEditMode(element); + } else if (curConfig.selectNew) { + selectOnly([element], true); + } // we create the insert command that is stored on the stack + // undo means to call cmd.unapply(), redo means to call cmd.apply() + + + addCommandToHistory(new InsertElementCommand$1(element)); + call('changed', [element]); + }, aniDur * 1000); + } + + startTransform = null; + }; + + const dblClick = function (evt) { + const evtTarget = evt.target; + const parent = evtTarget.parentNode; + let mouseTarget = getMouseTarget(evt); + const { + tagName + } = mouseTarget; + + if (tagName === 'text' && currentMode !== 'textedit') { + const pt = transformPoint(evt.pageX, evt.pageY, rootSctm); + textActions.select(mouseTarget, pt.x, pt.y); + } // Do nothing if already in current group + + + if (parent === currentGroup) { + return; + } + + if ((tagName === 'g' || tagName === 'a') && getRotationAngle(mouseTarget)) { + // TODO: Allow method of in-group editing without having to do + // this (similar to editing rotated paths) + // Ungroup and regroup + pushGroupProperties(mouseTarget); + mouseTarget = selectedElements[0]; + clearSelection(true); + } // Reset context + + + if (currentGroup) { + leaveContext(); + } + + if (parent.tagName !== 'g' && parent.tagName !== 'a' || parent === getCurrentDrawing().getCurrentLayer() || mouseTarget === selectorManager.selectorParentGroup) { + // Escape from in-group edit + return; + } + + setContext(mouseTarget); + }; // prevent links from being followed in the canvas + + + const handleLinkInCanvas = function (e) { + e.preventDefault(); + return false; + }; // Added mouseup to the container here. + // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. + + + $$a(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp); // $(window).mouseup(mouseUp); + // TODO(rafaelcastrocouto): User preference for shift key and zoom factor + + $$a(container).bind('mousewheel DOMMouseScroll', + /** + * @param {Event} e + * @fires module:svgcanvas.SvgCanvas#event:updateCanvas + * @fires module:svgcanvas.SvgCanvas#event:zoomDone + * @returns {void} + */ + function (e) { + if (!e.shiftKey) { + return; + } + + e.preventDefault(); + const evt = e.originalEvent; + rootSctm = $$a('#svgcontent g')[0].getScreenCTM().inverse(); + const workarea = $$a('#workarea'); + const scrbar = 15; + const rulerwidth = curConfig.showRulers ? 16 : 0; // mouse relative to content area in content pixels + + const pt = transformPoint(evt.pageX, evt.pageY, rootSctm); // full work area width in screen pixels + + const editorFullW = workarea.width(); + const editorFullH = workarea.height(); // work area width minus scroll and ruler in screen pixels + + const editorW = editorFullW - scrbar - rulerwidth; + const editorH = editorFullH - scrbar - rulerwidth; // work area width in content pixels + + const workareaViewW = editorW * rootSctm.a; + const workareaViewH = editorH * rootSctm.d; // content offset from canvas in screen pixels + + const wOffset = workarea.offset(); + const wOffsetLeft = wOffset.left + rulerwidth; + const wOffsetTop = wOffset.top + rulerwidth; + const delta = evt.wheelDelta ? evt.wheelDelta : evt.detail ? -evt.detail : 0; + + if (!delta) { + return; + } + + let factor = Math.max(3 / 4, Math.min(4 / 3, delta)); + let wZoom, hZoom; + + if (factor > 1) { + wZoom = Math.ceil(editorW / workareaViewW * factor * 100) / 100; + hZoom = Math.ceil(editorH / workareaViewH * factor * 100) / 100; + } else { + wZoom = Math.floor(editorW / workareaViewW * factor * 100) / 100; + hZoom = Math.floor(editorH / workareaViewH * factor * 100) / 100; + } + + let zoomlevel = Math.min(wZoom, hZoom); + zoomlevel = Math.min(10, Math.max(0.01, zoomlevel)); + + if (zoomlevel === currentZoom) { + return; + } + + factor = zoomlevel / currentZoom; // top left of workarea in content pixels before zoom + + const topLeftOld = transformPoint(wOffsetLeft, wOffsetTop, rootSctm); // top left of workarea in content pixels after zoom + + const topLeftNew = { + x: pt.x - (pt.x - topLeftOld.x) / factor, + y: pt.y - (pt.y - topLeftOld.y) / factor + }; // top left of workarea in canvas pixels relative to content after zoom + + const topLeftNewCanvas = { + x: topLeftNew.x * zoomlevel, + y: topLeftNew.y * zoomlevel + }; // new center in canvas pixels + + const newCtr = { + x: topLeftNewCanvas.x - rulerwidth + editorFullW / 2, + y: topLeftNewCanvas.y - rulerwidth + editorFullH / 2 + }; + canvas.setZoom(zoomlevel); + $$a('#zoom').val((zoomlevel * 100).toFixed(1)); + call('updateCanvas', { + center: false, + newCtr + }); + call('zoomDone'); + }); + })(); + /* eslint-disable jsdoc/require-property */ + + /** + * Group: Text edit functions + * Functions relating to editing text elements. + * @namespace {PlainObject} textActions + * @memberof module:svgcanvas.SvgCanvas# + */ + + + const textActions = canvas.textActions = function () { + /* eslint-enable jsdoc/require-property */ + let curtext; + let textinput; + let cursor; + let selblock; + let blinker; + let chardata = []; + let textbb; // , transbb; + + let matrix; + let lastX, lastY; + let allowDbl; + /** + * + * @param {Integer} index + * @returns {void} + */ + + function setCursor(index) { + const empty = textinput.value === ''; + $$a(textinput).focus(); + + if (!arguments.length) { + if (empty) { + index = 0; + } else { + if (textinput.selectionEnd !== textinput.selectionStart) { + return; + } + + index = textinput.selectionEnd; + } + } + + const charbb = chardata[index]; + + if (!empty) { + textinput.setSelectionRange(index, index); + } + + cursor = getElem('text_cursor'); + + if (!cursor) { + cursor = document.createElementNS(NS.SVG, 'line'); + assignAttributes(cursor, { + id: 'text_cursor', + stroke: '#333', + 'stroke-width': 1 + }); + cursor = getElem('selectorParentGroup').appendChild(cursor); + } + + if (!blinker) { + blinker = setInterval(function () { + const show = cursor.getAttribute('display') === 'none'; + cursor.setAttribute('display', show ? 'inline' : 'none'); + }, 600); + } + + const startPt = ptToScreen(charbb.x, textbb.y); + const endPt = ptToScreen(charbb.x, textbb.y + textbb.height); + assignAttributes(cursor, { + x1: startPt.x, + y1: startPt.y, + x2: endPt.x, + y2: endPt.y, + visibility: 'visible', + display: 'inline' + }); + + if (selblock) { + selblock.setAttribute('d', ''); + } } /** - * The main (left) mouse button is released (anywhere). - * @event module:svgcanvas.SvgCanvas#event:ext_mouseUp - * @type {PlainObject} - * @property {MouseEvent} event The event object - * @property {Float} mouse_x x coordinate on canvas - * @property {Float} mouse_y y coordinate on canvas + * + * @param {Integer} start + * @param {Integer} end + * @param {boolean} skipInput + * @returns {void} + */ + + + function setSelection(start, end, skipInput) { + if (start === end) { + setCursor(end); + return; + } + + if (!skipInput) { + textinput.setSelectionRange(start, end); + } + + selblock = getElem('text_selectblock'); + + if (!selblock) { + selblock = document.createElementNS(NS.SVG, 'path'); + assignAttributes(selblock, { + id: 'text_selectblock', + fill: 'green', + opacity: 0.5, + style: 'pointer-events:none' + }); + getElem('selectorParentGroup').append(selblock); + } + + const startbb = chardata[start]; + const endbb = chardata[end]; + cursor.setAttribute('visibility', 'hidden'); + const tl = ptToScreen(startbb.x, textbb.y), + tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y), + bl = ptToScreen(startbb.x, textbb.y + textbb.height), + br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); + const dstr = 'M' + tl.x + ',' + tl.y + ' L' + tr.x + ',' + tr.y + ' ' + br.x + ',' + br.y + ' ' + bl.x + ',' + bl.y + 'z'; + assignAttributes(selblock, { + d: dstr, + display: 'inline' + }); + } + /** + * + * @param {Float} mouseX + * @param {Float} mouseY + * @returns {Integer} + */ + + + function getIndexFromPoint(mouseX, mouseY) { + // Position cursor here + const pt = svgroot.createSVGPoint(); + pt.x = mouseX; + pt.y = mouseY; // No content, so return 0 + + if (chardata.length === 1) { + return 0; + } // Determine if cursor should be on left or right of character + + + let charpos = curtext.getCharNumAtPosition(pt); + + if (charpos < 0) { + // Out of text range, look at mouse coords + charpos = chardata.length - 2; + + if (mouseX <= chardata[0].x) { + charpos = 0; + } + } else if (charpos >= chardata.length - 2) { + charpos = chardata.length - 2; + } + + const charbb = chardata[charpos]; + const mid = charbb.x + charbb.width / 2; + + if (mouseX > mid) { + charpos++; + } + + return charpos; + } + /** + * + * @param {Float} mouseX + * @param {Float} mouseY + * @returns {void} + */ + + + function setCursorFromPoint(mouseX, mouseY) { + setCursor(getIndexFromPoint(mouseX, mouseY)); + } + /** + * + * @param {Float} x + * @param {Float} y + * @param {boolean} apply + * @returns {void} + */ + + + function setEndSelectionFromPoint(x, y, apply) { + const i1 = textinput.selectionStart; + const i2 = getIndexFromPoint(x, y); + const start = Math.min(i1, i2); + const end = Math.max(i1, i2); + setSelection(start, end, !apply); + } + /** + * + * @param {Float} xIn + * @param {Float} yIn + * @returns {module:math.XYObject} + */ + + + function screenToPt(xIn, yIn) { + const out = { + x: xIn, + y: yIn + }; + out.x /= currentZoom; + out.y /= currentZoom; + + if (matrix) { + const pt = transformPoint(out.x, out.y, matrix.inverse()); + out.x = pt.x; + out.y = pt.y; + } + + return out; + } + /** + * + * @param {Float} xIn + * @param {Float} yIn + * @returns {module:math.XYObject} + */ + + + function ptToScreen(xIn, yIn) { + const out = { + x: xIn, + y: yIn + }; + + if (matrix) { + const pt = transformPoint(out.x, out.y, matrix); + out.x = pt.x; + out.y = pt.y; + } + + out.x *= currentZoom; + out.y *= currentZoom; + return out; + } + /* + // Not currently in use + function hideCursor () { + if (cursor) { + cursor.setAttribute('visibility', 'hidden'); + } + } */ + /** + * + * @param {Event} evt + * @returns {void} + */ - var extResult = runExtensions('mouseUp', - /** @type {module:svgcanvas.SvgCanvas#event:ext_mouseUp} */ - { - event: evt, - mouse_x: mouseX, - mouse_y: mouseY - }, true); - $$9.each(extResult, function (i, r) { - if (r) { - keep = r.keep || keep; - element = r.element; - started = r.started || started; + + function selectAll(evt) { + setSelection(0, curtext.textContent.length); + $$a(this).unbind(evt); + } + /** + * + * @param {Event} evt + * @returns {void} + */ + + + function selectWord(evt) { + if (!allowDbl || !curtext) { + return; } - }); - - if (!keep && !isNullish(element)) { - getCurrentDrawing().releaseId(getId()); - element.remove(); - element = null; - t = evt.target; // if this element is in a group, go up until we reach the top-level group - // just below the layer groups - // TODO: once we implement links, we also would have to check for <a> elements - - while (t && t.parentNode && t.parentNode.parentNode && t.parentNode.parentNode.tagName === 'g') { - t = t.parentNode; - } // if we are not in the middle of creating a path, and we've clicked on some shape, - // then go to Select mode. - // WebKit returns <div> when the canvas is clicked, Firefox/Opera return <svg> - - - if ((currentMode !== 'path' || !drawnPath) && t && t.parentNode && t.parentNode.id !== 'selectorParentGroup' && t.id !== 'svgcanvas' && t.id !== 'svgroot') { - // switch into "select" mode if we've clicked on an element - canvas.setMode('select'); - selectOnly([t], true); - } - } else if (!isNullish(element)) { - /** - * @name module:svgcanvas.SvgCanvas#addedNew - * @type {boolean} - */ - canvas.addedNew = true; - - var aniDur = 0.2; - var cAni; - - if (opacAni.beginElement && Number.parseFloat(element.getAttribute('opacity')) !== curShape.opacity) { - cAni = $$9(opacAni).clone().attr({ - to: curShape.opacity, - dur: aniDur - }).appendTo(element); - - try { - // Fails in FF4 on foreignObject - cAni[0].beginElement(); - } catch (e) {} - } else { - aniDur = 0; - } // Ideally this would be done on the endEvent of the animation, - // but that doesn't seem to be supported in Webkit + const ept = transformPoint(evt.pageX, evt.pageY, rootSctm), + mouseX = ept.x * currentZoom, + mouseY = ept.y * currentZoom; + const pt = screenToPt(mouseX, mouseY); + const index = getIndexFromPoint(pt.x, pt.y); + const str = curtext.textContent; + const first = str.substr(0, index).replace(/[a-z\d]+$/i, '').length; + const m = str.substr(index).match(/^[a-z\d]+/i); + const last = (m ? m[0].length : 0) + index; + setSelection(first, last); // Set tripleclick + $$a(evt.target).click(selectAll); setTimeout(function () { - if (cAni) { - cAni.remove(); + $$a(evt.target).unbind('click', selectAll); + }, 300); + } + + return ( + /** @lends module:svgcanvas.SvgCanvas#textActions */ + { + /** + * @param {Element} target + * @param {Float} x + * @param {Float} y + * @returns {void} + */ + select(target, x, y) { + curtext = target; + textActions.toEditMode(x, y); + }, + + /** + * @param {Element} elem + * @returns {void} + */ + start(elem) { + curtext = elem; + textActions.toEditMode(); + }, + + /** + * @param {external:MouseEvent} evt + * @param {Element} mouseTarget + * @param {Float} startX + * @param {Float} startY + * @returns {void} + */ + mouseDown(evt, mouseTarget, startX, startY) { + const pt = screenToPt(startX, startY); + textinput.focus(); + setCursorFromPoint(pt.x, pt.y); + lastX = startX; + lastY = startY; // TODO: Find way to block native selection + }, + + /** + * @param {Float} mouseX + * @param {Float} mouseY + * @returns {void} + */ + mouseMove(mouseX, mouseY) { + const pt = screenToPt(mouseX, mouseY); + setEndSelectionFromPoint(pt.x, pt.y); + }, + + /** + * @param {external:MouseEvent} evt + * @param {Float} mouseX + * @param {Float} mouseY + * @returns {void} + */ + mouseUp(evt, mouseX, mouseY) { + const pt = screenToPt(mouseX, mouseY); + setEndSelectionFromPoint(pt.x, pt.y, true); // TODO: Find a way to make this work: Use transformed BBox instead of evt.target + // if (lastX === mouseX && lastY === mouseY + // && !rectsIntersect(transbb, {x: pt.x, y: pt.y, width: 0, height: 0})) { + // textActions.toSelectMode(true); + // } + + if (evt.target !== curtext && mouseX < lastX + 2 && mouseX > lastX - 2 && mouseY < lastY + 2 && mouseY > lastY - 2) { + textActions.toSelectMode(true); + } + }, + + /** + * @function + * @param {Integer} index + * @returns {void} + */ + setCursor, + + /** + * @param {Float} x + * @param {Float} y + * @returns {void} + */ + toEditMode(x, y) { + allowDbl = false; + currentMode = 'textedit'; + selectorManager.requestSelector(curtext).showGrips(false); // Make selector group accept clicks + + /* const selector = */ + + selectorManager.requestSelector(curtext); // Do we need this? Has side effect of setting lock, so keeping for now, but next line wasn't being used + // const sel = selector.selectorRect; + + textActions.init(); + $$a(curtext).css('cursor', 'text'); // if (supportsEditableText()) { + // curtext.setAttribute('editable', 'simple'); + // return; + // } + + if (!arguments.length) { + setCursor(); + } else { + const pt = screenToPt(x, y); + setCursorFromPoint(pt.x, pt.y); + } + + setTimeout(function () { + allowDbl = true; + }, 300); + }, + + /** + * @param {boolean|Element} selectElem + * @fires module:svgcanvas.SvgCanvas#event:selected + * @returns {void} + */ + toSelectMode(selectElem) { + currentMode = 'select'; + clearInterval(blinker); + blinker = null; + + if (selblock) { + $$a(selblock).attr('display', 'none'); + } + + if (cursor) { + $$a(cursor).attr('visibility', 'hidden'); + } + + $$a(curtext).css('cursor', 'move'); + + if (selectElem) { + clearSelection(); + $$a(curtext).css('cursor', 'move'); + call('selected', [curtext]); + addToSelection([curtext], true); + } + + if (curtext && !curtext.textContent.length) { + // No content, so delete + canvas.deleteSelectedElements(); + } + + $$a(textinput).blur(); + curtext = false; // if (supportsEditableText()) { + // curtext.removeAttribute('editable'); + // } + }, + + /** + * @param {Element} elem + * @returns {void} + */ + setInputElem(elem) { + textinput = elem; // $(textinput).blur(hideCursor); + }, + + /** + * @returns {void} + */ + clear() { + if (currentMode === 'textedit') { + textActions.toSelectMode(); + } + }, + + /** + * @param {Element} inputElem Not in use + * @returns {void} + */ + init(inputElem) { + if (!curtext) { + return; + } + + let i, end; // if (supportsEditableText()) { + // curtext.select(); + // return; + // } + + if (!curtext.parentNode) { + // Result of the ffClone, need to get correct element + curtext = selectedElements[0]; + selectorManager.requestSelector(curtext).showGrips(false); + } + + const str = curtext.textContent; + const len = str.length; + const xform = curtext.getAttribute('transform'); + textbb = getBBox(curtext); + matrix = xform ? getMatrix(curtext) : null; + chardata = []; + chardata.length = len; + textinput.focus(); + $$a(curtext).unbind('dblclick', selectWord).dblclick(selectWord); + + if (!len) { + end = { + x: textbb.x + textbb.width / 2, + width: 0 + }; + } + + for (i = 0; i < len; i++) { + const start = curtext.getStartPositionOfChar(i); + end = curtext.getEndPositionOfChar(i); + + if (!supportsGoodTextCharPos()) { + const offset = canvas.contentW * currentZoom; + start.x -= offset; + end.x -= offset; + start.x /= currentZoom; + end.x /= currentZoom; + } // Get a "bbox" equivalent for each character. Uses the + // bbox data of the actual text for y, height purposes + // TODO: Decide if y, width and height are actually necessary + + + chardata[i] = { + x: start.x, + y: textbb.y, + // start.y? + width: end.x - start.x, + height: textbb.height + }; + } // Add a last bbox for cursor at end of text + + + chardata.push({ + x: end.x, + width: 0 + }); + setSelection(textinput.selectionStart, textinput.selectionEnd, true); } - element.setAttribute('opacity', curShape.opacity); - element.setAttribute('style', 'pointer-events:inherit'); - cleanupElement(element); - - if (currentMode === 'path') { - pathActions$1.toEditMode(element); - } else if (curConfig.selectNew) { - selectOnly([element], true); - } // we create the insert command that is stored on the stack - // undo means to call cmd.unapply(), redo means to call cmd.apply() - - - addCommandToHistory(new InsertElementCommand$1(element)); - call('changed', [element]); - }, aniDur * 1000); - } - - startTransform = null; - }; - - var dblClick = function dblClick(evt) { - var evtTarget = evt.target; - var parent = evtTarget.parentNode; - var mouseTarget = getMouseTarget(evt); - var _mouseTarget = mouseTarget, - tagName = _mouseTarget.tagName; - - if (tagName === 'text' && currentMode !== 'textedit') { - var pt = transformPoint(evt.pageX, evt.pageY, rootSctm); - textActions.select(mouseTarget, pt.x, pt.y); - } // Do nothing if already in current group - - - if (parent === currentGroup) { - return; - } - - if ((tagName === 'g' || tagName === 'a') && getRotationAngle(mouseTarget)) { - // TODO: Allow method of in-group editing without having to do - // this (similar to editing rotated paths) - // Ungroup and regroup - pushGroupProperties(mouseTarget); - mouseTarget = selectedElements[0]; - clearSelection(true); - } // Reset context - - - if (currentGroup) { - leaveContext(); - } - - if (parent.tagName !== 'g' && parent.tagName !== 'a' || parent === getCurrentDrawing().getCurrentLayer() || mouseTarget === selectorManager.selectorParentGroup) { - // Escape from in-group edit - return; - } - - setContext(mouseTarget); - }; // prevent links from being followed in the canvas - - - var handleLinkInCanvas = function handleLinkInCanvas(e) { - e.preventDefault(); - return false; - }; // Added mouseup to the container here. - // TODO(codedread): Figure out why after the Closure compiler, the window mouseup is ignored. - - - $$9(container).mousedown(mouseDown).mousemove(mouseMove).click(handleLinkInCanvas).dblclick(dblClick).mouseup(mouseUp); // $(window).mouseup(mouseUp); - // TODO(rafaelcastrocouto): User preference for shift key and zoom factor - - $$9(container).bind('mousewheel DOMMouseScroll', - /** - * @param {Event} e - * @fires module:svgcanvas.SvgCanvas#event:updateCanvas - * @fires module:svgcanvas.SvgCanvas#event:zoomDone - * @returns {void} - */ - function (e) { - if (!e.shiftKey) { - return; - } - - e.preventDefault(); - var evt = e.originalEvent; - rootSctm = $$9('#svgcontent g')[0].getScreenCTM().inverse(); - var workarea = $$9('#workarea'); - var scrbar = 15; - var rulerwidth = curConfig.showRulers ? 16 : 0; // mouse relative to content area in content pixels - - var pt = transformPoint(evt.pageX, evt.pageY, rootSctm); // full work area width in screen pixels - - var editorFullW = workarea.width(); - var editorFullH = workarea.height(); // work area width minus scroll and ruler in screen pixels - - var editorW = editorFullW - scrbar - rulerwidth; - var editorH = editorFullH - scrbar - rulerwidth; // work area width in content pixels - - var workareaViewW = editorW * rootSctm.a; - var workareaViewH = editorH * rootSctm.d; // content offset from canvas in screen pixels - - var wOffset = workarea.offset(); - var wOffsetLeft = wOffset.left + rulerwidth; - var wOffsetTop = wOffset.top + rulerwidth; - var delta = evt.wheelDelta ? evt.wheelDelta : evt.detail ? -evt.detail : 0; - - if (!delta) { - return; - } - - var factor = Math.max(3 / 4, Math.min(4 / 3, delta)); - var wZoom, hZoom; - - if (factor > 1) { - wZoom = Math.ceil(editorW / workareaViewW * factor * 100) / 100; - hZoom = Math.ceil(editorH / workareaViewH * factor * 100) / 100; - } else { - wZoom = Math.floor(editorW / workareaViewW * factor * 100) / 100; - hZoom = Math.floor(editorH / workareaViewH * factor * 100) / 100; - } - - var zoomlevel = Math.min(wZoom, hZoom); - zoomlevel = Math.min(10, Math.max(0.01, zoomlevel)); - - if (zoomlevel === currentZoom) { - return; - } - - factor = zoomlevel / currentZoom; // top left of workarea in content pixels before zoom - - var topLeftOld = transformPoint(wOffsetLeft, wOffsetTop, rootSctm); // top left of workarea in content pixels after zoom - - var topLeftNew = { - x: pt.x - (pt.x - topLeftOld.x) / factor, - y: pt.y - (pt.y - topLeftOld.y) / factor - }; // top left of workarea in canvas pixels relative to content after zoom - - var topLeftNewCanvas = { - x: topLeftNew.x * zoomlevel, - y: topLeftNew.y * zoomlevel - }; // new center in canvas pixels - - var newCtr = { - x: topLeftNewCanvas.x - rulerwidth + editorFullW / 2, - y: topLeftNewCanvas.y - rulerwidth + editorFullH / 2 - }; - canvas.setZoom(zoomlevel); - $$9('#zoom').val((zoomlevel * 100).toFixed(1)); - call('updateCanvas', { - center: false, - newCtr: newCtr - }); - call('zoomDone'); - }); - })(); - /* eslint-disable jsdoc/require-property */ - - /** - * Group: Text edit functions - * Functions relating to editing text elements. - * @namespace {PlainObject} textActions - * @memberof module:svgcanvas.SvgCanvas# - */ - - - var textActions = canvas.textActions = function () { - /* eslint-enable jsdoc/require-property */ - var curtext; - var textinput; - var cursor; - var selblock; - var blinker; - var chardata = []; - var textbb; // , transbb; - - var matrix; - var lastX, lastY; - var allowDbl; - /** - * - * @param {Integer} index - * @returns {void} - */ - - function setCursor(index) { - var empty = textinput.value === ''; - $$9(textinput).focus(); - - if (!arguments.length) { - if (empty) { - index = 0; - } else { - if (textinput.selectionEnd !== textinput.selectionStart) { - return; - } - - index = textinput.selectionEnd; } - } - - var charbb = chardata[index]; - - if (!empty) { - textinput.setSelectionRange(index, index); - } - - cursor = getElem('text_cursor'); - - if (!cursor) { - cursor = document.createElementNS(NS.SVG, 'line'); - assignAttributes(cursor, { - id: 'text_cursor', - stroke: '#333', - 'stroke-width': 1 - }); - cursor = getElem('selectorParentGroup').appendChild(cursor); - } - - if (!blinker) { - blinker = setInterval(function () { - var show = cursor.getAttribute('display') === 'none'; - cursor.setAttribute('display', show ? 'inline' : 'none'); - }, 600); - } - - var startPt = ptToScreen(charbb.x, textbb.y); - var endPt = ptToScreen(charbb.x, textbb.y + textbb.height); - assignAttributes(cursor, { - x1: startPt.x, - y1: startPt.y, - x2: endPt.x, - y2: endPt.y, - visibility: 'visible', - display: 'inline' - }); - - if (selblock) { - selblock.setAttribute('d', ''); - } - } + ); + }(); /** - * - * @param {Integer} start - * @param {Integer} end - * @param {boolean} skipInput - * @returns {void} - */ - - - function setSelection(start, end, skipInput) { - if (start === end) { - setCursor(end); - return; - } - - if (!skipInput) { - textinput.setSelectionRange(start, end); - } - - selblock = getElem('text_selectblock'); - - if (!selblock) { - selblock = document.createElementNS(NS.SVG, 'path'); - assignAttributes(selblock, { - id: 'text_selectblock', - fill: 'green', - opacity: 0.5, - style: 'pointer-events:none' - }); - getElem('selectorParentGroup').append(selblock); - } - - var startbb = chardata[start]; - var endbb = chardata[end]; - cursor.setAttribute('visibility', 'hidden'); - var tl = ptToScreen(startbb.x, textbb.y), - tr = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y), - bl = ptToScreen(startbb.x, textbb.y + textbb.height), - br = ptToScreen(startbb.x + (endbb.x - startbb.x), textbb.y + textbb.height); - var dstr = 'M' + tl.x + ',' + tl.y + ' L' + tr.x + ',' + tr.y + ' ' + br.x + ',' + br.y + ' ' + bl.x + ',' + bl.y + 'z'; - assignAttributes(selblock, { - d: dstr, - display: 'inline' - }); - } - /** - * - * @param {Float} mouseX - * @param {Float} mouseY - * @returns {Integer} - */ - - - function getIndexFromPoint(mouseX, mouseY) { - // Position cursor here - var pt = svgroot.createSVGPoint(); - pt.x = mouseX; - pt.y = mouseY; // No content, so return 0 - - if (chardata.length === 1) { - return 0; - } // Determine if cursor should be on left or right of character - - - var charpos = curtext.getCharNumAtPosition(pt); - - if (charpos < 0) { - // Out of text range, look at mouse coords - charpos = chardata.length - 2; - - if (mouseX <= chardata[0].x) { - charpos = 0; - } - } else if (charpos >= chardata.length - 2) { - charpos = chardata.length - 2; - } - - var charbb = chardata[charpos]; - var mid = charbb.x + charbb.width / 2; - - if (mouseX > mid) { - charpos++; - } - - return charpos; - } - /** - * - * @param {Float} mouseX - * @param {Float} mouseY - * @returns {void} - */ - - - function setCursorFromPoint(mouseX, mouseY) { - setCursor(getIndexFromPoint(mouseX, mouseY)); - } - /** - * - * @param {Float} x - * @param {Float} y - * @param {boolean} apply - * @returns {void} - */ - - - function setEndSelectionFromPoint(x, y, apply) { - var i1 = textinput.selectionStart; - var i2 = getIndexFromPoint(x, y); - var start = Math.min(i1, i2); - var end = Math.max(i1, i2); - setSelection(start, end, !apply); - } - /** - * - * @param {Float} xIn - * @param {Float} yIn - * @returns {module:math.XYObject} - */ - - - function screenToPt(xIn, yIn) { - var out = { - x: xIn, - y: yIn - }; - out.x /= currentZoom; - out.y /= currentZoom; - - if (matrix) { - var pt = transformPoint(out.x, out.y, matrix.inverse()); - out.x = pt.x; - out.y = pt.y; - } - - return out; - } - /** - * - * @param {Float} xIn - * @param {Float} yIn - * @returns {module:math.XYObject} - */ - - - function ptToScreen(xIn, yIn) { - var out = { - x: xIn, - y: yIn - }; - - if (matrix) { - var pt = transformPoint(out.x, out.y, matrix); - out.x = pt.x; - out.y = pt.y; - } - - out.x *= currentZoom; - out.y *= currentZoom; - return out; - } - /* - // Not currently in use - function hideCursor () { - if (cursor) { - cursor.setAttribute('visibility', 'hidden'); - } - } + * Group: Serialization. */ /** - * - * @param {Event} evt - * @returns {void} - */ + * Looks at DOM elements inside the `<defs>` to see if they are referred to, + * removes them from the DOM if they are not. + * @function module:svgcanvas.SvgCanvas#removeUnusedDefElems + * @returns {Integer} The number of elements that were removed + */ - function selectAll(evt) { - setSelection(0, curtext.textContent.length); - $$9(this).unbind(evt); - } + const removeUnusedDefElems = this.removeUnusedDefElems = function () { + const defs = svgcontent.getElementsByTagNameNS(NS.SVG, 'defs'); + + if (!defs || !defs.length) { + return 0; + } // if (!defs.firstChild) { return; } + + + const defelemUses = []; + let numRemoved = 0; + const attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']; + const alen = attrs.length; + const allEls = svgcontent.getElementsByTagNameNS(NS.SVG, '*'); + const allLen = allEls.length; + let i, j; + + for (i = 0; i < allLen; i++) { + const el = allEls[i]; + + for (j = 0; j < alen; j++) { + const ref = getUrlFromAttr(el.getAttribute(attrs[j])); + + if (ref) { + defelemUses.push(ref.substr(1)); + } + } // gradients can refer to other gradients + + + const href = getHref(el); + + if (href && href.startsWith('#')) { + defelemUses.push(href.substr(1)); + } + } + + const defelems = $$a(defs).find('linearGradient, radialGradient, filter, marker, svg, symbol'); + i = defelems.length; + + while (i--) { + const defelem = defelems[i]; + const { + id + } = defelem; + + if (!defelemUses.includes(id)) { + // Not found, so remove (but remember) + removedElements[id] = defelem; + defelem.remove(); + numRemoved++; + } + } + + return numRemoved; + }; /** - * - * @param {Event} evt - * @returns {void} - */ + * Main function to set up the SVG content for output. + * @function module:svgcanvas.SvgCanvas#svgCanvasToString + * @returns {string} The SVG image for output + */ - function selectWord(evt) { - if (!allowDbl || !curtext) { - return; - } - - var ept = transformPoint(evt.pageX, evt.pageY, rootSctm), - mouseX = ept.x * currentZoom, - mouseY = ept.y * currentZoom; - var pt = screenToPt(mouseX, mouseY); - var index = getIndexFromPoint(pt.x, pt.y); - var str = curtext.textContent; - var first = str.substr(0, index).replace(/[a-z\d]+$/i, '').length; - var m = str.substr(index).match(/^[a-z\d]+/i); - var last = (m ? m[0].length : 0) + index; - setSelection(first, last); // Set tripleclick - - $$9(evt.target).click(selectAll); - setTimeout(function () { - $$9(evt.target).unbind('click', selectAll); - }, 300); - } - - return ( - /** @lends module:svgcanvas.SvgCanvas#textActions */ - { - /** - * @param {Element} target - * @param {Float} x - * @param {Float} y - * @returns {void} - */ - select: function select(target, x, y) { - curtext = target; - textActions.toEditMode(x, y); - }, - - /** - * @param {Element} elem - * @returns {void} - */ - start: function start(elem) { - curtext = elem; - textActions.toEditMode(); - }, - - /** - * @param {external:MouseEvent} evt - * @param {Element} mouseTarget - * @param {Float} startX - * @param {Float} startY - * @returns {void} - */ - mouseDown: function mouseDown(evt, mouseTarget, startX, startY) { - var pt = screenToPt(startX, startY); - textinput.focus(); - setCursorFromPoint(pt.x, pt.y); - lastX = startX; - lastY = startY; // TODO: Find way to block native selection - }, - - /** - * @param {Float} mouseX - * @param {Float} mouseY - * @returns {void} - */ - mouseMove: function mouseMove(mouseX, mouseY) { - var pt = screenToPt(mouseX, mouseY); - setEndSelectionFromPoint(pt.x, pt.y); - }, - - /** - * @param {external:MouseEvent} evt - * @param {Float} mouseX - * @param {Float} mouseY - * @returns {void} - */ - mouseUp: function mouseUp(evt, mouseX, mouseY) { - var pt = screenToPt(mouseX, mouseY); - setEndSelectionFromPoint(pt.x, pt.y, true); // TODO: Find a way to make this work: Use transformed BBox instead of evt.target - // if (lastX === mouseX && lastY === mouseY - // && !rectsIntersect(transbb, {x: pt.x, y: pt.y, width: 0, height: 0})) { - // textActions.toSelectMode(true); - // } - - if (evt.target !== curtext && mouseX < lastX + 2 && mouseX > lastX - 2 && mouseY < lastY + 2 && mouseY > lastY - 2) { - textActions.toSelectMode(true); - } - }, - - /** - * @function - * @param {Integer} index - * @returns {void} - */ - setCursor: setCursor, - - /** - * @param {Float} x - * @param {Float} y - * @returns {void} - */ - toEditMode: function toEditMode(x, y) { - allowDbl = false; - currentMode = 'textedit'; - selectorManager.requestSelector(curtext).showGrips(false); // Make selector group accept clicks - - /* const selector = */ - - selectorManager.requestSelector(curtext); // Do we need this? Has side effect of setting lock, so keeping for now, but next line wasn't being used - // const sel = selector.selectorRect; - - textActions.init(); - $$9(curtext).css('cursor', 'text'); // if (supportsEditableText()) { - // curtext.setAttribute('editable', 'simple'); - // return; - // } - - if (!arguments.length) { - setCursor(); - } else { - var pt = screenToPt(x, y); - setCursorFromPoint(pt.x, pt.y); - } - - setTimeout(function () { - allowDbl = true; - }, 300); - }, - - /** - * @param {boolean|Element} selectElem - * @fires module:svgcanvas.SvgCanvas#event:selected - * @returns {void} - */ - toSelectMode: function toSelectMode(selectElem) { - currentMode = 'select'; - clearInterval(blinker); - blinker = null; - - if (selblock) { - $$9(selblock).attr('display', 'none'); - } - - if (cursor) { - $$9(cursor).attr('visibility', 'hidden'); - } - - $$9(curtext).css('cursor', 'move'); - - if (selectElem) { - clearSelection(); - $$9(curtext).css('cursor', 'move'); - call('selected', [curtext]); - addToSelection([curtext], true); - } - - if (curtext && !curtext.textContent.length) { - // No content, so delete - canvas.deleteSelectedElements(); - } - - $$9(textinput).blur(); - curtext = false; // if (supportsEditableText()) { - // curtext.removeAttribute('editable'); - // } - }, - - /** - * @param {Element} elem - * @returns {void} - */ - setInputElem: function setInputElem(elem) { - textinput = elem; // $(textinput).blur(hideCursor); - }, - - /** - * @returns {void} - */ - clear: function clear() { - if (currentMode === 'textedit') { - textActions.toSelectMode(); - } - }, - - /** - * @param {Element} inputElem Not in use - * @returns {void} - */ - init: function init(inputElem) { - if (!curtext) { - return; - } - - var i, end; // if (supportsEditableText()) { - // curtext.select(); - // return; - // } - - if (!curtext.parentNode) { - // Result of the ffClone, need to get correct element - curtext = selectedElements[0]; - selectorManager.requestSelector(curtext).showGrips(false); - } - - var str = curtext.textContent; - var len = str.length; - var xform = curtext.getAttribute('transform'); - textbb = getBBox(curtext); - matrix = xform ? getMatrix(curtext) : null; - chardata = []; - chardata.length = len; - textinput.focus(); - $$9(curtext).unbind('dblclick', selectWord).dblclick(selectWord); - - if (!len) { - end = { - x: textbb.x + textbb.width / 2, - width: 0 - }; - } - - for (i = 0; i < len; i++) { - var start = curtext.getStartPositionOfChar(i); - end = curtext.getEndPositionOfChar(i); - - if (!supportsGoodTextCharPos()) { - var offset = canvas.contentW * currentZoom; - start.x -= offset; - end.x -= offset; - start.x /= currentZoom; - end.x /= currentZoom; - } // Get a "bbox" equivalent for each character. Uses the - // bbox data of the actual text for y, height purposes - // TODO: Decide if y, width and height are actually necessary + this.svgCanvasToString = function () { + // keep calling it until there are none to remove + while (removeUnusedDefElems() > 0) {} // eslint-disable-line no-empty - chardata[i] = { - x: start.x, - y: textbb.y, - // start.y? - width: end.x - start.x, - height: textbb.height - }; - } // Add a last bbox for cursor at end of text + pathActions.clear(true); // Keep SVG-Edit comment on top - - chardata.push({ - x: end.x, - width: 0 - }); - setSelection(textinput.selectionStart, textinput.selectionEnd, true); + $$a.each(svgcontent.childNodes, function (i, node) { + if (i && node.nodeType === 8 && node.data.includes('Created with')) { + svgcontent.firstChild.before(node); } + }); // Move out of in-group editing mode + + if (currentGroup) { + leaveContext(); + selectOnly([currentGroup]); } - ); - }(); - /** - * Group: Serialization. - */ - /** - * Looks at DOM elements inside the `<defs>` to see if they are referred to, - * removes them from the DOM if they are not. - * @function module:svgcanvas.SvgCanvas#removeUnusedDefElems - * @returns {Integer} The number of elements that were removed - */ + const nakedSvgs = []; // Unwrap gsvg if it has no special attributes (only id and style) + + $$a(svgcontent).find('g:data(gsvg)').each(function () { + const attrs = this.attributes; + let len = attrs.length; + + for (let i = 0; i < len; i++) { + if (attrs[i].nodeName === 'id' || attrs[i].nodeName === 'style') { + len--; + } + } // No significant attributes, so ungroup - var removeUnusedDefElems = this.removeUnusedDefElems = function () { - var defs = svgcontent.getElementsByTagNameNS(NS.SVG, 'defs'); - - if (!defs || !defs.length) { - return 0; - } // if (!defs.firstChild) { return; } - - - var defelemUses = []; - var numRemoved = 0; - var attrs = ['fill', 'stroke', 'filter', 'marker-start', 'marker-mid', 'marker-end']; - var alen = attrs.length; - var allEls = svgcontent.getElementsByTagNameNS(NS.SVG, '*'); - var allLen = allEls.length; - var i, j; - - for (i = 0; i < allLen; i++) { - var el = allEls[i]; - - for (j = 0; j < alen; j++) { - var ref = getUrlFromAttr(el.getAttribute(attrs[j])); - - if (ref) { - defelemUses.push(ref.substr(1)); + if (len <= 0) { + const svg = this.firstChild; + nakedSvgs.push(svg); + $$a(this).replaceWith(svg); } - } // gradients can refer to other gradients - - - var href = getHref(el); - - if (href && href.startsWith('#')) { - defelemUses.push(href.substr(1)); - } - } - - var defelems = $$9(defs).find('linearGradient, radialGradient, filter, marker, svg, symbol'); - i = defelems.length; - - while (i--) { - var defelem = defelems[i]; - var id = defelem.id; - - if (!defelemUses.includes(id)) { - // Not found, so remove (but remember) - removedElements[id] = defelem; - defelem.remove(); - numRemoved++; - } - } - - return numRemoved; - }; - /** - * Main function to set up the SVG content for output. - * @function module:svgcanvas.SvgCanvas#svgCanvasToString - * @returns {string} The SVG image for output - */ - - - this.svgCanvasToString = function () { - // keep calling it until there are none to remove - while (removeUnusedDefElems() > 0) {} // eslint-disable-line no-empty - - - pathActions$1.clear(true); // Keep SVG-Edit comment on top - - $$9.each(svgcontent.childNodes, function (i, node) { - if (i && node.nodeType === 8 && node.data.includes('Created with')) { - svgcontent.firstChild.before(node); - } - }); // Move out of in-group editing mode - - if (currentGroup) { - leaveContext(); - selectOnly([currentGroup]); - } - - var nakedSvgs = []; // Unwrap gsvg if it has no special attributes (only id and style) - - $$9(svgcontent).find('g:data(gsvg)').each(function () { - var attrs = this.attributes; - var len = attrs.length; - - for (var i = 0; i < len; i++) { - if (attrs[i].nodeName === 'id' || attrs[i].nodeName === 'style') { - len--; - } - } // No significant attributes, so ungroup - - - if (len <= 0) { - var svg = this.firstChild; - nakedSvgs.push(svg); - $$9(this).replaceWith(svg); - } - }); - var output = this.svgToString(svgcontent, 0); // Rewrap gsvg - - if (nakedSvgs.length) { - $$9(nakedSvgs).each(function () { - groupSvgElem(this); }); - } + const output = this.svgToString(svgcontent, 0); // Rewrap gsvg - return output; - }; - /** - * Sub function ran on each SVG element to convert it to a string as desired. - * @function module:svgcanvas.SvgCanvas#svgToString - * @param {Element} elem - The SVG element to convert - * @param {Integer} indent - Number of spaces to indent this tag - * @returns {string} The given element as an SVG tag - */ - - - this.svgToString = function (elem, indent) { - var out = []; - var unit = curConfig.baseUnit; - var unitRe = new RegExp('^-?[\\d\\.]+' + unit + '$'); - - if (elem) { - cleanupElement(elem); - - var attrs = _toConsumableArray(elem.attributes); - - var childs = elem.childNodes; - attrs.sort(function (a, b) { - return a.name > b.name ? -1 : 1; - }); - - for (var i = 0; i < indent; i++) { - out.push(' '); - } - - out.push('<'); - out.push(elem.nodeName); - - if (elem.id === 'svgcontent') { - // Process root element separately - var res = getResolution(); - var vb = ''; // TODO: Allow this by dividing all values by current baseVal - // Note that this also means we should properly deal with this on import - // if (curConfig.baseUnit !== 'px') { - // const unit = curConfig.baseUnit; - // const unitM = getTypeMap()[unit]; - // res.w = shortFloat(res.w / unitM); - // res.h = shortFloat(res.h / unitM); - // vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"'; - // res.w += unit; - // res.h += unit; - // } - - if (unit !== 'px') { - res.w = convertUnit(res.w, unit) + unit; - res.h = convertUnit(res.h, unit) + unit; - } - - out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="' + NS.SVG + '"'); - var nsuris = {}; // Check elements for namespaces, add if found - - $$9(elem).find('*').andSelf().each(function () { - // const el = this; - // for some elements have no attribute - var uri = this.namespaceURI; - - if (uri && !nsuris[uri] && nsMap[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml') { - nsuris[uri] = true; - out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"'); - } - - $$9.each(this.attributes, function (i, attr) { - var u = attr.namespaceURI; - - if (u && !nsuris[u] && nsMap[u] !== 'xmlns' && nsMap[u] !== 'xml') { - nsuris[u] = true; - out.push(' xmlns:' + nsMap[u] + '="' + u + '"'); - } - }); + if (nakedSvgs.length) { + $$a(nakedSvgs).each(function () { + groupSvgElem(this); }); - var _i2 = attrs.length; - var attrNames = ['width', 'height', 'xmlns', 'x', 'y', 'viewBox', 'id', 'overflow']; - - while (_i2--) { - var attr = attrs[_i2]; - var attrVal = toXml(attr.value); // Namespaces have already been dealt with, so skip - - if (attr.nodeName.startsWith('xmlns:')) { - continue; - } // only serialize attributes we don't use internally - - - if (attrVal !== '' && !attrNames.includes(attr.localName)) { - if (!attr.namespaceURI || nsMap[attr.namespaceURI]) { - out.push(' '); - out.push(attr.nodeName); - out.push('="'); - out.push(attrVal); - out.push('"'); - } - } - } - } else { - // Skip empty defs - if (elem.nodeName === 'defs' && !elem.firstChild) { - return ''; - } - - var mozAttrs = ['-moz-math-font-style', '_moz-math-font-style']; - - for (var _i3 = attrs.length - 1; _i3 >= 0; _i3--) { - var _attr = attrs[_i3]; - - var _attrVal = toXml(_attr.value); // remove bogus attributes added by Gecko - - - if (mozAttrs.includes(_attr.localName)) { - continue; - } - - if (_attrVal === 'null') { - var styleName = _attr.localName.replace(/-[a-z]/g, function (s) { - return s[1].toUpperCase(); - }); - - if (Object.prototype.hasOwnProperty.call(elem.style, styleName)) { - continue; - } - } - - if (_attrVal !== '') { - if (_attrVal.startsWith('pointer-events')) { - continue; - } - - if (_attr.localName === 'class' && _attrVal.startsWith('se_')) { - continue; - } - - out.push(' '); - - if (_attr.localName === 'd') { - _attrVal = pathActions$1.convertPath(elem, true); - } - - if (!isNaN(_attrVal)) { - _attrVal = shortFloat(_attrVal); - } else if (unitRe.test(_attrVal)) { - _attrVal = shortFloat(_attrVal) + unit; - } // Embed images when saving - - - if (saveOptions.apply && elem.nodeName === 'image' && _attr.localName === 'href' && saveOptions.images && saveOptions.images === 'embed') { - var img = encodableImages[_attrVal]; - - if (img) { - _attrVal = img; - } - } // map various namespaces to our fixed namespace prefixes - // (the default xmlns attribute itself does not get a prefix) - - - if (!_attr.namespaceURI || _attr.namespaceURI === NS.SVG || nsMap[_attr.namespaceURI]) { - out.push(_attr.nodeName); - out.push('="'); - out.push(_attrVal); - out.push('"'); - } - } - } } - if (elem.hasChildNodes()) { - out.push('>'); - indent++; - var bOneLine = false; + return output; + }; + /** + * Sub function ran on each SVG element to convert it to a string as desired. + * @function module:svgcanvas.SvgCanvas#svgToString + * @param {Element} elem - The SVG element to convert + * @param {Integer} indent - Number of spaces to indent this tag + * @returns {string} The given element as an SVG tag + */ - for (var _i4 = 0; _i4 < childs.length; _i4++) { - var child = childs.item(_i4); - switch (child.nodeType) { - case 1: - // element node - out.push('\n'); - out.push(this.svgToString(child, indent)); - break; + this.svgToString = function (elem, indent) { + const out = []; + const unit = curConfig.baseUnit; + const unitRe = new RegExp('^-?[\\d\\.]+' + unit + '$'); - case 3: - { - // text node - var str = child.nodeValue.replace(/^\s+|\s+$/g, ''); - - if (str !== '') { - bOneLine = true; - out.push(String(toXml(str))); - } - - break; - } - - case 4: - // cdata node - out.push('\n'); - out.push(new Array(indent + 1).join(' ')); - out.push('<![CDATA['); - out.push(child.nodeValue); - out.push(']]>'); - break; - - case 8: - // comment - out.push('\n'); - out.push(new Array(indent + 1).join(' ')); - out.push('<!--'); - out.push(child.data); - out.push('-->'); - break; - } // switch on node type + if (elem) { + cleanupElement(elem); + const attrs = [...elem.attributes]; + const childs = elem.childNodes; + attrs.sort((a, b) => { + return a.name > b.name ? -1 : 1; + }); + for (let i = 0; i < indent; i++) { + out.push(' '); } - indent--; - - if (!bOneLine) { - out.push('\n'); - - for (var _i5 = 0; _i5 < indent; _i5++) { - out.push(' '); - } - } - - out.push('</'); + out.push('<'); out.push(elem.nodeName); - out.push('>'); - } else { - out.push('/>'); - } - } - return out.join(''); - }; // end svgToString() + if (elem.id === 'svgcontent') { + // Process root element separately + const res = getResolution(); + const vb = ''; // TODO: Allow this by dividing all values by current baseVal + // Note that this also means we should properly deal with this on import + // if (curConfig.baseUnit !== 'px') { + // const unit = curConfig.baseUnit; + // const unitM = getTypeMap()[unit]; + // res.w = shortFloat(res.w / unitM); + // res.h = shortFloat(res.h / unitM); + // vb = ' viewBox="' + [0, 0, res.w, res.h].join(' ') + '"'; + // res.w += unit; + // res.h += unit; + // } - /** - * Function to run when image data is found. - * @callback module:svgcanvas.ImageEmbeddedCallback - * @param {string|false} result Data URL - * @returns {void} - */ + if (unit !== 'px') { + res.w = convertUnit(res.w, unit) + unit; + res.h = convertUnit(res.h, unit) + unit; + } - /** - * Converts a given image file to a data URL when possible, then runs a given callback. - * @function module:svgcanvas.SvgCanvas#embedImage - * @param {string} src - The path/URL of the image - * @returns {Promise<string|false>} Resolves to a Data URL (string|false) - */ + out.push(' width="' + res.w + '" height="' + res.h + '"' + vb + ' xmlns="' + NS.SVG + '"'); + const nsuris = {}; // Check elements for namespaces, add if found + + $$a(elem).find('*').andSelf().each(function () { + // const el = this; + // for some elements have no attribute + const uri = this.namespaceURI; + + if (uri && !nsuris[uri] && nsMap[uri] && nsMap[uri] !== 'xmlns' && nsMap[uri] !== 'xml') { + nsuris[uri] = true; + out.push(' xmlns:' + nsMap[uri] + '="' + uri + '"'); + } + + $$a.each(this.attributes, function (i, attr) { + const u = attr.namespaceURI; + + if (u && !nsuris[u] && nsMap[u] !== 'xmlns' && nsMap[u] !== 'xml') { + nsuris[u] = true; + out.push(' xmlns:' + nsMap[u] + '="' + u + '"'); + } + }); + }); + let i = attrs.length; + const attrNames = ['width', 'height', 'xmlns', 'x', 'y', 'viewBox', 'id', 'overflow']; + + while (i--) { + const attr = attrs[i]; + const attrVal = toXml(attr.value); // Namespaces have already been dealt with, so skip + + if (attr.nodeName.startsWith('xmlns:')) { + continue; + } // only serialize attributes we don't use internally - this.embedImage = function (src) { - // Todo: Remove this Promise in favor of making an async/await `Image.load` utility - return new Promise(function (resolve, reject) { - // eslint-disable-line promise/avoid-new - // load in the image and once it's loaded, get the dimensions - $$9(new Image()).load(function (response, status, xhr) { - if (status === 'error') { - reject(new Error('Error loading image: ' + xhr.status + ' ' + xhr.statusText)); - return; - } // create a canvas the same size as the raster image + if (attrVal !== '' && !attrNames.includes(attr.localName)) { + if (!attr.namespaceURI || nsMap[attr.namespaceURI]) { + out.push(' '); + out.push(attr.nodeName); + out.push('="'); + out.push(attrVal); + out.push('"'); + } + } + } + } else { + // Skip empty defs + if (elem.nodeName === 'defs' && !elem.firstChild) { + return ''; + } + + const mozAttrs = ['-moz-math-font-style', '_moz-math-font-style']; + + for (let i = attrs.length - 1; i >= 0; i--) { + const attr = attrs[i]; + let attrVal = toXml(attr.value); // remove bogus attributes added by Gecko + + if (mozAttrs.includes(attr.localName)) { + continue; + } + + if (attrVal === 'null') { + const styleName = attr.localName.replace(/-[a-z]/g, s => s[1].toUpperCase()); + + if (Object.prototype.hasOwnProperty.call(elem.style, styleName)) { + continue; + } + } + + if (attrVal !== '') { + if (attrVal.startsWith('pointer-events')) { + continue; + } + + if (attr.localName === 'class' && attrVal.startsWith('se_')) { + continue; + } + + out.push(' '); + + if (attr.localName === 'd') { + attrVal = pathActions.convertPath(elem, true); + } + + if (!isNaN(attrVal)) { + attrVal = shortFloat(attrVal); + } else if (unitRe.test(attrVal)) { + attrVal = shortFloat(attrVal) + unit; + } // Embed images when saving - var cvs = document.createElement('canvas'); - cvs.width = this.width; - cvs.height = this.height; // load the raster image into the canvas + if (saveOptions.apply && elem.nodeName === 'image' && attr.localName === 'href' && saveOptions.images && saveOptions.images === 'embed') { + const img = encodableImages[attrVal]; - cvs.getContext('2d').drawImage(this, 0, 0); // retrieve the data: URL + if (img) { + attrVal = img; + } + } // map various namespaces to our fixed namespace prefixes + // (the default xmlns attribute itself does not get a prefix) - try { - var urldata = ';svgedit_url=' + encodeURIComponent(src); - urldata = cvs.toDataURL().replace(';base64', urldata + ';base64'); - encodableImages[src] = urldata; - } catch (e) { - encodableImages[src] = false; + + if (!attr.namespaceURI || attr.namespaceURI === NS.SVG || nsMap[attr.namespaceURI]) { + out.push(attr.nodeName); + out.push('="'); + out.push(attrVal); + out.push('"'); + } + } + } } - lastGoodImgUrl = src; - resolve(encodableImages[src]); - }).attr('src', src); - }); - }; - /** - * Sets a given URL to be a "last good image" URL. - * @function module:svgcanvas.SvgCanvas#setGoodImage - * @param {string} val - * @returns {void} - */ + if (elem.hasChildNodes()) { + out.push('>'); + indent++; + let bOneLine = false; + for (let i = 0; i < childs.length; i++) { + const child = childs.item(i); - this.setGoodImage = function (val) { - lastGoodImgUrl = val; - }; - /** - * Does nothing by default, handled by optional widget/extension. - * @function module:svgcanvas.SvgCanvas#open - * @returns {void} - */ - - - this.open = function () { - /* */ - }; - /** - * Serializes the current drawing into SVG XML text and passes it to the 'saved' handler. - * This function also includes the XML prolog. Clients of the `SvgCanvas` bind their save - * function to the 'saved' event. - * @function module:svgcanvas.SvgCanvas#save - * @param {module:svgcanvas.SaveOptions} opts - * @fires module:svgcanvas.SvgCanvas#event:saved - * @returns {void} - */ - - - this.save = function (opts) { - // remove the selected outline before serializing - clearSelection(); // Update save options if provided - - if (opts) { - $$9.extend(saveOptions, opts); - } - - saveOptions.apply = true; // no need for doctype, see https://jwatt.org/svg/authoring/#doctype-declaration - - var str = this.svgCanvasToString(); - call('saved', str); - }; - /** - * @typedef {PlainObject} module:svgcanvas.IssuesAndCodes - * @property {string[]} issueCodes The locale-independent code names - * @property {string[]} issues The localized descriptions - */ - - /** - * Codes only is useful for locale-independent detection. - * @returns {module:svgcanvas.IssuesAndCodes} - */ - - - function getIssues() { - // remove the selected outline before serializing - clearSelection(); // Check for known CanVG issues - - var issues = []; - var issueCodes = []; // Selector and notice - - var issueList = { - feGaussianBlur: uiStrings.exportNoBlur, - foreignObject: uiStrings.exportNoforeignObject, - '[stroke-dasharray]': uiStrings.exportNoDashArray - }; - var content = $$9(svgcontent); // Add font/text check if Canvas Text API is not implemented - - if (!('font' in $$9('<canvas>')[0].getContext('2d'))) { - issueList.text = uiStrings.exportNoText; - } - - $$9.each(issueList, function (sel, descr) { - if (content.find(sel).length) { - issueCodes.push(sel); - issues.push(descr); - } - }); - return { - issues: issues, - issueCodes: issueCodes - }; - } - - var canvg; - /** - * @typedef {"feGaussianBlur"|"foreignObject"|"[stroke-dasharray]"|"text"} module:svgcanvas.IssueCode - */ - - /** - * @typedef {PlainObject} module:svgcanvas.ImageExportedResults - * @property {string} datauri Contents as a Data URL - * @property {string} bloburl May be the empty string - * @property {string} svg The SVG contents as a string - * @property {string[]} issues The localization messages of `issueCodes` - * @property {module:svgcanvas.IssueCode[]} issueCodes CanVG issues found with the SVG - * @property {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} type The chosen image type - * @property {"image/png"|"image/jpeg"|"image/bmp"|"image/webp"} mimeType The image MIME type - * @property {Float} quality A decimal between 0 and 1 (for use with JPEG or WEBP) - * @property {string} exportWindowName A convenience for passing along a `window.name` to target a window on which the export could be added - */ - - /** - * Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image, - * then calls "exported" with an object including the string, image - * information, and any issues found. - * @function module:svgcanvas.SvgCanvas#rasterExport - * @param {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} [imgType="PNG"] - * @param {Float} [quality] Between 0 and 1 - * @param {string} [exportWindowName] - * @param {PlainObject} [opts] - * @param {boolean} [opts.avoidEvent] - * @fires module:svgcanvas.SvgCanvas#event:exported - * @todo Confirm/fix ICO type - * @returns {Promise<module:svgcanvas.ImageExportedResults>} Resolves to {@link module:svgcanvas.ImageExportedResults} - */ - - this.rasterExport = /*#__PURE__*/function () { - var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(imgType, quality, exportWindowName) { - var opts, - type, - mimeType, - _getIssues, - issues, - issueCodes, - svg, - _yield$importSetGloba, - c, - _args2 = arguments; - - return regeneratorRuntime.wrap(function _callee2$(_context2) { - while (1) { - switch (_context2.prev = _context2.next) { - case 0: - opts = _args2.length > 3 && _args2[3] !== undefined ? _args2[3] : {}; - type = imgType === 'ICO' ? 'BMP' : imgType || 'PNG'; - mimeType = 'image/' + type.toLowerCase(); - _getIssues = getIssues(), issues = _getIssues.issues, issueCodes = _getIssues.issueCodes; - svg = this.svgCanvasToString(); - - if (canvg) { - _context2.next = 10; + switch (child.nodeType) { + case 1: + // element node + out.push('\n'); + out.push(this.svgToString(child, indent)); break; - } - _context2.next = 8; - return importSetGlobal(curConfig.canvgPath + 'canvg.js', { - global: 'canvg' - }); + case 3: + { + // text node + const str = child.nodeValue.replace(/^\s+|\s+$/g, ''); - case 8: - _yield$importSetGloba = _context2.sent; - canvg = _yield$importSetGloba.canvg; - - case 10: - if (!$$9('#export_canvas').length) { - $$9('<canvas>', { - id: 'export_canvas' - }).hide().appendTo('body'); - } - - c = $$9('#export_canvas')[0]; - c.width = canvas.contentW; - c.height = canvas.contentH; - _context2.next = 16; - return canvg(c, svg); - - case 16: - return _context2.abrupt("return", new Promise(function (resolve, reject) { - // eslint-disable-line promise/avoid-new - var dataURLType = type.toLowerCase(); - var datauri = quality ? c.toDataURL('image/' + dataURLType, quality) : c.toDataURL('image/' + dataURLType); - var bloburl; - /** - * Called when `bloburl` is available for export. - * @returns {void} - */ - - function done() { - var obj = { - datauri: datauri, - bloburl: bloburl, - svg: svg, - issues: issues, - issueCodes: issueCodes, - type: imgType, - mimeType: mimeType, - quality: quality, - exportWindowName: exportWindowName - }; - - if (!opts.avoidEvent) { - call('exported', obj); + if (str !== '') { + bOneLine = true; + out.push(String(toXml(str))); } - resolve(obj); + break; } - if (c.toBlob) { - c.toBlob(function (blob) { - bloburl = createObjectURL(blob); - done(); - }, mimeType, quality); - return; - } - - bloburl = dataURLToObjectURL(datauri); - done(); - })); - - case 17: - case "end": - return _context2.stop(); - } - } - }, _callee2, this); - })); - - return function (_x4, _x5, _x6) { - return _ref5.apply(this, arguments); - }; - }(); - /** - * @external jsPDF - */ - - /** - * @typedef {void|"save"|"arraybuffer"|"blob"|"datauristring"|"dataurlstring"|"dataurlnewwindow"|"datauri"|"dataurl"} external:jsPDF.OutputType - * @todo Newer version to add also allows these `outputType` values "bloburi"|"bloburl" which return strings, so document here and for `outputType` of `module:svgcanvas.PDFExportedResults` below if added - */ - - /** - * @typedef {PlainObject} module:svgcanvas.PDFExportedResults - * @property {string} svg The SVG PDF output - * @property {string|ArrayBuffer|Blob|window} output The output based on the `outputType`; - * if `undefined`, "datauristring", "dataurlstring", "datauri", - * or "dataurl", will be a string (`undefined` gives a document, while the others - * build as Data URLs; "datauri" and "dataurl" change the location of the current page); if - * "arraybuffer", will return `ArrayBuffer`; if "blob", returns a `Blob`; - * if "dataurlnewwindow", will change the current page's location and return a string - * if in Safari and no window object is found; otherwise opens in, and returns, a new `window` - * object; if "save", will have the same return as "dataurlnewwindow" if - * `navigator.getUserMedia` support is found without `URL.createObjectURL` support; otherwise - * returns `undefined` but attempts to save - * @property {external:jsPDF.OutputType} outputType - * @property {string[]} issues The human-readable localization messages of corresponding `issueCodes` - * @property {module:svgcanvas.IssueCode[]} issueCodes - * @property {string} exportWindowName - */ - - /** - * Generates a PDF based on the current image, then calls "exportedPDF" with - * an object including the string, the data URL, and any issues found. - * @function module:svgcanvas.SvgCanvas#exportPDF - * @param {string} [exportWindowName] Will also be used for the download file name here - * @param {external:jsPDF.OutputType} [outputType="dataurlstring"] - * @fires module:svgcanvas.SvgCanvas#event:exportedPDF - * @returns {Promise<module:svgcanvas.PDFExportedResults>} Resolves to {@link module:svgcanvas.PDFExportedResults} - */ - - - this.exportPDF = /*#__PURE__*/function () { - var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3(exportWindowName) { - var outputType, - modularVersion, - res, - orientation, - unit, - doc, - docTitle, - _getIssues2, - issues, - issueCodes, - svg, - obj, - _args3 = arguments; - - return regeneratorRuntime.wrap(function _callee3$(_context3) { - while (1) { - switch (_context3.prev = _context3.next) { - case 0: - outputType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : isChrome() ? 'save' : undefined; - - if (window.jsPDF) { - _context3.next = 7; + case 4: + // cdata node + out.push('\n'); + out.push(new Array(indent + 1).join(' ')); + out.push('<![CDATA['); + out.push(child.nodeValue); + out.push(']]>'); break; - } - _context3.next = 4; - return importScript([// We do not currently have these paths configurable as they are - // currently global-only, so not Rolled-up - 'jspdf/underscore-min.js', // 'jspdf/jspdf.min.js', - '../../svgedit-myfix/editor/jspdf/jspdf-1.0.150.debug.js']); + case 8: + // comment + out.push('\n'); + out.push(new Array(indent + 1).join(' ')); + out.push('<!--'); + out.push(child.data); + out.push('-->'); + break; + } // switch on node type - case 4: - modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; // Todo: Switch to `import()` when widely supported and available (also allow customization of path) - - _context3.next = 7; - return importScript(curConfig.jspdfPath + 'jspdf.plugin.svgToPdf.js', { - type: modularVersion ? 'module' : 'text/javascript' - }); - - case 7: - res = getResolution(); - orientation = res.w > res.h ? 'landscape' : 'portrait'; - unit = 'pt'; // curConfig.baseUnit; // We could use baseUnit, but that is presumably not intended for export purposes - // Todo: Give options to use predefined jsPDF formats like "a4", etc. from pull-down (with option to keep customizable) - - doc = jsPDF({ - orientation: orientation, - unit: unit, - format: [res.w, res.h] // , compressPdf: true - - }); - docTitle = getDocumentTitle(); - doc.setProperties({ - title: docTitle - /* , - subject: '', - author: '', - keywords: '', - creator: '' */ - - }); - _getIssues2 = getIssues(), issues = _getIssues2.issues, issueCodes = _getIssues2.issueCodes; - svg = this.svgCanvasToString(); - doc.addSVG(svg, 0, 0); // doc.output('save'); // Works to open in a new - // window; todo: configure this and other export - // options to optionally work in this manner as - // opposed to opening a new tab - - outputType = outputType || 'dataurlstring'; - obj = { - svg: svg, - issues: issues, - issueCodes: issueCodes, - exportWindowName: exportWindowName, - outputType: outputType - }; - obj.output = doc.output(outputType, outputType === 'save' ? exportWindowName || 'svg.pdf' : undefined); - call('exportedPDF', obj); - return _context3.abrupt("return", obj); - - case 21: - case "end": - return _context3.stop(); } + + indent--; + + if (!bOneLine) { + out.push('\n'); + + for (let i = 0; i < indent; i++) { + out.push(' '); + } + } + + out.push('</'); + out.push(elem.nodeName); + out.push('>'); + } else { + out.push('/>'); } - }, _callee3, this); - })); + } - return function (_x7) { - return _ref6.apply(this, arguments); - }; - }(); - /** - * Returns the current drawing as raw SVG XML text. - * @function module:svgcanvas.SvgCanvas#getSvgString - * @returns {string} The current drawing as raw SVG XML text. - */ + return out.join(''); + }; // end svgToString() + + /** + * Function to run when image data is found. + * @callback module:svgcanvas.ImageEmbeddedCallback + * @param {string|false} result Data URL + * @returns {void} + */ + + /** + * Converts a given image file to a data URL when possible, then runs a given callback. + * @function module:svgcanvas.SvgCanvas#embedImage + * @param {string} src - The path/URL of the image + * @returns {Promise<string|false>} Resolves to a Data URL (string|false) + */ - this.getSvgString = function () { - saveOptions.apply = false; - return this.svgCanvasToString(); - }; - /** - * This function determines whether to use a nonce in the prefix, when - * generating IDs for future documents in SVG-Edit. - * If you're controlling SVG-Edit externally, and want randomized IDs, call - * this BEFORE calling `svgCanvas.setSvgString`. - * @function module:svgcanvas.SvgCanvas#randomizeIds - * @param {boolean} [enableRandomization] If true, adds a nonce to the prefix. Thus - * `svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true)` - * @returns {void} - */ + this.embedImage = function (src) { + // Todo: Remove this Promise in favor of making an async/await `Image.load` utility + return new Promise(function (resolve, reject) { + // eslint-disable-line promise/avoid-new + // load in the image and once it's loaded, get the dimensions + $$a(new Image()).load(function (response, status, xhr) { + if (status === 'error') { + reject(new Error('Error loading image: ' + xhr.status + ' ' + xhr.statusText)); + return; + } // create a canvas the same size as the raster image - this.randomizeIds = function (enableRandomization) { - if (arguments.length > 0 && enableRandomization === false) { - randomizeIds(false, getCurrentDrawing()); - } else { - randomizeIds(true, getCurrentDrawing()); - } - }; - /** - * Ensure each element has a unique ID. - * @function module:svgcanvas.SvgCanvas#uniquifyElems - * @param {Element} g - The parent element of the tree to give unique IDs - * @returns {void} - */ + const cvs = document.createElement('canvas'); + cvs.width = this.width; + cvs.height = this.height; // load the raster image into the canvas + cvs.getContext('2d').drawImage(this, 0, 0); // retrieve the data: URL - var uniquifyElems = this.uniquifyElems = function (g) { - var ids = {}; // TODO: Handle markers and connectors. These are not yet re-identified properly - // as their referring elements do not get remapped. - // - // <marker id='se_marker_end_svg_7'/> - // <polyline id='svg_7' se:connector='svg_1 svg_6' marker-end='url(#se_marker_end_svg_7)'/> - // - // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute - // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute - - var refElems = ['filter', 'linearGradient', 'pattern', 'radialGradient', 'symbol', 'textPath', 'use']; - walkTree(g, function (n) { - // if it's an element node - if (n.nodeType === 1) { - // and the element has an ID - if (n.id) { - // and we haven't tracked this ID yet - if (!(n.id in ids)) { - // add this id to our map - ids[n.id] = { - elem: null, - attrs: [], - hrefs: [] - }; + try { + let urldata = ';svgedit_url=' + encodeURIComponent(src); + urldata = cvs.toDataURL().replace(';base64', urldata + ';base64'); + encodableImages[src] = urldata; + } catch (e) { + encodableImages[src] = false; } - ids[n.id].elem = n; - } // now search for all attributes on this element that might refer - // to other elements + lastGoodImgUrl = src; + resolve(encodableImages[src]); + }).attr('src', src); + }); + }; + /** + * Sets a given URL to be a "last good image" URL. + * @function module:svgcanvas.SvgCanvas#setGoodImage + * @param {string} val + * @returns {void} + */ - $$9.each(refAttrs, function (i, attr) { - var attrnode = n.getAttributeNode(attr); + this.setGoodImage = function (val) { + lastGoodImgUrl = val; + }; + /** + * Does nothing by default, handled by optional widget/extension. + * @function module:svgcanvas.SvgCanvas#open + * @returns {void} + */ - if (attrnode) { - // the incoming file has been sanitized, so we should be able to safely just strip off the leading # - var url = getUrlFromAttr(attrnode.value), - refid = url ? url.substr(1) : null; + + this.open = function () { + /* */ + }; + /** + * Serializes the current drawing into SVG XML text and passes it to the 'saved' handler. + * This function also includes the XML prolog. Clients of the `SvgCanvas` bind their save + * function to the 'saved' event. + * @function module:svgcanvas.SvgCanvas#save + * @param {module:svgcanvas.SaveOptions} opts + * @fires module:svgcanvas.SvgCanvas#event:saved + * @returns {void} + */ + + + this.save = function (opts) { + // remove the selected outline before serializing + clearSelection(); // Update save options if provided + + if (opts) { + $$a.extend(saveOptions, opts); + } + + saveOptions.apply = true; // no need for doctype, see https://jwatt.org/svg/authoring/#doctype-declaration + + const str = this.svgCanvasToString(); + call('saved', str); + }; + /** + * @typedef {PlainObject} module:svgcanvas.IssuesAndCodes + * @property {string[]} issueCodes The locale-independent code names + * @property {string[]} issues The localized descriptions + */ + + /** + * Codes only is useful for locale-independent detection. + * @returns {module:svgcanvas.IssuesAndCodes} + */ + + + function getIssues() { + // remove the selected outline before serializing + clearSelection(); // Check for known CanVG issues + + const issues = []; + const issueCodes = []; // Selector and notice + + const issueList = { + feGaussianBlur: uiStrings.exportNoBlur, + foreignObject: uiStrings.exportNoforeignObject, + '[stroke-dasharray]': uiStrings.exportNoDashArray + }; + const content = $$a(svgcontent); // Add font/text check if Canvas Text API is not implemented + + if (!('font' in $$a('<canvas>')[0].getContext('2d'))) { + issueList.text = uiStrings.exportNoText; + } + + $$a.each(issueList, function (sel, descr) { + if (content.find(sel).length) { + issueCodes.push(sel); + issues.push(descr); + } + }); + return { + issues, + issueCodes + }; + } + + let canvg; + /** + * @typedef {"feGaussianBlur"|"foreignObject"|"[stroke-dasharray]"|"text"} module:svgcanvas.IssueCode + */ + + /** + * @typedef {PlainObject} module:svgcanvas.ImageExportedResults + * @property {string} datauri Contents as a Data URL + * @property {string} bloburl May be the empty string + * @property {string} svg The SVG contents as a string + * @property {string[]} issues The localization messages of `issueCodes` + * @property {module:svgcanvas.IssueCode[]} issueCodes CanVG issues found with the SVG + * @property {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} type The chosen image type + * @property {"image/png"|"image/jpeg"|"image/bmp"|"image/webp"} mimeType The image MIME type + * @property {Float} quality A decimal between 0 and 1 (for use with JPEG or WEBP) + * @property {string} exportWindowName A convenience for passing along a `window.name` to target a window on which the export could be added + */ + + /** + * Generates a PNG (or JPG, BMP, WEBP) Data URL based on the current image, + * then calls "exported" with an object including the string, image + * information, and any issues found. + * @function module:svgcanvas.SvgCanvas#rasterExport + * @param {"PNG"|"JPEG"|"BMP"|"WEBP"|"ICO"} [imgType="PNG"] + * @param {Float} [quality] Between 0 and 1 + * @param {string} [exportWindowName] + * @param {PlainObject} [opts] + * @param {boolean} [opts.avoidEvent] + * @fires module:svgcanvas.SvgCanvas#event:exported + * @todo Confirm/fix ICO type + * @returns {Promise<module:svgcanvas.ImageExportedResults>} Resolves to {@link module:svgcanvas.ImageExportedResults} + */ + + this.rasterExport = async function (imgType, quality, exportWindowName, opts = {}) { + const type = imgType === 'ICO' ? 'BMP' : imgType || 'PNG'; + const mimeType = 'image/' + type.toLowerCase(); + const { + issues, + issueCodes + } = getIssues(); + const svg = this.svgCanvasToString(); + + if (!canvg) { + ({ + canvg + } = await importSetGlobal(curConfig.canvgPath + 'canvg.js', { + global: 'canvg' + })); + } + + if (!$$a('#export_canvas').length) { + $$a('<canvas>', { + id: 'export_canvas' + }).hide().appendTo('body'); + } + + const c = $$a('#export_canvas')[0]; + c.width = canvas.contentW; + c.height = canvas.contentH; + await canvg(c, svg); // Todo: Make async/await utility in place of `toBlob`, so we can remove this constructor + + return new Promise((resolve, reject) => { + // eslint-disable-line promise/avoid-new + const dataURLType = type.toLowerCase(); + const datauri = quality ? c.toDataURL('image/' + dataURLType, quality) : c.toDataURL('image/' + dataURLType); + let bloburl; + /** + * Called when `bloburl` is available for export. + * @returns {void} + */ + + function done() { + const obj = { + datauri, + bloburl, + svg, + issues, + issueCodes, + type: imgType, + mimeType, + quality, + exportWindowName + }; + + if (!opts.avoidEvent) { + call('exported', obj); + } + + resolve(obj); + } + + if (c.toBlob) { + c.toBlob(blob => { + bloburl = createObjectURL(blob); + done(); + }, mimeType, quality); + return; + } + + bloburl = dataURLToObjectURL(datauri); + done(); + }); + }; + /** + * @external jsPDF + */ + + /** + * @typedef {void|"save"|"arraybuffer"|"blob"|"datauristring"|"dataurlstring"|"dataurlnewwindow"|"datauri"|"dataurl"} external:jsPDF.OutputType + * @todo Newer version to add also allows these `outputType` values "bloburi"|"bloburl" which return strings, so document here and for `outputType` of `module:svgcanvas.PDFExportedResults` below if added + */ + + /** + * @typedef {PlainObject} module:svgcanvas.PDFExportedResults + * @property {string} svg The SVG PDF output + * @property {string|ArrayBuffer|Blob|window} output The output based on the `outputType`; + * if `undefined`, "datauristring", "dataurlstring", "datauri", + * or "dataurl", will be a string (`undefined` gives a document, while the others + * build as Data URLs; "datauri" and "dataurl" change the location of the current page); if + * "arraybuffer", will return `ArrayBuffer`; if "blob", returns a `Blob`; + * if "dataurlnewwindow", will change the current page's location and return a string + * if in Safari and no window object is found; otherwise opens in, and returns, a new `window` + * object; if "save", will have the same return as "dataurlnewwindow" if + * `navigator.getUserMedia` support is found without `URL.createObjectURL` support; otherwise + * returns `undefined` but attempts to save + * @property {external:jsPDF.OutputType} outputType + * @property {string[]} issues The human-readable localization messages of corresponding `issueCodes` + * @property {module:svgcanvas.IssueCode[]} issueCodes + * @property {string} exportWindowName + */ + + /** + * Generates a PDF based on the current image, then calls "exportedPDF" with + * an object including the string, the data URL, and any issues found. + * @function module:svgcanvas.SvgCanvas#exportPDF + * @param {string} [exportWindowName] Will also be used for the download file name here + * @param {external:jsPDF.OutputType} [outputType="dataurlstring"] + * @fires module:svgcanvas.SvgCanvas#event:exportedPDF + * @returns {Promise<module:svgcanvas.PDFExportedResults>} Resolves to {@link module:svgcanvas.PDFExportedResults} + */ + + + this.exportPDF = async function (exportWindowName, outputType = isChrome() ? 'save' : undefined) { + if (!window.jsPDF) { + // Todo: Switch to `import()` when widely supported and available (also allow customization of path) + await importScript([// We do not currently have these paths configurable as they are + // currently global-only, so not Rolled-up + 'jspdf/underscore-min.js', // 'jspdf/jspdf.min.js', + '../../svgedit-myfix/editor/jspdf/jspdf-1.0.150.debug.js']); + const modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; // Todo: Switch to `import()` when widely supported and available (also allow customization of path) + + await importScript(curConfig.jspdfPath + 'jspdf.plugin.svgToPdf.js', { + type: modularVersion ? 'module' : 'text/javascript' + }); // await importModule('jspdf/jspdf.plugin.svgToPdf.js'); + } + + const res = getResolution(); + const orientation = res.w > res.h ? 'landscape' : 'portrait'; + const unit = 'pt'; // curConfig.baseUnit; // We could use baseUnit, but that is presumably not intended for export purposes + // Todo: Give options to use predefined jsPDF formats like "a4", etc. from pull-down (with option to keep customizable) + + const doc = jsPDF({ + orientation, + unit, + format: [res.w, res.h] // , compressPdf: true + + }); + const docTitle = getDocumentTitle(); + doc.setProperties({ + title: docTitle + /* , + subject: '', + author: '', + keywords: '', + creator: '' */ + + }); + const { + issues, + issueCodes + } = getIssues(); + const svg = this.svgCanvasToString(); + doc.addSVG(svg, 0, 0); // doc.output('save'); // Works to open in a new + // window; todo: configure this and other export + // options to optionally work in this manner as + // opposed to opening a new tab + + outputType = outputType || 'dataurlstring'; + const obj = { + svg, + issues, + issueCodes, + exportWindowName, + outputType + }; + obj.output = doc.output(outputType, outputType === 'save' ? exportWindowName || 'svg.pdf' : undefined); + call('exportedPDF', obj); + return obj; + }; + /** + * Returns the current drawing as raw SVG XML text. + * @function module:svgcanvas.SvgCanvas#getSvgString + * @returns {string} The current drawing as raw SVG XML text. + */ + + + this.getSvgString = function () { + saveOptions.apply = false; + return this.svgCanvasToString(); + }; + /** + * This function determines whether to use a nonce in the prefix, when + * generating IDs for future documents in SVG-Edit. + * If you're controlling SVG-Edit externally, and want randomized IDs, call + * this BEFORE calling `svgCanvas.setSvgString`. + * @function module:svgcanvas.SvgCanvas#randomizeIds + * @param {boolean} [enableRandomization] If true, adds a nonce to the prefix. Thus + * `svgCanvas.randomizeIds() <==> svgCanvas.randomizeIds(true)` + * @returns {void} + */ + + + this.randomizeIds = function (enableRandomization) { + if (arguments.length > 0 && enableRandomization === false) { + randomizeIds(false, getCurrentDrawing()); + } else { + randomizeIds(true, getCurrentDrawing()); + } + }; + /** + * Ensure each element has a unique ID. + * @function module:svgcanvas.SvgCanvas#uniquifyElems + * @param {Element} g - The parent element of the tree to give unique IDs + * @returns {void} + */ + + + const uniquifyElems = this.uniquifyElems = function (g) { + const ids = {}; // TODO: Handle markers and connectors. These are not yet re-identified properly + // as their referring elements do not get remapped. + // + // <marker id='se_marker_end_svg_7'/> + // <polyline id='svg_7' se:connector='svg_1 svg_6' marker-end='url(#se_marker_end_svg_7)'/> + // + // Problem #1: if svg_1 gets renamed, we do not update the polyline's se:connector attribute + // Problem #2: if the polyline svg_7 gets renamed, we do not update the marker id nor the polyline's marker-end attribute + + const refElems = ['filter', 'linearGradient', 'pattern', 'radialGradient', 'symbol', 'textPath', 'use']; + walkTree(g, function (n) { + // if it's an element node + if (n.nodeType === 1) { + // and the element has an ID + if (n.id) { + // and we haven't tracked this ID yet + if (!(n.id in ids)) { + // add this id to our map + ids[n.id] = { + elem: null, + attrs: [], + hrefs: [] + }; + } + + ids[n.id].elem = n; + } // now search for all attributes on this element that might refer + // to other elements + + + $$a.each(refAttrs, function (i, attr) { + const attrnode = n.getAttributeNode(attr); + + if (attrnode) { + // the incoming file has been sanitized, so we should be able to safely just strip off the leading # + const url = getUrlFromAttr(attrnode.value), + refid = url ? url.substr(1) : null; + + if (refid) { + if (!(refid in ids)) { + // add this id to our map + ids[refid] = { + elem: null, + attrs: [], + hrefs: [] + }; + } + + ids[refid].attrs.push(attrnode); + } + } + }); // check xlink:href now + + const href = getHref(n); // TODO: what if an <image> or <a> element refers to an element internally? + + if (href && refElems.includes(n.nodeName)) { + const refid = href.substr(1); if (refid) { if (!(refid in ids)) { @@ -18456,3596 +17593,3545 @@ }; } - ids[refid].attrs.push(attrnode); + ids[refid].hrefs.push(n); } } - }); // check xlink:href now + } + }); // in ids, we now have a map of ids, elements and attributes, let's re-identify - var href = getHref(n); // TODO: what if an <image> or <a> element refers to an element internally? + for (const oldid in ids) { + if (!oldid) { + continue; + } - if (href && refElems.includes(n.nodeName)) { - var refid = href.substr(1); + const { + elem + } = ids[oldid]; - if (refid) { - if (!(refid in ids)) { - // add this id to our map - ids[refid] = { - elem: null, - attrs: [], - hrefs: [] - }; - } + if (elem) { + const newid = getNextId(); // assign element its new id - ids[refid].hrefs.push(n); + elem.id = newid; // remap all url() attributes + + const { + attrs + } = ids[oldid]; + let j = attrs.length; + + while (j--) { + const attr = attrs[j]; + attr.ownerElement.setAttribute(attr.name, 'url(#' + newid + ')'); + } // remap all href attributes + + + const hreffers = ids[oldid].hrefs; + let k = hreffers.length; + + while (k--) { + const hreffer = hreffers[k]; + setHref(hreffer, '#' + newid); } } } - }); // in ids, we now have a map of ids, elements and attributes, let's re-identify + }; + /** + * Assigns reference data for each use element. + * @function module:svgcanvas.SvgCanvas#setUseData + * @param {Element} parent + * @returns {void} + */ - for (var oldid in ids) { - if (!oldid) { - continue; + + const setUseData = this.setUseData = function (parent) { + let elems = $$a(parent); + + if (parent.tagName !== 'use') { + elems = elems.find('use'); } - var elem = ids[oldid].elem; + elems.each(function () { + const id = getHref(this).substr(1); + const refElem = getElem(id); - if (elem) { - var newid = getNextId(); // assign element its new id - - elem.id = newid; // remap all url() attributes - - var attrs = ids[oldid].attrs; - var j = attrs.length; - - while (j--) { - var attr = attrs[j]; - attr.ownerElement.setAttribute(attr.name, 'url(#' + newid + ')'); - } // remap all href attributes - - - var hreffers = ids[oldid].hrefs; - var k = hreffers.length; - - while (k--) { - var hreffer = hreffers[k]; - setHref(hreffer, '#' + newid); + if (!refElem) { + return; } - } - } - }; - /** - * Assigns reference data for each use element. - * @function module:svgcanvas.SvgCanvas#setUseData - * @param {Element} parent - * @returns {void} - */ + $$a(this).data('ref', refElem); - var setUseData = this.setUseData = function (parent) { - var elems = $$9(parent); - - if (parent.tagName !== 'use') { - elems = elems.find('use'); - } - - elems.each(function () { - var id = getHref(this).substr(1); - var refElem = getElem(id); - - if (!refElem) { - return; - } - - $$9(this).data('ref', refElem); - - if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') { - $$9(this).data('symbol', refElem).data('ref', refElem); - } - }); - }; - /** - * Converts gradients from userSpaceOnUse to objectBoundingBox. - * @function module:svgcanvas.SvgCanvas#convertGradients - * @param {Element} elem - * @returns {void} - */ - - - var convertGradients = this.convertGradients = function (elem) { - var elems = $$9(elem).find('linearGradient, radialGradient'); - - if (!elems.length && isWebkit()) { - // Bug in webkit prevents regular *Gradient selector search - elems = $$9(elem).find('*').filter(function () { - return this.tagName.includes('Gradient'); + if (refElem.tagName === 'symbol' || refElem.tagName === 'svg') { + $$a(this).data('symbol', refElem).data('ref', refElem); + } }); - } - - elems.each(function () { - var grad = this; // eslint-disable-line consistent-this - - if ($$9(grad).attr('gradientUnits') === 'userSpaceOnUse') { - // TODO: Support more than one element with this ref by duplicating parent grad - var fillStrokeElems = $$9(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - - if (!fillStrokeElems.length) { - return; - } // get object's bounding box + }; + /** + * Converts gradients from userSpaceOnUse to objectBoundingBox. + * @function module:svgcanvas.SvgCanvas#convertGradients + * @param {Element} elem + * @returns {void} + */ - var bb = getBBox(fillStrokeElems[0]); // This will occur if the element is inside a <defs> or a <symbol>, - // in which we shouldn't need to convert anyway. + const convertGradients = this.convertGradients = function (elem) { + let elems = $$a(elem).find('linearGradient, radialGradient'); - if (!bb) { - return; - } + if (!elems.length && isWebkit()) { + // Bug in webkit prevents regular *Gradient selector search + elems = $$a(elem).find('*').filter(function () { + return this.tagName.includes('Gradient'); + }); + } - if (grad.tagName === 'linearGradient') { - var gCoords = $$9(grad).attr(['x1', 'y1', 'x2', 'y2']); // If has transform, convert + elems.each(function () { + const grad = this; // eslint-disable-line consistent-this - var tlist = grad.gradientTransform.baseVal; + if ($$a(grad).attr('gradientUnits') === 'userSpaceOnUse') { + // TODO: Support more than one element with this ref by duplicating parent grad + const fillStrokeElems = $$a(svgcontent).find('[fill="url(#' + grad.id + ')"],[stroke="url(#' + grad.id + ')"]'); - if (tlist && tlist.numberOfItems > 0) { - var m = transformListToTransform(tlist).matrix; - var pt1 = transformPoint(gCoords.x1, gCoords.y1, m); - var pt2 = transformPoint(gCoords.x2, gCoords.y2, m); - gCoords.x1 = pt1.x; - gCoords.y1 = pt1.y; - gCoords.x2 = pt2.x; - gCoords.y2 = pt2.y; - grad.removeAttribute('gradientTransform'); + if (!fillStrokeElems.length) { + return; + } // get object's bounding box + + + const bb = getBBox(fillStrokeElems[0]); // This will occur if the element is inside a <defs> or a <symbol>, + // in which we shouldn't need to convert anyway. + + if (!bb) { + return; } - $$9(grad).attr({ - x1: (gCoords.x1 - bb.x) / bb.width, - y1: (gCoords.y1 - bb.y) / bb.height, - x2: (gCoords.x2 - bb.x) / bb.width, - y2: (gCoords.y2 - bb.y) / bb.height - }); - grad.removeAttribute('gradientUnits'); - } // else { - // Note: radialGradient elements cannot be easily converted - // because userSpaceOnUse will keep circular gradients, while - // objectBoundingBox will x/y scale the gradient according to - // its bbox. - // - // For now we'll do nothing, though we should probably have - // the gradient be updated as the element is moved, as - // inkscape/illustrator do. - // - // const gCoords = $(grad).attr(['cx', 'cy', 'r']); - // - // $(grad).attr({ - // cx: (gCoords.cx - bb.x) / bb.width, - // cy: (gCoords.cy - bb.y) / bb.height, - // r: gCoords.r - // }); - // - // grad.removeAttribute('gradientUnits'); - // } + if (grad.tagName === 'linearGradient') { + const gCoords = $$a(grad).attr(['x1', 'y1', 'x2', 'y2']); // If has transform, convert - } - }); - }; - /** - * Converts selected/given `<use>` or child SVG element to a group. - * @function module:svgcanvas.SvgCanvas#convertToGroup - * @param {Element} elem - * @fires module:svgcanvas.SvgCanvas#event:selected - * @returns {void} - */ + const tlist = grad.gradientTransform.baseVal; + + if (tlist && tlist.numberOfItems > 0) { + const m = transformListToTransform(tlist).matrix; + const pt1 = transformPoint(gCoords.x1, gCoords.y1, m); + const pt2 = transformPoint(gCoords.x2, gCoords.y2, m); + gCoords.x1 = pt1.x; + gCoords.y1 = pt1.y; + gCoords.x2 = pt2.x; + gCoords.y2 = pt2.y; + grad.removeAttribute('gradientTransform'); + } + + $$a(grad).attr({ + x1: (gCoords.x1 - bb.x) / bb.width, + y1: (gCoords.y1 - bb.y) / bb.height, + x2: (gCoords.x2 - bb.x) / bb.width, + y2: (gCoords.y2 - bb.y) / bb.height + }); + grad.removeAttribute('gradientUnits'); + } // else { + // Note: radialGradient elements cannot be easily converted + // because userSpaceOnUse will keep circular gradients, while + // objectBoundingBox will x/y scale the gradient according to + // its bbox. + // + // For now we'll do nothing, though we should probably have + // the gradient be updated as the element is moved, as + // inkscape/illustrator do. + // + // const gCoords = $(grad).attr(['cx', 'cy', 'r']); + // + // $(grad).attr({ + // cx: (gCoords.cx - bb.x) / bb.width, + // cy: (gCoords.cy - bb.y) / bb.height, + // r: gCoords.r + // }); + // + // grad.removeAttribute('gradientUnits'); + // } + + } + }); + }; + /** + * Converts selected/given `<use>` or child SVG element to a group. + * @function module:svgcanvas.SvgCanvas#convertToGroup + * @param {Element} elem + * @fires module:svgcanvas.SvgCanvas#event:selected + * @returns {void} + */ - var convertToGroup = this.convertToGroup = function (elem) { - if (!elem) { - elem = selectedElements[0]; - } - - var $elem = $$9(elem); - var batchCmd = new BatchCommand$1(); - var ts; - - if ($elem.data('gsvg')) { - // Use the gsvg as the new group - var svg = elem.firstChild; - var pt = $$9(svg).attr(['x', 'y']); - $$9(elem.firstChild.firstChild).unwrap(); - $$9(elem).removeData('gsvg'); - var tlist = getTransformList(elem); - var xform = svgroot.createSVGTransform(); - xform.setTranslate(pt.x, pt.y); - tlist.appendItem(xform); - recalculateDimensions(elem); - call('selected', [elem]); - } else if ($elem.data('symbol')) { - elem = $elem.data('symbol'); - ts = $elem.attr('transform'); - var pos = $elem.attr(['x', 'y']); - var vb = elem.getAttribute('viewBox'); - - if (vb) { - var nums = vb.split(' '); - pos.x -= Number(nums[0]); - pos.y -= Number(nums[1]); - } // Not ideal, but works - - - ts += ' translate(' + (pos.x || 0) + ',' + (pos.y || 0) + ')'; - var prev = $elem.prev(); // Remove <use> element - - batchCmd.addSubCommand(new RemoveElementCommand$1($elem[0], $elem[0].nextSibling, $elem[0].parentNode)); - $elem.remove(); // See if other elements reference this symbol - - var hasMore = $$9(svgcontent).find('use:data(symbol)').length; - var g = svgdoc.createElementNS(NS.SVG, 'g'); - var childs = elem.childNodes; - var i; - - for (i = 0; i < childs.length; i++) { - g.append(childs[i].cloneNode(true)); - } // Duplicate the gradients for Gecko, since they weren't included in the <symbol> - - - if (isGecko()) { - var dupeGrads = $$9(findDefs()).children('linearGradient,radialGradient,pattern').clone(); - $$9(g).append(dupeGrads); + const convertToGroup = this.convertToGroup = function (elem) { + if (!elem) { + elem = selectedElements[0]; } - if (ts) { - g.setAttribute('transform', ts); - } + const $elem = $$a(elem); + const batchCmd = new BatchCommand$1(); + let ts; - var parent = elem.parentNode; - uniquifyElems(g); // Put the dupe gradients back into <defs> (after uniquifying them) + if ($elem.data('gsvg')) { + // Use the gsvg as the new group + const svg = elem.firstChild; + const pt = $$a(svg).attr(['x', 'y']); + $$a(elem.firstChild.firstChild).unwrap(); + $$a(elem).removeData('gsvg'); + const tlist = getTransformList(elem); + const xform = svgroot.createSVGTransform(); + xform.setTranslate(pt.x, pt.y); + tlist.appendItem(xform); + recalculateDimensions(elem); + call('selected', [elem]); + } else if ($elem.data('symbol')) { + elem = $elem.data('symbol'); + ts = $elem.attr('transform'); + const pos = $elem.attr(['x', 'y']); + const vb = elem.getAttribute('viewBox'); - if (isGecko()) { - $$9(findDefs()).append($$9(g).find('linearGradient,radialGradient,pattern')); - } // now give the g itself a new id + if (vb) { + const nums = vb.split(' '); + pos.x -= Number(nums[0]); + pos.y -= Number(nums[1]); + } // Not ideal, but works - g.id = getNextId(); - prev.after(g); + ts += ' translate(' + (pos.x || 0) + ',' + (pos.y || 0) + ')'; + const prev = $elem.prev(); // Remove <use> element - if (parent) { - if (!hasMore) { - // remove symbol/svg element - var _elem = elem, - nextSibling = _elem.nextSibling; - elem.remove(); - batchCmd.addSubCommand(new RemoveElementCommand$1(elem, nextSibling, parent)); + batchCmd.addSubCommand(new RemoveElementCommand$1($elem[0], $elem[0].nextSibling, $elem[0].parentNode)); + $elem.remove(); // See if other elements reference this symbol + + const hasMore = $$a(svgcontent).find('use:data(symbol)').length; + const g = svgdoc.createElementNS(NS.SVG, 'g'); + const childs = elem.childNodes; + let i; + + for (i = 0; i < childs.length; i++) { + g.append(childs[i].cloneNode(true)); + } // Duplicate the gradients for Gecko, since they weren't included in the <symbol> + + + if (isGecko()) { + const dupeGrads = $$a(findDefs()).children('linearGradient,radialGradient,pattern').clone(); + $$a(g).append(dupeGrads); } - batchCmd.addSubCommand(new InsertElementCommand$1(g)); - } + if (ts) { + g.setAttribute('transform', ts); + } - setUseData(g); + const parent = elem.parentNode; + uniquifyElems(g); // Put the dupe gradients back into <defs> (after uniquifying them) - if (isGecko()) { - convertGradients(findDefs()); + if (isGecko()) { + $$a(findDefs()).append($$a(g).find('linearGradient,radialGradient,pattern')); + } // now give the g itself a new id + + + g.id = getNextId(); + prev.after(g); + + if (parent) { + if (!hasMore) { + // remove symbol/svg element + const { + nextSibling + } = elem; + elem.remove(); + batchCmd.addSubCommand(new RemoveElementCommand$1(elem, nextSibling, parent)); + } + + batchCmd.addSubCommand(new InsertElementCommand$1(g)); + } + + setUseData(g); + + if (isGecko()) { + convertGradients(findDefs()); + } else { + convertGradients(g); + } // recalculate dimensions on the top-level children so that unnecessary transforms + // are removed + + + walkTreePost(g, function (n) { + try { + recalculateDimensions(n); + } catch (e) { + console.log(e); // eslint-disable-line no-console + } + }); // Give ID for any visible element missing one + + $$a(g).find(visElems).each(function () { + if (!this.id) { + this.id = getNextId(); + } + }); + selectOnly([g]); + const cm = pushGroupProperties(g, true); + + if (cm) { + batchCmd.addSubCommand(cm); + } + + addCommandToHistory(batchCmd); } else { - convertGradients(g); - } // recalculate dimensions on the top-level children so that unnecessary transforms - // are removed - - - walkTreePost(g, function (n) { - try { - recalculateDimensions(n); - } catch (e) { - console.log(e); // eslint-disable-line no-console - } - }); // Give ID for any visible element missing one - - $$9(g).find(visElems).each(function () { - if (!this.id) { - this.id = getNextId(); - } - }); - selectOnly([g]); - var cm = pushGroupProperties(g, true); - - if (cm) { - batchCmd.addSubCommand(cm); + console.log('Unexpected element to ungroup:', elem); // eslint-disable-line no-console } - - addCommandToHistory(batchCmd); - } else { - console.log('Unexpected element to ungroup:', elem); // eslint-disable-line no-console - } - }; - /** - * This function sets the current drawing as the input SVG XML. - * @function module:svgcanvas.SvgCanvas#setSvgString - * @param {string} xmlString - The SVG as XML text. - * @param {boolean} [preventUndo=false] - Indicates if we want to do the - * changes without adding them to the undo stack - e.g. for initializing a - * drawing on page load. - * @fires module:svgcanvas.SvgCanvas#event:setnonce - * @fires module:svgcanvas.SvgCanvas#event:unsetnonce - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {boolean} This function returns `false` if the set was - * unsuccessful, `true` otherwise. - */ + }; + /** + * This function sets the current drawing as the input SVG XML. + * @function module:svgcanvas.SvgCanvas#setSvgString + * @param {string} xmlString - The SVG as XML text. + * @param {boolean} [preventUndo=false] - Indicates if we want to do the + * changes without adding them to the undo stack - e.g. for initializing a + * drawing on page load. + * @fires module:svgcanvas.SvgCanvas#event:setnonce + * @fires module:svgcanvas.SvgCanvas#event:unsetnonce + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {boolean} This function returns `false` if the set was + * unsuccessful, `true` otherwise. + */ - this.setSvgString = function (xmlString, preventUndo) { - try { - // convert string into XML document - var newDoc = text2xml(xmlString); + this.setSvgString = function (xmlString, preventUndo) { + try { + // convert string into XML document + const newDoc = text2xml(xmlString); + + if (newDoc.firstElementChild && newDoc.firstElementChild.namespaceURI !== NS.SVG) { + return false; + } + + this.prepareSvg(newDoc); + const batchCmd = new BatchCommand$1('Change Source'); // remove old svg document + + const { + nextSibling + } = svgcontent; + svgcontent.remove(); + const oldzoom = svgcontent; + batchCmd.addSubCommand(new RemoveElementCommand$1(oldzoom, nextSibling, svgroot)); // set new svg document + // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() + + if (svgdoc.adoptNode) { + svgcontent = svgdoc.adoptNode(newDoc.documentElement); + } else { + svgcontent = svgdoc.importNode(newDoc.documentElement, true); + } + + svgroot.append(svgcontent); + const content = $$a(svgcontent); + canvas.current_drawing_ = new Drawing(svgcontent, idprefix); // retrieve or set the nonce + + const nonce = getCurrentDrawing().getNonce(); + + if (nonce) { + call('setnonce', nonce); + } else { + call('unsetnonce'); + } // change image href vals if possible + + + content.find('image').each(function () { + const image = this; // eslint-disable-line consistent-this + + preventClickDefault(image); + const val = getHref(this); + + if (val) { + if (val.startsWith('data:')) { + // Check if an SVG-edit data URI + const m = val.match(/svgedit_url=(.*?);/); // const m = val.match(/svgedit_url=(?<url>.*?);/); + + if (m) { + const url = decodeURIComponent(m[1]); // const url = decodeURIComponent(m.groups.url); + + $$a(new Image()).load(function () { + image.setAttributeNS(NS.XLINK, 'xlink:href', url); + }).attr('src', url); + } + } // Add to encodableImages if it loads + + + canvas.embedImage(val); + } + }); // Wrap child SVGs in group elements + + content.find('svg').each(function () { + // Skip if it's in a <defs> + if ($$a(this).closest('defs').length) { + return; + } + + uniquifyElems(this); // Check if it already has a gsvg group + + const pa = this.parentNode; + + if (pa.childNodes.length === 1 && pa.nodeName === 'g') { + $$a(pa).data('gsvg', this); + pa.id = pa.id || getNextId(); + } else { + groupSvgElem(this); + } + }); // For Firefox: Put all paint elems in defs + + if (isGecko()) { + content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); + } // Set ref element for <use> elements + // TODO: This should also be done if the object is re-added through "redo" + + + setUseData(content); + convertGradients(content[0]); + const attrs = { + id: 'svgcontent', + overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden' + }; + let percs = false; // determine proper size + + if (content.attr('viewBox')) { + const vb = content.attr('viewBox').split(' '); + attrs.width = vb[2]; + attrs.height = vb[3]; // handle content that doesn't have a viewBox + } else { + $$a.each(['width', 'height'], function (i, dim) { + // Set to 100 if not given + const val = content.attr(dim) || '100%'; + + if (String(val).substr(-1) === '%') { + // Use user units if percentage given + percs = true; + } else { + attrs[dim] = convertToNum(dim, val); + } + }); + } // identify layers + + + identifyLayers(); // Give ID for any visible layer children missing one + + content.children().find(visElems).each(function () { + if (!this.id) { + this.id = getNextId(); + } + }); // Percentage width/height, so let's base it on visible elements + + if (percs) { + const bb = getStrokedBBoxDefaultVisible(); + attrs.width = bb.width + bb.x; + attrs.height = bb.height + bb.y; + } // Just in case negative numbers are given or + // result from the percs calculation + + + if (attrs.width <= 0) { + attrs.width = 100; + } + + if (attrs.height <= 0) { + attrs.height = 100; + } + + content.attr(attrs); + this.contentW = attrs.width; + this.contentH = attrs.height; + batchCmd.addSubCommand(new InsertElementCommand$1(svgcontent)); // update root to the correct size + + const changes = content.attr(['width', 'height']); + batchCmd.addSubCommand(new ChangeElementCommand$1(svgroot, changes)); // reset zoom + + currentZoom = 1; // reset transform lists + + resetListMap(); + clearSelection(); + clearData(); + svgroot.append(selectorManager.selectorParentGroup); + if (!preventUndo) addCommandToHistory(batchCmd); + call('changed', [svgcontent]); + } catch (e) { + console.log(e); // eslint-disable-line no-console - if (newDoc.firstElementChild && newDoc.firstElementChild.namespaceURI !== NS.SVG) { return false; } - this.prepareSvg(newDoc); - var batchCmd = new BatchCommand$1('Change Source'); // remove old svg document - - var _svgcontent = svgcontent, - nextSibling = _svgcontent.nextSibling; - svgcontent.remove(); - var oldzoom = svgcontent; - batchCmd.addSubCommand(new RemoveElementCommand$1(oldzoom, nextSibling, svgroot)); // set new svg document - // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - - if (svgdoc.adoptNode) { - svgcontent = svgdoc.adoptNode(newDoc.documentElement); - } else { - svgcontent = svgdoc.importNode(newDoc.documentElement, true); - } - - svgroot.append(svgcontent); - var content = $$9(svgcontent); - canvas.current_drawing_ = new Drawing(svgcontent, idprefix); // retrieve or set the nonce - - var nonce = getCurrentDrawing().getNonce(); - - if (nonce) { - call('setnonce', nonce); - } else { - call('unsetnonce'); - } // change image href vals if possible + return true; + }; + /** + * This function imports the input SVG XML as a `<symbol>` in the `<defs>`, then adds a + * `<use>` to the current layer. + * @function module:svgcanvas.SvgCanvas#importSvgString + * @param {string} xmlString - The SVG as XML text. + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {null|Element} This function returns null if the import was unsuccessful, or the element otherwise. + * @todo + * - properly handle if namespace is introduced by imported content (must add to svgcontent + * and update all prefixes in the imported node) + * - properly handle recalculating dimensions, `recalculateDimensions()` doesn't handle + * arbitrary transform lists, but makes some assumptions about how the transform list + * was obtained + */ - content.find('image').each(function () { - var image = this; // eslint-disable-line consistent-this + this.importSvgString = function (xmlString) { + let j, ts, useEl; - preventClickDefault(image); - var val = getHref(this); + try { + // Get unique ID + const uid = encode64(xmlString.length + xmlString).substr(0, 32); + let useExisting = false; // Look for symbol and make sure symbol exists in image - if (val) { - if (val.startsWith('data:')) { - // Check if an SVG-edit data URI - var m = val.match(/svgedit_url=(.*?);/); // const m = val.match(/svgedit_url=(?<url>.*?);/); - - if (m) { - var url = decodeURIComponent(m[1]); // const url = decodeURIComponent(m.groups.url); - - $$9(new Image()).load(function () { - image.setAttributeNS(NS.XLINK, 'xlink:href', url); - }).attr('src', url); - } - } // Add to encodableImages if it loads - - - canvas.embedImage(val); - } - }); // Wrap child SVGs in group elements - - content.find('svg').each(function () { - // Skip if it's in a <defs> - if ($$9(this).closest('defs').length) { - return; - } - - uniquifyElems(this); // Check if it already has a gsvg group - - var pa = this.parentNode; - - if (pa.childNodes.length === 1 && pa.nodeName === 'g') { - $$9(pa).data('gsvg', this); - pa.id = pa.id || getNextId(); - } else { - groupSvgElem(this); - } - }); // For Firefox: Put all paint elems in defs - - if (isGecko()) { - content.find('linearGradient, radialGradient, pattern').appendTo(findDefs()); - } // Set ref element for <use> elements - // TODO: This should also be done if the object is re-added through "redo" - - - setUseData(content); - convertGradients(content[0]); - var attrs = { - id: 'svgcontent', - overflow: curConfig.show_outside_canvas ? 'visible' : 'hidden' - }; - var percs = false; // determine proper size - - if (content.attr('viewBox')) { - var vb = content.attr('viewBox').split(' '); - attrs.width = vb[2]; - attrs.height = vb[3]; // handle content that doesn't have a viewBox - } else { - $$9.each(['width', 'height'], function (i, dim) { - // Set to 100 if not given - var val = content.attr(dim) || '100%'; - - if (String(val).substr(-1) === '%') { - // Use user units if percentage given - percs = true; - } else { - attrs[dim] = convertToNum(dim, val); + if (importIds[uid]) { + if ($$a(importIds[uid].symbol).parents('#svgroot').length) { + useExisting = true; } - }); - } // identify layers - - - identifyLayers(); // Give ID for any visible layer children missing one - - content.children().find(visElems).each(function () { - if (!this.id) { - this.id = getNextId(); } - }); // Percentage width/height, so let's base it on visible elements - if (percs) { - var bb = getStrokedBBoxDefaultVisible(); - attrs.width = bb.width + bb.x; - attrs.height = bb.height + bb.y; - } // Just in case negative numbers are given or - // result from the percs calculation + const batchCmd = new BatchCommand$1('Import Image'); + let symbol; - - if (attrs.width <= 0) { - attrs.width = 100; - } - - if (attrs.height <= 0) { - attrs.height = 100; - } - - content.attr(attrs); - this.contentW = attrs.width; - this.contentH = attrs.height; - batchCmd.addSubCommand(new InsertElementCommand$1(svgcontent)); // update root to the correct size - - var changes = content.attr(['width', 'height']); - batchCmd.addSubCommand(new ChangeElementCommand$1(svgroot, changes)); // reset zoom - - currentZoom = 1; // reset transform lists - - resetListMap(); - clearSelection(); - clearData(); - svgroot.append(selectorManager.selectorParentGroup); - if (!preventUndo) addCommandToHistory(batchCmd); - call('changed', [svgcontent]); - } catch (e) { - console.log(e); // eslint-disable-line no-console - - return false; - } - - return true; - }; - /** - * This function imports the input SVG XML as a `<symbol>` in the `<defs>`, then adds a - * `<use>` to the current layer. - * @function module:svgcanvas.SvgCanvas#importSvgString - * @param {string} xmlString - The SVG as XML text. - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {null|Element} This function returns null if the import was unsuccessful, or the element otherwise. - * @todo - * - properly handle if namespace is introduced by imported content (must add to svgcontent - * and update all prefixes in the imported node) - * - properly handle recalculating dimensions, `recalculateDimensions()` doesn't handle - * arbitrary transform lists, but makes some assumptions about how the transform list - * was obtained - */ - - - this.importSvgString = function (xmlString) { - var j, ts, useEl; - - try { - // Get unique ID - var uid = encode64(xmlString.length + xmlString).substr(0, 32); - var useExisting = false; // Look for symbol and make sure symbol exists in image - - if (importIds[uid]) { - if ($$9(importIds[uid].symbol).parents('#svgroot').length) { - useExisting = true; - } - } - - var batchCmd = new BatchCommand$1('Import Image'); - var symbol; - - if (useExisting) { - symbol = importIds[uid].symbol; - ts = importIds[uid].xform; - } else { - // convert string into XML document - var newDoc = text2xml(xmlString); - this.prepareSvg(newDoc); // import new svg document into our document - - var svg; // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - - if (svgdoc.adoptNode) { - svg = svgdoc.adoptNode(newDoc.documentElement); + if (useExisting) { + ({ + symbol + } = importIds[uid]); + ts = importIds[uid].xform; } else { - svg = svgdoc.importNode(newDoc.documentElement, true); - } + // convert string into XML document + const newDoc = text2xml(xmlString); + this.prepareSvg(newDoc); // import new svg document into our document - uniquifyElems(svg); - var innerw = convertToNum('width', svg.getAttribute('width')), - innerh = convertToNum('height', svg.getAttribute('height')), - innervb = svg.getAttribute('viewBox'), - // if no explicit viewbox, create one out of the width and height - vb = innervb ? innervb.split(' ') : [0, 0, innerw, innerh]; + let svg; // If DOM3 adoptNode() available, use it. Otherwise fall back to DOM2 importNode() - for (j = 0; j < 4; ++j) { - vb[j] = Number(vb[j]); - } // TODO: properly handle preserveAspectRatio + if (svgdoc.adoptNode) { + svg = svgdoc.adoptNode(newDoc.documentElement); + } else { + svg = svgdoc.importNode(newDoc.documentElement, true); + } + + uniquifyElems(svg); + const innerw = convertToNum('width', svg.getAttribute('width')), + innerh = convertToNum('height', svg.getAttribute('height')), + innervb = svg.getAttribute('viewBox'), + // if no explicit viewbox, create one out of the width and height + vb = innervb ? innervb.split(' ') : [0, 0, innerw, innerh]; + + for (j = 0; j < 4; ++j) { + vb[j] = Number(vb[j]); + } // TODO: properly handle preserveAspectRatio - var // canvasw = +svgcontent.getAttribute('width'), - canvash = Number(svgcontent.getAttribute('height')); // imported content should be 1/3 of the canvas on its largest dimension + const // canvasw = +svgcontent.getAttribute('width'), + canvash = Number(svgcontent.getAttribute('height')); // imported content should be 1/3 of the canvas on its largest dimension - if (innerh > innerw) { - ts = 'scale(' + canvash / 3 / vb[3] + ')'; - } else { - ts = 'scale(' + canvash / 3 / vb[2] + ')'; - } // Hack to make recalculateDimensions understand how to scale + if (innerh > innerw) { + ts = 'scale(' + canvash / 3 / vb[3] + ')'; + } else { + ts = 'scale(' + canvash / 3 / vb[2] + ')'; + } // Hack to make recalculateDimensions understand how to scale - ts = 'translate(0) ' + ts + ' translate(0)'; - symbol = svgdoc.createElementNS(NS.SVG, 'symbol'); - var defs = findDefs(); + ts = 'translate(0) ' + ts + ' translate(0)'; + symbol = svgdoc.createElementNS(NS.SVG, 'symbol'); + const defs = findDefs(); - if (isGecko()) { - // Move all gradients into root for Firefox, workaround for this bug: - // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 - // TODO: Make this properly undo-able. - $$9(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); - } + if (isGecko()) { + // Move all gradients into root for Firefox, workaround for this bug: + // https://bugzilla.mozilla.org/show_bug.cgi?id=353575 + // TODO: Make this properly undo-able. + $$a(svg).find('linearGradient, radialGradient, pattern').appendTo(defs); + } - while (svg.firstChild) { - var first = svg.firstChild; - symbol.append(first); - } + while (svg.firstChild) { + const first = svg.firstChild; + symbol.append(first); + } - var attrs = svg.attributes; + const attrs = svg.attributes; - var _iterator2 = _createForOfIteratorHelper(attrs), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var attr = _step2.value; + for (const attr of attrs) { // Ok for `NamedNodeMap` symbol.setAttribute(attr.nodeName, attr.value); } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); + + symbol.id = getNextId(); // Store data + + importIds[uid] = { + symbol, + xform: ts + }; + findDefs().append(symbol); + batchCmd.addSubCommand(new InsertElementCommand$1(symbol)); } - symbol.id = getNextId(); // Store data + useEl = svgdoc.createElementNS(NS.SVG, 'use'); + useEl.id = getNextId(); + setHref(useEl, '#' + symbol.id); + (currentGroup || getCurrentDrawing().getCurrentLayer()).append(useEl); + batchCmd.addSubCommand(new InsertElementCommand$1(useEl)); + clearSelection(); + useEl.setAttribute('transform', ts); + recalculateDimensions(useEl); + $$a(useEl).data('symbol', symbol).data('ref', symbol); + addToSelection([useEl]); // TODO: Find way to add this in a recalculateDimensions-parsable way + // if (vb[0] !== 0 || vb[1] !== 0) { + // ts = 'translate(' + (-vb[0]) + ',' + (-vb[1]) + ') ' + ts; + // } - importIds[uid] = { - symbol: symbol, - xform: ts - }; - findDefs().append(symbol); - batchCmd.addSubCommand(new InsertElementCommand$1(symbol)); + addCommandToHistory(batchCmd); + call('changed', [svgcontent]); + } catch (e) { + console.log(e); // eslint-disable-line no-console + + return null; + } // we want to return the element so we can automatically select it + + + return useEl; + }; // Could deprecate, but besides external uses, their usage makes clear that + // canvas is a dependency for all of these + + + const dr = { + identifyLayers, + createLayer, + cloneLayer, + deleteCurrentLayer, + setCurrentLayer, + renameCurrentLayer, + setCurrentLayerPosition, + setLayerVisibility, + moveSelectedToLayer, + mergeLayer, + mergeAllLayers, + leaveContext, + setContext + }; + Object.entries(dr).forEach(([prop, propVal]) => { + canvas[prop] = propVal; + }); + init$3( + /** + * @implements {module:draw.DrawCanvasInit} + */ + { + pathActions, + + getCurrentGroup() { + return currentGroup; + }, + + setCurrentGroup(cg) { + currentGroup = cg; + }, + + getSelectedElements, + getSVGContent, + undoMgr, + elData, + getCurrentDrawing, + clearSelection, + call, + addCommandToHistory, + + /** + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + changeSVGContent() { + call('changed', [svgcontent]); } - useEl = svgdoc.createElementNS(NS.SVG, 'use'); - useEl.id = getNextId(); - setHref(useEl, '#' + symbol.id); - (currentGroup || getCurrentDrawing().getCurrentLayer()).append(useEl); - batchCmd.addSubCommand(new InsertElementCommand$1(useEl)); - clearSelection(); - useEl.setAttribute('transform', ts); - recalculateDimensions(useEl); - $$9(useEl).data('symbol', symbol).data('ref', symbol); - addToSelection([useEl]); // TODO: Find way to add this in a recalculateDimensions-parsable way - // if (vb[0] !== 0 || vb[1] !== 0) { - // ts = 'translate(' + (-vb[0]) + ',' + (-vb[1]) + ') ' + ts; - // } - - addCommandToHistory(batchCmd); - call('changed', [svgcontent]); - } catch (e) { - console.log(e); // eslint-disable-line no-console - - return null; - } // we want to return the element so we can automatically select it - - - return useEl; - }; // Could deprecate, but besides external uses, their usage makes clear that - // canvas is a dependency for all of these - - - var dr = { - identifyLayers: identifyLayers, - createLayer: createLayer, - cloneLayer: cloneLayer, - deleteCurrentLayer: deleteCurrentLayer, - setCurrentLayer: setCurrentLayer, - renameCurrentLayer: renameCurrentLayer, - setCurrentLayerPosition: setCurrentLayerPosition, - setLayerVisibility: setLayerVisibility, - moveSelectedToLayer: moveSelectedToLayer, - mergeLayer: mergeLayer, - mergeAllLayers: mergeAllLayers, - leaveContext: leaveContext, - setContext: setContext - }; - Object.entries(dr).forEach(function (_ref7) { - var _ref8 = _slicedToArray(_ref7, 2), - prop = _ref8[0], - propVal = _ref8[1]; - - canvas[prop] = propVal; - }); - init$3( - /** - * @implements {module:draw.DrawCanvasInit} - */ - { - pathActions: pathActions$1, - getCurrentGroup: function getCurrentGroup() { - return currentGroup; - }, - setCurrentGroup: function setCurrentGroup(cg) { - currentGroup = cg; - }, - getSelectedElements: getSelectedElements, - getSVGContent: getSVGContent, - undoMgr: undoMgr, - elData: elData, - getCurrentDrawing: getCurrentDrawing, - clearSelection: clearSelection, - call: call, - addCommandToHistory: addCommandToHistory, + }); + /** + * Group: Document functions. + */ /** - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - changeSVGContent: function changeSVGContent() { - call('changed', [svgcontent]); - } - }); - /** - * Group: Document functions. - */ + * Clears the current document. This is not an undoable action. + * @function module:svgcanvas.SvgCanvas#clear + * @fires module:svgcanvas.SvgCanvas#event:cleared + * @returns {void} + */ - /** - * Clears the current document. This is not an undoable action. - * @function module:svgcanvas.SvgCanvas#clear - * @fires module:svgcanvas.SvgCanvas#event:cleared - * @returns {void} - */ + this.clear = function () { + pathActions.clear(); + clearSelection(); // clear the svgcontent node - this.clear = function () { - pathActions$1.clear(); - clearSelection(); // clear the svgcontent node + canvas.clearSvgContentElement(); // create new document - canvas.clearSvgContentElement(); // create new document + canvas.current_drawing_ = new Drawing(svgcontent); // create empty first layer - canvas.current_drawing_ = new Drawing(svgcontent); // create empty first layer + canvas.createLayer('Layer 1'); // clear the undo stack - canvas.createLayer('Layer 1'); // clear the undo stack + canvas.undoMgr.resetUndoStack(); // reset the selector manager - canvas.undoMgr.resetUndoStack(); // reset the selector manager + selectorManager.initGroup(); // reset the rubber band box - selectorManager.initGroup(); // reset the rubber band box - - rubberBox = selectorManager.getRubberBandBox(); - call('cleared'); - }; // Alias function + rubberBox = selectorManager.getRubberBandBox(); + call('cleared'); + }; // Alias function - this.linkControlPoints = pathActions$1.linkControlPoints; - /** - * @function module:svgcanvas.SvgCanvas#getContentElem - * @returns {Element} The content DOM element - */ + this.linkControlPoints = pathActions.linkControlPoints; + /** + * @function module:svgcanvas.SvgCanvas#getContentElem + * @returns {Element} The content DOM element + */ - this.getContentElem = function () { - return svgcontent; - }; - /** - * @function module:svgcanvas.SvgCanvas#getRootElem - * @returns {SVGSVGElement} The root DOM element - */ - - - this.getRootElem = function () { - return svgroot; - }; - /** - * @typedef {PlainObject} DimensionsAndZoom - * @property {Float} w Width - * @property {Float} h Height - * @property {Float} zoom Zoom - */ - - /** - * @function module:svgcanvas.SvgCanvas#getResolution - * @returns {DimensionsAndZoom} The current dimensions and zoom level in an object - */ - - - var getResolution = this.getResolution = function () { - // const vb = svgcontent.getAttribute('viewBox').split(' '); - // return {w:vb[2], h:vb[3], zoom: currentZoom}; - var w = svgcontent.getAttribute('width') / currentZoom; - var h = svgcontent.getAttribute('height') / currentZoom; - return { - w: w, - h: h, - zoom: currentZoom + this.getContentElem = function () { + return svgcontent; }; - }; - /** - * @function module:svgcanvas.SvgCanvas#getSnapToGrid - * @returns {boolean} The current snap to grid setting - */ + /** + * @function module:svgcanvas.SvgCanvas#getRootElem + * @returns {SVGSVGElement} The root DOM element + */ - this.getSnapToGrid = function () { - return curConfig.gridSnapping; - }; - /** - * @function module:svgcanvas.SvgCanvas#getVersion - * @returns {string} A string which describes the revision number of SvgCanvas. - */ + this.getRootElem = function () { + return svgroot; + }; + /** + * @typedef {PlainObject} DimensionsAndZoom + * @property {Float} w Width + * @property {Float} h Height + * @property {Float} zoom Zoom + */ + + /** + * @function module:svgcanvas.SvgCanvas#getResolution + * @returns {DimensionsAndZoom} The current dimensions and zoom level in an object + */ - this.getVersion = function () { - return 'svgcanvas.js ($Rev$)'; - }; - /** - * Update interface strings with given values. - * @function module:svgcanvas.SvgCanvas#setUiStrings - * @param {module:path.uiStrings} strs - Object with strings (see the [locales API]{@link module:locale.LocaleStrings} and the [tutorial]{@tutorial LocaleDocs}) - * @returns {void} - */ + const getResolution = this.getResolution = function () { + // const vb = svgcontent.getAttribute('viewBox').split(' '); + // return {w:vb[2], h:vb[3], zoom: currentZoom}; + const w = svgcontent.getAttribute('width') / currentZoom; + const h = svgcontent.getAttribute('height') / currentZoom; + return { + w, + h, + zoom: currentZoom + }; + }; + /** + * @function module:svgcanvas.SvgCanvas#getSnapToGrid + * @returns {boolean} The current snap to grid setting + */ - this.setUiStrings = function (strs) { - Object.assign(uiStrings, strs.notification); - $$9 = jQueryPluginDBox($$9, strs.common); - setUiStrings(strs); - }; - /** - * Update configuration options with given values. - * @function module:svgcanvas.SvgCanvas#setConfig - * @param {module:SVGEditor.Config} opts - Object with options - * @returns {void} - */ + this.getSnapToGrid = function () { + return curConfig.gridSnapping; + }; + /** + * @function module:svgcanvas.SvgCanvas#getVersion + * @returns {string} A string which describes the revision number of SvgCanvas. + */ - this.setConfig = function (opts) { - Object.assign(curConfig, opts); - }; - /** - * @function module:svgcanvas.SvgCanvas#getTitle - * @param {Element} [elem] - * @returns {string|void} the current group/SVG's title contents or - * `undefined` if no element is passed nd there are no selected elements. - */ + this.getVersion = function () { + return 'svgcanvas.js ($Rev$)'; + }; + /** + * Update interface strings with given values. + * @function module:svgcanvas.SvgCanvas#setUiStrings + * @param {module:path.uiStrings} strs - Object with strings (see the [locales API]{@link module:locale.LocaleStrings} and the [tutorial]{@tutorial LocaleDocs}) + * @returns {void} + */ - this.getTitle = function (elem) { - elem = elem || selectedElements[0]; + this.setUiStrings = function (strs) { + Object.assign(uiStrings, strs.notification); + $$a = jQueryPluginDBox($$a, strs.common); + setUiStrings(strs); + }; + /** + * Update configuration options with given values. + * @function module:svgcanvas.SvgCanvas#setConfig + * @param {module:SVGEditor.Config} opts - Object with options + * @returns {void} + */ - if (!elem) { - return undefined; - } - elem = $$9(elem).data('gsvg') || $$9(elem).data('symbol') || elem; - var childs = elem.childNodes; + this.setConfig = function (opts) { + Object.assign(curConfig, opts); + }; + /** + * @function module:svgcanvas.SvgCanvas#getTitle + * @param {Element} [elem] + * @returns {string|void} the current group/SVG's title contents or + * `undefined` if no element is passed nd there are no selected elements. + */ - var _iterator3 = _createForOfIteratorHelper(childs), - _step3; - try { - for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { - var child = _step3.value; + this.getTitle = function (elem) { + elem = elem || selectedElements[0]; + if (!elem) { + return undefined; + } + + elem = $$a(elem).data('gsvg') || $$a(elem).data('symbol') || elem; + const childs = elem.childNodes; + + for (const child of childs) { if (child.nodeName === 'title') { return child.textContent; } } - } catch (err) { - _iterator3.e(err); - } finally { - _iterator3.f(); - } - return ''; - }; - /** - * Sets the group/SVG's title content. - * @function module:svgcanvas.SvgCanvas#setGroupTitle - * @param {string} val - * @todo Combine this with `setDocumentTitle` - * @returns {void} - */ + return ''; + }; + /** + * Sets the group/SVG's title content. + * @function module:svgcanvas.SvgCanvas#setGroupTitle + * @param {string} val + * @todo Combine this with `setDocumentTitle` + * @returns {void} + */ - this.setGroupTitle = function (val) { - var elem = selectedElements[0]; - elem = $$9(elem).data('gsvg') || elem; - var ts = $$9(elem).children('title'); - var batchCmd = new BatchCommand$1('Set Label'); - var title; + this.setGroupTitle = function (val) { + let elem = selectedElements[0]; + elem = $$a(elem).data('gsvg') || elem; + const ts = $$a(elem).children('title'); + const batchCmd = new BatchCommand$1('Set Label'); + let title; - if (!val.length) { - // Remove title element - var tsNextSibling = ts.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand$1(ts[0], tsNextSibling, elem)); - ts.remove(); - } else if (ts.length) { - // Change title contents - title = ts[0]; - batchCmd.addSubCommand(new ChangeElementCommand$1(title, { - '#text': title.textContent - })); - title.textContent = val; - } else { - // Add title element - title = svgdoc.createElementNS(NS.SVG, 'title'); - title.textContent = val; - $$9(elem).prepend(title); - batchCmd.addSubCommand(new InsertElementCommand$1(title)); - } + if (!val.length) { + // Remove title element + const tsNextSibling = ts.nextSibling; + batchCmd.addSubCommand(new RemoveElementCommand$1(ts[0], tsNextSibling, elem)); + ts.remove(); + } else if (ts.length) { + // Change title contents + title = ts[0]; + batchCmd.addSubCommand(new ChangeElementCommand$1(title, { + '#text': title.textContent + })); + title.textContent = val; + } else { + // Add title element + title = svgdoc.createElementNS(NS.SVG, 'title'); + title.textContent = val; + $$a(elem).prepend(title); + batchCmd.addSubCommand(new InsertElementCommand$1(title)); + } - addCommandToHistory(batchCmd); - }; - /** - * @function module:svgcanvas.SvgCanvas#getDocumentTitle - * @returns {string|void} The current document title or an empty string if not found - */ + addCommandToHistory(batchCmd); + }; + /** + * @function module:svgcanvas.SvgCanvas#getDocumentTitle + * @returns {string|void} The current document title or an empty string if not found + */ - var getDocumentTitle = this.getDocumentTitle = function () { - return canvas.getTitle(svgcontent); - }; - /** - * Adds/updates a title element for the document with the given name. - * This is an undoable action. - * @function module:svgcanvas.SvgCanvas#setDocumentTitle - * @param {string} newTitle - String with the new title - * @returns {void} - */ + const getDocumentTitle = this.getDocumentTitle = function () { + return canvas.getTitle(svgcontent); + }; + /** + * Adds/updates a title element for the document with the given name. + * This is an undoable action. + * @function module:svgcanvas.SvgCanvas#setDocumentTitle + * @param {string} newTitle - String with the new title + * @returns {void} + */ - this.setDocumentTitle = function (newTitle) { - var childs = svgcontent.childNodes; - var docTitle = false, - oldTitle = ''; - var batchCmd = new BatchCommand$1('Change Image Title'); - - var _iterator4 = _createForOfIteratorHelper(childs), - _step4; - - try { - for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { - var child = _step4.value; + this.setDocumentTitle = function (newTitle) { + const childs = svgcontent.childNodes; + let docTitle = false, + oldTitle = ''; + const batchCmd = new BatchCommand$1('Change Image Title'); + for (const child of childs) { if (child.nodeName === 'title') { docTitle = child; oldTitle = docTitle.textContent; break; } } - } catch (err) { - _iterator4.e(err); - } finally { - _iterator4.f(); - } - if (!docTitle) { - docTitle = svgdoc.createElementNS(NS.SVG, 'title'); - svgcontent.insertBefore(docTitle, svgcontent.firstChild); // svgcontent.firstChild.before(docTitle); // Ok to replace above with this? - } + if (!docTitle) { + docTitle = svgdoc.createElementNS(NS.SVG, 'title'); + svgcontent.insertBefore(docTitle, svgcontent.firstChild); // svgcontent.firstChild.before(docTitle); // Ok to replace above with this? + } - if (newTitle.length) { - docTitle.textContent = newTitle; - } else { - // No title given, so element is not necessary - docTitle.remove(); - } - - batchCmd.addSubCommand(new ChangeElementCommand$1(docTitle, { - '#text': oldTitle - })); - addCommandToHistory(batchCmd); - }; - /** - * Returns the editor's namespace URL, optionally adding it to the root element. - * @function module:svgcanvas.SvgCanvas#getEditorNS - * @param {boolean} [add] - Indicates whether or not to add the namespace value - * @returns {string} The editor's namespace URL - */ - - - this.getEditorNS = function (add) { - if (add) { - svgcontent.setAttribute('xmlns:se', NS.SE); - } - - return NS.SE; - }; - /** - * Changes the document's dimensions to the given size. - * @function module:svgcanvas.SvgCanvas#setResolution - * @param {Float|"fit"} x - Number with the width of the new dimensions in user units. - * Can also be the string "fit" to indicate "fit to content". - * @param {Float} y - Number with the height of the new dimensions in user units. - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {boolean} Indicates if resolution change was successful. - * It will fail on "fit to content" option with no content to fit to. - */ - - - this.setResolution = function (x, y) { - var res = getResolution(); - var w = res.w, - h = res.h; - var batchCmd; - - if (x === 'fit') { - // Get bounding box - var bbox = getStrokedBBoxDefaultVisible(); - - if (bbox) { - batchCmd = new BatchCommand$1('Fit Canvas to Content'); - var visEls = getVisibleElements(); - addToSelection(visEls); - var dx = [], - dy = []; - $$9.each(visEls, function (i, item) { - dx.push(bbox.x * -1); - dy.push(bbox.y * -1); - }); - var cmd = canvas.moveSelectedElements(dx, dy, true); - batchCmd.addSubCommand(cmd); - clearSelection(); - x = Math.round(bbox.width); - y = Math.round(bbox.height); + if (newTitle.length) { + docTitle.textContent = newTitle; } else { - return false; - } - } - - if (x !== w || y !== h) { - if (!batchCmd) { - batchCmd = new BatchCommand$1('Change Image Dimensions'); + // No title given, so element is not necessary + docTitle.remove(); } - x = convertToNum('width', x); - y = convertToNum('height', y); - svgcontent.setAttribute('width', x); - svgcontent.setAttribute('height', y); - this.contentW = x; - this.contentH = y; - batchCmd.addSubCommand(new ChangeElementCommand$1(svgcontent, { - width: w, - height: h - })); - svgcontent.setAttribute('viewBox', [0, 0, x / currentZoom, y / currentZoom].join(' ')); - batchCmd.addSubCommand(new ChangeElementCommand$1(svgcontent, { - viewBox: ['0 0', w, h].join(' ') + batchCmd.addSubCommand(new ChangeElementCommand$1(docTitle, { + '#text': oldTitle })); addCommandToHistory(batchCmd); - call('changed', [svgcontent]); - } - - return true; - }; - /** - * @typedef {module:jQueryAttr.Attributes} module:svgcanvas.ElementPositionInCanvas - * @property {Float} x - * @property {Float} y - */ - - /** - * @function module:svgcanvas.SvgCanvas#getOffset - * @returns {module:svgcanvas.ElementPositionInCanvas} An object with `x`, `y` values indicating the svgcontent element's - * position in the editor's canvas. - */ + }; + /** + * Returns the editor's namespace URL, optionally adding it to the root element. + * @function module:svgcanvas.SvgCanvas#getEditorNS + * @param {boolean} [add] - Indicates whether or not to add the namespace value + * @returns {string} The editor's namespace URL + */ - this.getOffset = function () { - return $$9(svgcontent).attr(['x', 'y']); - }; - /** - * @typedef {PlainObject} module:svgcanvas.ZoomAndBBox - * @property {Float} zoom - * @property {module:utilities.BBoxObject} bbox - */ - - /** - * Sets the zoom level on the canvas-side based on the given value. - * @function module:svgcanvas.SvgCanvas#setBBoxZoom - * @param {"selection"|"canvas"|"content"|"layer"|module:SVGEditor.BBoxObjectWithFactor} val - Bounding box object to zoom to or string indicating zoom option. Note: the object value type is defined in `svg-editor.js` - * @param {Integer} editorW - The editor's workarea box's width - * @param {Integer} editorH - The editor's workarea box's height - * @returns {module:svgcanvas.ZoomAndBBox|void} - */ - - - this.setBBoxZoom = function (val, editorW, editorH) { - var spacer = 0.85; - var bb; - - var calcZoom = function calcZoom(bb) { - // eslint-disable-line no-shadow - if (!bb) { - return false; + this.getEditorNS = function (add) { + if (add) { + svgcontent.setAttribute('xmlns:se', NS.SE); } - var wZoom = Math.round(editorW / bb.width * 100 * spacer) / 100; - var hZoom = Math.round(editorH / bb.height * 100 * spacer) / 100; - var zoom = Math.min(wZoom, hZoom); - canvas.setZoom(zoom); - return { - zoom: zoom, - bbox: bb - }; + return NS.SE; }; + /** + * Changes the document's dimensions to the given size. + * @function module:svgcanvas.SvgCanvas#setResolution + * @param {Float|"fit"} x - Number with the width of the new dimensions in user units. + * Can also be the string "fit" to indicate "fit to content". + * @param {Float} y - Number with the height of the new dimensions in user units. + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {boolean} Indicates if resolution change was successful. + * It will fail on "fit to content" option with no content to fit to. + */ - if (_typeof(val) === 'object') { - bb = val; - if (bb.width === 0 || bb.height === 0) { - var newzoom = bb.zoom ? bb.zoom : currentZoom * bb.factor; - canvas.setZoom(newzoom); + this.setResolution = function (x, y) { + const res = getResolution(); + const { + w, + h + } = res; + let batchCmd; + + if (x === 'fit') { + // Get bounding box + const bbox = getStrokedBBoxDefaultVisible(); + + if (bbox) { + batchCmd = new BatchCommand$1('Fit Canvas to Content'); + const visEls = getVisibleElements(); + addToSelection(visEls); + const dx = [], + dy = []; + $$a.each(visEls, function (i, item) { + dx.push(bbox.x * -1); + dy.push(bbox.y * -1); + }); + const cmd = canvas.moveSelectedElements(dx, dy, true); + batchCmd.addSubCommand(cmd); + clearSelection(); + x = Math.round(bbox.width); + y = Math.round(bbox.height); + } else { + return false; + } + } + + if (x !== w || y !== h) { + if (!batchCmd) { + batchCmd = new BatchCommand$1('Change Image Dimensions'); + } + + x = convertToNum('width', x); + y = convertToNum('height', y); + svgcontent.setAttribute('width', x); + svgcontent.setAttribute('height', y); + this.contentW = x; + this.contentH = y; + batchCmd.addSubCommand(new ChangeElementCommand$1(svgcontent, { + width: w, + height: h + })); + svgcontent.setAttribute('viewBox', [0, 0, x / currentZoom, y / currentZoom].join(' ')); + batchCmd.addSubCommand(new ChangeElementCommand$1(svgcontent, { + viewBox: ['0 0', w, h].join(' ') + })); + addCommandToHistory(batchCmd); + call('changed', [svgcontent]); + } + + return true; + }; + /** + * @typedef {module:jQueryAttr.Attributes} module:svgcanvas.ElementPositionInCanvas + * @property {Float} x + * @property {Float} y + */ + + /** + * @function module:svgcanvas.SvgCanvas#getOffset + * @returns {module:svgcanvas.ElementPositionInCanvas} An object with `x`, `y` values indicating the svgcontent element's + * position in the editor's canvas. + */ + + + this.getOffset = function () { + return $$a(svgcontent).attr(['x', 'y']); + }; + /** + * @typedef {PlainObject} module:svgcanvas.ZoomAndBBox + * @property {Float} zoom + * @property {module:utilities.BBoxObject} bbox + */ + + /** + * Sets the zoom level on the canvas-side based on the given value. + * @function module:svgcanvas.SvgCanvas#setBBoxZoom + * @param {"selection"|"canvas"|"content"|"layer"|module:SVGEditor.BBoxObjectWithFactor} val - Bounding box object to zoom to or string indicating zoom option. Note: the object value type is defined in `svg-editor.js` + * @param {Integer} editorW - The editor's workarea box's width + * @param {Integer} editorH - The editor's workarea box's height + * @returns {module:svgcanvas.ZoomAndBBox|void} + */ + + + this.setBBoxZoom = function (val, editorW, editorH) { + let spacer = 0.85; + let bb; + + const calcZoom = function (bb) { + // eslint-disable-line no-shadow + if (!bb) { + return false; + } + + const wZoom = Math.round(editorW / bb.width * 100 * spacer) / 100; + const hZoom = Math.round(editorH / bb.height * 100 * spacer) / 100; + const zoom = Math.min(wZoom, hZoom); + canvas.setZoom(zoom); return { - zoom: currentZoom, + zoom, bbox: bb }; + }; + + if (typeof val === 'object') { + bb = val; + + if (bb.width === 0 || bb.height === 0) { + const newzoom = bb.zoom ? bb.zoom : currentZoom * bb.factor; + canvas.setZoom(newzoom); + return { + zoom: currentZoom, + bbox: bb + }; + } + + return calcZoom(bb); + } + + switch (val) { + case 'selection': + { + if (!selectedElements[0]) { + return undefined; + } + + const selectedElems = $$a.map(selectedElements, function (n) { + if (n) { + return n; + } + + return undefined; + }); + bb = getStrokedBBoxDefaultVisible(selectedElems); + break; + } + + case 'canvas': + { + const res = getResolution(); + spacer = 0.95; + bb = { + width: res.w, + height: res.h, + x: 0, + y: 0 + }; + break; + } + + case 'content': + bb = getStrokedBBoxDefaultVisible(); + break; + + case 'layer': + bb = getStrokedBBoxDefaultVisible(getVisibleElements(getCurrentDrawing().getCurrentLayer())); + break; + + default: + return undefined; } return calcZoom(bb); - } + }; + /** + * The zoom level has changed. Supplies the new zoom level as a number (not percentage). + * @event module:svgcanvas.SvgCanvas#event:ext_zoomChanged + * @type {Float} + */ - switch (val) { - case 'selection': - { - if (!selectedElements[0]) { - return undefined; - } + /** + * The bottom panel was updated. + * @event module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate + * @type {PlainObject} + * @property {boolean} nofill Indicates fill is disabled + * @property {boolean} nostroke Indicates stroke is disabled + */ - var selectedElems = $$9.map(selectedElements, function (n) { - if (n) { - return n; + /** + * The element selection has changed (elements were added/removed from selection). + * @event module:svgcanvas.SvgCanvas#event:ext_selectedChanged + * @type {PlainObject} + * @property {Element[]} elems Array of the newly selected elements + * @property {Element|null} selectedElement The single selected element + * @property {boolean} multiselected Indicates whether one or more elements were selected + */ + + /** + * Called when part of element is in process of changing, generally on + * mousemove actions like rotate, move, etc. + * @event module:svgcanvas.SvgCanvas#event:ext_elementTransition + * @type {PlainObject} + * @property {Element[]} elems Array of transitioning elements + */ + + /** + * One or more elements were changed. + * @event module:svgcanvas.SvgCanvas#event:ext_elementChanged + * @type {PlainObject} + * @property {Element[]} elems Array of the affected elements + */ + + /** + * Invoked as soon as the locale is ready. + * @event module:svgcanvas.SvgCanvas#event:ext_langReady + * @type {PlainObject} + * @property {string} lang The two-letter language code + * @property {module:SVGEditor.uiStrings} uiStrings + * @property {module:SVGEditor~ImportLocale} importLocale + */ + + /** + * The language was changed. Two-letter code of the new language. + * @event module:svgcanvas.SvgCanvas#event:ext_langChanged + * @type {string} + */ + + /** + * Means for an extension to add locale data. The two-letter language code. + * @event module:svgcanvas.SvgCanvas#event:ext_addLangData + * @type {PlainObject} + * @property {string} lang + * @property {module:SVGEditor~ImportLocale} importLocale + */ + + /** + * Called when new image is created. + * @event module:svgcanvas.SvgCanvas#event:ext_onNewDocument + * @type {void} + */ + + /** + * Called when sidepanel is resized or toggled. + * @event module:svgcanvas.SvgCanvas#event:ext_workareaResized + * @type {void} + */ + + /** + * Called upon addition of the extension, or, if svgicons are set, + * after the icons are ready when extension SVG icons have loaded. + * @event module:svgcanvas.SvgCanvas#event:ext_callback + * @type {void} + */ + + /** + * Sets the zoom to the given level. + * @function module:svgcanvas.SvgCanvas#setZoom + * @param {Float} zoomLevel - Float indicating the zoom level to change to + * @fires module:svgcanvas.SvgCanvas#event:ext_zoomChanged + * @returns {void} + */ + + + this.setZoom = function (zoomLevel) { + const res = getResolution(); + svgcontent.setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel); + currentZoom = zoomLevel; + $$a.each(selectedElements, function (i, elem) { + if (!elem) { + return; + } + + selectorManager.requestSelector(elem).resize(); + }); + pathActions.zoomChange(); + runExtensions('zoomChanged', + /** @type {module:svgcanvas.SvgCanvas#event:ext_zoomChanged} */ + zoomLevel); + }; + /** + * @function module:svgcanvas.SvgCanvas#getMode + * @returns {string} The current editor mode string + */ + + + this.getMode = function () { + return currentMode; + }; + /** + * Sets the editor's mode to the given string. + * @function module:svgcanvas.SvgCanvas#setMode + * @param {string} name - String with the new mode to change to + * @returns {void} + */ + + + this.setMode = function (name) { + pathActions.clear(true); + textActions.clear(); + curProperties = selectedElements[0] && selectedElements[0].nodeName === 'text' ? curText : curShape; + currentMode = name; + }; + /** + * Group: Element Styling. + */ + + /** + * @typedef {PlainObject} module:svgcanvas.PaintOptions + * @property {"solidColor"} type + */ + + /** + * @function module:svgcanvas.SvgCanvas#getColor + * @param {string} type + * @returns {string|module:svgcanvas.PaintOptions|Float|module:jGraduate~Paint} The current fill/stroke option + */ + + + this.getColor = function (type) { + return curProperties[type]; + }; + /** + * Change the current stroke/fill color/gradient value. + * @function module:svgcanvas.SvgCanvas#setColor + * @param {string} type - String indicating fill or stroke + * @param {string} val - The value to set the stroke attribute to + * @param {boolean} preventUndo - Boolean indicating whether or not this should be an undoable option + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.setColor = function (type, val, preventUndo) { + curShape[type] = val; + curProperties[type + '_paint'] = { + type: 'solidColor' + }; + const elems = []; + /** + * + * @param {Element} e + * @returns {void} + */ + + function addNonG(e) { + if (e.nodeName !== 'g') { + elems.push(e); + } + } + + let i = selectedElements.length; + + while (i--) { + const elem = selectedElements[i]; + + if (elem) { + if (elem.tagName === 'g') { + walkTree(elem, addNonG); + } else if (type === 'fill') { + if (elem.tagName !== 'polyline' && elem.tagName !== 'line') { + elems.push(elem); } - - return undefined; - }); - bb = getStrokedBBoxDefaultVisible(selectedElems); - break; + } else { + elems.push(elem); + } } + } - case 'canvas': - { - var res = getResolution(); - spacer = 0.95; - bb = { - width: res.w, - height: res.h, - x: 0, - y: 0 - }; - break; + if (elems.length > 0) { + if (!preventUndo) { + changeSelectedAttribute(type, val, elems); + call('changed', elems); + } else { + changeSelectedAttributeNoUndo(type, val, elems); } - - case 'content': - bb = getStrokedBBoxDefaultVisible(); - break; - - case 'layer': - bb = getStrokedBBoxDefaultVisible(getVisibleElements(getCurrentDrawing().getCurrentLayer())); - break; - - default: - return undefined; - } - - return calcZoom(bb); - }; - /** - * The zoom level has changed. Supplies the new zoom level as a number (not percentage). - * @event module:svgcanvas.SvgCanvas#event:ext_zoomChanged - * @type {Float} - */ - - /** - * The bottom panel was updated. - * @event module:svgcanvas.SvgCanvas#event:ext_toolButtonStateUpdate - * @type {PlainObject} - * @property {boolean} nofill Indicates fill is disabled - * @property {boolean} nostroke Indicates stroke is disabled - */ - - /** - * The element selection has changed (elements were added/removed from selection). - * @event module:svgcanvas.SvgCanvas#event:ext_selectedChanged - * @type {PlainObject} - * @property {Element[]} elems Array of the newly selected elements - * @property {Element|null} selectedElement The single selected element - * @property {boolean} multiselected Indicates whether one or more elements were selected - */ - - /** - * Called when part of element is in process of changing, generally on - * mousemove actions like rotate, move, etc. - * @event module:svgcanvas.SvgCanvas#event:ext_elementTransition - * @type {PlainObject} - * @property {Element[]} elems Array of transitioning elements - */ - - /** - * One or more elements were changed. - * @event module:svgcanvas.SvgCanvas#event:ext_elementChanged - * @type {PlainObject} - * @property {Element[]} elems Array of the affected elements - */ - - /** - * Invoked as soon as the locale is ready. - * @event module:svgcanvas.SvgCanvas#event:ext_langReady - * @type {PlainObject} - * @property {string} lang The two-letter language code - * @property {module:SVGEditor.uiStrings} uiStrings - * @property {module:SVGEditor~ImportLocale} importLocale - */ - - /** - * The language was changed. Two-letter code of the new language. - * @event module:svgcanvas.SvgCanvas#event:ext_langChanged - * @type {string} - */ - - /** - * Means for an extension to add locale data. The two-letter language code. - * @event module:svgcanvas.SvgCanvas#event:ext_addLangData - * @type {PlainObject} - * @property {string} lang - * @property {module:SVGEditor~ImportLocale} importLocale - */ - - /** - * Called when new image is created. - * @event module:svgcanvas.SvgCanvas#event:ext_onNewDocument - * @type {void} - */ - - /** - * Called when sidepanel is resized or toggled. - * @event module:svgcanvas.SvgCanvas#event:ext_workareaResized - * @type {void} - */ - - /** - * Called upon addition of the extension, or, if svgicons are set, - * after the icons are ready when extension SVG icons have loaded. - * @event module:svgcanvas.SvgCanvas#event:ext_callback - * @type {void} - */ - - /** - * Sets the zoom to the given level. - * @function module:svgcanvas.SvgCanvas#setZoom - * @param {Float} zoomLevel - Float indicating the zoom level to change to - * @fires module:svgcanvas.SvgCanvas#event:ext_zoomChanged - * @returns {void} - */ + } + }; + /** + * Apply the current gradient to selected element's fill or stroke. + * @function module:svgcanvas.SvgCanvas#setGradient + * @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element + * @returns {void} + */ - this.setZoom = function (zoomLevel) { - var res = getResolution(); - svgcontent.setAttribute('viewBox', '0 0 ' + res.w / zoomLevel + ' ' + res.h / zoomLevel); - currentZoom = zoomLevel; - $$9.each(selectedElements, function (i, elem) { - if (!elem) { + const setGradient = this.setGradient = function (type) { + if (!curProperties[type + '_paint'] || curProperties[type + '_paint'].type === 'solidColor') { return; } - selectorManager.requestSelector(elem).resize(); - }); - pathActions$1.zoomChange(); - runExtensions('zoomChanged', - /** @type {module:svgcanvas.SvgCanvas#event:ext_zoomChanged} */ - zoomLevel); - }; - /** - * @function module:svgcanvas.SvgCanvas#getMode - * @returns {string} The current editor mode string - */ + let grad = canvas[type + 'Grad']; // find out if there is a duplicate gradient already in the defs + const duplicateGrad = findDuplicateGradient(grad); + const defs = findDefs(); // no duplicate found, so import gradient into defs - this.getMode = function () { - return currentMode; - }; - /** - * Sets the editor's mode to the given string. - * @function module:svgcanvas.SvgCanvas#setMode - * @param {string} name - String with the new mode to change to - * @returns {void} - */ + if (!duplicateGrad) { + // const origGrad = grad; + grad = defs.appendChild(svgdoc.importNode(grad, true)); // get next id and set it on the grad - - this.setMode = function (name) { - pathActions$1.clear(true); - textActions.clear(); - curProperties = selectedElements[0] && selectedElements[0].nodeName === 'text' ? curText : curShape; - currentMode = name; - }; - /** - * Group: Element Styling. - */ - - /** - * @typedef {PlainObject} module:svgcanvas.PaintOptions - * @property {"solidColor"} type - */ - - /** - * @function module:svgcanvas.SvgCanvas#getColor - * @param {string} type - * @returns {string|module:svgcanvas.PaintOptions|Float|module:jGraduate~Paint} The current fill/stroke option - */ - - - this.getColor = function (type) { - return curProperties[type]; - }; - /** - * Change the current stroke/fill color/gradient value. - * @function module:svgcanvas.SvgCanvas#setColor - * @param {string} type - String indicating fill or stroke - * @param {string} val - The value to set the stroke attribute to - * @param {boolean} preventUndo - Boolean indicating whether or not this should be an undoable option - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.setColor = function (type, val, preventUndo) { - curShape[type] = val; - curProperties[type + '_paint'] = { - type: 'solidColor' - }; - var elems = []; - /** - * - * @param {Element} e - * @returns {void} - */ - - function addNonG(e) { - if (e.nodeName !== 'g') { - elems.push(e); + grad.id = getNextId(); + } else { + // use existing gradient + grad = duplicateGrad; } - } - var i = selectedElements.length; + canvas.setColor(type, 'url(#' + grad.id + ')'); + }; + /** + * Check if exact gradient already exists. + * @function module:svgcanvas~findDuplicateGradient + * @param {SVGGradientElement} grad - The gradient DOM element to compare to others + * @returns {SVGGradientElement} The existing gradient if found, `null` if not + */ - while (i--) { - var elem = selectedElements[i]; - if (elem) { - if (elem.tagName === 'g') { - walkTree(elem, addNonG); - } else if (type === 'fill') { - if (elem.tagName !== 'polyline' && elem.tagName !== 'line') { - elems.push(elem); + const findDuplicateGradient = function (grad) { + const defs = findDefs(); + const existingGrads = $$a(defs).find('linearGradient, radialGradient'); + let i = existingGrads.length; + const radAttrs = ['r', 'cx', 'cy', 'fx', 'fy']; + + while (i--) { + const og = existingGrads[i]; + + if (grad.tagName === 'linearGradient') { + if (grad.getAttribute('x1') !== og.getAttribute('x1') || grad.getAttribute('y1') !== og.getAttribute('y1') || grad.getAttribute('x2') !== og.getAttribute('x2') || grad.getAttribute('y2') !== og.getAttribute('y2')) { + continue; } } else { - elems.push(elem); - } - } - } - - if (elems.length > 0) { - if (!preventUndo) { - changeSelectedAttribute(type, val, elems); - call('changed', elems); - } else { - changeSelectedAttributeNoUndo(type, val, elems); - } - } - }; - /** - * Apply the current gradient to selected element's fill or stroke. - * @function module:svgcanvas.SvgCanvas#setGradient - * @param {"fill"|"stroke"} type - String indicating "fill" or "stroke" to apply to an element - * @returns {void} - */ - - - var setGradient = this.setGradient = function (type) { - if (!curProperties[type + '_paint'] || curProperties[type + '_paint'].type === 'solidColor') { - return; - } - - var grad = canvas[type + 'Grad']; // find out if there is a duplicate gradient already in the defs - - var duplicateGrad = findDuplicateGradient(grad); - var defs = findDefs(); // no duplicate found, so import gradient into defs - - if (!duplicateGrad) { - // const origGrad = grad; - grad = defs.appendChild(svgdoc.importNode(grad, true)); // get next id and set it on the grad - - grad.id = getNextId(); - } else { - // use existing gradient - grad = duplicateGrad; - } - - canvas.setColor(type, 'url(#' + grad.id + ')'); - }; - /** - * Check if exact gradient already exists. - * @function module:svgcanvas~findDuplicateGradient - * @param {SVGGradientElement} grad - The gradient DOM element to compare to others - * @returns {SVGGradientElement} The existing gradient if found, `null` if not - */ - - - var findDuplicateGradient = function findDuplicateGradient(grad) { - var defs = findDefs(); - var existingGrads = $$9(defs).find('linearGradient, radialGradient'); - var i = existingGrads.length; - var radAttrs = ['r', 'cx', 'cy', 'fx', 'fy']; - - while (i--) { - var og = existingGrads[i]; - - if (grad.tagName === 'linearGradient') { - if (grad.getAttribute('x1') !== og.getAttribute('x1') || grad.getAttribute('y1') !== og.getAttribute('y1') || grad.getAttribute('x2') !== og.getAttribute('x2') || grad.getAttribute('y2') !== og.getAttribute('y2')) { - continue; - } - } else { - var _ret = function () { - var gradAttrs = $$9(grad).attr(radAttrs); - var ogAttrs = $$9(og).attr(radAttrs); - var diff = false; - $$9.each(radAttrs, function (j, attr) { + const gradAttrs = $$a(grad).attr(radAttrs); + const ogAttrs = $$a(og).attr(radAttrs); + let diff = false; + $$a.each(radAttrs, function (j, attr) { if (gradAttrs[attr] !== ogAttrs[attr]) { diff = true; } }); if (diff) { - return "continue"; + continue; } - }(); + } // else could be a duplicate, iterate through stops - if (_ret === "continue") continue; - } // else could be a duplicate, iterate through stops + const stops = grad.getElementsByTagNameNS(NS.SVG, 'stop'); + const ostops = og.getElementsByTagNameNS(NS.SVG, 'stop'); - var stops = grad.getElementsByTagNameNS(NS.SVG, 'stop'); - var ostops = og.getElementsByTagNameNS(NS.SVG, 'stop'); - - if (stops.length !== ostops.length) { - continue; - } - - var j = stops.length; - - while (j--) { - var stop = stops[j]; - var ostop = ostops[j]; - - if (stop.getAttribute('offset') !== ostop.getAttribute('offset') || stop.getAttribute('stop-opacity') !== ostop.getAttribute('stop-opacity') || stop.getAttribute('stop-color') !== ostop.getAttribute('stop-color')) { - break; - } - } - - if (j === -1) { - return og; - } - } // for each gradient in defs - - - return null; - }; - /** - * Set a color/gradient to a fill/stroke. - * @function module:svgcanvas.SvgCanvas#setPaint - * @param {"fill"|"stroke"} type - String with "fill" or "stroke" - * @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply - * @returns {void} - */ - - - this.setPaint = function (type, paint) { - // make a copy - var p = new $$9.jGraduate.Paint(paint); - this.setPaintOpacity(type, p.alpha / 100, true); // now set the current paint object - - curProperties[type + '_paint'] = p; - - switch (p.type) { - case 'solidColor': - this.setColor(type, p.solidColor !== 'none' ? '#' + p.solidColor : 'none'); - break; - - case 'linearGradient': - case 'radialGradient': - canvas[type + 'Grad'] = p[p.type]; - setGradient(type); - break; - } - }; - /** - * @function module:svgcanvas.SvgCanvas#setStrokePaint - * @param {module:jGraduate~Paint} paint - * @returns {void} - */ - - - this.setStrokePaint = function (paint) { - this.setPaint('stroke', paint); - }; - /** - * @function module:svgcanvas.SvgCanvas#setFillPaint - * @param {module:jGraduate~Paint} paint - * @returns {void} - */ - - - this.setFillPaint = function (paint) { - this.setPaint('fill', paint); - }; - /** - * @function module:svgcanvas.SvgCanvas#getStrokeWidth - * @returns {Float|string} The current stroke-width value - */ - - - this.getStrokeWidth = function () { - return curProperties.stroke_width; - }; - /** - * Sets the stroke width for the current selected elements. - * When attempting to set a line's width to 0, this changes it to 1 instead. - * @function module:svgcanvas.SvgCanvas#setStrokeWidth - * @param {Float} val - A Float indicating the new stroke width value - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.setStrokeWidth = function (val) { - if (val === 0 && ['line', 'path'].includes(currentMode)) { - canvas.setStrokeWidth(1); - return; - } - - curProperties.stroke_width = val; - var elems = []; - /** - * - * @param {Element} e - * @returns {void} - */ - - function addNonG(e) { - if (e.nodeName !== 'g') { - elems.push(e); - } - } - - var i = selectedElements.length; - - while (i--) { - var elem = selectedElements[i]; - - if (elem) { - if (elem.tagName === 'g') { - walkTree(elem, addNonG); - } else { - elems.push(elem); - } - } - } - - if (elems.length > 0) { - changeSelectedAttribute('stroke-width', val, elems); - call('changed', selectedElements); - } - }; - /** - * Set the given stroke-related attribute the given value for selected elements. - * @function module:svgcanvas.SvgCanvas#setStrokeAttr - * @param {string} attr - String with the attribute name - * @param {string|Float} val - String or number with the attribute value - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.setStrokeAttr = function (attr, val) { - curShape[attr.replace('-', '_')] = val; - var elems = []; - var i = selectedElements.length; - - while (i--) { - var elem = selectedElements[i]; - - if (elem) { - if (elem.tagName === 'g') { - walkTree(elem, function (e) { - if (e.nodeName !== 'g') { - elems.push(e); - } - }); - } else { - elems.push(elem); - } - } - } - - if (elems.length > 0) { - changeSelectedAttribute(attr, val, elems); - call('changed', selectedElements); - } - }; - /** - * @typedef {PlainObject} module:svgcanvas.StyleOptions - * @property {string} fill - * @property {Float} fill_opacity - * @property {string} stroke - * @property {Float} stroke_width - * @property {string} stroke_dasharray - * @property {string} stroke_linejoin - * @property {string} stroke_linecap - * @property {Float} stroke_opacity - * @property {Float} opacity - */ - - /** - * @function module:svgcanvas.SvgCanvas#getStyle - * @returns {module:svgcanvas.StyleOptions} current style options - */ - - - this.getStyle = function () { - return curShape; - }; - /** - * @function module:svgcanvas.SvgCanvas#getOpacity - * @returns {Float} the current opacity - */ - - - this.getOpacity = getOpacity; - /** - * Sets the given opacity on the current selected elements. - * @function module:svgcanvas.SvgCanvas#setOpacity - * @param {string} val - * @returns {void} - */ - - this.setOpacity = function (val) { - curShape.opacity = val; - changeSelectedAttribute('opacity', val); - }; - /** - * @function module:svgcanvas.SvgCanvas#getFillOpacity - * @returns {Float} the current fill opacity - */ - - - this.getFillOpacity = function () { - return curShape.fill_opacity; - }; - /** - * @function module:svgcanvas.SvgCanvas#getStrokeOpacity - * @returns {string} the current stroke opacity - */ - - - this.getStrokeOpacity = function () { - return curShape.stroke_opacity; - }; - /** - * Sets the current fill/stroke opacity. - * @function module:svgcanvas.SvgCanvas#setPaintOpacity - * @param {string} type - String with "fill" or "stroke" - * @param {Float} val - Float with the new opacity value - * @param {boolean} preventUndo - Indicates whether or not this should be an undoable action - * @returns {void} - */ - - - this.setPaintOpacity = function (type, val, preventUndo) { - curShape[type + '_opacity'] = val; - - if (!preventUndo) { - changeSelectedAttribute(type + '-opacity', val); - } else { - changeSelectedAttributeNoUndo(type + '-opacity', val); - } - }; - /** - * Gets the current fill/stroke opacity. - * @function module:svgcanvas.SvgCanvas#getPaintOpacity - * @param {"fill"|"stroke"} type - String with "fill" or "stroke" - * @returns {Float} Fill/stroke opacity - */ - - - this.getPaintOpacity = function (type) { - return type === 'fill' ? this.getFillOpacity() : this.getStrokeOpacity(); - }; - /** - * Gets the `stdDeviation` blur value of the given element. - * @function module:svgcanvas.SvgCanvas#getBlur - * @param {Element} elem - The element to check the blur value for - * @returns {string} stdDeviation blur attribute value - */ - - - this.getBlur = function (elem) { - var val = 0; // const elem = selectedElements[0]; - - if (elem) { - var filterUrl = elem.getAttribute('filter'); - - if (filterUrl) { - var blur = getElem(elem.id + '_blur'); - - if (blur) { - val = blur.firstChild.getAttribute('stdDeviation'); - } - } - } - - return val; - }; - - (function () { - var curCommand = null; - var filter = null; - var filterHidden = false; - /** - * Sets the `stdDeviation` blur value on the selected element without being undoable. - * @function module:svgcanvas.SvgCanvas#setBlurNoUndo - * @param {Float} val - The new `stdDeviation` value - * @returns {void} - */ - - canvas.setBlurNoUndo = function (val) { - if (!filter) { - canvas.setBlur(val); - return; - } - - if (val === 0) { - // Don't change the StdDev, as that will hide the element. - // Instead, just remove the value for "filter" - changeSelectedAttributeNoUndo('filter', ''); - filterHidden = true; - } else { - var elem = selectedElements[0]; - - if (filterHidden) { - changeSelectedAttributeNoUndo('filter', 'url(#' + elem.id + '_blur)'); - } - - if (isWebkit()) { - // console.log('e', elem); // eslint-disable-line no-console - elem.removeAttribute('filter'); - elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); - } - - changeSelectedAttributeNoUndo('stdDeviation', val, [filter.firstChild]); - canvas.setBlurOffsets(filter, val); - } - }; - /** - * - * @returns {void} - */ - - - function finishChange() { - var bCmd = canvas.undoMgr.finishUndoableChange(); - curCommand.addSubCommand(bCmd); - addCommandToHistory(curCommand); - curCommand = null; - filter = null; - } - /** - * Sets the `x`, `y`, `width`, `height` values of the filter element in order to - * make the blur not be clipped. Removes them if not neeeded. - * @function module:svgcanvas.SvgCanvas#setBlurOffsets - * @param {Element} filterElem - The filter DOM element to update - * @param {Float} stdDev - The standard deviation value on which to base the offset size - * @returns {void} - */ - - - canvas.setBlurOffsets = function (filterElem, stdDev) { - if (stdDev > 3) { - // TODO: Create algorithm here where size is based on expected blur - assignAttributes(filterElem, { - x: '-50%', - y: '-50%', - width: '200%', - height: '200%' - }); // Removing these attributes hides text in Chrome (see Issue 579) - } else if (!isWebkit()) { - filterElem.removeAttribute('x'); - filterElem.removeAttribute('y'); - filterElem.removeAttribute('width'); - filterElem.removeAttribute('height'); - } - }; - /** - * Adds/updates the blur filter to the selected element. - * @function module:svgcanvas.SvgCanvas#setBlur - * @param {Float} val - Float with the new `stdDeviation` blur value - * @param {boolean} complete - Whether or not the action should be completed (to add to the undo manager) - * @returns {void} - */ - - - canvas.setBlur = function (val, complete) { - if (curCommand) { - finishChange(); - return; - } // Looks for associated blur, creates one if not found - - - var elem = selectedElements[0]; - var elemId = elem.id; - filter = getElem(elemId + '_blur'); - val -= 0; - var batchCmd = new BatchCommand$1(); // Blur found! - - if (filter) { - if (val === 0) { - filter = null; - } - } else { - // Not found, so create - var newblur = addSVGElementFromJson({ - element: 'feGaussianBlur', - attr: { - "in": 'SourceGraphic', - stdDeviation: val - } - }); - filter = addSVGElementFromJson({ - element: 'filter', - attr: { - id: elemId + '_blur' - } - }); - filter.append(newblur); - findDefs().append(filter); - batchCmd.addSubCommand(new InsertElementCommand$1(filter)); - } - - var changes = { - filter: elem.getAttribute('filter') - }; - - if (val === 0) { - elem.removeAttribute('filter'); - batchCmd.addSubCommand(new ChangeElementCommand$1(elem, changes)); - return; - } - - changeSelectedAttribute('filter', 'url(#' + elemId + '_blur)'); - batchCmd.addSubCommand(new ChangeElementCommand$1(elem, changes)); - canvas.setBlurOffsets(filter, val); - curCommand = batchCmd; - canvas.undoMgr.beginUndoableChange('stdDeviation', [filter ? filter.firstChild : null]); - - if (complete) { - canvas.setBlurNoUndo(val); - finishChange(); - } - }; - })(); - /** - * Check whether selected element is bold or not. - * @function module:svgcanvas.SvgCanvas#getBold - * @returns {boolean} Indicates whether or not element is bold - */ - - - this.getBold = function () { - // should only have one element selected - var selected = selectedElements[0]; - - if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - return selected.getAttribute('font-weight') === 'bold'; - } - - return false; - }; - /** - * Make the selected element bold or normal. - * @function module:svgcanvas.SvgCanvas#setBold - * @param {boolean} b - Indicates bold (`true`) or normal (`false`) - * @returns {void} - */ - - - this.setBold = function (b) { - var selected = selectedElements[0]; - - if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - changeSelectedAttribute('font-weight', b ? 'bold' : 'normal'); - } - - if (!selectedElements[0].textContent) { - textActions.setCursor(); - } - }; - /** - * Check whether selected element is in italics or not. - * @function module:svgcanvas.SvgCanvas#getItalic - * @returns {boolean} Indicates whether or not element is italic - */ - - - this.getItalic = function () { - var selected = selectedElements[0]; - - if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - return selected.getAttribute('font-style') === 'italic'; - } - - return false; - }; - /** - * Make the selected element italic or normal. - * @function module:svgcanvas.SvgCanvas#setItalic - * @param {boolean} i - Indicates italic (`true`) or normal (`false`) - * @returns {void} - */ - - - this.setItalic = function (i) { - var selected = selectedElements[0]; - - if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { - changeSelectedAttribute('font-style', i ? 'italic' : 'normal'); - } - - if (!selectedElements[0].textContent) { - textActions.setCursor(); - } - }; - /** - * @function module:svgcanvas.SvgCanvas#getFontFamily - * @returns {string} The current font family - */ - - - this.getFontFamily = function () { - return curText.font_family; - }; - /** - * Set the new font family. - * @function module:svgcanvas.SvgCanvas#setFontFamily - * @param {string} val - String with the new font family - * @returns {void} - */ - - - this.setFontFamily = function (val) { - curText.font_family = val; - changeSelectedAttribute('font-family', val); - - if (selectedElements[0] && !selectedElements[0].textContent) { - textActions.setCursor(); - } - }; - /** - * Set the new font color. - * @function module:svgcanvas.SvgCanvas#setFontColor - * @param {string} val - String with the new font color - * @returns {void} - */ - - - this.setFontColor = function (val) { - curText.fill = val; - changeSelectedAttribute('fill', val); - }; - /** - * @function module:svgcanvas.SvgCanvas#getFontColor - * @returns {string} The current font color - */ - - - this.getFontColor = function () { - return curText.fill; - }; - /** - * @function module:svgcanvas.SvgCanvas#getFontSize - * @returns {Float} The current font size - */ - - - this.getFontSize = function () { - return curText.font_size; - }; - /** - * Applies the given font size to the selected element. - * @function module:svgcanvas.SvgCanvas#setFontSize - * @param {Float} val - Float with the new font size - * @returns {void} - */ - - - this.setFontSize = function (val) { - curText.font_size = val; - changeSelectedAttribute('font-size', val); - - if (!selectedElements[0].textContent) { - textActions.setCursor(); - } - }; - /** - * @function module:svgcanvas.SvgCanvas#getText - * @returns {string} The current text (`textContent`) of the selected element - */ - - - this.getText = function () { - var selected = selectedElements[0]; - - if (isNullish(selected)) { - return ''; - } - - return selected.textContent; - }; - /** - * Updates the text element with the given string. - * @function module:svgcanvas.SvgCanvas#setTextContent - * @param {string} val - String with the new text - * @returns {void} - */ - - - this.setTextContent = function (val) { - changeSelectedAttribute('#text', val); - textActions.init(val); - textActions.setCursor(); - }; - /** - * Sets the new image URL for the selected image element. Updates its size if - * a new URL is given. - * @function module:svgcanvas.SvgCanvas#setImageURL - * @param {string} val - String with the image URL/path - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.setImageURL = function (val) { - var elem = selectedElements[0]; - - if (!elem) { - return; - } - - var attrs = $$9(elem).attr(['width', 'height']); - var setsize = !attrs.width || !attrs.height; - var curHref = getHref(elem); // Do nothing if no URL change or size change - - if (curHref === val && !setsize) { - return; - } - - var batchCmd = new BatchCommand$1('Change Image URL'); - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand$1(elem, { - '#href': curHref - })); - $$9(new Image()).load(function () { - var changes = $$9(elem).attr(['width', 'height']); - $$9(elem).attr({ - width: this.width, - height: this.height - }); - selectorManager.requestSelector(elem).resize(); - batchCmd.addSubCommand(new ChangeElementCommand$1(elem, changes)); - addCommandToHistory(batchCmd); - call('changed', [elem]); - }).attr('src', val); - }; - /** - * Sets the new link URL for the selected anchor element. - * @function module:svgcanvas.SvgCanvas#setLinkURL - * @param {string} val - String with the link URL/path - * @returns {void} - */ - - - this.setLinkURL = function (val) { - var elem = selectedElements[0]; - - if (!elem) { - return; - } - - if (elem.tagName !== 'a') { - // See if parent is an anchor - var parentsA = $$9(elem).parents('a'); - - if (parentsA.length) { - elem = parentsA[0]; - } else { - return; - } - } - - var curHref = getHref(elem); - - if (curHref === val) { - return; - } - - var batchCmd = new BatchCommand$1('Change Link URL'); - setHref(elem, val); - batchCmd.addSubCommand(new ChangeElementCommand$1(elem, { - '#href': curHref - })); - addCommandToHistory(batchCmd); - }; - /** - * Sets the `rx` and `ry` values to the selected `rect` element - * to change its corner radius. - * @function module:svgcanvas.SvgCanvas#setRectRadius - * @param {string|Float} val - The new radius - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.setRectRadius = function (val) { - var selected = selectedElements[0]; - - if (!isNullish(selected) && selected.tagName === 'rect') { - var r = selected.getAttribute('rx'); - - if (r !== String(val)) { - selected.setAttribute('rx', val); - selected.setAttribute('ry', val); - addCommandToHistory(new ChangeElementCommand$1(selected, { - rx: r, - ry: r - }, 'Radius')); - call('changed', [selected]); - } - } - }; - /** - * Wraps the selected element(s) in an anchor element or converts group to one. - * @function module:svgcanvas.SvgCanvas#makeHyperlink - * @param {string} url - * @returns {void} - */ - - - this.makeHyperlink = function (url) { - canvas.groupSelectedElements('a', url); // TODO: If element is a single "g", convert to "a" - // if (selectedElements.length > 1 && selectedElements[1]) { - }; - /** - * @function module:svgcanvas.SvgCanvas#removeHyperlink - * @returns {void} - */ - - - this.removeHyperlink = function () { - canvas.ungroupSelectedElement(); - }; - /** - * Group: Element manipulation. - */ - - /** - * Sets the new segment type to the selected segment(s). - * @function module:svgcanvas.SvgCanvas#setSegType - * @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list - * @returns {void} - */ - - - this.setSegType = function (newType) { - pathActions$1.setSegType(newType); - }; - /** - * Convert selected element to a path, or get the BBox of an element-as-path. - * @function module:svgcanvas.SvgCanvas#convertToPath - * @todo (codedread): Remove the getBBox argument and split this function into two. - * @param {Element} elem - The DOM element to be converted - * @param {boolean} getBBox - Boolean on whether or not to only return the path's BBox - * @returns {void|DOMRect|false|SVGPathElement|null} If the getBBox flag is true, the resulting path's bounding box object. - * Otherwise the resulting path element is returned. - */ - - - this.convertToPath = function (elem, getBBox) { - if (isNullish(elem)) { - var elems = selectedElements; - $$9.each(elems, function (i, el) { - if (el) { - canvas.convertToPath(el); - } - }); - return undefined; - } - - if (getBBox) { - return getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions$1); - } // TODO: Why is this applying attributes from curShape, then inside utilities.convertToPath it's pulling addition attributes from elem? - // TODO: If convertToPath is called with one elem, curShape and elem are probably the same; but calling with multiple is a bug or cool feature. - - - var attrs = { - fill: curShape.fill, - 'fill-opacity': curShape.fill_opacity, - stroke: curShape.stroke, - 'stroke-width': curShape.stroke_width, - 'stroke-dasharray': curShape.stroke_dasharray, - 'stroke-linejoin': curShape.stroke_linejoin, - 'stroke-linecap': curShape.stroke_linecap, - 'stroke-opacity': curShape.stroke_opacity, - opacity: curShape.opacity, - visibility: 'hidden' - }; - return convertToPath(elem, attrs, addSVGElementFromJson, pathActions$1, clearSelection, addToSelection, hstry, addCommandToHistory); - }; - /** - * This function makes the changes to the elements. It does not add the change - * to the history stack. - * @param {string} attr - Attribute name - * @param {string|Float} newValue - String or number with the new attribute value - * @param {Element[]} elems - The DOM elements to apply the change to - * @returns {void} - */ - - - var changeSelectedAttributeNoUndo = function changeSelectedAttributeNoUndo(attr, newValue, elems) { - if (currentMode === 'pathedit') { - // Editing node - pathActions$1.moveNode(attr, newValue); - } - - elems = elems || selectedElements; - var i = elems.length; - var noXYElems = ['g', 'polyline', 'path']; // const goodGAttrs = ['transform', 'opacity', 'filter']; - - var _loop = function _loop() { - var elem = elems[i]; - - if (isNullish(elem)) { - return "continue"; - } // Set x,y vals on elements that don't have them - - - if ((attr === 'x' || attr === 'y') && noXYElems.includes(elem.tagName)) { - var bbox = getStrokedBBoxDefaultVisible([elem]); - var diffX = attr === 'x' ? newValue - bbox.x : 0; - var diffY = attr === 'y' ? newValue - bbox.y : 0; - canvas.moveSelectedElements(diffX * currentZoom, diffY * currentZoom, true); - return "continue"; - } // only allow the transform/opacity/filter attribute to change on <g> elements, slightly hacky - // TODO: Missing statement body - // if (elem.tagName === 'g' && goodGAttrs.includes(attr)) {} - - - var oldval = attr === '#text' ? elem.textContent : elem.getAttribute(attr); - - if (isNullish(oldval)) { - oldval = ''; - } - - if (oldval !== String(newValue)) { - if (attr === '#text') { - // const oldW = utilsGetBBox(elem).width; - elem.textContent = newValue; // FF bug occurs on on rotated elements - - if (/rotate/.test(elem.getAttribute('transform'))) { - elem = ffClone(elem); - } // Hoped to solve the issue of moving text with text-anchor="start", - // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd - // const box = getBBox(elem), left = box.x, top = box.y, {width, height} = box, - // dx = width - oldW, dy = 0; - // const angle = getRotationAngle(elem, true); - // if (angle) { - // const r = Math.sqrt(dx * dx + dy * dy); - // const theta = Math.atan2(dy, dx) - angle; - // dx = r * Math.cos(theta); - // dy = r * Math.sin(theta); - // - // elem.setAttribute('x', elem.getAttribute('x') - dx); - // elem.setAttribute('y', elem.getAttribute('y') - dy); - // } - - } else if (attr === '#href') { - setHref(elem, newValue); - } else { - elem.setAttribute(attr, newValue); - } // Go into "select" mode for text changes - // NOTE: Important that this happens AFTER elem.setAttribute() or else attributes like - // font-size can get reset to their old value, ultimately by svgEditor.updateContextPanel(), - // after calling textActions.toSelectMode() below - - - if (currentMode === 'textedit' && attr !== '#text' && elem.textContent.length) { - textActions.toSelectMode(elem); - } // if (i === 0) { - // selectedBBoxes[0] = utilsGetBBox(elem); - // } - // Use the Firefox ffClone hack for text elements with gradients or - // where other text attributes are changed. - - - if (isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) { - if (String(newValue).startsWith('url') || ['font-size', 'font-family', 'x', 'y'].includes(attr) && elem.textContent) { - elem = ffClone(elem); - } - } // Timeout needed for Opera & Firefox - // codedread: it is now possible for this function to be called with elements - // that are not in the selectedElements array, we need to only request a - // selector if the element is in that array - - - if (selectedElements.includes(elem)) { - setTimeout(function () { - // Due to element replacement, this element may no longer - // be part of the DOM - if (!elem.parentNode) { - return; - } - - selectorManager.requestSelector(elem).resize(); - }, 0); - } // if this element was rotated, and we changed the position of this element - // we need to update the rotational transform attribute - - - var angle = getRotationAngle(elem); - - if (angle !== 0 && attr !== 'transform') { - var tlist = getTransformList(elem); - var n = tlist.numberOfItems; - - while (n--) { - var xform = tlist.getItem(n); - - if (xform.type === 4) { - // remove old rotate - tlist.removeItem(n); - var box = getBBox(elem); - var center = transformPoint(box.x + box.width / 2, box.y + box.height / 2, transformListToTransform(tlist).matrix); - var cx = center.x, - cy = center.y; - var newrot = svgroot.createSVGTransform(); - newrot.setRotate(angle, cx, cy); - tlist.insertItemBefore(newrot, n); - break; - } - } - } - } // if oldValue != newValue - - }; - - while (i--) { - var _ret2 = _loop(); - - if (_ret2 === "continue") continue; - } // for each elem - - }; - /** - * Change the given/selected element and add the original value to the history stack. - * If you want to change all `selectedElements`, ignore the `elems` argument. - * If you want to change only a subset of `selectedElements`, then send the - * subset to this function in the `elems` argument. - * @function module:svgcanvas.SvgCanvas#changeSelectedAttribute - * @param {string} attr - String with the attribute name - * @param {string|Float} val - String or number with the new attribute value - * @param {Element[]} elems - The DOM elements to apply the change to - * @returns {void} - */ - - - var changeSelectedAttribute = this.changeSelectedAttribute = function (attr, val, elems) { - elems = elems || selectedElements; - canvas.undoMgr.beginUndoableChange(attr, elems); // const i = elems.length; - - changeSelectedAttributeNoUndo(attr, val, elems); - var batchCmd = canvas.undoMgr.finishUndoableChange(); - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } - }; - /** - * Removes all selected elements from the DOM and adds the change to the - * history stack. - * @function module:svgcanvas.SvgCanvas#deleteSelectedElements - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.deleteSelectedElements = function () { - var batchCmd = new BatchCommand$1('Delete Elements'); - var len = selectedElements.length; - var selectedCopy = []; // selectedElements is being deleted - - for (var i = 0; i < len; ++i) { - var selected = selectedElements[i]; - - if (isNullish(selected)) { - break; - } - - var parent = selected.parentNode; - var t = selected; // this will unselect the element and remove the selectedOutline - - selectorManager.releaseSelector(t); // Remove the path if present. - - removePath_(t.id); // Get the parent if it's a single-child anchor - - if (parent.tagName === 'a' && parent.childNodes.length === 1) { - t = parent; - parent = parent.parentNode; - } - - var _t = t, - nextSibling = _t.nextSibling; - t.remove(); - var elem = t; - selectedCopy.push(selected); // for the copy - - batchCmd.addSubCommand(new RemoveElementCommand$1(elem, nextSibling, parent)); - } - - selectedElements = []; - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } - - call('changed', selectedCopy); - clearSelection(); - }; - /** - * Removes all selected elements from the DOM and adds the change to the - * history stack. Remembers removed elements on the clipboard. - * @function module:svgcanvas.SvgCanvas#cutSelectedElements - * @returns {void} - */ - - - this.cutSelectedElements = function () { - canvas.copySelectedElements(); - canvas.deleteSelectedElements(); - }; - - var CLIPBOARD_ID = 'svgedit_clipboard'; - /** - * Flash the clipboard data momentarily on localStorage so all tabs can see. - * @returns {void} - */ - - function flashStorage() { - var data = sessionStorage.getItem(CLIPBOARD_ID); - localStorage.setItem(CLIPBOARD_ID, data); - setTimeout(function () { - localStorage.removeItem(CLIPBOARD_ID); - }, 1); - } - /** - * Transfers sessionStorage from one tab to another. - * @param {!Event} ev Storage event. - * @returns {void} - */ - - - function storageChange(ev) { - if (!ev.newValue) return; // This is a call from removeItem. - - if (ev.key === CLIPBOARD_ID + '_startup') { - // Another tab asked for our sessionStorage. - localStorage.removeItem(CLIPBOARD_ID + '_startup'); - flashStorage(); - } else if (ev.key === CLIPBOARD_ID) { - // Another tab sent data. - sessionStorage.setItem(CLIPBOARD_ID, ev.newValue); - } - } // Listen for changes to localStorage. - - - window.addEventListener('storage', storageChange, false); // Ask other tabs for sessionStorage (this is ONLY to trigger event). - - localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random()); - /** - * Remembers the current selected elements on the clipboard. - * @function module:svgcanvas.SvgCanvas#copySelectedElements - * @returns {void} - */ - - this.copySelectedElements = function () { - var data = JSON.stringify(selectedElements.map(function (x) { - return getJsonFromSvgElement(x); - })); // Use sessionStorage for the clipboard data. - - sessionStorage.setItem(CLIPBOARD_ID, data); - flashStorage(); - var menu = $$9('#cmenu_canvas'); // Context menu might not exist (it is provided by editor.js). - - if (menu.enableContextMenuItems) { - menu.enableContextMenuItems('#paste,#paste_in_place'); - } - }; - /** - * @function module:svgcanvas.SvgCanvas#pasteElements - * @param {"in_place"|"point"|void} type - * @param {Integer|void} x Expected if type is "point" - * @param {Integer|void} y Expected if type is "point" - * @fires module:svgcanvas.SvgCanvas#event:changed - * @fires module:svgcanvas.SvgCanvas#event:ext_IDsUpdated - * @returns {void} - */ - - - this.pasteElements = function (type, x, y) { - var clipb = JSON.parse(sessionStorage.getItem(CLIPBOARD_ID)); - if (!clipb) return; - var len = clipb.length; - if (!len) return; - var pasted = []; - var batchCmd = new BatchCommand$1('Paste elements'); // const drawing = getCurrentDrawing(); - - /** - * @typedef {PlainObject<string, string>} module:svgcanvas.ChangedIDs - */ - - /** - * @type {module:svgcanvas.ChangedIDs} - */ - - var changedIDs = {}; // Recursively replace IDs and record the changes - - /** - * - * @param {module:svgcanvas.SVGAsJSON} elem - * @returns {void} - */ - - function checkIDs(elem) { - if (elem.attr && elem.attr.id) { - changedIDs[elem.attr.id] = getNextId(); - elem.attr.id = changedIDs[elem.attr.id]; - } - - if (elem.children) elem.children.forEach(checkIDs); - } - - clipb.forEach(checkIDs); // Give extensions like the connector extension a chance to reflect new IDs and remove invalid elements - - /** - * Triggered when `pasteElements` is called from a paste action (context menu or key). - * @event module:svgcanvas.SvgCanvas#event:ext_IDsUpdated - * @type {PlainObject} - * @property {module:svgcanvas.SVGAsJSON[]} elems - * @property {module:svgcanvas.ChangedIDs} changes Maps past ID (on attribute) to current ID - */ - - runExtensions('IDsUpdated', - /** @type {module:svgcanvas.SvgCanvas#event:ext_IDsUpdated} */ - { - elems: clipb, - changes: changedIDs - }, true).forEach(function (extChanges) { - if (!extChanges || !('remove' in extChanges)) return; - extChanges.remove.forEach(function (removeID) { - clipb = clipb.filter(function (clipBoardItem) { - return clipBoardItem.attr.id !== removeID; - }); - }); - }); // Move elements to lastClickPoint - - while (len--) { - var elem = clipb[len]; - - if (!elem) { - continue; - } - - var copy = addSVGElementFromJson(elem); - pasted.push(copy); - batchCmd.addSubCommand(new InsertElementCommand$1(copy)); - restoreRefElems(copy); - } - - selectOnly(pasted); - - if (type !== 'in_place') { - var ctrX, ctrY; - - if (!type) { - ctrX = lastClickPoint.x; - ctrY = lastClickPoint.y; - } else if (type === 'point') { - ctrX = x; - ctrY = y; - } - - var bbox = getStrokedBBoxDefaultVisible(pasted); - var cx = ctrX - (bbox.x + bbox.width / 2), - cy = ctrY - (bbox.y + bbox.height / 2), - dx = [], - dy = []; - $$9.each(pasted, function (i, item) { - dx.push(cx); - dy.push(cy); - }); - var cmd = canvas.moveSelectedElements(dx, dy, false); - if (cmd) batchCmd.addSubCommand(cmd); - } - - addCommandToHistory(batchCmd); - call('changed', pasted); - }; - /** - * Wraps all the selected elements in a group (`g`) element. - * @function module:svgcanvas.SvgCanvas#groupSelectedElements - * @param {"a"|"g"} [type="g"] - type of element to group into, defaults to `<g>` - * @param {string} [urlArg] - * @returns {void} - */ - - - this.groupSelectedElements = function (type, urlArg) { - if (!type) { - type = 'g'; - } - - var cmdStr = ''; - var url; - - switch (type) { - case 'a': - { - cmdStr = 'Make hyperlink'; - url = urlArg || ''; - break; - } - - default: - { - type = 'g'; - cmdStr = 'Group Elements'; - break; - } - } - - var batchCmd = new BatchCommand$1(cmdStr); // create and insert the group element - - var g = addSVGElementFromJson({ - element: type, - attr: { - id: getNextId() - } - }); - - if (type === 'a') { - setHref(g, url); - } - - batchCmd.addSubCommand(new InsertElementCommand$1(g)); // now move all children into the group - - var i = selectedElements.length; - - while (i--) { - var elem = selectedElements[i]; - - if (isNullish(elem)) { - continue; - } - - if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { - elem = elem.parentNode; - } - - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; - g.append(elem); - batchCmd.addSubCommand(new MoveElementCommand$1(elem, oldNextSibling, oldParent)); - } - - if (!batchCmd.isEmpty()) { - addCommandToHistory(batchCmd); - } // update selection - - - selectOnly([g], true); - }; - /** - * Pushes all appropriate parent group properties down to its children, then - * removes them from the group. - * @function module:svgcanvas.SvgCanvas#pushGroupProperties - * @param {SVGAElement|SVGGElement} g - * @param {boolean} undoable - * @returns {BatchCommand|void} - */ - - - var pushGroupProperties = this.pushGroupProperties = function (g, undoable) { - var children = g.childNodes; - var len = children.length; - var xform = g.getAttribute('transform'); - var glist = getTransformList(g); - var m = transformListToTransform(glist).matrix; - var batchCmd = new BatchCommand$1('Push group properties'); // TODO: get all fill/stroke properties from the group that we are about to destroy - // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", - // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", - // "stroke-width" - // and then for each child, if they do not have the attribute (or the value is 'inherit') - // then set the child's attribute - - var gangle = getRotationAngle(g); - var gattrs = $$9(g).attr(['filter', 'opacity']); - var gfilter, gblur, changes; - var drawing = getCurrentDrawing(); - - for (var i = 0; i < len; i++) { - var elem = children[i]; - - if (elem.nodeType !== 1) { - continue; - } - - if (gattrs.opacity !== null && gattrs.opacity !== 1) { - // const c_opac = elem.getAttribute('opacity') || 1; - var newOpac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100) / 100; - changeSelectedAttribute('opacity', newOpac, [elem]); - } - - if (gattrs.filter) { - var cblur = this.getBlur(elem); - var origCblur = cblur; - - if (!gblur) { - gblur = this.getBlur(g); - } - - if (cblur) { - // Is this formula correct? - cblur = Number(gblur) + Number(cblur); - } else if (cblur === 0) { - cblur = gblur; - } // If child has no current filter, get group's filter or clone it. - - - if (!origCblur) { - // Set group's filter to use first child's ID - if (!gfilter) { - gfilter = getRefElem(gattrs.filter); - } else { - // Clone the group's filter - gfilter = drawing.copyElem(gfilter); - findDefs().append(gfilter); - } - } else { - gfilter = getRefElem(elem.getAttribute('filter')); - } // Change this in future for different filters - - - var suffix = gfilter.firstChild.tagName === 'feGaussianBlur' ? 'blur' : 'filter'; - gfilter.id = elem.id + '_' + suffix; - changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); // Update blur value - - if (cblur) { - changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); - canvas.setBlurOffsets(gfilter, cblur); - } - } - - var chtlist = getTransformList(elem); // Don't process gradient transforms - - if (elem.tagName.includes('Gradient')) { - chtlist = null; - } // Hopefully not a problem to add this. Necessary for elements like <desc/> - - - if (!chtlist) { - continue; - } // Apparently <defs> can get get a transformlist, but we don't want it to have one! - - - if (elem.tagName === 'defs') { - continue; - } - - if (glist.numberOfItems) { - // TODO: if the group's transform is just a rotate, we can always transfer the - // rotate() down to the children (collapsing consecutive rotates and factoring - // out any translates) - if (gangle && glist.numberOfItems === 1) { - // [Rg] [Rc] [Mc] - // we want [Tr] [Rc2] [Mc] where: - // - [Rc2] is at the child's current center but has the - // sum of the group and child's rotation angles - // - [Tr] is the equivalent translation that this child - // undergoes if the group wasn't there - // [Tr] = [Rg] [Rc] [Rc2_inv] - // get group's rotation matrix (Rg) - var rgm = glist.getItem(0).matrix; // get child's rotation matrix (Rc) - - var rcm = svgroot.createSVGMatrix(); - var cangle = getRotationAngle(elem); - - if (cangle) { - rcm = chtlist.getItem(0).matrix; - } // get child's old center of rotation - - - var cbox = getBBox(elem); - var ceqm = transformListToTransform(chtlist).matrix; - var coldc = transformPoint(cbox.x + cbox.width / 2, cbox.y + cbox.height / 2, ceqm); // sum group and child's angles - - var sangle = gangle + cangle; // get child's rotation at the old center (Rc2_inv) - - var r2 = svgroot.createSVGTransform(); - r2.setRotate(sangle, coldc.x, coldc.y); // calculate equivalent translate - - var trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); // set up tlist - - if (cangle) { - chtlist.removeItem(0); - } - - if (sangle) { - if (chtlist.numberOfItems) { - chtlist.insertItemBefore(r2, 0); - } else { - chtlist.appendItem(r2); - } - } - - if (trm.e || trm.f) { - var tr = svgroot.createSVGTransform(); - tr.setTranslate(trm.e, trm.f); - - if (chtlist.numberOfItems) { - chtlist.insertItemBefore(tr, 0); - } else { - chtlist.appendItem(tr); - } - } - } else { - // more complicated than just a rotate - // transfer the group's transform down to each child and then - // call recalculateDimensions() - var oldxform = elem.getAttribute('transform'); - changes = {}; - changes.transform = oldxform || ''; - var newxform = svgroot.createSVGTransform(); // [ gm ] [ chm ] = [ chm ] [ gm' ] - // [ gm' ] = [ chmInv ] [ gm ] [ chm ] - - var chm = transformListToTransform(chtlist).matrix, - chmInv = chm.inverse(); - var gm = matrixMultiply(chmInv, m, chm); - newxform.setMatrix(gm); - chtlist.appendItem(newxform); - } - - var cmd = recalculateDimensions(elem); - - if (cmd) { - batchCmd.addSubCommand(cmd); - } - } - } // remove transform and make it undo-able - - - if (xform) { - changes = {}; - changes.transform = xform; - g.setAttribute('transform', ''); - g.removeAttribute('transform'); - batchCmd.addSubCommand(new ChangeElementCommand$1(g, changes)); - } - - if (undoable && !batchCmd.isEmpty()) { - return batchCmd; - } - - return undefined; - }; - /** - * Unwraps all the elements in a selected group (`g`) element. This requires - * significant recalculations to apply group's transforms, etc. to its children. - * @function module:svgcanvas.SvgCanvas#ungroupSelectedElement - * @returns {void} - */ - - - this.ungroupSelectedElement = function () { - var g = selectedElements[0]; - - if (!g) { - return; - } - - if ($$9(g).data('gsvg') || $$9(g).data('symbol')) { - // Is svg, so actually convert to group - convertToGroup(g); - return; - } - - if (g.tagName === 'use') { - // Somehow doesn't have data set, so retrieve - var symbol = getElem(getHref(g).substr(1)); - $$9(g).data('symbol', symbol).data('ref', symbol); - convertToGroup(g); - return; - } - - var parentsA = $$9(g).parents('a'); - - if (parentsA.length) { - g = parentsA[0]; - } // Look for parent "a" - - - if (g.tagName === 'g' || g.tagName === 'a') { - var batchCmd = new BatchCommand$1('Ungroup Elements'); - var cmd = pushGroupProperties(g, true); - - if (cmd) { - batchCmd.addSubCommand(cmd); - } - - var parent = g.parentNode; - var anchor = g.nextSibling; - var children = new Array(g.childNodes.length); - var i = 0; - - while (g.firstChild) { - var elem = g.firstChild; - var oldNextSibling = elem.nextSibling; - var oldParent = elem.parentNode; // Remove child title elements - - if (elem.tagName === 'title') { - var nextSibling = elem.nextSibling; - batchCmd.addSubCommand(new RemoveElementCommand$1(elem, nextSibling, oldParent)); - elem.remove(); + if (stops.length !== ostops.length) { continue; } - if (anchor) { - anchor.before(elem); - } else { - g.after(elem); + let j = stops.length; + + while (j--) { + const stop = stops[j]; + const ostop = ostops[j]; + + if (stop.getAttribute('offset') !== ostop.getAttribute('offset') || stop.getAttribute('stop-opacity') !== ostop.getAttribute('stop-opacity') || stop.getAttribute('stop-color') !== ostop.getAttribute('stop-color')) { + break; + } } - children[i++] = elem; + if (j === -1) { + return og; + } + } // for each gradient in defs + + + return null; + }; + /** + * Set a color/gradient to a fill/stroke. + * @function module:svgcanvas.SvgCanvas#setPaint + * @param {"fill"|"stroke"} type - String with "fill" or "stroke" + * @param {module:jGraduate.jGraduatePaintOptions} paint - The jGraduate paint object to apply + * @returns {void} + */ + + + this.setPaint = function (type, paint) { + // make a copy + const p = new $$a.jGraduate.Paint(paint); + this.setPaintOpacity(type, p.alpha / 100, true); // now set the current paint object + + curProperties[type + '_paint'] = p; + + switch (p.type) { + case 'solidColor': + this.setColor(type, p.solidColor !== 'none' ? '#' + p.solidColor : 'none'); + break; + + case 'linearGradient': + case 'radialGradient': + canvas[type + 'Grad'] = p[p.type]; + setGradient(type); + break; + } + }; + /** + * @function module:svgcanvas.SvgCanvas#setStrokePaint + * @param {module:jGraduate~Paint} paint + * @returns {void} + */ + + + this.setStrokePaint = function (paint) { + this.setPaint('stroke', paint); + }; + /** + * @function module:svgcanvas.SvgCanvas#setFillPaint + * @param {module:jGraduate~Paint} paint + * @returns {void} + */ + + + this.setFillPaint = function (paint) { + this.setPaint('fill', paint); + }; + /** + * @function module:svgcanvas.SvgCanvas#getStrokeWidth + * @returns {Float|string} The current stroke-width value + */ + + + this.getStrokeWidth = function () { + return curProperties.stroke_width; + }; + /** + * Sets the stroke width for the current selected elements. + * When attempting to set a line's width to 0, this changes it to 1 instead. + * @function module:svgcanvas.SvgCanvas#setStrokeWidth + * @param {Float} val - A Float indicating the new stroke width value + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.setStrokeWidth = function (val) { + if (val === 0 && ['line', 'path'].includes(currentMode)) { + canvas.setStrokeWidth(1); + return; + } + + curProperties.stroke_width = val; + const elems = []; + /** + * + * @param {Element} e + * @returns {void} + */ + + function addNonG(e) { + if (e.nodeName !== 'g') { + elems.push(e); + } + } + + let i = selectedElements.length; + + while (i--) { + const elem = selectedElements[i]; + + if (elem) { + if (elem.tagName === 'g') { + walkTree(elem, addNonG); + } else { + elems.push(elem); + } + } + } + + if (elems.length > 0) { + changeSelectedAttribute('stroke-width', val, elems); + call('changed', selectedElements); + } + }; + /** + * Set the given stroke-related attribute the given value for selected elements. + * @function module:svgcanvas.SvgCanvas#setStrokeAttr + * @param {string} attr - String with the attribute name + * @param {string|Float} val - String or number with the attribute value + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.setStrokeAttr = function (attr, val) { + curShape[attr.replace('-', '_')] = val; + const elems = []; + let i = selectedElements.length; + + while (i--) { + const elem = selectedElements[i]; + + if (elem) { + if (elem.tagName === 'g') { + walkTree(elem, function (e) { + if (e.nodeName !== 'g') { + elems.push(e); + } + }); + } else { + elems.push(elem); + } + } + } + + if (elems.length > 0) { + changeSelectedAttribute(attr, val, elems); + call('changed', selectedElements); + } + }; + /** + * @typedef {PlainObject} module:svgcanvas.StyleOptions + * @property {string} fill + * @property {Float} fill_opacity + * @property {string} stroke + * @property {Float} stroke_width + * @property {string} stroke_dasharray + * @property {string} stroke_linejoin + * @property {string} stroke_linecap + * @property {Float} stroke_opacity + * @property {Float} opacity + */ + + /** + * @function module:svgcanvas.SvgCanvas#getStyle + * @returns {module:svgcanvas.StyleOptions} current style options + */ + + + this.getStyle = function () { + return curShape; + }; + /** + * @function module:svgcanvas.SvgCanvas#getOpacity + * @returns {Float} the current opacity + */ + + + this.getOpacity = getOpacity; + /** + * Sets the given opacity on the current selected elements. + * @function module:svgcanvas.SvgCanvas#setOpacity + * @param {string} val + * @returns {void} + */ + + this.setOpacity = function (val) { + curShape.opacity = val; + changeSelectedAttribute('opacity', val); + }; + /** + * @function module:svgcanvas.SvgCanvas#getFillOpacity + * @returns {Float} the current fill opacity + */ + + + this.getFillOpacity = function () { + return curShape.fill_opacity; + }; + /** + * @function module:svgcanvas.SvgCanvas#getStrokeOpacity + * @returns {string} the current stroke opacity + */ + + + this.getStrokeOpacity = function () { + return curShape.stroke_opacity; + }; + /** + * Sets the current fill/stroke opacity. + * @function module:svgcanvas.SvgCanvas#setPaintOpacity + * @param {string} type - String with "fill" or "stroke" + * @param {Float} val - Float with the new opacity value + * @param {boolean} preventUndo - Indicates whether or not this should be an undoable action + * @returns {void} + */ + + + this.setPaintOpacity = function (type, val, preventUndo) { + curShape[type + '_opacity'] = val; + + if (!preventUndo) { + changeSelectedAttribute(type + '-opacity', val); + } else { + changeSelectedAttributeNoUndo(type + '-opacity', val); + } + }; + /** + * Gets the current fill/stroke opacity. + * @function module:svgcanvas.SvgCanvas#getPaintOpacity + * @param {"fill"|"stroke"} type - String with "fill" or "stroke" + * @returns {Float} Fill/stroke opacity + */ + + + this.getPaintOpacity = function (type) { + return type === 'fill' ? this.getFillOpacity() : this.getStrokeOpacity(); + }; + /** + * Gets the `stdDeviation` blur value of the given element. + * @function module:svgcanvas.SvgCanvas#getBlur + * @param {Element} elem - The element to check the blur value for + * @returns {string} stdDeviation blur attribute value + */ + + + this.getBlur = function (elem) { + let val = 0; // const elem = selectedElements[0]; + + if (elem) { + const filterUrl = elem.getAttribute('filter'); + + if (filterUrl) { + const blur = getElem(elem.id + '_blur'); + + if (blur) { + val = blur.firstChild.getAttribute('stdDeviation'); + } + } + } + + return val; + }; + + (function () { + let curCommand = null; + let filter = null; + let filterHidden = false; + /** + * Sets the `stdDeviation` blur value on the selected element without being undoable. + * @function module:svgcanvas.SvgCanvas#setBlurNoUndo + * @param {Float} val - The new `stdDeviation` value + * @returns {void} + */ + + canvas.setBlurNoUndo = function (val) { + if (!filter) { + canvas.setBlur(val); + return; + } + + if (val === 0) { + // Don't change the StdDev, as that will hide the element. + // Instead, just remove the value for "filter" + changeSelectedAttributeNoUndo('filter', ''); + filterHidden = true; + } else { + const elem = selectedElements[0]; + + if (filterHidden) { + changeSelectedAttributeNoUndo('filter', 'url(#' + elem.id + '_blur)'); + } + + if (isWebkit()) { + // console.log('e', elem); // eslint-disable-line no-console + elem.removeAttribute('filter'); + elem.setAttribute('filter', 'url(#' + elem.id + '_blur)'); + } + + changeSelectedAttributeNoUndo('stdDeviation', val, [filter.firstChild]); + canvas.setBlurOffsets(filter, val); + } + }; + /** + * + * @returns {void} + */ + + + function finishChange() { + const bCmd = canvas.undoMgr.finishUndoableChange(); + curCommand.addSubCommand(bCmd); + addCommandToHistory(curCommand); + curCommand = null; + filter = null; + } + /** + * Sets the `x`, `y`, `width`, `height` values of the filter element in order to + * make the blur not be clipped. Removes them if not neeeded. + * @function module:svgcanvas.SvgCanvas#setBlurOffsets + * @param {Element} filterElem - The filter DOM element to update + * @param {Float} stdDev - The standard deviation value on which to base the offset size + * @returns {void} + */ + + + canvas.setBlurOffsets = function (filterElem, stdDev) { + if (stdDev > 3) { + // TODO: Create algorithm here where size is based on expected blur + assignAttributes(filterElem, { + x: '-50%', + y: '-50%', + width: '200%', + height: '200%' + }); // Removing these attributes hides text in Chrome (see Issue 579) + } else if (!isWebkit()) { + filterElem.removeAttribute('x'); + filterElem.removeAttribute('y'); + filterElem.removeAttribute('width'); + filterElem.removeAttribute('height'); + } + }; + /** + * Adds/updates the blur filter to the selected element. + * @function module:svgcanvas.SvgCanvas#setBlur + * @param {Float} val - Float with the new `stdDeviation` blur value + * @param {boolean} complete - Whether or not the action should be completed (to add to the undo manager) + * @returns {void} + */ + + + canvas.setBlur = function (val, complete) { + if (curCommand) { + finishChange(); + return; + } // Looks for associated blur, creates one if not found + + + const elem = selectedElements[0]; + const elemId = elem.id; + filter = getElem(elemId + '_blur'); + val -= 0; + const batchCmd = new BatchCommand$1(); // Blur found! + + if (filter) { + if (val === 0) { + filter = null; + } + } else { + // Not found, so create + const newblur = addSVGElementFromJson({ + element: 'feGaussianBlur', + attr: { + in: 'SourceGraphic', + stdDeviation: val + } + }); + filter = addSVGElementFromJson({ + element: 'filter', + attr: { + id: elemId + '_blur' + } + }); + filter.append(newblur); + findDefs().append(filter); + batchCmd.addSubCommand(new InsertElementCommand$1(filter)); + } + + const changes = { + filter: elem.getAttribute('filter') + }; + + if (val === 0) { + elem.removeAttribute('filter'); + batchCmd.addSubCommand(new ChangeElementCommand$1(elem, changes)); + return; + } + + changeSelectedAttribute('filter', 'url(#' + elemId + '_blur)'); + batchCmd.addSubCommand(new ChangeElementCommand$1(elem, changes)); + canvas.setBlurOffsets(filter, val); + curCommand = batchCmd; + canvas.undoMgr.beginUndoableChange('stdDeviation', [filter ? filter.firstChild : null]); + + if (complete) { + canvas.setBlurNoUndo(val); + finishChange(); + } + }; + })(); + /** + * Check whether selected element is bold or not. + * @function module:svgcanvas.SvgCanvas#getBold + * @returns {boolean} Indicates whether or not element is bold + */ + + + this.getBold = function () { + // should only have one element selected + const selected = selectedElements[0]; + + if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { + return selected.getAttribute('font-weight') === 'bold'; + } + + return false; + }; + /** + * Make the selected element bold or normal. + * @function module:svgcanvas.SvgCanvas#setBold + * @param {boolean} b - Indicates bold (`true`) or normal (`false`) + * @returns {void} + */ + + + this.setBold = function (b) { + const selected = selectedElements[0]; + + if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { + changeSelectedAttribute('font-weight', b ? 'bold' : 'normal'); + } + + if (!selectedElements[0].textContent) { + textActions.setCursor(); + } + }; + /** + * Check whether selected element is in italics or not. + * @function module:svgcanvas.SvgCanvas#getItalic + * @returns {boolean} Indicates whether or not element is italic + */ + + + this.getItalic = function () { + const selected = selectedElements[0]; + + if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { + return selected.getAttribute('font-style') === 'italic'; + } + + return false; + }; + /** + * Make the selected element italic or normal. + * @function module:svgcanvas.SvgCanvas#setItalic + * @param {boolean} i - Indicates italic (`true`) or normal (`false`) + * @returns {void} + */ + + + this.setItalic = function (i) { + const selected = selectedElements[0]; + + if (!isNullish(selected) && selected.tagName === 'text' && isNullish(selectedElements[1])) { + changeSelectedAttribute('font-style', i ? 'italic' : 'normal'); + } + + if (!selectedElements[0].textContent) { + textActions.setCursor(); + } + }; + /** + * @function module:svgcanvas.SvgCanvas#getFontFamily + * @returns {string} The current font family + */ + + + this.getFontFamily = function () { + return curText.font_family; + }; + /** + * Set the new font family. + * @function module:svgcanvas.SvgCanvas#setFontFamily + * @param {string} val - String with the new font family + * @returns {void} + */ + + + this.setFontFamily = function (val) { + curText.font_family = val; + changeSelectedAttribute('font-family', val); + + if (selectedElements[0] && !selectedElements[0].textContent) { + textActions.setCursor(); + } + }; + /** + * Set the new font color. + * @function module:svgcanvas.SvgCanvas#setFontColor + * @param {string} val - String with the new font color + * @returns {void} + */ + + + this.setFontColor = function (val) { + curText.fill = val; + changeSelectedAttribute('fill', val); + }; + /** + * @function module:svgcanvas.SvgCanvas#getFontColor + * @returns {string} The current font color + */ + + + this.getFontColor = function () { + return curText.fill; + }; + /** + * @function module:svgcanvas.SvgCanvas#getFontSize + * @returns {Float} The current font size + */ + + + this.getFontSize = function () { + return curText.font_size; + }; + /** + * Applies the given font size to the selected element. + * @function module:svgcanvas.SvgCanvas#setFontSize + * @param {Float} val - Float with the new font size + * @returns {void} + */ + + + this.setFontSize = function (val) { + curText.font_size = val; + changeSelectedAttribute('font-size', val); + + if (!selectedElements[0].textContent) { + textActions.setCursor(); + } + }; + /** + * @function module:svgcanvas.SvgCanvas#getText + * @returns {string} The current text (`textContent`) of the selected element + */ + + + this.getText = function () { + const selected = selectedElements[0]; + + if (isNullish(selected)) { + return ''; + } + + return selected.textContent; + }; + /** + * Updates the text element with the given string. + * @function module:svgcanvas.SvgCanvas#setTextContent + * @param {string} val - String with the new text + * @returns {void} + */ + + + this.setTextContent = function (val) { + changeSelectedAttribute('#text', val); + textActions.init(val); + textActions.setCursor(); + }; + /** + * Sets the new image URL for the selected image element. Updates its size if + * a new URL is given. + * @function module:svgcanvas.SvgCanvas#setImageURL + * @param {string} val - String with the image URL/path + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.setImageURL = function (val) { + const elem = selectedElements[0]; + + if (!elem) { + return; + } + + const attrs = $$a(elem).attr(['width', 'height']); + const setsize = !attrs.width || !attrs.height; + const curHref = getHref(elem); // Do nothing if no URL change or size change + + if (curHref === val && !setsize) { + return; + } + + const batchCmd = new BatchCommand$1('Change Image URL'); + setHref(elem, val); + batchCmd.addSubCommand(new ChangeElementCommand$1(elem, { + '#href': curHref + })); + $$a(new Image()).load(function () { + const changes = $$a(elem).attr(['width', 'height']); + $$a(elem).attr({ + width: this.width, + height: this.height + }); + selectorManager.requestSelector(elem).resize(); + batchCmd.addSubCommand(new ChangeElementCommand$1(elem, changes)); + addCommandToHistory(batchCmd); + call('changed', [elem]); + }).attr('src', val); + }; + /** + * Sets the new link URL for the selected anchor element. + * @function module:svgcanvas.SvgCanvas#setLinkURL + * @param {string} val - String with the link URL/path + * @returns {void} + */ + + + this.setLinkURL = function (val) { + let elem = selectedElements[0]; + + if (!elem) { + return; + } + + if (elem.tagName !== 'a') { + // See if parent is an anchor + const parentsA = $$a(elem).parents('a'); + + if (parentsA.length) { + elem = parentsA[0]; + } else { + return; + } + } + + const curHref = getHref(elem); + + if (curHref === val) { + return; + } + + const batchCmd = new BatchCommand$1('Change Link URL'); + setHref(elem, val); + batchCmd.addSubCommand(new ChangeElementCommand$1(elem, { + '#href': curHref + })); + addCommandToHistory(batchCmd); + }; + /** + * Sets the `rx` and `ry` values to the selected `rect` element + * to change its corner radius. + * @function module:svgcanvas.SvgCanvas#setRectRadius + * @param {string|Float} val - The new radius + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.setRectRadius = function (val) { + const selected = selectedElements[0]; + + if (!isNullish(selected) && selected.tagName === 'rect') { + const r = selected.getAttribute('rx'); + + if (r !== String(val)) { + selected.setAttribute('rx', val); + selected.setAttribute('ry', val); + addCommandToHistory(new ChangeElementCommand$1(selected, { + rx: r, + ry: r + }, 'Radius')); + call('changed', [selected]); + } + } + }; + /** + * Wraps the selected element(s) in an anchor element or converts group to one. + * @function module:svgcanvas.SvgCanvas#makeHyperlink + * @param {string} url + * @returns {void} + */ + + + this.makeHyperlink = function (url) { + canvas.groupSelectedElements('a', url); // TODO: If element is a single "g", convert to "a" + // if (selectedElements.length > 1 && selectedElements[1]) { + }; + /** + * @function module:svgcanvas.SvgCanvas#removeHyperlink + * @returns {void} + */ + + + this.removeHyperlink = function () { + canvas.ungroupSelectedElement(); + }; + /** + * Group: Element manipulation. + */ + + /** + * Sets the new segment type to the selected segment(s). + * @function module:svgcanvas.SvgCanvas#setSegType + * @param {Integer} newType - New segment type. See {@link https://www.w3.org/TR/SVG/paths.html#InterfaceSVGPathSeg} for list + * @returns {void} + */ + + + this.setSegType = function (newType) { + pathActions.setSegType(newType); + }; + /** + * Convert selected element to a path, or get the BBox of an element-as-path. + * @function module:svgcanvas.SvgCanvas#convertToPath + * @todo (codedread): Remove the getBBox argument and split this function into two. + * @param {Element} elem - The DOM element to be converted + * @param {boolean} getBBox - Boolean on whether or not to only return the path's BBox + * @returns {void|DOMRect|false|SVGPathElement|null} If the getBBox flag is true, the resulting path's bounding box object. + * Otherwise the resulting path element is returned. + */ + + + this.convertToPath = function (elem, getBBox) { + if (isNullish(elem)) { + const elems = selectedElements; + $$a.each(elems, function (i, el) { + if (el) { + canvas.convertToPath(el); + } + }); + return undefined; + } + + if (getBBox) { + return getBBoxOfElementAsPath(elem, addSVGElementFromJson, pathActions); + } // TODO: Why is this applying attributes from curShape, then inside utilities.convertToPath it's pulling addition attributes from elem? + // TODO: If convertToPath is called with one elem, curShape and elem are probably the same; but calling with multiple is a bug or cool feature. + + + const attrs = { + fill: curShape.fill, + 'fill-opacity': curShape.fill_opacity, + stroke: curShape.stroke, + 'stroke-width': curShape.stroke_width, + 'stroke-dasharray': curShape.stroke_dasharray, + 'stroke-linejoin': curShape.stroke_linejoin, + 'stroke-linecap': curShape.stroke_linecap, + 'stroke-opacity': curShape.stroke_opacity, + opacity: curShape.opacity, + visibility: 'hidden' + }; + return convertToPath(elem, attrs, addSVGElementFromJson, pathActions, clearSelection, addToSelection, hstry, addCommandToHistory); + }; + /** + * This function makes the changes to the elements. It does not add the change + * to the history stack. + * @param {string} attr - Attribute name + * @param {string|Float} newValue - String or number with the new attribute value + * @param {Element[]} elems - The DOM elements to apply the change to + * @returns {void} + */ + + + const changeSelectedAttributeNoUndo = function (attr, newValue, elems) { + if (currentMode === 'pathedit') { + // Editing node + pathActions.moveNode(attr, newValue); + } + + elems = elems || selectedElements; + let i = elems.length; + const noXYElems = ['g', 'polyline', 'path']; // const goodGAttrs = ['transform', 'opacity', 'filter']; + + while (i--) { + let elem = elems[i]; + + if (isNullish(elem)) { + continue; + } // Set x,y vals on elements that don't have them + + + if ((attr === 'x' || attr === 'y') && noXYElems.includes(elem.tagName)) { + const bbox = getStrokedBBoxDefaultVisible([elem]); + const diffX = attr === 'x' ? newValue - bbox.x : 0; + const diffY = attr === 'y' ? newValue - bbox.y : 0; + canvas.moveSelectedElements(diffX * currentZoom, diffY * currentZoom, true); + continue; + } // only allow the transform/opacity/filter attribute to change on <g> elements, slightly hacky + // TODO: Missing statement body + // if (elem.tagName === 'g' && goodGAttrs.includes(attr)) {} + + + let oldval = attr === '#text' ? elem.textContent : elem.getAttribute(attr); + + if (isNullish(oldval)) { + oldval = ''; + } + + if (oldval !== String(newValue)) { + if (attr === '#text') { + // const oldW = utilsGetBBox(elem).width; + elem.textContent = newValue; // FF bug occurs on on rotated elements + + if (/rotate/.test(elem.getAttribute('transform'))) { + elem = ffClone(elem); + } // Hoped to solve the issue of moving text with text-anchor="start", + // but this doesn't actually fix it. Hopefully on the right track, though. -Fyrd + // const box = getBBox(elem), left = box.x, top = box.y, {width, height} = box, + // dx = width - oldW, dy = 0; + // const angle = getRotationAngle(elem, true); + // if (angle) { + // const r = Math.sqrt(dx * dx + dy * dy); + // const theta = Math.atan2(dy, dx) - angle; + // dx = r * Math.cos(theta); + // dy = r * Math.sin(theta); + // + // elem.setAttribute('x', elem.getAttribute('x') - dx); + // elem.setAttribute('y', elem.getAttribute('y') - dy); + // } + + } else if (attr === '#href') { + setHref(elem, newValue); + } else { + elem.setAttribute(attr, newValue); + } // Go into "select" mode for text changes + // NOTE: Important that this happens AFTER elem.setAttribute() or else attributes like + // font-size can get reset to their old value, ultimately by svgEditor.updateContextPanel(), + // after calling textActions.toSelectMode() below + + + if (currentMode === 'textedit' && attr !== '#text' && elem.textContent.length) { + textActions.toSelectMode(elem); + } // if (i === 0) { + // selectedBBoxes[0] = utilsGetBBox(elem); + // } + // Use the Firefox ffClone hack for text elements with gradients or + // where other text attributes are changed. + + + if (isGecko() && elem.nodeName === 'text' && /rotate/.test(elem.getAttribute('transform'))) { + if (String(newValue).startsWith('url') || ['font-size', 'font-family', 'x', 'y'].includes(attr) && elem.textContent) { + elem = ffClone(elem); + } + } // Timeout needed for Opera & Firefox + // codedread: it is now possible for this function to be called with elements + // that are not in the selectedElements array, we need to only request a + // selector if the element is in that array + + + if (selectedElements.includes(elem)) { + setTimeout(function () { + // Due to element replacement, this element may no longer + // be part of the DOM + if (!elem.parentNode) { + return; + } + + selectorManager.requestSelector(elem).resize(); + }, 0); + } // if this element was rotated, and we changed the position of this element + // we need to update the rotational transform attribute + + + const angle = getRotationAngle(elem); + + if (angle !== 0 && attr !== 'transform') { + const tlist = getTransformList(elem); + let n = tlist.numberOfItems; + + while (n--) { + const xform = tlist.getItem(n); + + if (xform.type === 4) { + // remove old rotate + tlist.removeItem(n); + const box = getBBox(elem); + const center = transformPoint(box.x + box.width / 2, box.y + box.height / 2, transformListToTransform(tlist).matrix); + const cx = center.x, + cy = center.y; + const newrot = svgroot.createSVGTransform(); + newrot.setRotate(angle, cx, cy); + tlist.insertItemBefore(newrot, n); + break; + } + } + } + } // if oldValue != newValue + + } // for each elem + + }; + /** + * Change the given/selected element and add the original value to the history stack. + * If you want to change all `selectedElements`, ignore the `elems` argument. + * If you want to change only a subset of `selectedElements`, then send the + * subset to this function in the `elems` argument. + * @function module:svgcanvas.SvgCanvas#changeSelectedAttribute + * @param {string} attr - String with the attribute name + * @param {string|Float} val - String or number with the new attribute value + * @param {Element[]} elems - The DOM elements to apply the change to + * @returns {void} + */ + + + const changeSelectedAttribute = this.changeSelectedAttribute = function (attr, val, elems) { + elems = elems || selectedElements; + canvas.undoMgr.beginUndoableChange(attr, elems); // const i = elems.length; + + changeSelectedAttributeNoUndo(attr, val, elems); + const batchCmd = canvas.undoMgr.finishUndoableChange(); + + if (!batchCmd.isEmpty()) { + addCommandToHistory(batchCmd); + } + }; + /** + * Removes all selected elements from the DOM and adds the change to the + * history stack. + * @function module:svgcanvas.SvgCanvas#deleteSelectedElements + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.deleteSelectedElements = function () { + const batchCmd = new BatchCommand$1('Delete Elements'); + const len = selectedElements.length; + const selectedCopy = []; // selectedElements is being deleted + + for (let i = 0; i < len; ++i) { + const selected = selectedElements[i]; + + if (isNullish(selected)) { + break; + } + + let parent = selected.parentNode; + let t = selected; // this will unselect the element and remove the selectedOutline + + selectorManager.releaseSelector(t); // Remove the path if present. + + removePath_(t.id); // Get the parent if it's a single-child anchor + + if (parent.tagName === 'a' && parent.childNodes.length === 1) { + t = parent; + parent = parent.parentNode; + } + + const { + nextSibling + } = t; + t.remove(); + const elem = t; + selectedCopy.push(selected); // for the copy + + batchCmd.addSubCommand(new RemoveElementCommand$1(elem, nextSibling, parent)); + } + + selectedElements = []; + + if (!batchCmd.isEmpty()) { + addCommandToHistory(batchCmd); + } + + call('changed', selectedCopy); + clearSelection(); + }; + /** + * Removes all selected elements from the DOM and adds the change to the + * history stack. Remembers removed elements on the clipboard. + * @function module:svgcanvas.SvgCanvas#cutSelectedElements + * @returns {void} + */ + + + this.cutSelectedElements = function () { + canvas.copySelectedElements(); + canvas.deleteSelectedElements(); + }; + + const CLIPBOARD_ID = 'svgedit_clipboard'; + /** + * Flash the clipboard data momentarily on localStorage so all tabs can see. + * @returns {void} + */ + + function flashStorage() { + const data = sessionStorage.getItem(CLIPBOARD_ID); + localStorage.setItem(CLIPBOARD_ID, data); + setTimeout(function () { + localStorage.removeItem(CLIPBOARD_ID); + }, 1); + } + /** + * Transfers sessionStorage from one tab to another. + * @param {!Event} ev Storage event. + * @returns {void} + */ + + + function storageChange(ev) { + if (!ev.newValue) return; // This is a call from removeItem. + + if (ev.key === CLIPBOARD_ID + '_startup') { + // Another tab asked for our sessionStorage. + localStorage.removeItem(CLIPBOARD_ID + '_startup'); + flashStorage(); + } else if (ev.key === CLIPBOARD_ID) { + // Another tab sent data. + sessionStorage.setItem(CLIPBOARD_ID, ev.newValue); + } + } // Listen for changes to localStorage. + + + window.addEventListener('storage', storageChange, false); // Ask other tabs for sessionStorage (this is ONLY to trigger event). + + localStorage.setItem(CLIPBOARD_ID + '_startup', Math.random()); + /** + * Remembers the current selected elements on the clipboard. + * @function module:svgcanvas.SvgCanvas#copySelectedElements + * @returns {void} + */ + + this.copySelectedElements = function () { + const data = JSON.stringify(selectedElements.map(x => getJsonFromSvgElement(x))); // Use sessionStorage for the clipboard data. + + sessionStorage.setItem(CLIPBOARD_ID, data); + flashStorage(); + const menu = $$a('#cmenu_canvas'); // Context menu might not exist (it is provided by editor.js). + + if (menu.enableContextMenuItems) { + menu.enableContextMenuItems('#paste,#paste_in_place'); + } + }; + /** + * @function module:svgcanvas.SvgCanvas#pasteElements + * @param {"in_place"|"point"|void} type + * @param {Integer|void} x Expected if type is "point" + * @param {Integer|void} y Expected if type is "point" + * @fires module:svgcanvas.SvgCanvas#event:changed + * @fires module:svgcanvas.SvgCanvas#event:ext_IDsUpdated + * @returns {void} + */ + + + this.pasteElements = function (type, x, y) { + let clipb = JSON.parse(sessionStorage.getItem(CLIPBOARD_ID)); + if (!clipb) return; + let len = clipb.length; + if (!len) return; + const pasted = []; + const batchCmd = new BatchCommand$1('Paste elements'); // const drawing = getCurrentDrawing(); + + /** + * @typedef {PlainObject<string, string>} module:svgcanvas.ChangedIDs + */ + + /** + * @type {module:svgcanvas.ChangedIDs} + */ + + const changedIDs = {}; // Recursively replace IDs and record the changes + + /** + * + * @param {module:svgcanvas.SVGAsJSON} elem + * @returns {void} + */ + + function checkIDs(elem) { + if (elem.attr && elem.attr.id) { + changedIDs[elem.attr.id] = getNextId(); + elem.attr.id = changedIDs[elem.attr.id]; + } + + if (elem.children) elem.children.forEach(checkIDs); + } + + clipb.forEach(checkIDs); // Give extensions like the connector extension a chance to reflect new IDs and remove invalid elements + + /** + * Triggered when `pasteElements` is called from a paste action (context menu or key). + * @event module:svgcanvas.SvgCanvas#event:ext_IDsUpdated + * @type {PlainObject} + * @property {module:svgcanvas.SVGAsJSON[]} elems + * @property {module:svgcanvas.ChangedIDs} changes Maps past ID (on attribute) to current ID + */ + + runExtensions('IDsUpdated', + /** @type {module:svgcanvas.SvgCanvas#event:ext_IDsUpdated} */ + { + elems: clipb, + changes: changedIDs + }, true).forEach(function (extChanges) { + if (!extChanges || !('remove' in extChanges)) return; + extChanges.remove.forEach(function (removeID) { + clipb = clipb.filter(function (clipBoardItem) { + return clipBoardItem.attr.id !== removeID; + }); + }); + }); // Move elements to lastClickPoint + + while (len--) { + const elem = clipb[len]; + + if (!elem) { + continue; + } + + const copy = addSVGElementFromJson(elem); + pasted.push(copy); + batchCmd.addSubCommand(new InsertElementCommand$1(copy)); + restoreRefElems(copy); + } + + selectOnly(pasted); + + if (type !== 'in_place') { + let ctrX, ctrY; + + if (!type) { + ctrX = lastClickPoint.x; + ctrY = lastClickPoint.y; + } else if (type === 'point') { + ctrX = x; + ctrY = y; + } + + const bbox = getStrokedBBoxDefaultVisible(pasted); + const cx = ctrX - (bbox.x + bbox.width / 2), + cy = ctrY - (bbox.y + bbox.height / 2), + dx = [], + dy = []; + $$a.each(pasted, function (i, item) { + dx.push(cx); + dy.push(cy); + }); + const cmd = canvas.moveSelectedElements(dx, dy, false); + if (cmd) batchCmd.addSubCommand(cmd); + } + + addCommandToHistory(batchCmd); + call('changed', pasted); + }; + /** + * Wraps all the selected elements in a group (`g`) element. + * @function module:svgcanvas.SvgCanvas#groupSelectedElements + * @param {"a"|"g"} [type="g"] - type of element to group into, defaults to `<g>` + * @param {string} [urlArg] + * @returns {void} + */ + + + this.groupSelectedElements = function (type, urlArg) { + if (!type) { + type = 'g'; + } + + let cmdStr = ''; + let url; + + switch (type) { + case 'a': + { + cmdStr = 'Make hyperlink'; + url = urlArg || ''; + break; + } + + default: + { + type = 'g'; + cmdStr = 'Group Elements'; + break; + } + } + + const batchCmd = new BatchCommand$1(cmdStr); // create and insert the group element + + const g = addSVGElementFromJson({ + element: type, + attr: { + id: getNextId() + } + }); + + if (type === 'a') { + setHref(g, url); + } + + batchCmd.addSubCommand(new InsertElementCommand$1(g)); // now move all children into the group + + let i = selectedElements.length; + + while (i--) { + let elem = selectedElements[i]; + + if (isNullish(elem)) { + continue; + } + + if (elem.parentNode.tagName === 'a' && elem.parentNode.childNodes.length === 1) { + elem = elem.parentNode; + } + + const oldNextSibling = elem.nextSibling; + const oldParent = elem.parentNode; + g.append(elem); batchCmd.addSubCommand(new MoveElementCommand$1(elem, oldNextSibling, oldParent)); - } // remove the group from the selection - - - clearSelection(); // delete the group element (but make undo-able) - - var gNextSibling = g.nextSibling; - g.remove(); - batchCmd.addSubCommand(new RemoveElementCommand$1(g, gNextSibling, parent)); + } if (!batchCmd.isEmpty()) { addCommandToHistory(batchCmd); } // update selection - addToSelection(children); - } - }; - /** - * Repositions the selected element to the bottom in the DOM to appear on top of - * other elements. - * @function module:svgcanvas.SvgCanvas#moveToTopSelectedElement - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ + selectOnly([g], true); + }; + /** + * Pushes all appropriate parent group properties down to its children, then + * removes them from the group. + * @function module:svgcanvas.SvgCanvas#pushGroupProperties + * @param {SVGAElement|SVGGElement} g + * @param {boolean} undoable + * @returns {BatchCommand|void} + */ - this.moveToTopSelectedElement = function () { - var _selectedElements = selectedElements, - _selectedElements2 = _slicedToArray(_selectedElements, 1), - selected = _selectedElements2[0]; + const pushGroupProperties = this.pushGroupProperties = function (g, undoable) { + const children = g.childNodes; + const len = children.length; + const xform = g.getAttribute('transform'); + const glist = getTransformList(g); + const m = transformListToTransform(glist).matrix; + const batchCmd = new BatchCommand$1('Push group properties'); // TODO: get all fill/stroke properties from the group that we are about to destroy + // "fill", "fill-opacity", "fill-rule", "stroke", "stroke-dasharray", "stroke-dashoffset", + // "stroke-linecap", "stroke-linejoin", "stroke-miterlimit", "stroke-opacity", + // "stroke-width" + // and then for each child, if they do not have the attribute (or the value is 'inherit') + // then set the child's attribute - if (!isNullish(selected)) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - t = t.parentNode.appendChild(t); // If the element actually moved position, add the command and fire the changed - // event handler. + const gangle = getRotationAngle(g); + const gattrs = $$a(g).attr(['filter', 'opacity']); + let gfilter, gblur, changes; + const drawing = getCurrentDrawing(); - if (oldNextSibling !== t.nextSibling) { - addCommandToHistory(new MoveElementCommand$1(t, oldNextSibling, oldParent, 'top')); - call('changed', [t]); - } - } - }; - /** - * Repositions the selected element to the top in the DOM to appear under - * other elements. - * @function module:svgcanvas.SvgCanvas#moveToBottomSelectedElement - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ + for (let i = 0; i < len; i++) { + const elem = children[i]; - - this.moveToBottomSelectedElement = function () { - var _selectedElements3 = selectedElements, - _selectedElements4 = _slicedToArray(_selectedElements3, 1), - selected = _selectedElements4[0]; - - if (!isNullish(selected)) { - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - var firstChild = t.parentNode.firstChild; - - if (firstChild.tagName === 'title') { - firstChild = firstChild.nextSibling; - } // This can probably be removed, as the defs should not ever apppear - // inside a layer group - - - if (firstChild.tagName === 'defs') { - firstChild = firstChild.nextSibling; - } - - t = t.parentNode.insertBefore(t, firstChild); // If the element actually moved position, add the command and fire the changed - // event handler. - - if (oldNextSibling !== t.nextSibling) { - addCommandToHistory(new MoveElementCommand$1(t, oldNextSibling, oldParent, 'bottom')); - call('changed', [t]); - } - } - }; - /** - * Moves the select element up or down the stack, based on the visibly - * intersecting elements. - * @function module:svgcanvas.SvgCanvas#moveUpDownSelected - * @param {"Up"|"Down"} dir - String that's either 'Up' or 'Down' - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {void} - */ - - - this.moveUpDownSelected = function (dir) { - var selected = selectedElements[0]; - - if (!selected) { - return; - } - - curBBoxes = []; - var closest, foundCur; // jQuery sorts this list - - var list = $$9(getIntersectionList(getStrokedBBoxDefaultVisible([selected]))).toArray(); - - if (dir === 'Down') { - list.reverse(); - } - - $$9.each(list, function () { - if (!foundCur) { - if (this === selected) { - foundCur = true; + if (elem.nodeType !== 1) { + continue; } - return true; + if (gattrs.opacity !== null && gattrs.opacity !== 1) { + // const c_opac = elem.getAttribute('opacity') || 1; + const newOpac = Math.round((elem.getAttribute('opacity') || 1) * gattrs.opacity * 100) / 100; + changeSelectedAttribute('opacity', newOpac, [elem]); + } + + if (gattrs.filter) { + let cblur = this.getBlur(elem); + const origCblur = cblur; + + if (!gblur) { + gblur = this.getBlur(g); + } + + if (cblur) { + // Is this formula correct? + cblur = Number(gblur) + Number(cblur); + } else if (cblur === 0) { + cblur = gblur; + } // If child has no current filter, get group's filter or clone it. + + + if (!origCblur) { + // Set group's filter to use first child's ID + if (!gfilter) { + gfilter = getRefElem(gattrs.filter); + } else { + // Clone the group's filter + gfilter = drawing.copyElem(gfilter); + findDefs().append(gfilter); + } + } else { + gfilter = getRefElem(elem.getAttribute('filter')); + } // Change this in future for different filters + + + const suffix = gfilter.firstChild.tagName === 'feGaussianBlur' ? 'blur' : 'filter'; + gfilter.id = elem.id + '_' + suffix; + changeSelectedAttribute('filter', 'url(#' + gfilter.id + ')', [elem]); // Update blur value + + if (cblur) { + changeSelectedAttribute('stdDeviation', cblur, [gfilter.firstChild]); + canvas.setBlurOffsets(gfilter, cblur); + } + } + + let chtlist = getTransformList(elem); // Don't process gradient transforms + + if (elem.tagName.includes('Gradient')) { + chtlist = null; + } // Hopefully not a problem to add this. Necessary for elements like <desc/> + + + if (!chtlist) { + continue; + } // Apparently <defs> can get get a transformlist, but we don't want it to have one! + + + if (elem.tagName === 'defs') { + continue; + } + + if (glist.numberOfItems) { + // TODO: if the group's transform is just a rotate, we can always transfer the + // rotate() down to the children (collapsing consecutive rotates and factoring + // out any translates) + if (gangle && glist.numberOfItems === 1) { + // [Rg] [Rc] [Mc] + // we want [Tr] [Rc2] [Mc] where: + // - [Rc2] is at the child's current center but has the + // sum of the group and child's rotation angles + // - [Tr] is the equivalent translation that this child + // undergoes if the group wasn't there + // [Tr] = [Rg] [Rc] [Rc2_inv] + // get group's rotation matrix (Rg) + const rgm = glist.getItem(0).matrix; // get child's rotation matrix (Rc) + + let rcm = svgroot.createSVGMatrix(); + const cangle = getRotationAngle(elem); + + if (cangle) { + rcm = chtlist.getItem(0).matrix; + } // get child's old center of rotation + + + const cbox = getBBox(elem); + const ceqm = transformListToTransform(chtlist).matrix; + const coldc = transformPoint(cbox.x + cbox.width / 2, cbox.y + cbox.height / 2, ceqm); // sum group and child's angles + + const sangle = gangle + cangle; // get child's rotation at the old center (Rc2_inv) + + const r2 = svgroot.createSVGTransform(); + r2.setRotate(sangle, coldc.x, coldc.y); // calculate equivalent translate + + const trm = matrixMultiply(rgm, rcm, r2.matrix.inverse()); // set up tlist + + if (cangle) { + chtlist.removeItem(0); + } + + if (sangle) { + if (chtlist.numberOfItems) { + chtlist.insertItemBefore(r2, 0); + } else { + chtlist.appendItem(r2); + } + } + + if (trm.e || trm.f) { + const tr = svgroot.createSVGTransform(); + tr.setTranslate(trm.e, trm.f); + + if (chtlist.numberOfItems) { + chtlist.insertItemBefore(tr, 0); + } else { + chtlist.appendItem(tr); + } + } + } else { + // more complicated than just a rotate + // transfer the group's transform down to each child and then + // call recalculateDimensions() + const oldxform = elem.getAttribute('transform'); + changes = {}; + changes.transform = oldxform || ''; + const newxform = svgroot.createSVGTransform(); // [ gm ] [ chm ] = [ chm ] [ gm' ] + // [ gm' ] = [ chmInv ] [ gm ] [ chm ] + + const chm = transformListToTransform(chtlist).matrix, + chmInv = chm.inverse(); + const gm = matrixMultiply(chmInv, m, chm); + newxform.setMatrix(gm); + chtlist.appendItem(newxform); + } + + const cmd = recalculateDimensions(elem); + + if (cmd) { + batchCmd.addSubCommand(cmd); + } + } + } // remove transform and make it undo-able + + + if (xform) { + changes = {}; + changes.transform = xform; + g.setAttribute('transform', ''); + g.removeAttribute('transform'); + batchCmd.addSubCommand(new ChangeElementCommand$1(g, changes)); } - closest = this; // eslint-disable-line consistent-this + if (undoable && !batchCmd.isEmpty()) { + return batchCmd; + } - return false; - }); - - if (!closest) { - return; - } - - var t = selected; - var oldParent = t.parentNode; - var oldNextSibling = t.nextSibling; - $$9(closest)[dir === 'Down' ? 'before' : 'after'](t); // If the element actually moved position, add the command and fire the changed - // event handler. - - if (oldNextSibling !== t.nextSibling) { - addCommandToHistory(new MoveElementCommand$1(t, oldNextSibling, oldParent, 'Move ' + dir)); - call('changed', [t]); - } - }; - /** - * Moves selected elements on the X/Y axis. - * @function module:svgcanvas.SvgCanvas#moveSelectedElements - * @param {Float} dx - Float with the distance to move on the x-axis - * @param {Float} dy - Float with the distance to move on the y-axis - * @param {boolean} undoable - Boolean indicating whether or not the action should be undoable - * @fires module:svgcanvas.SvgCanvas#event:changed - * @returns {BatchCommand|void} Batch command for the move - */ + return undefined; + }; + /** + * Unwraps all the elements in a selected group (`g`) element. This requires + * significant recalculations to apply group's transforms, etc. to its children. + * @function module:svgcanvas.SvgCanvas#ungroupSelectedElement + * @returns {void} + */ - this.moveSelectedElements = function (dx, dy, undoable) { - // if undoable is not sent, default to true - // if single values, scale them to the zoom - if (dx.constructor !== Array) { - dx /= currentZoom; - dy /= currentZoom; - } + this.ungroupSelectedElement = function () { + let g = selectedElements[0]; - undoable = undoable || true; - var batchCmd = new BatchCommand$1('position'); - var i = selectedElements.length; + if (!g) { + return; + } - while (i--) { - var selected = selectedElements[i]; + if ($$a(g).data('gsvg') || $$a(g).data('symbol')) { + // Is svg, so actually convert to group + convertToGroup(g); + return; + } - if (!isNullish(selected)) { - // if (i === 0) { - // selectedBBoxes[0] = utilsGetBBox(selected); - // } - // const b = {}; - // for (const j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; - // selectedBBoxes[i] = b; - var xform = svgroot.createSVGTransform(); - var tlist = getTransformList(selected); // dx and dy could be arrays + if (g.tagName === 'use') { + // Somehow doesn't have data set, so retrieve + const symbol = getElem(getHref(g).substr(1)); + $$a(g).data('symbol', symbol).data('ref', symbol); + convertToGroup(g); + return; + } - if (dx.constructor === Array) { - // if (i === 0) { - // selectedBBoxes[0].x += dx[0]; - // selectedBBoxes[0].y += dy[0]; - // } - xform.setTranslate(dx[i], dy[i]); - } else { - // if (i === 0) { - // selectedBBoxes[0].x += dx; - // selectedBBoxes[0].y += dy; - // } - xform.setTranslate(dx, dy); - } + const parentsA = $$a(g).parents('a'); - if (tlist.numberOfItems) { - tlist.insertItemBefore(xform, 0); - } else { - tlist.appendItem(xform); - } + if (parentsA.length) { + g = parentsA[0]; + } // Look for parent "a" - var cmd = recalculateDimensions(selected); + + if (g.tagName === 'g' || g.tagName === 'a') { + const batchCmd = new BatchCommand$1('Ungroup Elements'); + const cmd = pushGroupProperties(g, true); if (cmd) { batchCmd.addSubCommand(cmd); } - selectorManager.requestSelector(selected).resize(); + const parent = g.parentNode; + const anchor = g.nextSibling; + const children = new Array(g.childNodes.length); + let i = 0; + + while (g.firstChild) { + const elem = g.firstChild; + const oldNextSibling = elem.nextSibling; + const oldParent = elem.parentNode; // Remove child title elements + + if (elem.tagName === 'title') { + const { + nextSibling + } = elem; + batchCmd.addSubCommand(new RemoveElementCommand$1(elem, nextSibling, oldParent)); + elem.remove(); + continue; + } + + if (anchor) { + anchor.before(elem); + } else { + g.after(elem); + } + + children[i++] = elem; + batchCmd.addSubCommand(new MoveElementCommand$1(elem, oldNextSibling, oldParent)); + } // remove the group from the selection + + + clearSelection(); // delete the group element (but make undo-able) + + const gNextSibling = g.nextSibling; + g.remove(); + batchCmd.addSubCommand(new RemoveElementCommand$1(g, gNextSibling, parent)); + + if (!batchCmd.isEmpty()) { + addCommandToHistory(batchCmd); + } // update selection + + + addToSelection(children); } - } - - if (!batchCmd.isEmpty()) { - if (undoable) { - addCommandToHistory(batchCmd); - } - - call('changed', selectedElements); - return batchCmd; - } - - return undefined; - }; - /** - * Create deep DOM copies (clones) of all selected elements and move them slightly - * from their originals. - * @function module:svgcanvas.SvgCanvas#cloneSelectedElements - * @param {Float} x Float with the distance to move on the x-axis - * @param {Float} y Float with the distance to move on the y-axis - * @returns {void} - */ - - - this.cloneSelectedElements = function (x, y) { - var i, elem; - var batchCmd = new BatchCommand$1('Clone Elements'); // find all the elements selected (stop at first null) - - var len = selectedElements.length; + }; /** - * Sorts an array numerically and ascending. - * @param {Element} a - * @param {Element} b - * @returns {Integer} - */ - - function sortfunction(a, b) { - return $$9(b).index() - $$9(a).index(); - } - - selectedElements.sort(sortfunction); - - for (i = 0; i < len; ++i) { - elem = selectedElements[i]; - - if (isNullish(elem)) { - break; - } - } // use slice to quickly get the subset of elements we need - - - var copiedElements = selectedElements.slice(0, i); - this.clearSelection(true); // note that we loop in the reverse way because of the way elements are added - // to the selectedElements array (top-first) - - var drawing = getCurrentDrawing(); - i = copiedElements.length; - - while (i--) { - // clone each element and replace it within copiedElements - elem = copiedElements[i] = drawing.copyElem(copiedElements[i]); - (currentGroup || drawing.getCurrentLayer()).append(elem); - batchCmd.addSubCommand(new InsertElementCommand$1(elem)); - } - - if (!batchCmd.isEmpty()) { - addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding - - this.moveSelectedElements(x, y, false); - addCommandToHistory(batchCmd); - } - }; - /** - * Aligns selected elements. - * @function module:svgcanvas.SvgCanvas#alignSelectedElements - * @param {string} type - String with single character indicating the alignment type - * @param {"selected"|"largest"|"smallest"|"page"} relativeTo - * @returns {void} - */ - - - this.alignSelectedElements = function (type, relativeTo) { - var bboxes = []; // angles = []; - - var len = selectedElements.length; - - if (!len) { - return; - } - - var minx = Number.MAX_VALUE, - maxx = Number.MIN_VALUE, - miny = Number.MAX_VALUE, - maxy = Number.MIN_VALUE; - var curwidth = Number.MIN_VALUE, - curheight = Number.MIN_VALUE; - - for (var i = 0; i < len; ++i) { - if (isNullish(selectedElements[i])) { - break; - } - - var elem = selectedElements[i]; - bboxes[i] = getStrokedBBoxDefaultVisible([elem]); // now bbox is axis-aligned and handles rotation - - switch (relativeTo) { - case 'smallest': - if ((type === 'l' || type === 'c' || type === 'r') && (curwidth === Number.MIN_VALUE || curwidth > bboxes[i].width) || (type === 't' || type === 'm' || type === 'b') && (curheight === Number.MIN_VALUE || curheight > bboxes[i].height)) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - - break; - - case 'largest': - if ((type === 'l' || type === 'c' || type === 'r') && (curwidth === Number.MIN_VALUE || curwidth < bboxes[i].width) || (type === 't' || type === 'm' || type === 'b') && (curheight === Number.MIN_VALUE || curheight < bboxes[i].height)) { - minx = bboxes[i].x; - miny = bboxes[i].y; - maxx = bboxes[i].x + bboxes[i].width; - maxy = bboxes[i].y + bboxes[i].height; - curwidth = bboxes[i].width; - curheight = bboxes[i].height; - } - - break; - - default: - // 'selected' - if (bboxes[i].x < minx) { - minx = bboxes[i].x; - } - - if (bboxes[i].y < miny) { - miny = bboxes[i].y; - } - - if (bboxes[i].x + bboxes[i].width > maxx) { - maxx = bboxes[i].x + bboxes[i].width; - } - - if (bboxes[i].y + bboxes[i].height > maxy) { - maxy = bboxes[i].y + bboxes[i].height; - } - - break; - } - } // loop for each element to find the bbox and adjust min/max - - - if (relativeTo === 'page') { - minx = 0; - miny = 0; - maxx = canvas.contentW; - maxy = canvas.contentH; - } - - var dx = new Array(len); - var dy = new Array(len); - - for (var _i6 = 0; _i6 < len; ++_i6) { - if (isNullish(selectedElements[_i6])) { - break; - } // const elem = selectedElements[i]; - - - var bbox = bboxes[_i6]; - dx[_i6] = 0; - dy[_i6] = 0; - - switch (type) { - case 'l': - // left (horizontal) - dx[_i6] = minx - bbox.x; - break; - - case 'c': - // center (horizontal) - dx[_i6] = (minx + maxx) / 2 - (bbox.x + bbox.width / 2); - break; - - case 'r': - // right (horizontal) - dx[_i6] = maxx - (bbox.x + bbox.width); - break; - - case 't': - // top (vertical) - dy[_i6] = miny - bbox.y; - break; - - case 'm': - // middle (vertical) - dy[_i6] = (miny + maxy) / 2 - (bbox.y + bbox.height / 2); - break; - - case 'b': - // bottom (vertical) - dy[_i6] = maxy - (bbox.y + bbox.height); - break; - } - } - - this.moveSelectedElements(dx, dy); - }; - /** - * Group: Additional editor tools. - */ - - /** - * @name module:svgcanvas.SvgCanvas#contentW - * @type {Float} - */ - - - this.contentW = getResolution().w; - /** - * @name module:svgcanvas.SvgCanvas#contentH - * @type {Float} - */ - - this.contentH = getResolution().h; - /** - * @typedef {PlainObject} module:svgcanvas.CanvasInfo - * @property {Float} x - The canvas' new x coordinate - * @property {Float} y - The canvas' new y coordinate - * @property {string} oldX - The canvas' old x coordinate - * @property {string} oldY - The canvas' old y coordinate - * @property {Float} d_x - The x position difference - * @property {Float} d_y - The y position difference - */ - - /** - * Updates the editor canvas width/height/position after a zoom has occurred. - * @function module:svgcanvas.SvgCanvas#updateCanvas - * @param {Float} w - Float with the new width - * @param {Float} h - Float with the new height - * @fires module:svgcanvas.SvgCanvas#event:ext_canvasUpdated - * @returns {module:svgcanvas.CanvasInfo} - */ - - this.updateCanvas = function (w, h) { - svgroot.setAttribute('width', w); - svgroot.setAttribute('height', h); - var bg = $$9('#canvasBackground')[0]; - var oldX = svgcontent.getAttribute('x'); - var oldY = svgcontent.getAttribute('y'); - var x = (w - this.contentW * currentZoom) / 2; - var y = (h - this.contentH * currentZoom) / 2; - assignAttributes(svgcontent, { - width: this.contentW * currentZoom, - height: this.contentH * currentZoom, - x: x, - y: y, - viewBox: '0 0 ' + this.contentW + ' ' + this.contentH - }); - assignAttributes(bg, { - width: svgcontent.getAttribute('width'), - height: svgcontent.getAttribute('height'), - x: x, - y: y - }); - var bgImg = getElem('background_image'); - - if (bgImg) { - assignAttributes(bgImg, { - width: '100%', - height: '100%' - }); - } - - selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')'); - /** - * Invoked upon updates to the canvas. - * @event module:svgcanvas.SvgCanvas#event:ext_canvasUpdated - * @type {PlainObject} - * @property {Integer} new_x - * @property {Integer} new_y - * @property {string} old_x (Of Integer) - * @property {string} old_y (Of Integer) - * @property {Integer} d_x - * @property {Integer} d_y + * Repositions the selected element to the bottom in the DOM to appear on top of + * other elements. + * @function module:svgcanvas.SvgCanvas#moveToTopSelectedElement + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} */ - runExtensions('canvasUpdated', - /** - * @type {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated} - */ - { - new_x: x, - new_y: y, - old_x: oldX, - old_y: oldY, - d_x: x - oldX, - d_y: y - oldY - }); - return { - x: x, - y: y, - old_x: oldX, - old_y: oldY, - d_x: x - oldX, - d_y: y - oldY - }; - }; - /** - * Set the background of the editor (NOT the actual document). - * @function module:svgcanvas.SvgCanvas#setBackground - * @param {string} color - String with fill color to apply - * @param {string} url - URL or path to image to use - * @returns {void} - */ + this.moveToTopSelectedElement = function () { + const [selected] = selectedElements; - this.setBackground = function (color, url) { - var bg = getElem('canvasBackground'); - var border = $$9(bg).find('rect')[0]; - var bgImg = getElem('background_image'); - var bgPattern = getElem('background_pattern'); - border.setAttribute('fill', color === 'chessboard' ? '#fff' : color); + if (!isNullish(selected)) { + let t = selected; + const oldParent = t.parentNode; + const oldNextSibling = t.nextSibling; + t = t.parentNode.appendChild(t); // If the element actually moved position, add the command and fire the changed + // event handler. - if (color === 'chessboard') { - if (!bgPattern) { - bgPattern = svgdoc.createElementNS(NS.SVG, 'foreignObject'); - assignAttributes(bgPattern, { - id: 'background_pattern', - width: '100%', - height: '100%', - preserveAspectRatio: 'xMinYMin', - style: 'pointer-events:none' - }); - var div = document.createElement('div'); - assignAttributes(div, { - style: 'pointer-events:none;width:100%;height:100%;background-image:url(data:image/gif;base64,R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7);' - }); - bgPattern.appendChild(div); - bg.append(bgPattern); - } - } else if (bgPattern) { - bgPattern.remove(); - } - - if (url) { - if (!bgImg) { - bgImg = svgdoc.createElementNS(NS.SVG, 'image'); - assignAttributes(bgImg, { - id: 'background_image', - width: '100%', - height: '100%', - preserveAspectRatio: 'xMinYMin', - style: 'pointer-events:none' - }); - } - - setHref(bgImg, url); - bg.append(bgImg); - } else if (bgImg) { - bgImg.remove(); - } - }; - /** - * Select the next/previous element within the current layer. - * @function module:svgcanvas.SvgCanvas#cycleElement - * @param {boolean} next - true = next and false = previous element - * @fires module:svgcanvas.SvgCanvas#event:selected - * @returns {void} - */ - - - this.cycleElement = function (next) { - var num; - var curElem = selectedElements[0]; - var elem = false; - var allElems = getVisibleElements(currentGroup || getCurrentDrawing().getCurrentLayer()); - - if (!allElems.length) { - return; - } - - if (isNullish(curElem)) { - num = next ? allElems.length - 1 : 0; - elem = allElems[num]; - } else { - var i = allElems.length; - - while (i--) { - if (allElems[i] === curElem) { - num = next ? i - 1 : i + 1; - - if (num >= allElems.length) { - num = 0; - } else if (num < 0) { - num = allElems.length - 1; - } - - elem = allElems[num]; - break; + if (oldNextSibling !== t.nextSibling) { + addCommandToHistory(new MoveElementCommand$1(t, oldNextSibling, oldParent, 'top')); + call('changed', [t]); } } - } - - selectOnly([elem], true); - call('selected', selectedElements); - }; - - this.clear(); - /** - * @interface module:svgcanvas.PrivateMethods - * @type {PlainObject} - * @property {module:svgcanvas~addCommandToHistory} addCommandToHistory - * @property {module:history.HistoryCommand} BatchCommand - * @property {module:history.HistoryCommand} ChangeElementCommand - * @property {module:utilities.decode64} decode64 - * @property {module:utilities.dropXMLInternalSubset} dropXMLInternalSubset - * @property {module:utilities.encode64} encode64 - * @property {module:svgcanvas~ffClone} ffClone - * @property {module:svgcanvas~findDuplicateGradient} findDuplicateGradient - * @property {module:utilities.getPathBBox} getPathBBox - * @property {module:units.getTypeMap} getTypeMap - * @property {module:draw.identifyLayers} identifyLayers - * @property {module:history.HistoryCommand} InsertElementCommand - * @property {module:browser.isChrome} isChrome - * @property {module:math.isIdentity} isIdentity - * @property {module:browser.isIE} isIE - * @property {module:svgcanvas~logMatrix} logMatrix - * @property {module:history.HistoryCommand} MoveElementCommand - * @property {module:namespaces.NS} NS - * @property {module:utilities.preventClickDefault} preventClickDefault - * @property {module:history.HistoryCommand} RemoveElementCommand - * @property {module:SVGTransformList.SVGEditTransformList} SVGEditTransformList - * @property {module:utilities.text2xml} text2xml - * @property {module:math.transformBox} transformBox - * @property {module:math.transformPoint} transformPoint - * @property {module:utilities.walkTree} walkTree - */ - - /** - * @deprecated getPrivateMethods - * Since all methods are/should be public somehow, this function should be removed; - * we might require `import` in place of this in the future once ES6 Modules - * widespread - - * Being able to access private methods publicly seems wrong somehow, - * but currently appears to be the best way to allow testing and provide - * access to them to plugins. - * @function module:svgcanvas.SvgCanvas#getPrivateMethods - * @returns {module:svgcanvas.PrivateMethods} - */ - - this.getPrivateMethods = function () { - var obj = { - addCommandToHistory: addCommandToHistory, - BatchCommand: BatchCommand$1, - ChangeElementCommand: ChangeElementCommand$1, - decode64: decode64, - dropXMLInternalSubset: dropXMLInternalSubset, - encode64: encode64, - ffClone: ffClone, - findDefs: findDefs, - findDuplicateGradient: findDuplicateGradient, - getElem: getElem, - getPathBBox: getPathBBox, - getTypeMap: getTypeMap, - getUrlFromAttr: getUrlFromAttr, - identifyLayers: identifyLayers, - InsertElementCommand: InsertElementCommand$1, - isChrome: isChrome, - isIdentity: isIdentity, - isIE: isIE, - logMatrix: logMatrix, - MoveElementCommand: MoveElementCommand$1, - NS: NS, - preventClickDefault: preventClickDefault, - RemoveElementCommand: RemoveElementCommand$1, - SVGEditTransformList: SVGTransformList, - text2xml: text2xml, - transformBox: transformBox, - transformPoint: transformPoint, - walkTree: walkTree }; - return obj; - }; - } // End constructor - ; // End class + /** + * Repositions the selected element to the top in the DOM to appear under + * other elements. + * @function module:svgcanvas.SvgCanvas#moveToBottomSelectedElement + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.moveToBottomSelectedElement = function () { + const [selected] = selectedElements; + + if (!isNullish(selected)) { + let t = selected; + const oldParent = t.parentNode; + const oldNextSibling = t.nextSibling; + let { + firstChild + } = t.parentNode; + + if (firstChild.tagName === 'title') { + firstChild = firstChild.nextSibling; + } // This can probably be removed, as the defs should not ever apppear + // inside a layer group + + + if (firstChild.tagName === 'defs') { + firstChild = firstChild.nextSibling; + } + + t = t.parentNode.insertBefore(t, firstChild); // If the element actually moved position, add the command and fire the changed + // event handler. + + if (oldNextSibling !== t.nextSibling) { + addCommandToHistory(new MoveElementCommand$1(t, oldNextSibling, oldParent, 'bottom')); + call('changed', [t]); + } + } + }; + /** + * Moves the select element up or down the stack, based on the visibly + * intersecting elements. + * @function module:svgcanvas.SvgCanvas#moveUpDownSelected + * @param {"Up"|"Down"} dir - String that's either 'Up' or 'Down' + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {void} + */ + + + this.moveUpDownSelected = function (dir) { + const selected = selectedElements[0]; + + if (!selected) { + return; + } + + curBBoxes = []; + let closest, foundCur; // jQuery sorts this list + + const list = $$a(getIntersectionList(getStrokedBBoxDefaultVisible([selected]))).toArray(); + + if (dir === 'Down') { + list.reverse(); + } + + $$a.each(list, function () { + if (!foundCur) { + if (this === selected) { + foundCur = true; + } + + return true; + } + + closest = this; // eslint-disable-line consistent-this + + return false; + }); + + if (!closest) { + return; + } + + const t = selected; + const oldParent = t.parentNode; + const oldNextSibling = t.nextSibling; + $$a(closest)[dir === 'Down' ? 'before' : 'after'](t); // If the element actually moved position, add the command and fire the changed + // event handler. + + if (oldNextSibling !== t.nextSibling) { + addCommandToHistory(new MoveElementCommand$1(t, oldNextSibling, oldParent, 'Move ' + dir)); + call('changed', [t]); + } + }; + /** + * Moves selected elements on the X/Y axis. + * @function module:svgcanvas.SvgCanvas#moveSelectedElements + * @param {Float} dx - Float with the distance to move on the x-axis + * @param {Float} dy - Float with the distance to move on the y-axis + * @param {boolean} undoable - Boolean indicating whether or not the action should be undoable + * @fires module:svgcanvas.SvgCanvas#event:changed + * @returns {BatchCommand|void} Batch command for the move + */ + + + this.moveSelectedElements = function (dx, dy, undoable) { + // if undoable is not sent, default to true + // if single values, scale them to the zoom + if (dx.constructor !== Array) { + dx /= currentZoom; + dy /= currentZoom; + } + + undoable = undoable || true; + const batchCmd = new BatchCommand$1('position'); + let i = selectedElements.length; + + while (i--) { + const selected = selectedElements[i]; + + if (!isNullish(selected)) { + // if (i === 0) { + // selectedBBoxes[0] = utilsGetBBox(selected); + // } + // const b = {}; + // for (const j in selectedBBoxes[i]) b[j] = selectedBBoxes[i][j]; + // selectedBBoxes[i] = b; + const xform = svgroot.createSVGTransform(); + const tlist = getTransformList(selected); // dx and dy could be arrays + + if (dx.constructor === Array) { + // if (i === 0) { + // selectedBBoxes[0].x += dx[0]; + // selectedBBoxes[0].y += dy[0]; + // } + xform.setTranslate(dx[i], dy[i]); + } else { + // if (i === 0) { + // selectedBBoxes[0].x += dx; + // selectedBBoxes[0].y += dy; + // } + xform.setTranslate(dx, dy); + } + + if (tlist.numberOfItems) { + tlist.insertItemBefore(xform, 0); + } else { + tlist.appendItem(xform); + } + + const cmd = recalculateDimensions(selected); + + if (cmd) { + batchCmd.addSubCommand(cmd); + } + + selectorManager.requestSelector(selected).resize(); + } + } + + if (!batchCmd.isEmpty()) { + if (undoable) { + addCommandToHistory(batchCmd); + } + + call('changed', selectedElements); + return batchCmd; + } + + return undefined; + }; + /** + * Create deep DOM copies (clones) of all selected elements and move them slightly + * from their originals. + * @function module:svgcanvas.SvgCanvas#cloneSelectedElements + * @param {Float} x Float with the distance to move on the x-axis + * @param {Float} y Float with the distance to move on the y-axis + * @returns {void} + */ + + + this.cloneSelectedElements = function (x, y) { + let i, elem; + const batchCmd = new BatchCommand$1('Clone Elements'); // find all the elements selected (stop at first null) + + const len = selectedElements.length; + /** + * Sorts an array numerically and ascending. + * @param {Element} a + * @param {Element} b + * @returns {Integer} + */ + + function sortfunction(a, b) { + return $$a(b).index() - $$a(a).index(); + } + + selectedElements.sort(sortfunction); + + for (i = 0; i < len; ++i) { + elem = selectedElements[i]; + + if (isNullish(elem)) { + break; + } + } // use slice to quickly get the subset of elements we need + + + const copiedElements = selectedElements.slice(0, i); + this.clearSelection(true); // note that we loop in the reverse way because of the way elements are added + // to the selectedElements array (top-first) + + const drawing = getCurrentDrawing(); + i = copiedElements.length; + + while (i--) { + // clone each element and replace it within copiedElements + elem = copiedElements[i] = drawing.copyElem(copiedElements[i]); + (currentGroup || drawing.getCurrentLayer()).append(elem); + batchCmd.addSubCommand(new InsertElementCommand$1(elem)); + } + + if (!batchCmd.isEmpty()) { + addToSelection(copiedElements.reverse()); // Need to reverse for correct selection-adding + + this.moveSelectedElements(x, y, false); + addCommandToHistory(batchCmd); + } + }; + /** + * Aligns selected elements. + * @function module:svgcanvas.SvgCanvas#alignSelectedElements + * @param {string} type - String with single character indicating the alignment type + * @param {"selected"|"largest"|"smallest"|"page"} relativeTo + * @returns {void} + */ + + + this.alignSelectedElements = function (type, relativeTo) { + const bboxes = []; // angles = []; + + const len = selectedElements.length; + + if (!len) { + return; + } + + let minx = Number.MAX_VALUE, + maxx = Number.MIN_VALUE, + miny = Number.MAX_VALUE, + maxy = Number.MIN_VALUE; + let curwidth = Number.MIN_VALUE, + curheight = Number.MIN_VALUE; + + for (let i = 0; i < len; ++i) { + if (isNullish(selectedElements[i])) { + break; + } + + const elem = selectedElements[i]; + bboxes[i] = getStrokedBBoxDefaultVisible([elem]); // now bbox is axis-aligned and handles rotation + + switch (relativeTo) { + case 'smallest': + if ((type === 'l' || type === 'c' || type === 'r') && (curwidth === Number.MIN_VALUE || curwidth > bboxes[i].width) || (type === 't' || type === 'm' || type === 'b') && (curheight === Number.MIN_VALUE || curheight > bboxes[i].height)) { + minx = bboxes[i].x; + miny = bboxes[i].y; + maxx = bboxes[i].x + bboxes[i].width; + maxy = bboxes[i].y + bboxes[i].height; + curwidth = bboxes[i].width; + curheight = bboxes[i].height; + } + + break; + + case 'largest': + if ((type === 'l' || type === 'c' || type === 'r') && (curwidth === Number.MIN_VALUE || curwidth < bboxes[i].width) || (type === 't' || type === 'm' || type === 'b') && (curheight === Number.MIN_VALUE || curheight < bboxes[i].height)) { + minx = bboxes[i].x; + miny = bboxes[i].y; + maxx = bboxes[i].x + bboxes[i].width; + maxy = bboxes[i].y + bboxes[i].height; + curwidth = bboxes[i].width; + curheight = bboxes[i].height; + } + + break; + + default: + // 'selected' + if (bboxes[i].x < minx) { + minx = bboxes[i].x; + } + + if (bboxes[i].y < miny) { + miny = bboxes[i].y; + } + + if (bboxes[i].x + bboxes[i].width > maxx) { + maxx = bboxes[i].x + bboxes[i].width; + } + + if (bboxes[i].y + bboxes[i].height > maxy) { + maxy = bboxes[i].y + bboxes[i].height; + } + + break; + } + } // loop for each element to find the bbox and adjust min/max + + + if (relativeTo === 'page') { + minx = 0; + miny = 0; + maxx = canvas.contentW; + maxy = canvas.contentH; + } + + const dx = new Array(len); + const dy = new Array(len); + + for (let i = 0; i < len; ++i) { + if (isNullish(selectedElements[i])) { + break; + } // const elem = selectedElements[i]; + + + const bbox = bboxes[i]; + dx[i] = 0; + dy[i] = 0; + + switch (type) { + case 'l': + // left (horizontal) + dx[i] = minx - bbox.x; + break; + + case 'c': + // center (horizontal) + dx[i] = (minx + maxx) / 2 - (bbox.x + bbox.width / 2); + break; + + case 'r': + // right (horizontal) + dx[i] = maxx - (bbox.x + bbox.width); + break; + + case 't': + // top (vertical) + dy[i] = miny - bbox.y; + break; + + case 'm': + // middle (vertical) + dy[i] = (miny + maxy) / 2 - (bbox.y + bbox.height / 2); + break; + + case 'b': + // bottom (vertical) + dy[i] = maxy - (bbox.y + bbox.height); + break; + } + } + + this.moveSelectedElements(dx, dy); + }; + /** + * Group: Additional editor tools. + */ + + /** + * @name module:svgcanvas.SvgCanvas#contentW + * @type {Float} + */ + + + this.contentW = getResolution().w; + /** + * @name module:svgcanvas.SvgCanvas#contentH + * @type {Float} + */ + + this.contentH = getResolution().h; + /** + * @typedef {PlainObject} module:svgcanvas.CanvasInfo + * @property {Float} x - The canvas' new x coordinate + * @property {Float} y - The canvas' new y coordinate + * @property {string} oldX - The canvas' old x coordinate + * @property {string} oldY - The canvas' old y coordinate + * @property {Float} d_x - The x position difference + * @property {Float} d_y - The y position difference + */ + + /** + * Updates the editor canvas width/height/position after a zoom has occurred. + * @function module:svgcanvas.SvgCanvas#updateCanvas + * @param {Float} w - Float with the new width + * @param {Float} h - Float with the new height + * @fires module:svgcanvas.SvgCanvas#event:ext_canvasUpdated + * @returns {module:svgcanvas.CanvasInfo} + */ + + this.updateCanvas = function (w, h) { + svgroot.setAttribute('width', w); + svgroot.setAttribute('height', h); + const bg = $$a('#canvasBackground')[0]; + const oldX = svgcontent.getAttribute('x'); + const oldY = svgcontent.getAttribute('y'); + const x = (w - this.contentW * currentZoom) / 2; + const y = (h - this.contentH * currentZoom) / 2; + assignAttributes(svgcontent, { + width: this.contentW * currentZoom, + height: this.contentH * currentZoom, + x, + y, + viewBox: '0 0 ' + this.contentW + ' ' + this.contentH + }); + assignAttributes(bg, { + width: svgcontent.getAttribute('width'), + height: svgcontent.getAttribute('height'), + x, + y + }); + const bgImg = getElem('background_image'); + + if (bgImg) { + assignAttributes(bgImg, { + width: '100%', + height: '100%' + }); + } + + selectorManager.selectorParentGroup.setAttribute('transform', 'translate(' + x + ',' + y + ')'); + /** + * Invoked upon updates to the canvas. + * @event module:svgcanvas.SvgCanvas#event:ext_canvasUpdated + * @type {PlainObject} + * @property {Integer} new_x + * @property {Integer} new_y + * @property {string} old_x (Of Integer) + * @property {string} old_y (Of Integer) + * @property {Integer} d_x + * @property {Integer} d_y + */ + + runExtensions('canvasUpdated', + /** + * @type {module:svgcanvas.SvgCanvas#event:ext_canvasUpdated} + */ + { + new_x: x, + new_y: y, + old_x: oldX, + old_y: oldY, + d_x: x - oldX, + d_y: y - oldY + }); + return { + x, + y, + old_x: oldX, + old_y: oldY, + d_x: x - oldX, + d_y: y - oldY + }; + }; + /** + * Set the background of the editor (NOT the actual document). + * @function module:svgcanvas.SvgCanvas#setBackground + * @param {string} color - String with fill color to apply + * @param {string} url - URL or path to image to use + * @returns {void} + */ + + + this.setBackground = function (color, url) { + const bg = getElem('canvasBackground'); + const border = $$a(bg).find('rect')[0]; + let bgImg = getElem('background_image'); + let bgPattern = getElem('background_pattern'); + border.setAttribute('fill', color === 'chessboard' ? '#fff' : color); + + if (color === 'chessboard') { + if (!bgPattern) { + bgPattern = svgdoc.createElementNS(NS.SVG, 'foreignObject'); + assignAttributes(bgPattern, { + id: 'background_pattern', + width: '100%', + height: '100%', + preserveAspectRatio: 'xMinYMin', + style: 'pointer-events:none' + }); + const div = document.createElement('div'); + assignAttributes(div, { + style: 'pointer-events:none;width:100%;height:100%;background-image:url(data:image/gif;base64,R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7);' + }); + bgPattern.appendChild(div); + bg.append(bgPattern); + } + } else if (bgPattern) { + bgPattern.remove(); + } + + if (url) { + if (!bgImg) { + bgImg = svgdoc.createElementNS(NS.SVG, 'image'); + assignAttributes(bgImg, { + id: 'background_image', + width: '100%', + height: '100%', + preserveAspectRatio: 'xMinYMin', + style: 'pointer-events:none' + }); + } + + setHref(bgImg, url); + bg.append(bgImg); + } else if (bgImg) { + bgImg.remove(); + } + }; + /** + * Select the next/previous element within the current layer. + * @function module:svgcanvas.SvgCanvas#cycleElement + * @param {boolean} next - true = next and false = previous element + * @fires module:svgcanvas.SvgCanvas#event:selected + * @returns {void} + */ + + + this.cycleElement = function (next) { + let num; + const curElem = selectedElements[0]; + let elem = false; + const allElems = getVisibleElements(currentGroup || getCurrentDrawing().getCurrentLayer()); + + if (!allElems.length) { + return; + } + + if (isNullish(curElem)) { + num = next ? allElems.length - 1 : 0; + elem = allElems[num]; + } else { + let i = allElems.length; + + while (i--) { + if (allElems[i] === curElem) { + num = next ? i - 1 : i + 1; + + if (num >= allElems.length) { + num = 0; + } else if (num < 0) { + num = allElems.length - 1; + } + + elem = allElems[num]; + break; + } + } + } + + selectOnly([elem], true); + call('selected', selectedElements); + }; + + this.clear(); + /** + * @interface module:svgcanvas.PrivateMethods + * @type {PlainObject} + * @property {module:svgcanvas~addCommandToHistory} addCommandToHistory + * @property {module:history.HistoryCommand} BatchCommand + * @property {module:history.HistoryCommand} ChangeElementCommand + * @property {module:utilities.decode64} decode64 + * @property {module:utilities.dropXMLInternalSubset} dropXMLInternalSubset + * @property {module:utilities.encode64} encode64 + * @property {module:svgcanvas~ffClone} ffClone + * @property {module:svgcanvas~findDuplicateGradient} findDuplicateGradient + * @property {module:utilities.getPathBBox} getPathBBox + * @property {module:units.getTypeMap} getTypeMap + * @property {module:draw.identifyLayers} identifyLayers + * @property {module:history.HistoryCommand} InsertElementCommand + * @property {module:browser.isChrome} isChrome + * @property {module:math.isIdentity} isIdentity + * @property {module:browser.isIE} isIE + * @property {module:svgcanvas~logMatrix} logMatrix + * @property {module:history.HistoryCommand} MoveElementCommand + * @property {module:namespaces.NS} NS + * @property {module:utilities.preventClickDefault} preventClickDefault + * @property {module:history.HistoryCommand} RemoveElementCommand + * @property {module:SVGTransformList.SVGEditTransformList} SVGEditTransformList + * @property {module:utilities.text2xml} text2xml + * @property {module:math.transformBox} transformBox + * @property {module:math.transformPoint} transformPoint + * @property {module:utilities.walkTree} walkTree + */ + + /** + * @deprecated getPrivateMethods + * Since all methods are/should be public somehow, this function should be removed; + * we might require `import` in place of this in the future once ES6 Modules + * widespread + + * Being able to access private methods publicly seems wrong somehow, + * but currently appears to be the best way to allow testing and provide + * access to them to plugins. + * @function module:svgcanvas.SvgCanvas#getPrivateMethods + * @returns {module:svgcanvas.PrivateMethods} + */ + + this.getPrivateMethods = function () { + const obj = { + addCommandToHistory, + BatchCommand: BatchCommand$1, + ChangeElementCommand: ChangeElementCommand$1, + decode64, + dropXMLInternalSubset, + encode64, + ffClone, + findDefs, + findDuplicateGradient, + getElem, + getPathBBox, + getTypeMap, + getUrlFromAttr, + identifyLayers: identifyLayers, + InsertElementCommand: InsertElementCommand$1, + isChrome, + isIdentity, + isIE, + logMatrix, + MoveElementCommand: MoveElementCommand$1, + NS, + preventClickDefault, + RemoveElementCommand: RemoveElementCommand$1, + SVGEditTransformList: SVGTransformList, + text2xml, + transformBox, + transformPoint, + walkTree + }; + return obj; + }; + } // End constructor + + + } // End class // Todo: Update: https://github.com/jeresig/jquery.hotkeys @@ -22290,12 +21376,12 @@ }); }); */ - var isOpera$1 = Boolean(window.opera); + const isOpera$1 = Boolean(window.opera); - var fixIDs = function fixIDs(svgEl, svgNum, force) { - var defs = svgEl.find('defs'); + const fixIDs = function (svgEl, svgNum, force) { + const defs = svgEl.find('defs'); if (!defs.length) return svgEl; - var idElems; + let idElems; if (isOpera$1) { idElems = defs.find('*').filter(function () { @@ -22305,20 +21391,22 @@ idElems = defs.find('[id]'); } - var allElems = svgEl[0].getElementsByTagName('*'), - len = allElems.length; + const allElems = svgEl[0].getElementsByTagName('*'), + len = allElems.length; idElems.each(function (i) { - var id = this.id; + const { + id + } = this; /* const noDupes = ($(svgdoc).find('#' + id).length <= 1); if (isOpera) noDupes = false; // Opera didn't clone svgEl, so not reliable if(!force && noDupes) return; */ - var newId = 'x' + id + svgNum + i; + const newId = 'x' + id + svgNum + i; this.id = newId; - var oldVal = 'url(#' + id + ')'; - var newVal = 'url(#' + newId + ')'; // Selector method, possibly faster but fails in Opera / jQuery 1.4.3 + const oldVal = 'url(#' + id + ')'; + const newVal = 'url(#' + newId + ')'; // Selector method, possibly faster but fails in Opera / jQuery 1.4.3 // svgEl.find('[fill="url(#' + id + ')"]').each(function() { // this.setAttribute('fill', 'url(#' + newId + ')'); // }).end().find('[stroke="url(#' + id + ')"]').each(function() { @@ -22332,7 +21420,7 @@ // }); for (i = 0; i < len; i++) { - var elem = allElems[i]; + const elem = allElems[i]; if (elem.getAttribute('fill') === oldVal) { elem.setAttribute('fill', newVal); @@ -22363,7 +21451,7 @@ function jQueryPluginSVGIcons($) { - var svgIcons = {}; + const svgIcons = {}; /** * Map of raster images with each key being the SVG icon ID * to replace, and the value the image file name. @@ -22410,22 +21498,21 @@ * @returns {void} */ - $.svgIcons = function (file) { - var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; - var svgns = 'http://www.w3.org/2000/svg', - xlinkns = 'http://www.w3.org/1999/xlink', - iconW = opts.w || 24, - iconH = opts.h || 24; - var elems, + $.svgIcons = function (file, opts = {}) { + const svgns = 'http://www.w3.org/2000/svg', + xlinkns = 'http://www.w3.org/1999/xlink', + iconW = opts.w || 24, + iconH = opts.h || 24; + let elems, svgdoc, testImg, iconsMade = false, dataLoaded = false, loadAttempts = 0; - var // ua = navigator.userAgent, + const // ua = navigator.userAgent, // isSafari = (ua.includes('Safari/') && !ua.includes('Chrome/')), dataPre = 'data:image/svg+xml;charset=utf-8;base64,'; - var dataEl; + let dataEl; if (opts.svgz) { dataEl = $('<object data="' + file + '" type=image/svg+xml>').appendTo('body').hide(); @@ -22438,11 +21525,12 @@ useFallback(); } } else { - var parser = new DOMParser(); + const parser = new DOMParser(); $.ajax({ url: file, dataType: 'string', - success: function success(data) { + + success(data) { if (!data) { $(useFallback); return; @@ -22453,7 +21541,8 @@ getIcons('ajax'); }); }, - error: function error(err) { + + error(err) { // TODO: Fix Opera widget icon bug if (window.opera) { $(function () { @@ -22473,6 +21562,7 @@ $(useFallback); } } + }); } /** @@ -22491,7 +21581,7 @@ svgdoc = dataEl[0].contentDocument; // Needed again for Webkit - var isReady = svgdoc && svgdoc.getElementById('svg_eof'); + const isReady = svgdoc && svgdoc.getElementById('svg_eof'); if (!isReady && !(noWait && isReady)) { loadAttempts++; @@ -22512,7 +21602,7 @@ elems = $(svgdoc.firstChild).children(); // .getElementsByTagName('foreignContent'); if (!opts.no_img) { - var testSrc = dataPre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; + const testSrc = dataPre + 'PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNzUiIGhlaWdodD0iMjc1Ij48L3N2Zz4%3D'; testImg = $(new Image()).attr({ src: testSrc, width: 0, @@ -22545,11 +21635,11 @@ if (opts.replace) { if (setID) icon.attr('id', id); - var cl = target.attr('class'); + const cl = target.attr('class'); if (cl) icon.attr('class', 'svg_icon ' + cl); if (!target.alt) { - var alt = 'icon'; + let alt = 'icon'; if (opts.alts) { alt = opts.alts[id] || alt; @@ -22570,7 +21660,7 @@ } } - var holder; + let holder; /** * @param {external:jQuery} icon A wrapped `defs` or Image * @param {string} id SVG icon ID @@ -22592,12 +21682,10 @@ */ - function makeIcons() { - var toImage = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; - var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + function makeIcons(toImage = false, fallback = false) { if (iconsMade) return; if (opts.no_img) toImage = false; - var tempHolder; + let tempHolder; if (toImage) { tempHolder = $(document.createElement('div')); @@ -22605,43 +21693,45 @@ } if (fallback) { - var path = opts.fallback_path || ''; + const path = opts.fallback_path || ''; $.each(fallback, function (id, imgsrc) { holder = $('#' + id); - var alt = 'icon'; + let alt = 'icon'; if (opts.alts) { alt = opts.alts[id] || alt; } - var icon = $(new Image()).attr({ - "class": 'svg_icon', + const icon = $(new Image()).attr({ + class: 'svg_icon', src: path + imgsrc, width: iconW, height: iconH, - alt: alt + alt }); addIcon(icon, id); }); } else { - var len = elems.length; + const len = elems.length; - for (var i = 0; i < len; i++) { - var elem = elems[i]; - var id = elem.id; + for (let i = 0; i < len; i++) { + const elem = elems[i]; + const { + id + } = elem; if (id === 'svg_eof') break; holder = $('#' + id); - var svgroot = document.createElementNS(svgns, 'svg'); // Per https://www.w3.org/TR/xml-names11/#defaulting, the namespace for + const svgroot = document.createElementNS(svgns, 'svg'); // Per https://www.w3.org/TR/xml-names11/#defaulting, the namespace for // attributes should have no value. svgroot.setAttribute('viewBox', [0, 0, iconW, iconH].join(' ')); - var svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; // Make flexible by converting width/height to viewBox + let svg = elem.getElementsByTagNameNS(svgns, 'svg')[0]; // Make flexible by converting width/height to viewBox - var w = svg.getAttribute('width'); - var h = svg.getAttribute('height'); + const w = svg.getAttribute('width'); + const h = svg.getAttribute('height'); svg.removeAttribute('width'); svg.removeAttribute('height'); - var vb = svg.getAttribute('viewBox'); + const vb = svg.getAttribute('viewBox'); if (!vb) { svg.setAttribute('viewBox', [0, 0, w, h].join(' ')); @@ -22657,21 +21747,21 @@ if (!isOpera$1) svg = svg.cloneNode(true); svgroot.append(svg); - var icon = void 0; + let icon; if (toImage) { tempHolder.empty().append(svgroot); - var str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); - var alt = 'icon'; + const str = dataPre + encode64(unescape(encodeURIComponent(new XMLSerializer().serializeToString(svgroot)))); + let alt = 'icon'; if (opts.alts) { alt = opts.alts[id] || alt; } icon = $(new Image()).attr({ - "class": 'svg_icon', + class: 'svg_icon', src: str, - alt: alt + alt }); } else { icon = fixIDs($(svgroot), i); @@ -22685,7 +21775,7 @@ $.each(opts.placement, function (sel, id) { if (!svgIcons[id]) return; $(sel).each(function (i) { - var copy = svgIcons[id].clone(); + let copy = svgIcons[id].clone(); if (i > 0 && !toImage) copy = fixIDs(copy, i); setIcon($(this), copy, id); }); @@ -22709,7 +21799,7 @@ function useFallback() { if (file.includes('.svgz')) { - var regFile = file.replace('.svgz', '.svg'); + const regFile = file.replace('.svgz', '.svg'); if (window.console) { console.log('.svgz failed, trying with .svg'); // eslint-disable-line no-console @@ -22730,7 +21820,7 @@ $.getSvgIcon = function (id, uniqueClone) { - var icon = svgIcons[id]; + let icon = svgIcons[id]; if (uniqueClone && icon) { icon = fixIDs(icon, 0).clone(true); @@ -22761,11 +21851,11 @@ $.resizeSvgIcons = function (obj) { // FF2 and older don't detect .svg_icon, so we change it detect svg elems instead - var changeSel = !$('.svg_icon:first').length; + const changeSel = !$('.svg_icon:first').length; $.each(obj, function (sel, size) { - var arr = Array.isArray(size); - var w = arr ? size[0] : size, - h = arr ? size[1] : size; + const arr = Array.isArray(size); + const w = arr ? size[0] : size, + h = arr ? size[1] : size; if (changeSel) { sel = sel.replace(/\.svg_icon/g, 'svg'); @@ -22820,19 +21910,21 @@ */ /* eslint-enable jsdoc/require-property */ - var ns = { + const ns = { svg: 'http://www.w3.org/2000/svg', xlink: 'http://www.w3.org/1999/xlink' }; if (!window.console) { window.console = { - log: function log(str) { + log(str) { /* */ }, - dir: function dir(str) { + + dir(str) { /* */ } + }; } /** @@ -22850,7 +21942,7 @@ $.loadingStylesheets = []; } - var stylesheet = 'jgraduate/css/jGraduate.css'; + const stylesheet = 'jgraduate/css/jGraduate.css'; if (!$.loadingStylesheets.includes(stylesheet)) { $.loadingStylesheets.push(stylesheet); @@ -22869,86 +21961,86 @@ */ - var Paint = - /** - * @param {module:jGraduate.jGraduatePaintOptions} [opt] - */ - function Paint(opt) { - _classCallCheck(this, Paint); + class Paint { + /** + * @param {module:jGraduate.jGraduatePaintOptions} [opt] + */ + constructor(opt) { + const options = opt || {}; + this.alpha = isNaN(options.alpha) ? 100 : options.alpha; // copy paint object - var options = opt || {}; - this.alpha = isNaN(options.alpha) ? 100 : options.alpha; // copy paint object + if (options.copy) { + /** + * @name module:jGraduate~Paint#type + * @type {"none"|"solidColor"|"linearGradient"|"radialGradient"} + */ + this.type = options.copy.type; + /** + * Represents opacity (0-100). + * @name module:jGraduate~Paint#alpha + * @type {Float} + */ - if (options.copy) { - /** - * @name module:jGraduate~Paint#type - * @type {"none"|"solidColor"|"linearGradient"|"radialGradient"} - */ - this.type = options.copy.type; - /** - * Represents opacity (0-100). - * @name module:jGraduate~Paint#alpha - * @type {Float} - */ + this.alpha = options.copy.alpha; + /** + * Represents #RRGGBB hex of color. + * @name module:jGraduate~Paint#solidColor + * @type {string} + */ - this.alpha = options.copy.alpha; - /** - * Represents #RRGGBB hex of color. - * @name module:jGraduate~Paint#solidColor - * @type {string} - */ + this.solidColor = null; + /** + * @name module:jGraduate~Paint#linearGradient + * @type {SVGLinearGradientElement} + */ - this.solidColor = null; - /** - * @name module:jGraduate~Paint#linearGradient - * @type {SVGLinearGradientElement} - */ + this.linearGradient = null; + /** + * @name module:jGraduate~Paint#radialGradient + * @type {SVGRadialGradientElement} + */ - this.linearGradient = null; - /** - * @name module:jGraduate~Paint#radialGradient - * @type {SVGRadialGradientElement} - */ + this.radialGradient = null; - this.radialGradient = null; + switch (this.type) { + case 'none': + break; - switch (this.type) { - case 'none': - break; + case 'solidColor': + this.solidColor = options.copy.solidColor; + break; - case 'solidColor': - this.solidColor = options.copy.solidColor; - break; + case 'linearGradient': + this.linearGradient = options.copy.linearGradient.cloneNode(true); + break; - case 'linearGradient': - this.linearGradient = options.copy.linearGradient.cloneNode(true); - break; + case 'radialGradient': + this.radialGradient = options.copy.radialGradient.cloneNode(true); + break; + } // create linear gradient paint - case 'radialGradient': - this.radialGradient = options.copy.radialGradient.cloneNode(true); - break; - } // create linear gradient paint - - } else if (options.linearGradient) { - this.type = 'linearGradient'; - this.solidColor = null; - this.radialGradient = null; - this.linearGradient = options.linearGradient.cloneNode(true); // create linear gradient paint - } else if (options.radialGradient) { - this.type = 'radialGradient'; - this.solidColor = null; - this.linearGradient = null; - this.radialGradient = options.radialGradient.cloneNode(true); // create solid color paint - } else if (options.solidColor) { - this.type = 'solidColor'; - this.solidColor = options.solidColor; // create empty paint - } else { - this.type = 'none'; - this.solidColor = null; - this.linearGradient = null; - this.radialGradient = null; + } else if (options.linearGradient) { + this.type = 'linearGradient'; + this.solidColor = null; + this.radialGradient = null; + this.linearGradient = options.linearGradient.cloneNode(true); // create linear gradient paint + } else if (options.radialGradient) { + this.type = 'radialGradient'; + this.solidColor = null; + this.linearGradient = null; + this.radialGradient = options.radialGradient.cloneNode(true); // create solid color paint + } else if (options.solidColor) { + this.type = 'solidColor'; + this.solidColor = options.solidColor; // create empty paint + } else { + this.type = 'none'; + this.solidColor = null; + this.linearGradient = null; + this.radialGradient = null; + } } - }; + + } /* eslint-disable jsdoc/require-property */ /** @@ -22966,7 +22058,7 @@ * @class external:jQuery.jGraduate.Paint * @see module:jGraduate~Paint */ - Paint: Paint + Paint }; // JSDoc doesn't show this as belonging to our `module:jGraduate.Options` type, // so we use `@see` @@ -23014,7 +22106,7 @@ newstop: 'inverse' // same, inverse, black, white }; - var isGecko = navigator.userAgent.includes('Gecko/'); + const isGecko = navigator.userAgent.includes('Gecko/'); /** * @typedef {PlainObject<string, string>} module:jGraduate.Attrs */ @@ -23027,20 +22119,12 @@ function setAttrs(elem, attrs) { if (isGecko) { - Object.entries(attrs).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - aname = _ref2[0], - val = _ref2[1]; - + Object.entries(attrs).forEach(([aname, val]) => { elem.setAttribute(aname, val); }); } else { - Object.entries(attrs).forEach(function (_ref3) { - var _ref4 = _slicedToArray(_ref3, 2), - aname = _ref4[0], - val = _ref4[1]; - - var prop = elem[aname]; + Object.entries(attrs).forEach(([aname, val]) => { + const prop = elem[aname]; if (prop && prop.constructor === 'SVGLength') { prop.baseVal.value = val; @@ -23059,7 +22143,7 @@ function mkElem(name, attrs, newparent) { - var elem = document.createElementNS(ns.svg, name); + const elem = document.createElementNS(ns.svg, name); setAttrs(elem, attrs); if (newparent) { @@ -23106,10 +22190,10 @@ $.fn.jGraduate = function (options, okCallback, cancelCallback) { return this.each(function () { - var $this = $(this), - $settings = $.extend(true, {}, $.fn.jGraduateDefaults, options || {}), - id = $this.attr('id'), - idref = '#' + $this.attr('id') + ' '; + const $this = $(this), + $settings = $.extend(true, {}, $.fn.jGraduateDefaults, options || {}), + id = $this.attr('id'), + idref = '#' + $this.attr('id') + ' '; if (!idref) { /* await */ @@ -23117,7 +22201,7 @@ return; } - var okClicked = function okClicked() { + const okClicked = function () { switch ($this.paint.type) { case 'radialGradient': $this.paint.linearGradient = null; @@ -23136,7 +22220,7 @@ $this.hide(); }; - var cancelClicked = function cancelClicked() { + const cancelClicked = function () { typeof $this.cancelCallback === 'function' && $this.cancelCallback(); $this.hide(); }; @@ -23150,9 +22234,9 @@ okCallback: typeof okCallback === 'function' ? okCallback : null, cancelCallback: typeof cancelCallback === 'function' ? cancelCallback : null }); - var // pos = $this.position(), + let // pos = $this.position(), color = null; - var $win = $(window); + const $win = $(window); if ($this.paint.type === 'none') { $this.paint = new $.jGraduate.Paint({ @@ -23162,22 +22246,22 @@ $this.addClass('jGraduate_Picker'); $this.html('<ul class="jGraduate_tabs">' + '<li class="jGraduate_tab_color jGraduate_tab_current" data-type="col">Solid Color</li>' + '<li class="jGraduate_tab_lingrad" data-type="lg">Linear Gradient</li>' + '<li class="jGraduate_tab_radgrad" data-type="rg">Radial Gradient</li>' + '</ul>' + '<div class="jGraduate_colPick"></div>' + '<div class="jGraduate_gradPick"></div>' + '<div class="jGraduate_LightBox"></div>' + '<div id="' + id + '_jGraduate_stopPicker" class="jGraduate_stopPicker"></div>'); - var colPicker = $(idref + '> .jGraduate_colPick'); - var gradPicker = $(idref + '> .jGraduate_gradPick'); + const colPicker = $(idref + '> .jGraduate_colPick'); + const gradPicker = $(idref + '> .jGraduate_gradPick'); gradPicker.html('<div id="' + id + '_jGraduate_Swatch" class="jGraduate_Swatch">' + '<h2 class="jGraduate_Title">' + $settings.window.pickerTitle + '</h2>' + '<div id="' + id + '_jGraduate_GradContainer" class="jGraduate_GradContainer"></div>' + '<div id="' + id + '_jGraduate_StopSlider" class="jGraduate_StopSlider"></div>' + '</div>' + '<div class="jGraduate_Form jGraduate_Points jGraduate_lg_field">' + '<div class="jGraduate_StopSection">' + '<label class="jGraduate_Form_Heading">Begin Point</label>' + '<div class="jGraduate_Form_Section">' + '<label>x:</label>' + '<input type="text" id="' + id + '_jGraduate_x1" size="3" title="Enter starting x value between 0.0 and 1.0"/>' + '<label>y:</label>' + '<input type="text" id="' + id + '_jGraduate_y1" size="3" title="Enter starting y value between 0.0 and 1.0"/>' + '</div>' + '</div>' + '<div class="jGraduate_StopSection">' + '<label class="jGraduate_Form_Heading">End Point</label>' + '<div class="jGraduate_Form_Section">' + '<label>x:</label>' + '<input type="text" id="' + id + '_jGraduate_x2" size="3" title="Enter ending x value between 0.0 and 1.0"/>' + '<label>y:</label>' + '<input type="text" id="' + id + '_jGraduate_y2" size="3" title="Enter ending y value between 0.0 and 1.0"/>' + '</div>' + '</div>' + '</div>' + '<div class="jGraduate_Form jGraduate_Points jGraduate_rg_field">' + '<div class="jGraduate_StopSection">' + '<label class="jGraduate_Form_Heading">Center Point</label>' + '<div class="jGraduate_Form_Section">' + '<label>x:</label>' + '<input type="text" id="' + id + '_jGraduate_cx" size="3" title="Enter x value between 0.0 and 1.0"/>' + '<label>y:</label>' + '<input type="text" id="' + id + '_jGraduate_cy" size="3" title="Enter y value between 0.0 and 1.0"/>' + '</div>' + '</div>' + '<div class="jGraduate_StopSection">' + '<label class="jGraduate_Form_Heading">Focal Point</label>' + '<div class="jGraduate_Form_Section">' + '<label>Match center: <input type="checkbox" checked="checked" id="' + id + '_jGraduate_match_ctr"/></label><br/>' + '<label>x:</label>' + '<input type="text" id="' + id + '_jGraduate_fx" size="3" title="Enter x value between 0.0 and 1.0"/>' + '<label>y:</label>' + '<input type="text" id="' + id + '_jGraduate_fy" size="3" title="Enter y value between 0.0 and 1.0"/>' + '</div>' + '</div>' + '</div>' + '<div class="jGraduate_StopSection jGraduate_SpreadMethod">' + '<label class="jGraduate_Form_Heading">Spread method</label>' + '<div class="jGraduate_Form_Section">' + '<select class="jGraduate_spreadMethod">' + '<option value=pad selected>Pad</option>' + '<option value=reflect>Reflect</option>' + '<option value=repeat>Repeat</option>' + '</select>' + '</div>' + '</div>' + '<div class="jGraduate_Form">' + '<div class="jGraduate_Slider jGraduate_RadiusField jGraduate_rg_field">' + '<label class="prelabel">Radius:</label>' + '<div id="' + id + '_jGraduate_Radius" class="jGraduate_SliderBar jGraduate_Radius" title="Click to set radius">' + '<img id="' + id + '_jGraduate_RadiusArrows" class="jGraduate_RadiusArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' + '</div>' + '<label><input type="text" id="' + id + '_jGraduate_RadiusInput" size="3" value="100"/>%</label>' + '</div>' + '<div class="jGraduate_Slider jGraduate_EllipField jGraduate_rg_field">' + '<label class="prelabel">Ellip:</label>' + '<div id="' + id + '_jGraduate_Ellip" class="jGraduate_SliderBar jGraduate_Ellip" title="Click to set Ellip">' + '<img id="' + id + '_jGraduate_EllipArrows" class="jGraduate_EllipArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' + '</div>' + '<label><input type="text" id="' + id + '_jGraduate_EllipInput" size="3" value="0"/>%</label>' + '</div>' + '<div class="jGraduate_Slider jGraduate_AngleField jGraduate_rg_field">' + '<label class="prelabel">Angle:</label>' + '<div id="' + id + '_jGraduate_Angle" class="jGraduate_SliderBar jGraduate_Angle" title="Click to set Angle">' + '<img id="' + id + '_jGraduate_AngleArrows" class="jGraduate_AngleArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' + '</div>' + '<label><input type="text" id="' + id + '_jGraduate_AngleInput" size="3" value="0"/>deg</label>' + '</div>' + '<div class="jGraduate_Slider jGraduate_OpacField">' + '<label class="prelabel">Opac:</label>' + '<div id="' + id + '_jGraduate_Opac" class="jGraduate_SliderBar jGraduate_Opac" title="Click to set Opac">' + '<img id="' + id + '_jGraduate_OpacArrows" class="jGraduate_OpacArrows" src="' + $settings.images.clientPath + 'rangearrows2.gif">' + '</div>' + '<label><input type="text" id="' + id + '_jGraduate_OpacInput" size="3" value="100"/>%</label>' + '</div>' + '</div>' + '<div class="jGraduate_OkCancel">' + '<input type="button" id="' + id + '_jGraduate_Ok" class="jGraduate_Ok" value="OK"/>' + '<input type="button" id="' + id + '_jGraduate_Cancel" class="jGraduate_Cancel" value="Cancel"/>' + '</div>'); // -------------- // Set up all the SVG elements (the gradient, stops and rectangle) - var MAX = 256, - MARGINX = 0, - MARGINY = 0, - // STOP_RADIUS = 15 / 2, + const MAX = 256, + MARGINX = 0, + MARGINY = 0, + // STOP_RADIUS = 15 / 2, SIZEX = MAX - 2 * MARGINX, - SIZEY = MAX - 2 * MARGINY; - var attrInput = {}; - var SLIDERW = 145; + SIZEY = MAX - 2 * MARGINY; + const attrInput = {}; + const SLIDERW = 145; $('.jGraduate_SliderBar').width(SLIDERW); - var container = $('#' + id + '_jGraduate_GradContainer')[0]; - var svg = mkElem('svg', { + const container = $('#' + id + '_jGraduate_GradContainer')[0]; + const svg = mkElem('svg', { id: id + '_jgraduate_svg', width: MAX, height: MAX, @@ -23187,11 +22271,11 @@ // curType = curType || $this.paint.type; // if we are sent a gradient, import it - var curType = $this.paint.type; - var grad = $this.paint[curType]; - var curGradient = grad; - var gradalpha = $this.paint.alpha; - var isSolid = curType === 'solidColor'; // Make any missing gradients + let curType = $this.paint.type; + let grad = $this.paint[curType]; + let curGradient = grad; + const gradalpha = $this.paint.alpha; + const isSolid = curType === 'solidColor'; // Make any missing gradients switch (curType) { case 'solidColor': // fall through @@ -23223,14 +22307,13 @@ }, svg); } - var stopGroup; // eslint-disable-line prefer-const + let stopGroup; // eslint-disable-line prefer-const if (isSolid) { grad = curGradient = $('#' + id + '_lg_jgraduate_grad')[0]; color = $this.paint[curType]; mkStop(0, '#' + color, 1); - - var type = _typeof($settings.newstop); + const type = typeof $settings.newstop; if (type === 'string') { switch ($settings.newstop) { @@ -23241,11 +22324,11 @@ case 'inverse': { // Invert current color for second stop - var inverted = ''; + let inverted = ''; - for (var i = 0; i < 6; i += 2) { + for (let i = 0; i < 6; i += 2) { // const ch = color.substr(i, 2); - var inv = (255 - Number.parseInt(color.substr(i, 2), 16)).toString(16); + let inv = (255 - Number.parseInt(color.substr(i, 2), 16)).toString(16); if (inv.length < 2) inv = 0 + inv; inverted += inv; } @@ -23263,20 +22346,20 @@ break; } } else if (type === 'object') { - var opac = 'opac' in $settings.newstop ? $settings.newstop.opac : 1; + const opac = 'opac' in $settings.newstop ? $settings.newstop.opac : 1; mkStop(1, $settings.newstop.color || '#' + color, opac); } } - var x1 = Number.parseFloat(grad.getAttribute('x1') || 0.0), - y1 = Number.parseFloat(grad.getAttribute('y1') || 0.0), - x2 = Number.parseFloat(grad.getAttribute('x2') || 1.0), - y2 = Number.parseFloat(grad.getAttribute('y2') || 0.0); - var cx = Number.parseFloat(grad.getAttribute('cx') || 0.5), - cy = Number.parseFloat(grad.getAttribute('cy') || 0.5), - fx = Number.parseFloat(grad.getAttribute('fx') || cx), - fy = Number.parseFloat(grad.getAttribute('fy') || cy); - var previewRect = mkElem('rect', { + const x1 = Number.parseFloat(grad.getAttribute('x1') || 0.0), + y1 = Number.parseFloat(grad.getAttribute('y1') || 0.0), + x2 = Number.parseFloat(grad.getAttribute('x2') || 1.0), + y2 = Number.parseFloat(grad.getAttribute('y2') || 0.0); + const cx = Number.parseFloat(grad.getAttribute('cx') || 0.5), + cy = Number.parseFloat(grad.getAttribute('cy') || 0.5), + fx = Number.parseFloat(grad.getAttribute('fx') || cx), + fy = Number.parseFloat(grad.getAttribute('fy') || cy); + const previewRect = mkElem('rect', { id: id + '_jgraduate_rect', x: MARGINX, y: MARGINY, @@ -23286,25 +22369,25 @@ 'fill-opacity': gradalpha / 100 }, svg); // stop visuals created here - var beginCoord = $('<div/>').attr({ - "class": 'grad_coord jGraduate_lg_field', + const beginCoord = $('<div/>').attr({ + class: 'grad_coord jGraduate_lg_field', title: 'Begin Stop' }).text(1).css({ top: y1 * MAX, left: x1 * MAX }).data('coord', 'start').appendTo(container); - var endCoord = beginCoord.clone().text(2).css({ + const endCoord = beginCoord.clone().text(2).css({ top: y2 * MAX, left: x2 * MAX }).attr('title', 'End stop').data('coord', 'end').appendTo(container); - var centerCoord = $('<div/>').attr({ - "class": 'grad_coord jGraduate_rg_field', + const centerCoord = $('<div/>').attr({ + class: 'grad_coord jGraduate_rg_field', title: 'Center stop' }).text('C').css({ top: cy * MAX, left: cx * MAX }).data('coord', 'center').appendTo(container); - var focusCoord = centerCoord.clone().text('F').css({ + const focusCoord = centerCoord.clone().text('F').css({ top: fy * MAX, left: fx * MAX, display: 'none' @@ -23320,10 +22403,10 @@ // }, 500); // }); - var showFocus; + let showFocus; $.each(['x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'fx', 'fy'], function (i, attr) { - var isRadial = isNaN(attr[1]); - var attrval = curGradient.getAttribute(attr); + const isRadial = isNaN(attr[1]); + let attrval = curGradient.getAttribute(attr); if (!attrval) { // Set defaults @@ -23350,8 +22433,8 @@ } } - var $elem = isRadial ? attr[0] === 'c' ? centerCoord : focusCoord : attr[1] === '1' ? beginCoord : endCoord; - var cssName = attr.includes('x') ? 'left' : 'top'; + const $elem = isRadial ? attr[0] === 'c' ? centerCoord : focusCoord : attr[1] === '1' ? beginCoord : endCoord; + const cssName = attr.includes('x') ? 'left' : 'top'; $elem.css(cssName, this.value * MAX); }).change(); }); @@ -23366,7 +22449,7 @@ */ function mkStop(n, colr, opac, sel, stopElem) { - var stop = stopElem || mkElem('stop', { + const stop = stopElem || mkElem('stop', { 'stop-color': colr, 'stop-opacity': opac, offset: n @@ -23381,13 +22464,13 @@ } if (opac === null) opac = 1; - var pickerD = 'M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z'; - var pathbg = mkElem('path', { + const pickerD = 'M-6.2,0.9c3.6-4,6.7-4.3,6.7-12.4c-0.2,7.9,3.1,8.8,6.5,12.4c3.5,3.8,2.9,9.6,0,12.3c-3.1,2.8-10.4,2.7-13.2,0C-9.6,9.9-9.4,4.4-6.2,0.9z'; + const pathbg = mkElem('path', { d: pickerD, fill: 'url(#jGraduate_trans)', transform: 'translate(' + (10 + n * MAX) + ', 26)' }, stopGroup); - var path = mkElem('path', { + const path = mkElem('path', { d: pickerD, fill: colr, 'fill-opacity': opac, @@ -23404,11 +22487,11 @@ return false; }).data('stop', stop).data('bg', pathbg).dblclick(function () { $('div.jGraduate_LightBox').show(); - var colorhandle = this; // eslint-disable-line consistent-this + const colorhandle = this; // eslint-disable-line consistent-this - var stopOpacity = Number(stop.getAttribute('stop-opacity')) || 1; - var stopColor = stop.getAttribute('stop-color') || 1; - var thisAlpha = (Number.parseFloat(stopOpacity) * 255).toString(16); + let stopOpacity = Number(stop.getAttribute('stop-opacity')) || 1; + let stopColor = stop.getAttribute('stop-color') || 1; + let thisAlpha = (Number.parseFloat(stopOpacity) * 255).toString(16); while (thisAlpha.length < 2) { thisAlpha = '0' + thisAlpha; @@ -23444,12 +22527,12 @@ }); }); $(curGradient).find('stop').each(function () { - var curS = $(this); + const curS = $(this); if (Number(this.getAttribute('offset')) > n) { if (!colr) { - var newcolor = this.getAttribute('stop-color'); - var newopac = this.getAttribute('stop-opacity'); + const newcolor = this.getAttribute('stop-color'); + const newopac = this.getAttribute('stop-opacity'); stop.setAttribute('stop-color', newcolor); path.setAttribute('fill', newcolor); stop.setAttribute('stop-opacity', newopac === null ? 1 : newopac); @@ -23473,15 +22556,15 @@ function remStop() { delStop.setAttribute('display', 'none'); - var path = $(curStop); - var stop = path.data('stop'); - var bg = path.data('bg'); + const path = $(curStop); + const stop = path.data('stop'); + const bg = path.data('bg'); $([curStop, stop, bg]).remove(); } - var stopMakerDiv = $('#' + id + '_jGraduate_StopSlider'); - var stops, curStop, drag; - var delStop = mkElem('path', { + const stopMakerDiv = $('#' + id + '_jGraduate_StopSlider'); + let stops, curStop, drag; + const delStop = mkElem('path', { d: 'm9.75,-6l-19.5,19.5m0,-19.5l19.5,19.5', fill: 'none', stroke: '#D00', @@ -23502,7 +22585,7 @@ // root.append(delStop); } - var stopOffset; + let stopOffset; /** * * @returns {void} @@ -23518,24 +22601,24 @@ drag = null; } - var scaleX = 1, + let scaleX = 1, scaleY = 1, angle = 0; - var cX = cx; - var cY = cy; + let cX = cx; + let cY = cy; /** * * @returns {void} */ function xform() { - var rot = angle ? 'rotate(' + angle + ',' + cX + ',' + cY + ') ' : ''; + const rot = angle ? 'rotate(' + angle + ',' + cX + ',' + cY + ') ' : ''; if (scaleX === 1 && scaleY === 1) { curGradient.removeAttribute('gradientTransform'); // $('#ang').addClass('dis'); } else { - var x = -cX * (scaleX - 1); - var y = -cY * (scaleY - 1); + const x = -cX * (scaleX - 1); + const y = -cY * (scaleY - 1); curGradient.setAttribute('gradientTransform', rot + 'translate(' + x + ',' + y + ') scale(' + scaleX + ',' + scaleY + ')'); // $('#ang').removeClass('dis'); } } @@ -23546,10 +22629,10 @@ function dragColor(evt) { - var x = evt.pageX - stopOffset.left; - var y = evt.pageY - stopOffset.top; + let x = evt.pageX - stopOffset.left; + const y = evt.pageY - stopOffset.top; x = x < 10 ? 10 : x > MAX + 10 ? MAX + 10 : x; - var xfStr = 'translate(' + x + ', 26)'; + const xfStr = 'translate(' + x + ', 26)'; if (y < -60 || y > 130) { delStop.setAttribute('display', 'block'); @@ -23560,13 +22643,13 @@ drag.setAttribute('transform', xfStr); $.data(drag, 'bg').setAttribute('transform', xfStr); - var stop = $.data(drag, 'stop'); - var sX = (x - 10) / MAX; + const stop = $.data(drag, 'stop'); + const sX = (x - 10) / MAX; stop.setAttribute('offset', sX); - var last = 0; + let last = 0; $(curGradient).find('stop').each(function (i) { - var cur = this.getAttribute('offset'); - var t = $(this); + const cur = this.getAttribute('offset'); + const t = $(this); if (cur < last) { t.prev().before(t); @@ -23577,27 +22660,29 @@ }); } - var stopMakerSVG = mkElem('svg', { + const stopMakerSVG = mkElem('svg', { width: '100%', height: 45 }, stopMakerDiv[0]); - var transPattern = mkElem('pattern', { + const transPattern = mkElem('pattern', { width: 16, height: 16, patternUnits: 'userSpaceOnUse', id: 'jGraduate_trans' }, stopMakerSVG); - var transImg = mkElem('image', { + const transImg = mkElem('image', { width: 16, height: 16 }, transPattern); - var bgImage = $settings.images.clientPath + 'map-opacity.png'; + const bgImage = $settings.images.clientPath + 'map-opacity.png'; transImg.setAttributeNS(ns.xlink, 'xlink:href', bgImage); $(stopMakerSVG).click(function (evt) { stopOffset = stopMakerDiv.offset(); - var target = evt.target; + const { + target + } = evt; if (target.tagName === 'path') return; - var x = evt.pageX - stopOffset.left - 8; + let x = evt.pageX - stopOffset.left - 8; x = x < 10 ? 10 : x > MAX + 10 ? MAX + 10 : x; mkStop(x / MAX, 0, 0, true); evt.stopPropagation(); @@ -23614,24 +22699,24 @@ 'stroke-width': 2, stroke: '#000' }, stopMakerSVG); - var spreadMethodOpt = gradPicker.find('.jGraduate_spreadMethod').change(function () { + const spreadMethodOpt = gradPicker.find('.jGraduate_spreadMethod').change(function () { curGradient.setAttribute('spreadMethod', $(this).val()); }); // handle dragging the stop around the swatch - var draggingCoord = null; + let draggingCoord = null; - var onCoordDrag = function onCoordDrag(evt) { - var x = evt.pageX - offset.left; - var y = evt.pageY - offset.top; // clamp stop to the swatch + const onCoordDrag = function (evt) { + let x = evt.pageX - offset.left; + let y = evt.pageY - offset.top; // clamp stop to the swatch x = x < 0 ? 0 : x > MAX ? MAX : x; y = y < 0 ? 0 : y > MAX ? MAX : y; draggingCoord.css('left', x).css('top', y); // calculate stop offset - var fracx = x / SIZEX; - var fracy = y / SIZEY; - var type = draggingCoord.data('coord'); - var grd = curGradient; + const fracx = x / SIZEX; + const fracy = y / SIZEY; + const type = draggingCoord.data('coord'); + const grd = curGradient; switch (type) { case 'start': @@ -23669,7 +22754,7 @@ evt.preventDefault(); }; - var onCoordUp = function onCoordUp() { + const onCoordUp = function () { draggingCoord = null; $win.unbind('mousemove', onCoordDrag).unbind('mouseup', onCoordUp); }; // Linear gradient @@ -23677,7 +22762,7 @@ stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); - var numstops = stops.length; // if there are not at least two stops, then + let numstops = stops.length; // if there are not at least two stops, then if (numstops < 2) { while (numstops < 2) { @@ -23688,12 +22773,12 @@ stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); } - for (var _i = 0; _i < numstops; _i++) { - mkStop(0, 0, 0, 0, stops[_i]); + for (let i = 0; i < numstops; i++) { + mkStop(0, 0, 0, 0, stops[i]); } spreadMethodOpt.val(curGradient.getAttribute('spreadMethod') || 'pad'); - var offset; // No match, so show focus point + let offset; // No match, so show focus point showFocus = false; previewRect.setAttribute('fill-opacity', gradalpha / 100); @@ -23726,13 +22811,13 @@ } $('#' + id + '_jGraduate_match_ctr')[0].checked = !showFocus; - var lastfx, lastfy; + let lastfx, lastfy; $('#' + id + '_jGraduate_match_ctr').change(function () { showFocus = !this.checked; focusCoord.toggle(showFocus); attrInput.fx.val(''); attrInput.fy.val(''); - var grd = curGradient; + const grd = curGradient; if (!showFocus) { lastfx = grd.getAttribute('fx'); @@ -23740,8 +22825,8 @@ grd.removeAttribute('fx'); grd.removeAttribute('fy'); } else { - var fX = lastfx || 0.5; - var fY = lastfy || 0.5; + const fX = lastfx || 0.5; + const fY = lastfy || 0.5; grd.setAttribute('fx', fX); grd.setAttribute('fy', fY); attrInput.fx.val(fX); @@ -23760,21 +22845,24 @@ stops = curGradient.getElementsByTagNameNS(ns.svg, 'stop'); } - var slider; + let slider; - var setSlider = function setSlider(e) { - var _slider = slider, - left = _slider.offset.left; - var div = slider.parent; - var x = e.pageX - left - Number.parseInt(div.css('border-left-width')); + const setSlider = function (e) { + const { + offset: { + left + } + } = slider; + const div = slider.parent; + let x = e.pageX - left - Number.parseInt(div.css('border-left-width')); if (x > SLIDERW) x = SLIDERW; if (x <= 0) x = 0; - var posx = x - 5; + const posx = x - 5; x /= SLIDERW; switch (slider.type) { case 'radius': - x = Math.pow(x * 2, 2.5); + x = (x * 2) ** 2.5; if (x > 0.98 && x < 1.02) x = 1; if (x <= 0.01) x = 0.01; curGradient.setAttribute('r', x); @@ -23824,18 +22912,18 @@ slider.input.val(x); }; - var ellipVal = 0, + let ellipVal = 0, angleVal = 0; if (curType === 'radialGradient') { - var tlist = curGradient.gradientTransform.baseVal; + const tlist = curGradient.gradientTransform.baseVal; if (tlist.numberOfItems === 2) { - var t = tlist.getItem(0); - var s = tlist.getItem(1); + const t = tlist.getItem(0); + const s = tlist.getItem(1); if (t.type === 2 && s.type === 3) { - var m = s.matrix; + const m = s.matrix; if (m.a !== 1) { ellipVal = Math.round(-(1 - m.a) * 100); @@ -23845,26 +22933,24 @@ } } else if (tlist.numberOfItems === 3) { // Assume [R][T][S] - var r = tlist.getItem(0); + const r = tlist.getItem(0); + const t = tlist.getItem(1); + const s = tlist.getItem(2); - var _t = tlist.getItem(1); - - var _s = tlist.getItem(2); - - if (r.type === 4 && _t.type === 2 && _s.type === 3) { + if (r.type === 4 && t.type === 2 && s.type === 3) { angleVal = Math.round(r.angle); - var _m = _s.matrix; + const m = s.matrix; - if (_m.a !== 1) { - ellipVal = Math.round(-(1 - _m.a) * 100); - } else if (_m.d !== 1) { - ellipVal = Math.round((1 - _m.d) * 100); + if (m.a !== 1) { + ellipVal = Math.round(-(1 - m.a) * 100); + } else if (m.d !== 1) { + ellipVal = Math.round((1 - m.d) * 100); } } } } - var sliders = { + const sliders = { radius: { handle: '#' + id + '_jGraduate_RadiusArrows', input: '#' + id + '_jGraduate_RadiusInput', @@ -23887,28 +22973,28 @@ } }; $.each(sliders, function (type, data) { - var handle = $(data.handle); + const handle = $(data.handle); handle.mousedown(function (evt) { - var parent = handle.parent(); + const parent = handle.parent(); slider = { - type: type, + type, elem: handle, input: $(data.input), - parent: parent, + parent, offset: parent.offset() }; $win.mousemove(dragSlider).mouseup(stopSlider); evt.preventDefault(); }); $(data.input).val(data.val).change(function () { - var isRad = curType === 'radialGradient'; - var val = Number(this.value); - var xpos = 0; + const isRad = curType === 'radialGradient'; + let val = Number(this.value); + let xpos = 0; switch (type) { case 'radius': if (isRad) curGradient.setAttribute('r', val / 100); - xpos = Math.pow(val / 100, 1 / 2.5) / 2 * SLIDERW; + xpos = (val / 100) ** (1 / 2.5) / 2 * SLIDERW; break; case 'opacity': @@ -23957,18 +23043,18 @@ }).change(); }); - var dragSlider = function dragSlider(evt) { + const dragSlider = function (evt) { setSlider(evt); evt.preventDefault(); }; - var stopSlider = function stopSlider(evt) { + const stopSlider = function (evt) { $win.unbind('mousemove', dragSlider).unbind('mouseup', stopSlider); slider = null; }; // -------------- - var thisAlpha = ($this.paint.alpha * 255 / 100).toString(16); + let thisAlpha = ($this.paint.alpha * 255 / 100).toString(16); while (thisAlpha.length < 2) { thisAlpha = '0' + thisAlpha; @@ -24009,12 +23095,12 @@ }, null, function () { cancelClicked(); }); - var tabs = $(idref + ' .jGraduate_tabs li'); + const tabs = $(idref + ' .jGraduate_tabs li'); tabs.click(function () { tabs.removeClass('jGraduate_tab_current'); $(this).addClass('jGraduate_tab_current'); $(idref + ' > div').hide(); - var type = $(this).attr('data-type'); + const type = $(this).attr('data-type'); /* const container = */ $(idref + ' .jGraduate_gradPick').show(); @@ -24027,13 +23113,13 @@ curType = type === 'lg' ? 'linearGradient' : 'radialGradient'; $('#' + id + '_jGraduate_OpacInput').val($this.paint.alpha).change(); - var newGrad = $('#' + id + '_' + type + '_jgraduate_grad')[0]; + const newGrad = $('#' + id + '_' + type + '_jgraduate_grad')[0]; if (curGradient !== newGrad) { - var curStops = $(curGradient).find('stop'); + const curStops = $(curGradient).find('stop'); $(newGrad).empty().append(curStops); curGradient = newGrad; - var sm = spreadMethodOpt.val(); + const sm = spreadMethodOpt.val(); curGradient.setAttribute('spreadMethod', sm); } @@ -24050,7 +23136,7 @@ }); $(idref + ' > div').hide(); tabs.removeClass('jGraduate_tab_current'); - var tab; + let tab; switch ($this.paint.type) { case 'linearGradient': @@ -24068,7 +23154,7 @@ $this.show(); // jPicker will try to show after a 0ms timeout, so need to fire this after that - setTimeout(function () { + setTimeout(() => { tab.addClass('jGraduate_tab_current').click(); }, 10); }); @@ -24159,7 +23245,7 @@ $.loadingStylesheets = []; } - var stylesheet = 'spinbtn/jQuery.SpinButton.css'; + const stylesheet = 'spinbtn/jQuery.SpinButton.css'; if (!$.loadingStylesheets.includes(stylesheet)) { $.loadingStylesheets.push(stylesheet); @@ -24213,8 +23299,8 @@ */ function coord(el, prop) { - var b = document.body; - var c = el[prop]; + const b = document.body; + let c = el[prop]; while ((el = el.offsetParent) && el !== b) { if (!$.browser.msie || el.currentStyle.position !== 'relative') { @@ -24253,7 +23339,7 @@ this.spinCfg.smallStep = cfg.smallStep || this.spinCfg.step / 2; this.adjustValue = function (i) { - var v; + let v; if (isNaN(this.value)) { v = this.spinCfg.reset; @@ -24281,12 +23367,12 @@ $(this).addClass(cfg.spinClass || 'spin-button').mousemove(function (e) { // Determine which button mouse is over, or not (spin direction): - var x = e.pageX || e.x; - var y = e.pageY || e.y; - var el = e.target; - var scale = cfg.stateObj.tool_scale || 1; - var height = $(el).height() / 2; - var direction = x > coord(el, 'offsetLeft') + el.offsetWidth * scale - this.spinCfg._btn_width ? y < coord(el, 'offsetTop') + height * scale ? 1 : -1 : 0; + const x = e.pageX || e.x; + const y = e.pageY || e.y; + const el = e.target; + const scale = cfg.stateObj.tool_scale || 1; + const height = $(el).height() / 2; + const direction = x > coord(el, 'offsetLeft') + el.offsetWidth * scale - this.spinCfg._btn_width ? y < coord(el, 'offsetTop') + height * scale ? 1 : -1 : 0; if (direction !== this.spinCfg._direction) { // Style up/down buttons: @@ -24316,22 +23402,20 @@ window.clearInterval(this.spinCfg._repeat); window.clearTimeout(this.spinCfg._delay); }).mousedown(function (e) { - var _this = this; - if (e.button === 0 && this.spinCfg._direction !== 0) { // Respond to click on one of the buttons: - var stepSize = e.shiftKey ? this.spinCfg.smallStep : this.spinCfg.step; + const stepSize = e.shiftKey ? this.spinCfg.smallStep : this.spinCfg.step; - var adjust = function adjust() { - _this.adjustValue(_this.spinCfg._direction * stepSize); + const adjust = () => { + this.adjustValue(this.spinCfg._direction * stepSize); }; adjust(); // Initial delay before repeating adjustment - this.spinCfg._delay = window.setTimeout(function () { + this.spinCfg._delay = window.setTimeout(() => { adjust(); // Repeat adjust at regular intervals - _this.spinCfg._repeat = window.setInterval(adjust, _this.spinCfg.interval); + this.spinCfg._repeat = window.setInterval(adjust, this.spinCfg.interval); }, this.spinCfg.delay); } }).mouseup(function (e) { @@ -24449,6 +23533,24 @@ return $; } + /** + * @file jQuery Context Menu Plugin + * Cory S.N. LaViska + * A Beautiful Site ({@link https://abeautifulsite.net/}) + * Modified by Alexis Deveria + * + * More info: {@link https://abeautifulsite.net/2008/09/jquery-context-menu-plugin/} + * + * @module jQueryContextMenu + * @todo Update to latest version and adapt (and needs jQuery update as well): {@link https://github.com/swisnl/jQuery-contextMenu} + * @version 1.0.1 + * + * @license (MIT OR GPL-2.0-or-later) + * + * This plugin is dual-licensed under the GNU General Public License + * and the MIT License and is copyright A Beautiful Site, LLC. + * + */ /** * @callback module:jQueryContextMenu.jQueryContextMenuListener * @param {string} href The `href` value after the first character (for bypassing an initial `#`) @@ -24478,8 +23580,8 @@ */ function jQueryContextMenu($) { - var win = $(window); - var doc = $(document); + const win = $(window); + const doc = $(document); $.extend($.fn, { /** * @memberof external:jQuery.fn @@ -24487,7 +23589,7 @@ * @param {module:jQueryContextMenu.jQueryContextMenuListener} listener * @returns {external:jQuery} */ - contextMenu: function contextMenu(o, listener) { + contextMenu(o, listener) { // Defaults if (o.menu === undefined) return false; if (o.inSpeed === undefined) o.inSpeed = 150; @@ -24497,15 +23599,15 @@ if (o.outSpeed === 0) o.outSpeed = -1; // Loop each context menu $(this).each(function () { - var el = $(this); - var offset = $(el).offset(); - var menu = $('#' + o.menu); // Add contextMenu class + const el = $(this); + const offset = $(el).offset(); + const menu = $('#' + o.menu); // Add contextMenu class menu.addClass('contextMenu'); // Simulate a true right click $(this).bind('mousedown', function (evt) { $(this).mouseup(function (e) { - var srcElement = $(this); + const srcElement = $(this); srcElement.unbind('mouseup'); if (!(evt.button === 2 || o.allowLeft || evt.ctrlKey && isMac())) { @@ -24518,10 +23620,10 @@ if (el.hasClass('disabled')) return false; // Detect mouse position - var x = e.pageX, + let x = e.pageX, y = e.pageY; - var xOff = win.width() - menu.width(), - yOff = win.height() - menu.height(); + const xOff = win.width() - menu.width(), + yOff = win.height() - menu.height(); if (x > xOff - 15) x = xOff - 15; if (y > yOff - 30) y = yOff - 30; // 30 is needed to prevent scrollbars in FF // Show the menu @@ -24638,7 +23740,7 @@ * @param {void|string} o Comma-separated * @returns {external:jQuery} */ - disableContextMenuItems: function disableContextMenuItems(o) { + disableContextMenuItems(o) { if (o === undefined) { // Disable all $(this).find('LI').addClass('disabled'); @@ -24647,21 +23749,11 @@ $(this).each(function () { if (o !== undefined) { - var d = o.split(','); + const d = o.split(','); - var _iterator = _createForOfIteratorHelper(d), - _step; - - try { - for (_iterator.s(); !(_step = _iterator.n()).done;) { - var href = _step.value; - // eslint-disable-next-line unicorn/no-fn-reference-in-iterator - $(this).find('A[href="' + href + '"]').parent().addClass('disabled'); - } - } catch (err) { - _iterator.e(err); - } finally { - _iterator.f(); + for (const href of d) { + // eslint-disable-next-line unicorn/no-fn-reference-in-iterator + $(this).find('A[href="' + href + '"]').parent().addClass('disabled'); } } }); @@ -24674,7 +23766,7 @@ * @param {void|string} o Comma-separated * @returns {external:jQuery} */ - enableContextMenuItems: function enableContextMenuItems(o) { + enableContextMenuItems(o) { if (o === undefined) { // Enable all $(this).find('LI.disabled').removeClass('disabled'); @@ -24683,21 +23775,11 @@ $(this).each(function () { if (o !== undefined) { - var d = o.split(','); + const d = o.split(','); - var _iterator2 = _createForOfIteratorHelper(d), - _step2; - - try { - for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { - var href = _step2.value; - // eslint-disable-next-line unicorn/no-fn-reference-in-iterator - $(this).find('A[href="' + href + '"]').parent().removeClass('disabled'); - } - } catch (err) { - _iterator2.e(err); - } finally { - _iterator2.f(); + for (const href of d) { + // eslint-disable-next-line unicorn/no-fn-reference-in-iterator + $(this).find('A[href="' + href + '"]').parent().removeClass('disabled'); } } }); @@ -24709,7 +23791,7 @@ * @memberof external:jQuery.fn * @returns {external:jQuery} */ - disableContextMenu: function disableContextMenu() { + disableContextMenu() { $(this).each(function () { $(this).addClass('disabled'); }); @@ -24721,7 +23803,7 @@ * @memberof external:jQuery.fn * @returns {external:jQuery} */ - enableContextMenu: function enableContextMenu() { + enableContextMenu() { $(this).each(function () { $(this).removeClass('disabled'); }); @@ -24733,7 +23815,7 @@ * @memberof external:jQuery.fn * @returns {external:jQuery} */ - destroyContextMenu: function destroyContextMenu() { + destroyContextMenu() { // Destroy specified context menus $(this).each(function () { // Disable action @@ -24741,6 +23823,7 @@ }); return $(this); } + }); return $; } @@ -24776,7 +23859,7 @@ */ function toFixedNumeric(value, precision) { if (precision === undefined) precision = 0; - return Math.round(value * Math.pow(10, precision)) / Math.pow(10, precision); + return Math.round(value * 10 ** precision) / 10 ** precision; } /** * Whether a value is `null` or `undefined`. @@ -24785,7 +23868,7 @@ */ - var isNullish$1 = function isNullish(val) { + const isNullish$1 = val => { return val === null || val === undefined; }; /** @@ -24795,7 +23878,7 @@ */ - var jPicker = function jPicker($) { + const jPicker = function ($) { if (!$.loadingStylesheets) { /** * @name loadingStylesheets @@ -24805,7 +23888,7 @@ $.loadingStylesheets = []; } - var stylesheet = 'jgraduate/css/jPicker.css'; + const stylesheet = 'jgraduate/css/jPicker.css'; if (!$.loadingStylesheets.includes(stylesheet)) { $.loadingStylesheets.push(stylesheet); @@ -24828,766 +23911,764 @@ */ - var Slider = - /** - * @param {external:jQuery} bar - * @param {module:jPicker.SliderOptions} options - */ - function Slider(bar, options) { - _classCallCheck(this, Slider); - - var that = this; + class Slider { /** - * Fire events on the supplied `context` - * @param {module:jPicker.JPickerInit} context - * @returns {void} + * @param {external:jQuery} bar + * @param {module:jPicker.SliderOptions} options */ + constructor(bar, options) { + const that = this; + /** + * Fire events on the supplied `context` + * @param {module:jPicker.JPickerInit} context + * @returns {void} + */ - function fireChangeEvents(context) { - changeEvents.forEach(function (changeEvent) { - changeEvent.call(that, that, context); - }); - } - /** - * Bind the mousedown to the bar not the arrow for quick snapping to the clicked location. - * @param {external:jQuery.Event} e - * @returns {void} - */ + function fireChangeEvents(context) { + changeEvents.forEach(changeEvent => { + changeEvent.call(that, that, context); + }); + } + /** + * Bind the mousedown to the bar not the arrow for quick snapping to the clicked location. + * @param {external:jQuery.Event} e + * @returns {void} + */ - function mouseDown(e) { - var off = bar.offset(); - offset = { - l: off.left | 0, - t: off.top | 0 - }; - clearTimeout(timeout); // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run + function mouseDown(e) { + const off = bar.offset(); + offset = { + l: off.left | 0, + t: off.top | 0 + }; + clearTimeout(timeout); // using setTimeout for visual updates - once the style is updated the browser will re-render internally allowing the next Javascript to run - timeout = setTimeout(function () { - setValuesFromMousePosition.call(that, e); - }, 0); // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing + timeout = setTimeout(function () { + setValuesFromMousePosition.call(that, e); + }, 0); // Bind mousemove and mouseup event to the document so it responds when dragged of of the bar - we will unbind these when on mouseup to save processing - $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); - e.preventDefault(); // don't try to select anything or drag the image to the desktop - } - /** - * Set the values as the mouse moves. - * @param {external:jQuery.Event} e - * @returns {false} - */ + $(document).bind('mousemove', mouseMove).bind('mouseup', mouseUp); + e.preventDefault(); // don't try to select anything or drag the image to the desktop + } + /** + * Set the values as the mouse moves. + * @param {external:jQuery.Event} e + * @returns {false} + */ - function mouseMove(e) { - clearTimeout(timeout); - timeout = setTimeout(function () { - setValuesFromMousePosition.call(that, e); - }, 0); - e.stopPropagation(); - e.preventDefault(); - return false; - } - /** - * Unbind the document events - they aren't needed when not dragging. - * @param {external:jQuery.Event} e - * @returns {false} - */ + function mouseMove(e) { + clearTimeout(timeout); + timeout = setTimeout(function () { + setValuesFromMousePosition.call(that, e); + }, 0); + e.stopPropagation(); + e.preventDefault(); + return false; + } + /** + * Unbind the document events - they aren't needed when not dragging. + * @param {external:jQuery.Event} e + * @returns {false} + */ - function mouseUp(e) { - $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); - e.stopPropagation(); - e.preventDefault(); - return false; - } - /** - * Calculate mouse position and set value within the current range. - * @param {Event} e - * @returns {void} - */ + function mouseUp(e) { + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + e.stopPropagation(); + e.preventDefault(); + return false; + } + /** + * Calculate mouse position and set value within the current range. + * @param {Event} e + * @returns {void} + */ - function setValuesFromMousePosition(e) { - var barW = bar.w, - // local copies for YUI compressor - barH = bar.h; - var locX = e.pageX - offset.l, - locY = e.pageY - offset.t; // keep the arrow within the bounds of the bar + function setValuesFromMousePosition(e) { + const barW = bar.w, + // local copies for YUI compressor + barH = bar.h; + let locX = e.pageX - offset.l, + locY = e.pageY - offset.t; // keep the arrow within the bounds of the bar - if (locX < 0) locX = 0;else if (locX > barW) locX = barW; - if (locY < 0) locY = 0;else if (locY > barH) locY = barH; - val.call(that, 'xy', { - x: locX / barW * rangeX + minX, - y: locY / barH * rangeY + minY - }); - } - /** - * - * @returns {void} - */ + if (locX < 0) locX = 0;else if (locX > barW) locX = barW; + if (locY < 0) locY = 0;else if (locY > barH) locY = barH; + val.call(that, 'xy', { + x: locX / barW * rangeX + minX, + y: locY / barH * rangeY + minY + }); + } + /** + * + * @returns {void} + */ - function draw() { - var barW = bar.w, - barH = bar.h, - arrowW = arrow.w, - arrowH = arrow.h; - var arrowOffsetX = 0, - arrowOffsetY = 0; - setTimeout(function () { - if (rangeX > 0) { - // range is greater than zero - // constrain to bounds - if (x === maxX) arrowOffsetX = barW;else arrowOffsetX = x / rangeX * barW | 0; + function draw() { + const barW = bar.w, + barH = bar.h, + arrowW = arrow.w, + arrowH = arrow.h; + let arrowOffsetX = 0, + arrowOffsetY = 0; + setTimeout(function () { + if (rangeX > 0) { + // range is greater than zero + // constrain to bounds + if (x === maxX) arrowOffsetX = barW;else arrowOffsetX = x / rangeX * barW | 0; + } + + if (rangeY > 0) { + // range is greater than zero + // constrain to bounds + if (y === maxY) arrowOffsetY = barH;else arrowOffsetY = y / rangeY * barH | 0; + } // if arrow width is greater than bar width, center arrow and prevent horizontal dragging + + + if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) + else arrowOffsetX -= arrowW >> 1; // if arrow height is greater than bar height, center arrow and prevent vertical dragging + + if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1);else arrowOffsetY -= arrowH >> 1; // set the arrow position based on these offsets + + arrow.css({ + left: arrowOffsetX + 'px', + top: arrowOffsetY + 'px' + }); + }); + } + /** + * Get or set a value. + * @param {?("xy"|"x"|"y")} name + * @param {module:math.XYObject} value + * @param {module:jPicker.Slider} context + * @returns {module:math.XYObject|Float|void} + */ + + + function val(name, value, context) { + const set = value !== undefined; + + if (!set) { + if (isNullish$1(name)) name = 'xy'; + + switch (name.toLowerCase()) { + case 'x': + return x; + + case 'y': + return y; + + case 'xy': + default: + return { + x, + y + }; + } } - if (rangeY > 0) { - // range is greater than zero - // constrain to bounds - if (y === maxY) arrowOffsetY = barH;else arrowOffsetY = y / rangeY * barH | 0; - } // if arrow width is greater than bar width, center arrow and prevent horizontal dragging - - - if (arrowW >= barW) arrowOffsetX = (barW >> 1) - (arrowW >> 1); // number >> 1 - superfast bitwise divide by two and truncate (move bits over one bit discarding lowest) - else arrowOffsetX -= arrowW >> 1; // if arrow height is greater than bar height, center arrow and prevent vertical dragging - - if (arrowH >= barH) arrowOffsetY = (barH >> 1) - (arrowH >> 1);else arrowOffsetY -= arrowH >> 1; // set the arrow position based on these offsets - - arrow.css({ - left: arrowOffsetX + 'px', - top: arrowOffsetY + 'px' - }); - }); - } - /** - * Get or set a value. - * @param {?("xy"|"x"|"y")} name - * @param {module:math.XYObject} value - * @param {module:jPicker.Slider} context - * @returns {module:math.XYObject|Float|void} - */ - - - function val(name, value, context) { - var set = value !== undefined; - - if (!set) { + if (!isNullish$1(context) && context === that) return undefined; + let changed = false; + let newX, newY; if (isNullish$1(name)) name = 'xy'; switch (name.toLowerCase()) { case 'x': - return x; + newX = value && (value.x && value.x | 0 || value | 0) || 0; + break; case 'y': - return y; + newY = value && (value.y && value.y | 0 || value | 0) || 0; + break; case 'xy': default: - return { - x: x, - y: y - }; + newX = value && value.x && value.x | 0 || 0; + newY = value && value.y && value.y | 0 || 0; + break; } - } - if (!isNullish$1(context) && context === that) return undefined; - var changed = false; - var newX, newY; - if (isNullish$1(name)) name = 'xy'; + if (!isNullish$1(newX)) { + if (newX < minX) newX = minX;else if (newX > maxX) newX = maxX; - switch (name.toLowerCase()) { - case 'x': - newX = value && (value.x && value.x | 0 || value | 0) || 0; - break; - - case 'y': - newY = value && (value.y && value.y | 0 || value | 0) || 0; - break; - - case 'xy': - default: - newX = value && value.x && value.x | 0 || 0; - newY = value && value.y && value.y | 0 || 0; - break; - } - - if (!isNullish$1(newX)) { - if (newX < minX) newX = minX;else if (newX > maxX) newX = maxX; - - if (x !== newX) { - x = newX; - changed = true; + if (x !== newX) { + x = newX; + changed = true; + } } - } - if (!isNullish$1(newY)) { - if (newY < minY) newY = minY;else if (newY > maxY) newY = maxY; + if (!isNullish$1(newY)) { + if (newY < minY) newY = minY;else if (newY > maxY) newY = maxY; - if (y !== newY) { - y = newY; - changed = true; + if (y !== newY) { + y = newY; + changed = true; + } } + + changed && fireChangeEvents.call(that, context || that); + return undefined; } + /** + * @typedef {PlainObject} module:jPicker.MinMaxRangeX + * @property {Float} minX + * @property {Float} maxX + * @property {Float} rangeX + */ - changed && fireChangeEvents.call(that, context || that); - return undefined; - } - /** - * @typedef {PlainObject} module:jPicker.MinMaxRangeX - * @property {Float} minX - * @property {Float} maxX - * @property {Float} rangeX - */ + /** + * @typedef {PlainObject} module:jPicker.MinMaxRangeY + * @property {Float} minY + * @property {Float} maxY + * @property {Float} rangeY + */ - /** - * @typedef {PlainObject} module:jPicker.MinMaxRangeY - * @property {Float} minY - * @property {Float} maxY - * @property {Float} rangeY - */ + /** + * @typedef {module:jPicker.MinMaxRangeY|module:jPicker.MinMaxRangeX} module:jPicker.MinMaxRangeXY + */ - /** - * @typedef {module:jPicker.MinMaxRangeY|module:jPicker.MinMaxRangeX} module:jPicker.MinMaxRangeXY - */ - - /** - * - * @param {"minx"|"maxx"|"rangex"|"miny"|"maxy"|"rangey"|"all"} name - * @param {module:jPicker.MinMaxRangeXY} value - * @returns {module:jPicker.MinMaxRangeXY|module:jPicker.MinMaxRangeX|module:jPicker.MinMaxRangeY|void} - */ + /** + * + * @param {"minx"|"maxx"|"rangex"|"miny"|"maxy"|"rangey"|"all"} name + * @param {module:jPicker.MinMaxRangeXY} value + * @returns {module:jPicker.MinMaxRangeXY|module:jPicker.MinMaxRangeX|module:jPicker.MinMaxRangeY|void} + */ - function range(name, value) { - var set = value !== undefined; + function range(name, value) { + const set = value !== undefined; - if (!set) { + if (!set) { + if (isNullish$1(name)) name = 'all'; + + switch (name.toLowerCase()) { + case 'minx': + return minX; + + case 'maxx': + return maxX; + + case 'rangex': + return { + minX, + maxX, + rangeX + }; + + case 'miny': + return minY; + + case 'maxy': + return maxY; + + case 'rangey': + return { + minY, + maxY, + rangeY + }; + + case 'all': + default: + return { + minX, + maxX, + rangeX, + minY, + maxY, + rangeY + }; + } + } + + let // changed = false, + newMinX, newMaxX, newMinY, newMaxY; if (isNullish$1(name)) name = 'all'; switch (name.toLowerCase()) { case 'minx': - return minX; + newMinX = value && (value.minX && value.minX | 0 || value | 0) || 0; + break; case 'maxx': - return maxX; + newMaxX = value && (value.maxX && value.maxX | 0 || value | 0) || 0; + break; case 'rangex': - return { - minX: minX, - maxX: maxX, - rangeX: rangeX - }; + newMinX = value && value.minX && value.minX | 0 || 0; + newMaxX = value && value.maxX && value.maxX | 0 || 0; + break; case 'miny': - return minY; + newMinY = value && (value.minY && value.minY | 0 || value | 0) || 0; + break; case 'maxy': - return maxY; + newMaxY = value && (value.maxY && value.maxY | 0 || value | 0) || 0; + break; case 'rangey': - return { - minY: minY, - maxY: maxY, - rangeY: rangeY - }; + newMinY = value && value.minY && value.minY | 0 || 0; + newMaxY = value && value.maxY && value.maxY | 0 || 0; + break; case 'all': default: - return { - minX: minX, - maxX: maxX, - rangeX: rangeX, - minY: minY, - maxY: maxY, - rangeY: rangeY - }; + newMinX = value && value.minX && value.minX | 0 || 0; + newMaxX = value && value.maxX && value.maxX | 0 || 0; + newMinY = value && value.minY && value.minY | 0 || 0; + newMaxY = value && value.maxY && value.maxY | 0 || 0; + break; } + + if (!isNullish$1(newMinX) && minX !== newMinX) { + minX = newMinX; + rangeX = maxX - minX; + } + + if (!isNullish$1(newMaxX) && maxX !== newMaxX) { + maxX = newMaxX; + rangeX = maxX - minX; + } + + if (!isNullish$1(newMinY) && minY !== newMinY) { + minY = newMinY; + rangeY = maxY - minY; + } + + if (!isNullish$1(newMaxY) && maxY !== newMaxY) { + maxY = newMaxY; + rangeY = maxY - minY; + } + + return undefined; + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + + + function bind(callback) { + // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback === 'function') changeEvents.push(callback); + } + /** + * @param {GenericCallback} callback + * @returns {void} + */ + + + function unbind(callback) { + // eslint-disable-line promise/prefer-await-to-callbacks + if (typeof callback !== 'function') return; + let i; + + while (i = changeEvents.includes(callback)) changeEvents.splice(i, 1); + } + /** + * + * @returns {void} + */ + + + function destroy() { + // unbind all possible events and null objects + $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); + bar.unbind('mousedown', mouseDown); + bar = null; + arrow = null; + changeEvents = null; } - var // changed = false, - newMinX, newMaxX, newMinY, newMaxY; - if (isNullish$1(name)) name = 'all'; + let offset, + timeout, + x = 0, + y = 0, + minX = 0, + maxX = 100, + rangeX = 100, + minY = 0, + maxY = 100, + rangeY = 100, + arrow = bar.find('img:first'), + // the arrow image to drag + changeEvents = []; + $.extend(true, // public properties, methods, and event bindings - these we need + // to access from other controls + that, { + val, + range, + bind, + unbind, + destroy + }); // initialize this control - switch (name.toLowerCase()) { - case 'minx': - newMinX = value && (value.minX && value.minX | 0 || value | 0) || 0; - break; + arrow.src = options.arrow && options.arrow.image; + arrow.w = options.arrow && options.arrow.width || arrow.width(); + arrow.h = options.arrow && options.arrow.height || arrow.height(); + bar.w = options.map && options.map.width || bar.width(); + bar.h = options.map && options.map.height || bar.height(); // bind mousedown event - case 'maxx': - newMaxX = value && (value.maxX && value.maxX | 0 || value | 0) || 0; - break; - - case 'rangex': - newMinX = value && value.minX && value.minX | 0 || 0; - newMaxX = value && value.maxX && value.maxX | 0 || 0; - break; - - case 'miny': - newMinY = value && (value.minY && value.minY | 0 || value | 0) || 0; - break; - - case 'maxy': - newMaxY = value && (value.maxY && value.maxY | 0 || value | 0) || 0; - break; - - case 'rangey': - newMinY = value && value.minY && value.minY | 0 || 0; - newMaxY = value && value.maxY && value.maxY | 0 || 0; - break; - - case 'all': - default: - newMinX = value && value.minX && value.minX | 0 || 0; - newMaxX = value && value.maxX && value.maxX | 0 || 0; - newMinY = value && value.minY && value.minY | 0 || 0; - newMaxY = value && value.maxY && value.maxY | 0 || 0; - break; - } - - if (!isNullish$1(newMinX) && minX !== newMinX) { - minX = newMinX; - rangeX = maxX - minX; - } - - if (!isNullish$1(newMaxX) && maxX !== newMaxX) { - maxX = newMaxX; - rangeX = maxX - minX; - } - - if (!isNullish$1(newMinY) && minY !== newMinY) { - minY = newMinY; - rangeY = maxY - minY; - } - - if (!isNullish$1(newMaxY) && maxY !== newMaxY) { - maxY = newMaxY; - rangeY = maxY - minY; - } - - return undefined; - } - /** - * @param {GenericCallback} callback - * @returns {void} - */ - - - function bind(callback) { - // eslint-disable-line promise/prefer-await-to-callbacks - if (typeof callback === 'function') changeEvents.push(callback); - } - /** - * @param {GenericCallback} callback - * @returns {void} - */ - - - function unbind(callback) { - // eslint-disable-line promise/prefer-await-to-callbacks - if (typeof callback !== 'function') return; - var i; - - while (i = changeEvents.includes(callback)) { - changeEvents.splice(i, 1); - } - } - /** - * - * @returns {void} - */ - - - function destroy() { - // unbind all possible events and null objects - $(document).unbind('mouseup', mouseUp).unbind('mousemove', mouseMove); - bar.unbind('mousedown', mouseDown); - bar = null; - arrow = null; - changeEvents = null; + bar.bind('mousedown', mouseDown); + bind.call(that, draw); } - var offset, - timeout, - x = 0, - y = 0, - minX = 0, - maxX = 100, - rangeX = 100, - minY = 0, - maxY = 100, - rangeY = 100, - arrow = bar.find('img:first'), - // the arrow image to drag - changeEvents = []; - $.extend(true, // public properties, methods, and event bindings - these we need - // to access from other controls - that, { - val: val, - range: range, - bind: bind, - unbind: unbind, - destroy: destroy - }); // initialize this control - - arrow.src = options.arrow && options.arrow.image; - arrow.w = options.arrow && options.arrow.width || arrow.width(); - arrow.h = options.arrow && options.arrow.height || arrow.height(); - bar.w = options.map && options.map.width || bar.width(); - bar.h = options.map && options.map.height || bar.height(); // bind mousedown event - - bar.bind('mousedown', mouseDown); - bind.call(that, draw); - }; + } /** * Controls for all the input elements for the typing in color values. */ - var ColorValuePicker = - /** - * @param {external:jQuery} picker - * @param {external:jQuery.jPicker.Color} color - * @param {external:jQuery.fn.$.fn.jPicker} bindedHex - * @param {Float} alphaPrecision - */ - function ColorValuePicker(picker, color, bindedHex, alphaPrecision) { - _classCallCheck(this, ColorValuePicker); - - var that = this; // private properties and methods - - var inputs = picker.find('td.Text input'); // input box key down - use arrows to alter color - + class ColorValuePicker { /** - * - * @param {Event} e - * @returns {Event|false|void} + * @param {external:jQuery} picker + * @param {external:jQuery.jPicker.Color} color + * @param {external:jQuery.fn.$.fn.jPicker} bindedHex + * @param {Float} alphaPrecision */ + constructor(picker, color, bindedHex, alphaPrecision) { + const that = this; // private properties and methods - function keyDown(e) { - if (e.target.value === '' && e.target !== hex.get(0) && (!isNullish$1(bindedHex) && e.target !== bindedHex.get(0) || isNullish$1(bindedHex))) return undefined; - if (!validateKey(e)) return e; + const inputs = picker.find('td.Text input'); // input box key down - use arrows to alter color - switch (e.target) { - case red.get(0): - switch (e.keyCode) { - case 38: - red.val(setValueInRange.call(that, (red.val() << 0) + 1, 0, 255)); - color.val('r', red.val(), e.target); - return false; + /** + * + * @param {Event} e + * @returns {Event|false|void} + */ - case 40: - red.val(setValueInRange.call(that, (red.val() << 0) - 1, 0, 255)); - color.val('r', red.val(), e.target); - return false; - } + function keyDown(e) { + if (e.target.value === '' && e.target !== hex.get(0) && (!isNullish$1(bindedHex) && e.target !== bindedHex.get(0) || isNullish$1(bindedHex))) return undefined; + if (!validateKey(e)) return e; - break; - - case green.get(0): - switch (e.keyCode) { - case 38: - green.val(setValueInRange.call(that, (green.val() << 0) + 1, 0, 255)); - color.val('g', green.val(), e.target); - return false; - - case 40: - green.val(setValueInRange.call(that, (green.val() << 0) - 1, 0, 255)); - color.val('g', green.val(), e.target); - return false; - } - - break; - - case blue.get(0): - switch (e.keyCode) { - case 38: - blue.val(setValueInRange.call(that, (blue.val() << 0) + 1, 0, 255)); - color.val('b', blue.val(), e.target); - return false; - - case 40: - blue.val(setValueInRange.call(that, (blue.val() << 0) - 1, 0, 255)); - color.val('b', blue.val(), e.target); - return false; - } - - break; - - case alpha && alpha.get(0): - switch (e.keyCode) { - case 38: - alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) + 1, 0, 100)); - color.val('a', toFixedNumeric(alpha.val() * 255 / 100, alphaPrecision), e.target); - return false; - - case 40: - alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) - 1, 0, 100)); - color.val('a', toFixedNumeric(alpha.val() * 255 / 100, alphaPrecision), e.target); - return false; - } - - break; - - case hue.get(0): - switch (e.keyCode) { - case 38: - hue.val(setValueInRange.call(that, (hue.val() << 0) + 1, 0, 360)); - color.val('h', hue.val(), e.target); - return false; - - case 40: - hue.val(setValueInRange.call(that, (hue.val() << 0) - 1, 0, 360)); - color.val('h', hue.val(), e.target); - return false; - } - - break; - - case saturation.get(0): - switch (e.keyCode) { - case 38: - saturation.val(setValueInRange.call(that, (saturation.val() << 0) + 1, 0, 100)); - color.val('s', saturation.val(), e.target); - return false; - - case 40: - saturation.val(setValueInRange.call(that, (saturation.val() << 0) - 1, 0, 100)); - color.val('s', saturation.val(), e.target); - return false; - } - - break; - - case value.get(0): - switch (e.keyCode) { - case 38: - value.val(setValueInRange.call(that, (value.val() << 0) + 1, 0, 100)); - color.val('v', value.val(), e.target); - return false; - - case 40: - value.val(setValueInRange.call(that, (value.val() << 0) - 1, 0, 100)); - color.val('v', value.val(), e.target); - return false; - } - - break; - } - - return undefined; - } // input box key up - validate value and set color - - /** - * @param {Event} e - * @returns {Event|void} - * @todo Why is this returning an event? - */ - - - function keyUp(e) { - if (e.target.value === '' && e.target !== hex.get(0) && (!isNullish$1(bindedHex) && e.target !== bindedHex.get(0) || isNullish$1(bindedHex))) return undefined; - if (!validateKey(e)) return e; - - switch (e.target) { - case red.get(0): - red.val(setValueInRange.call(that, red.val(), 0, 255)); - color.val('r', red.val(), e.target); - break; - - case green.get(0): - green.val(setValueInRange.call(that, green.val(), 0, 255)); - color.val('g', green.val(), e.target); - break; - - case blue.get(0): - blue.val(setValueInRange.call(that, blue.val(), 0, 255)); - color.val('b', blue.val(), e.target); - break; - - case alpha && alpha.get(0): - alpha.val(setValueInRange.call(that, alpha.val(), 0, 100)); - color.val('a', toFixedNumeric(alpha.val() * 255 / 100, alphaPrecision), e.target); - break; - - case hue.get(0): - hue.val(setValueInRange.call(that, hue.val(), 0, 360)); - color.val('h', hue.val(), e.target); - break; - - case saturation.get(0): - saturation.val(setValueInRange.call(that, saturation.val(), 0, 100)); - color.val('s', saturation.val(), e.target); - break; - - case value.get(0): - value.val(setValueInRange.call(that, value.val(), 0, 100)); - color.val('v', value.val(), e.target); - break; - - case hex.get(0): - hex.val(hex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); - bindedHex && bindedHex.val(hex.val()); - color.val('hex', hex.val() !== '' ? hex.val() : null, e.target); - break; - - case bindedHex && bindedHex.get(0): - bindedHex.val(bindedHex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); - hex.val(bindedHex.val()); - color.val('hex', bindedHex.val() !== '' ? bindedHex.val() : null, e.target); - break; - - case ahex && ahex.get(0): - ahex.val(ahex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2)); - color.val('a', !isNullish$1(ahex.val()) ? Number.parseInt(ahex.val(), 16) : null, e.target); - break; - } - - return undefined; - } // input box blur - reset to original if value empty - - /** - * @param {Event} e - * @returns {void} - */ - - - function blur(e) { - if (!isNullish$1(color.val())) { switch (e.target) { case red.get(0): - red.val(color.val('r')); + switch (e.keyCode) { + case 38: + red.val(setValueInRange.call(that, (red.val() << 0) + 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + + case 40: + red.val(setValueInRange.call(that, (red.val() << 0) - 1, 0, 255)); + color.val('r', red.val(), e.target); + return false; + } + break; case green.get(0): - green.val(color.val('g')); + switch (e.keyCode) { + case 38: + green.val(setValueInRange.call(that, (green.val() << 0) + 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + + case 40: + green.val(setValueInRange.call(that, (green.val() << 0) - 1, 0, 255)); + color.val('g', green.val(), e.target); + return false; + } + break; case blue.get(0): - blue.val(color.val('b')); + switch (e.keyCode) { + case 38: + blue.val(setValueInRange.call(that, (blue.val() << 0) + 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + + case 40: + blue.val(setValueInRange.call(that, (blue.val() << 0) - 1, 0, 255)); + color.val('b', blue.val(), e.target); + return false; + } + break; case alpha && alpha.get(0): - alpha.val(toFixedNumeric(color.val('a') * 100 / 255, alphaPrecision)); + switch (e.keyCode) { + case 38: + alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) + 1, 0, 100)); + color.val('a', toFixedNumeric(alpha.val() * 255 / 100, alphaPrecision), e.target); + return false; + + case 40: + alpha.val(setValueInRange.call(that, Number.parseFloat(alpha.val()) - 1, 0, 100)); + color.val('a', toFixedNumeric(alpha.val() * 255 / 100, alphaPrecision), e.target); + return false; + } + break; case hue.get(0): - hue.val(color.val('h')); + switch (e.keyCode) { + case 38: + hue.val(setValueInRange.call(that, (hue.val() << 0) + 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + + case 40: + hue.val(setValueInRange.call(that, (hue.val() << 0) - 1, 0, 360)); + color.val('h', hue.val(), e.target); + return false; + } + break; case saturation.get(0): - saturation.val(color.val('s')); + switch (e.keyCode) { + case 38: + saturation.val(setValueInRange.call(that, (saturation.val() << 0) + 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + + case 40: + saturation.val(setValueInRange.call(that, (saturation.val() << 0) - 1, 0, 100)); + color.val('s', saturation.val(), e.target); + return false; + } + break; case value.get(0): - value.val(color.val('v')); + switch (e.keyCode) { + case 38: + value.val(setValueInRange.call(that, (value.val() << 0) + 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + + case 40: + value.val(setValueInRange.call(that, (value.val() << 0) - 1, 0, 100)); + color.val('v', value.val(), e.target); + return false; + } + + break; + } + + return undefined; + } // input box key up - validate value and set color + + /** + * @param {Event} e + * @returns {Event|void} + * @todo Why is this returning an event? + */ + + + function keyUp(e) { + if (e.target.value === '' && e.target !== hex.get(0) && (!isNullish$1(bindedHex) && e.target !== bindedHex.get(0) || isNullish$1(bindedHex))) return undefined; + if (!validateKey(e)) return e; + + switch (e.target) { + case red.get(0): + red.val(setValueInRange.call(that, red.val(), 0, 255)); + color.val('r', red.val(), e.target); + break; + + case green.get(0): + green.val(setValueInRange.call(that, green.val(), 0, 255)); + color.val('g', green.val(), e.target); + break; + + case blue.get(0): + blue.val(setValueInRange.call(that, blue.val(), 0, 255)); + color.val('b', blue.val(), e.target); + break; + + case alpha && alpha.get(0): + alpha.val(setValueInRange.call(that, alpha.val(), 0, 100)); + color.val('a', toFixedNumeric(alpha.val() * 255 / 100, alphaPrecision), e.target); + break; + + case hue.get(0): + hue.val(setValueInRange.call(that, hue.val(), 0, 360)); + color.val('h', hue.val(), e.target); + break; + + case saturation.get(0): + saturation.val(setValueInRange.call(that, saturation.val(), 0, 100)); + color.val('s', saturation.val(), e.target); + break; + + case value.get(0): + value.val(setValueInRange.call(that, value.val(), 0, 100)); + color.val('v', value.val(), e.target); break; case hex.get(0): + hex.val(hex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); + bindedHex && bindedHex.val(hex.val()); + color.val('hex', hex.val() !== '' ? hex.val() : null, e.target); + break; + case bindedHex && bindedHex.get(0): - hex.val(color.val('hex')); - bindedHex && bindedHex.val(color.val('hex')); + bindedHex.val(bindedHex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 6)); + hex.val(bindedHex.val()); + color.val('hex', bindedHex.val() !== '' ? bindedHex.val() : null, e.target); break; case ahex && ahex.get(0): - ahex.val(color.val('ahex').substring(6)); + ahex.val(ahex.val().replace(/[^a-fA-F\d]/g, '').toLowerCase().substring(0, 2)); + color.val('a', !isNullish$1(ahex.val()) ? Number.parseInt(ahex.val(), 16) : null, e.target); break; } + + return undefined; + } // input box blur - reset to original if value empty + + /** + * @param {Event} e + * @returns {void} + */ + + + function blur(e) { + if (!isNullish$1(color.val())) { + switch (e.target) { + case red.get(0): + red.val(color.val('r')); + break; + + case green.get(0): + green.val(color.val('g')); + break; + + case blue.get(0): + blue.val(color.val('b')); + break; + + case alpha && alpha.get(0): + alpha.val(toFixedNumeric(color.val('a') * 100 / 255, alphaPrecision)); + break; + + case hue.get(0): + hue.val(color.val('h')); + break; + + case saturation.get(0): + saturation.val(color.val('s')); + break; + + case value.get(0): + value.val(color.val('v')); + break; + + case hex.get(0): + case bindedHex && bindedHex.get(0): + hex.val(color.val('hex')); + bindedHex && bindedHex.val(color.val('hex')); + break; + + case ahex && ahex.get(0): + ahex.val(color.val('ahex').substring(6)); + break; + } + } } - } - /** - * @param {Event} e - * @returns {boolean} - */ + /** + * @param {Event} e + * @returns {boolean} + */ - function validateKey(e) { - switch (e.keyCode) { - case 9: - case 16: - case 29: - case 37: - case 39: - return false; + function validateKey(e) { + switch (e.keyCode) { + case 9: + case 16: + case 29: + case 37: + case 39: + return false; - case 'c'.charCodeAt(): - case 'v'.charCodeAt(): - if (e.ctrlKey) return false; + case 'c'.charCodeAt(): + case 'v'.charCodeAt(): + if (e.ctrlKey) return false; + } + + return true; + } + /** + * Constrain value within range. + * @param {Float|string} value + * @param {Float} min + * @param {Float} max + * @returns {Float|string} Returns a number or numeric string + */ + + + function setValueInRange(value, min, max) { + if (value === '' || isNaN(value)) return min; + if (value > max) return max; + if (value < min) return min; + return value; + } + /** + * @param {external:jQuery} ui + * @param {Element} context + * @returns {void} + */ + + + function colorChanged(ui, context) { + const all = ui.val('all'); + if (context !== red.get(0)) red.val(!isNullish$1(all) ? all.r : ''); + if (context !== green.get(0)) green.val(!isNullish$1(all) ? all.g : ''); + if (context !== blue.get(0)) blue.val(!isNullish$1(all) ? all.b : ''); + if (alpha && context !== alpha.get(0)) alpha.val(!isNullish$1(all) ? toFixedNumeric(all.a * 100 / 255, alphaPrecision) : ''); + if (context !== hue.get(0)) hue.val(!isNullish$1(all) ? all.h : ''); + if (context !== saturation.get(0)) saturation.val(!isNullish$1(all) ? all.s : ''); + if (context !== value.get(0)) value.val(!isNullish$1(all) ? all.v : ''); + if (context !== hex.get(0) && (bindedHex && context !== bindedHex.get(0) || !bindedHex)) hex.val(!isNullish$1(all) ? all.hex : ''); + if (bindedHex && context !== bindedHex.get(0) && context !== hex.get(0)) bindedHex.val(!isNullish$1(all) ? all.hex : ''); + if (ahex && context !== ahex.get(0)) ahex.val(!isNullish$1(all) ? all.ahex.substring(6) : ''); + } + /** + * Unbind all events and null objects. + * @returns {void} + */ + + + function destroy() { + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); + color.unbind(colorChanged); + red = null; + green = null; + blue = null; + alpha = null; + hue = null; + saturation = null; + value = null; + hex = null; + ahex = null; } - return true; - } - /** - * Constrain value within range. - * @param {Float|string} value - * @param {Float} min - * @param {Float} max - * @returns {Float|string} Returns a number or numeric string - */ - - - function setValueInRange(value, min, max) { - if (value === '' || isNaN(value)) return min; - if (value > max) return max; - if (value < min) return min; - return value; - } - /** - * @param {external:jQuery} ui - * @param {Element} context - * @returns {void} - */ - - - function colorChanged(ui, context) { - var all = ui.val('all'); - if (context !== red.get(0)) red.val(!isNullish$1(all) ? all.r : ''); - if (context !== green.get(0)) green.val(!isNullish$1(all) ? all.g : ''); - if (context !== blue.get(0)) blue.val(!isNullish$1(all) ? all.b : ''); - if (alpha && context !== alpha.get(0)) alpha.val(!isNullish$1(all) ? toFixedNumeric(all.a * 100 / 255, alphaPrecision) : ''); - if (context !== hue.get(0)) hue.val(!isNullish$1(all) ? all.h : ''); - if (context !== saturation.get(0)) saturation.val(!isNullish$1(all) ? all.s : ''); - if (context !== value.get(0)) value.val(!isNullish$1(all) ? all.v : ''); - if (context !== hex.get(0) && (bindedHex && context !== bindedHex.get(0) || !bindedHex)) hex.val(!isNullish$1(all) ? all.hex : ''); - if (bindedHex && context !== bindedHex.get(0) && context !== hex.get(0)) bindedHex.val(!isNullish$1(all) ? all.hex : ''); - if (ahex && context !== ahex.get(0)) ahex.val(!isNullish$1(all) ? all.ahex.substring(6) : ''); - } - /** - * Unbind all events and null objects. - * @returns {void} - */ - - - function destroy() { - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).unbind('keyup', keyUp).unbind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).unbind('keydown', keyDown); - color.unbind(colorChanged); - red = null; - green = null; - blue = null; - alpha = null; - hue = null; - saturation = null; - value = null; - hex = null; - ahex = null; + let red = inputs.eq(3), + green = inputs.eq(4), + blue = inputs.eq(5), + alpha = inputs.length > 7 ? inputs.eq(6) : null, + hue = inputs.eq(0), + saturation = inputs.eq(1), + value = inputs.eq(2), + hex = inputs.eq(inputs.length > 7 ? 7 : 6), + ahex = inputs.length > 7 ? inputs.eq(8) : null; + $.extend(true, that, { + // public properties and methods + destroy + }); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); + red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); + color.bind(colorChanged); } - var red = inputs.eq(3), - green = inputs.eq(4), - blue = inputs.eq(5), - alpha = inputs.length > 7 ? inputs.eq(6) : null, - hue = inputs.eq(0), - saturation = inputs.eq(1), - value = inputs.eq(2), - hex = inputs.eq(inputs.length > 7 ? 7 : 6), - ahex = inputs.length > 7 ? inputs.eq(8) : null; - $.extend(true, that, { - // public properties and methods - destroy: destroy - }); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).add(hex).add(bindedHex).add(ahex).bind('keyup', keyUp).bind('blur', blur); - red.add(green).add(blue).add(alpha).add(hue).add(saturation).add(value).bind('keydown', keyDown); - color.bind(colorChanged); - }; + } /** * @typedef {PlainObject} module:jPicker.JPickerInit * @property {Integer} [a] @@ -25632,9 +24713,9 @@ * @param {module:jPicker.JPickerInit} init * @returns {external:jQuery.jPicker.Color} */ - Color: function Color(init) { + Color: function (init) { // eslint-disable-line object-shorthand - var that = this; + const that = this; /** * * @param {module:jPicker.Slider} context @@ -25642,9 +24723,7 @@ */ function fireChangeEvents(context) { - for (var i = 0; i < changeEvents.length; i++) { - changeEvents[i].call(that, that, context); - } + for (let i = 0; i < changeEvents.length; i++) changeEvents[i].call(that, that, context); } /** * @param {string|"ahex"|"hex"|"all"|""|null|void} name String composed of letters "r", "g", "b", "a", "h", "s", and/or "v" @@ -25656,21 +24735,21 @@ function val(name, value, context) { // Kind of ugly - var set = Boolean(value); + const set = Boolean(value); if (set && value.ahex === '') value.ahex = '00000000'; if (!set) { - var ret; + let ret; if (isNullish$1(name) || name === '') name = 'all'; if (isNullish$1(r)) return null; switch (name.toLowerCase()) { case 'ahex': return ColorMethods.rgbaToHex({ - r: r, - g: g, - b: b, - a: a + r, + g, + b, + a }); case 'hex': @@ -25678,13 +24757,13 @@ case 'all': return { - r: r, - g: g, - b: b, - a: a, - h: h, - s: s, - v: v, + r, + g, + b, + a, + h, + s, + v, hex: val.call(that, 'hex'), ahex: val.call(that, 'ahex') }; @@ -25692,9 +24771,8 @@ default: { ret = {}; - var nameLength = name.length; - - _toConsumableArray(name).forEach(function (ch) { + const nameLength = name.length; + [...name].forEach(ch => { switch (ch) { case 'r': if (nameLength === 1) ret = r;else ret.r = r; @@ -25728,12 +24806,12 @@ } } - return _typeof(ret) === 'object' && !Object.keys(ret).length ? val.call(that, 'all') : ret; + return typeof ret === 'object' && !Object.keys(ret).length ? val.call(that, 'all') : ret; } if (!isNullish$1(context) && context === that) return undefined; if (isNullish$1(name)) name = ''; - var changed = false; + let changed = false; if (isNullish$1(value)) { if (!isNullish$1(r)) { @@ -25779,13 +24857,12 @@ case 'ahex': case 'hex': { - var _ret = ColorMethods.hexToRgba(value && (value.ahex || value.hex) || value || 'none'); - + const ret = ColorMethods.hexToRgba(value && (value.ahex || value.hex) || value || 'none'); val.call(that, 'rgba', { - r: _ret.r, - g: _ret.g, - b: _ret.b, - a: name === 'ahex' ? _ret.a : !isNullish$1(a) ? a : 255 + r: ret.r, + g: ret.g, + b: ret.b, + a: name === 'ahex' ? ret.a : !isNullish$1(a) ? a : 255 }, context); break; } @@ -25797,8 +24874,8 @@ return undefined; } - var newV = {}; - var rgb = false, + const newV = {}; + let rgb = false, hsv = false; if (value.r !== undefined && !name.includes('r')) name += 'r'; if (value.g !== undefined && !name.includes('g')) name += 'g'; @@ -25807,8 +24884,7 @@ if (value.h !== undefined && !name.includes('h')) name += 'h'; if (value.s !== undefined && !name.includes('s')) name += 's'; if (value.v !== undefined && !name.includes('v')) name += 'v'; - - _toConsumableArray(name).forEach(function (ch) { + [...name].forEach(ch => { switch (ch) { case 'r': if (hsv) return; @@ -25817,7 +24893,9 @@ if (newV.r < 0) newV.r = 0;else if (newV.r > 255) newV.r = 255; if (r !== newV.r) { - r = newV.r; + ({ + r + } = newV); changed = true; } @@ -25830,7 +24908,9 @@ if (newV.g < 0) newV.g = 0;else if (newV.g > 255) newV.g = 255; if (g !== newV.g) { - g = newV.g; + ({ + g + } = newV); changed = true; } @@ -25843,7 +24923,9 @@ if (newV.b < 0) newV.b = 0;else if (newV.b > 255) newV.b = 255; if (b !== newV.b) { - b = newV.b; + ({ + b + } = newV); changed = true; } @@ -25854,7 +24936,9 @@ if (newV.a < 0) newV.a = 0;else if (newV.a > 255) newV.a = 255; if (a !== newV.a) { - a = newV.a; + ({ + a + } = newV); changed = true; } @@ -25867,7 +24951,9 @@ if (newV.h < 0) newV.h = 0;else if (newV.h > 360) newV.h = 360; if (h !== newV.h) { - h = newV.h; + ({ + h + } = newV); changed = true; } @@ -25880,7 +24966,9 @@ if (newV.s < 0) newV.s = 0;else if (newV.s > 100) newV.s = 100; if (s !== newV.s) { - s = newV.s; + ({ + s + } = newV); changed = true; } @@ -25893,7 +24981,9 @@ if (newV.v < 0) newV.v = 0;else if (newV.v > 100) newV.v = 100; if (v !== newV.v) { - v = newV.v; + ({ + v + } = newV); changed = true; } @@ -25906,30 +24996,30 @@ r = r || 0; g = g || 0; b = b || 0; - - var _ret2 = ColorMethods.rgbToHsv({ - r: r, - g: g, - b: b + const ret = ColorMethods.rgbToHsv({ + r, + g, + b }); - - h = _ret2.h; - s = _ret2.s; - v = _ret2.v; + ({ + h, + s, + v + } = ret); } else if (hsv) { h = h || 0; s = !isNullish$1(s) ? s : 100; v = !isNullish$1(v) ? v : 100; - - var _ret3 = ColorMethods.hsvToRgb({ - h: h, - s: s, - v: v + const ret = ColorMethods.hsvToRgb({ + h, + s, + v }); - - r = _ret3.r; - g = _ret3.g; - b = _ret3.b; + ({ + r, + g, + b + } = ret); } a = !isNullish$1(a) ? a : 255; @@ -25961,7 +25051,7 @@ function unbind(callback) { // eslint-disable-line promise/prefer-await-to-callbacks if (typeof callback !== 'function') return; - var i; + let i; while (i = changeEvents.includes(callback)) { changeEvents.splice(i, 1); @@ -25977,7 +25067,7 @@ changeEvents = null; } - var r, + let r, g, b, a, @@ -25987,10 +25077,10 @@ changeEvents = []; $.extend(true, that, { // public properties and methods - val: val, - bind: bind, - unbind: unbind, - destroy: destroy + val, + bind, + unbind, + destroy }); if (init) { @@ -26032,7 +25122,7 @@ * @param {string} hex * @returns {module:jPicker.RGBA} */ - hexToRgba: function hexToRgba(hex) { + hexToRgba(hex) { if (hex === '' || hex === 'none') return { r: null, g: null, @@ -26040,7 +25130,7 @@ a: null }; hex = this.validateHex(hex); - var r = '00', + let r = '00', g = '00', b = '00', a = '255'; @@ -26077,7 +25167,7 @@ * @param {string} hex * @returns {string} */ - validateHex: function validateHex(hex) { + validateHex(hex) { // if (typeof hex === 'object') return ''; hex = hex.toLowerCase().replace(/[^a-f\d]/g, ''); if (hex.length > 8) hex = hex.substring(0, 8); @@ -26088,7 +25178,7 @@ * @param {module:jPicker.RGBA} rgba * @returns {string} */ - rgbaToHex: function rgbaToHex(rgba) { + rgbaToHex(rgba) { return this.intToHex(rgba.r) + this.intToHex(rgba.g) + this.intToHex(rgba.b) + this.intToHex(rgba.a); }, @@ -26096,8 +25186,8 @@ * @param {Integer} dec * @returns {string} */ - intToHex: function intToHex(dec) { - var result = (dec | 0).toString(16); + intToHex(dec) { + let result = (dec | 0).toString(16); if (result.length === 1) result = '0' + result; return result.toLowerCase(); }, @@ -26106,7 +25196,7 @@ * @param {string} hex * @returns {Integer} */ - hexToInt: function hexToInt(hex) { + hexToInt(hex) { return Number.parseInt(hex, 16); }, @@ -26121,16 +25211,16 @@ * @param {module:jPicker.RGB} rgb * @returns {module:jPicker.HSV} */ - rgbToHsv: function rgbToHsv(rgb) { - var r = rgb.r / 255, - g = rgb.g / 255, - b = rgb.b / 255, - hsv = { + rgbToHsv(rgb) { + const r = rgb.r / 255, + g = rgb.g / 255, + b = rgb.b / 255, + hsv = { h: 0, s: 0, v: 0 }; - var min = 0, + let min = 0, max = 0; if (r >= g && r >= b) { @@ -26146,7 +25236,7 @@ hsv.v = max; hsv.s = max ? (max - min) / max : 0; - var delta; + let delta; if (!hsv.s) hsv.h = 0;else { delta = max - min; if (r === max) hsv.h = (g - b) / delta;else if (g === max) hsv.h = 2 + (b - r) / delta;else hsv.h = 4 + (r - g) / delta; @@ -26162,16 +25252,18 @@ * @param {module:jPicker.HSV} hsv * @returns {module:jPicker.RGB} */ - hsvToRgb: function hsvToRgb(hsv) { - var rgb = { + hsvToRgb(hsv) { + const rgb = { r: 0, g: 0, b: 0, a: 100 }; - var h = hsv.h, - s = hsv.s, - v = hsv.v; + let { + h, + s, + v + } = hsv; if (s === 0) { if (v === 0) rgb.r = rgb.g = rgb.b = 0;else rgb.r = rgb.g = rgb.b = v * 255 / 100 | 0; @@ -26180,11 +25272,11 @@ h /= 60; s /= 100; v /= 100; - var i = h | 0, - f = h - i, - p = v * (1 - s), - q = v * (1 - s * f), - t = v * (1 - s * (1 - f)); + const i = h | 0, + f = h - i, + p = v * (1 - s), + q = v * (1 - s * f), + t = v * (1 - s * (1 - f)); switch (i) { case 0: @@ -26231,12 +25323,14 @@ return rgb; } + } }; - var _$$jPicker = $.jPicker, - Color = _$$jPicker.Color, - List = _$$jPicker.List, - ColorMethods = _$$jPicker.ColorMethods; // local copies for YUI compressor + const { + Color, + List, + ColorMethods + } = $.jPicker; // local copies for YUI compressor /* eslint-disable jsdoc/require-returns */ @@ -26284,8 +25378,8 @@ $.fn.jPicker = function (options, commitCallback, liveCallback, cancelCallback) { return this.each(function () { - var that = this, - settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor + const that = this, + settings = $.extend(true, {}, $.fn.jPicker.defaults, options); // local copies for YUI compressor if ($(that).get(0).nodeName.toLowerCase() === 'input') { // Add color picker icon if binding to an input element and bind the events to the input @@ -26322,7 +25416,7 @@ settings.window.liveUpdate = false; // Basic control binding for inline use - You will need to override the liveCallback or commitCallback function to retrieve results } - var isLessThanIE7 = Number.parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; // needed to run the AlphaImageLoader function for IE6 + const isLessThanIE7 = Number.parseFloat(navigator.appVersion.split('MSIE')[1]) < 7 && document.body.filters; // needed to run the AlphaImageLoader function for IE6 // set color mode and update visuals for the new color mode /** @@ -26333,9 +25427,13 @@ */ function setColorMode(colorMode) { - var active = color.active, - hex = active.val('hex'); - var rgbMap, rgbBar; + const { + active + } = color, + // local copies for YUI compressor + // {clientPath} = images, + hex = active.val('hex'); + let rgbMap, rgbBar; settings.color.mode = colorMode; switch (colorMode) { @@ -26595,9 +25693,11 @@ function mapValueChanged(ui, context) { - var active = color.active; + const { + active + } = color; if (context !== colorMap && isNullish$1(active.val())) return; - var xy = ui.val('all'); + const xy = ui.val('all'); switch (settings.color.mode) { case 'h': @@ -26653,7 +25753,9 @@ function colorBarValueChanged(ui, context) { - var active = color.active; + const { + active + } = color; if (context !== colorBar && isNullish$1(active.val())) return; switch (settings.color.mode) { @@ -26711,7 +25813,7 @@ switch (settings.color.mode) { case 'h': { - var sv = ui.val('sv'); + const sv = ui.val('sv'); colorMap.val('xy', { x: !isNullish$1(sv) ? sv.s : 100, y: 100 - (!isNullish$1(sv) ? sv.v : 100) @@ -26723,7 +25825,7 @@ case 'a': { - var hv = ui.val('hv'); + const hv = ui.val('hv'); colorMap.val('xy', { x: hv && hv.h || 0, y: 100 - (!isNullish$1(hv) ? hv.v : 100) @@ -26733,7 +25835,7 @@ case 'v': { - var hs = ui.val('hs'); + const hs = ui.val('hs'); colorMap.val('xy', { x: hs && hs.h || 0, y: 100 - (!isNullish$1(hs) ? hs.s : 100) @@ -26743,7 +25845,7 @@ case 'r': { - var bg = ui.val('bg'); + const bg = ui.val('bg'); colorMap.val('xy', { x: bg && bg.b || 0, y: 255 - (bg && bg.g || 0) @@ -26753,7 +25855,7 @@ case 'g': { - var br = ui.val('br'); + const br = ui.val('br'); colorMap.val('xy', { x: br && br.b || 0, y: 255 - (br && br.r || 0) @@ -26763,7 +25865,7 @@ case 'b': { - var rg = ui.val('rg'); + const rg = ui.val('rg'); colorMap.val('xy', { x: rg && rg.r || 0, y: 255 - (rg && rg.g || 0) @@ -26781,14 +25883,14 @@ case 's': { - var s = ui.val('s'); + const s = ui.val('s'); colorBar.val('y', 100 - (!isNullish$1(s) ? s : 100), context); break; } case 'v': { - var v = ui.val('v'); + const v = ui.val('v'); colorBar.val('y', 100 - (!isNullish$1(v) ? v : 100), context); break; } @@ -26807,7 +25909,7 @@ case 'a': { - var a = ui.val('a'); + const a = ui.val('a'); colorBar.val('y', 255 - (!isNullish$1(a) ? a : 255), context); break; } @@ -26822,7 +25924,7 @@ function updatePreview(ui) { try { - var all = ui.val('all'); + const all = ui.val('all'); activePreview.css({ backgroundColor: all && '#' + all.hex || 'transparent' }); @@ -26848,14 +25950,14 @@ case 's': case 'a': { - var s = ui.val('s'); + const s = ui.val('s'); setAlpha.call(that, colorMapL2, 100 - (!isNullish$1(s) ? s : 100)); break; } case 'v': { - var v = ui.val('v'); + const v = ui.val('v'); setAlpha.call(that, colorMapL1, !isNullish$1(v) ? v : 100); break; } @@ -26873,7 +25975,7 @@ break; } - var a = ui.val('a'); + const a = ui.val('a'); setAlpha.call(that, colorMapL3, toFixedNumeric((255 - (a || 0)) * 100 / 255, 4)); } /** @@ -26886,15 +25988,15 @@ switch (settings.color.mode) { case 'h': { - var a = ui.val('a'); + const a = ui.val('a'); setAlpha.call(that, colorBarL5, toFixedNumeric((255 - (a || 0)) * 100 / 255, 4)); break; } case 's': { - var hva = ui.val('hva'), - saturatedColor = new Color({ + const hva = ui.val('hva'), + saturatedColor = new Color({ h: hva && hva.h || 0, s: 100, v: !isNullish$1(hva) ? hva.v : 100 @@ -26907,8 +26009,8 @@ case 'v': { - var hsa = ui.val('hsa'), - valueColor = new Color({ + const hsa = ui.val('hsa'), + valueColor = new Color({ h: hsa && hsa.h || 0, s: !isNullish$1(hsa) ? hsa.s : 100, v: 100 @@ -26922,8 +26024,8 @@ case 'g': case 'b': { - var rgba = ui.val('rgba'); - var hValue = 0, + const rgba = ui.val('rgba'); + let hValue = 0, vValue = 0; if (settings.color.mode === 'r') { @@ -26937,7 +26039,7 @@ vValue = rgba && rgba.g || 0; } - var middle = vValue > hValue ? hValue : vValue; + const middle = vValue > hValue ? hValue : vValue; setAlpha.call(that, colorBarL2, hValue > vValue ? toFixedNumeric((hValue - vValue) / (255 - vValue) * 100, 4) : 0); setAlpha.call(that, colorBarL3, vValue > hValue ? toFixedNumeric((vValue - hValue) / (255 - hValue) * 100, 4) : 0); setAlpha.call(that, colorBarL4, toFixedNumeric(middle / 255 * 100, 4)); @@ -26947,11 +26049,10 @@ case 'a': { - var _a = ui.val('a'); - + const a = ui.val('a'); setBG.call(that, colorBarDiv, ui.val('hex') || '000000'); - setAlpha.call(that, colorBarL5, !isNullish$1(_a) ? 0 : 100); - setAlpha.call(that, colorBarL6, !isNullish$1(_a) ? 100 : 0); + setAlpha.call(that, colorBarL5, !isNullish$1(a) ? 0 : 100); + setAlpha.call(that, colorBarL6, !isNullish$1(a) ? 100 : 0); break; } } @@ -27012,7 +26113,7 @@ if (alpha > 0 && alpha < 100) { if (isLessThanIE7) { - var src = obj.attr('pngSrc'); + const src = obj.attr('pngSrc'); if (!isNullish$1(src) && (src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png'))) { obj.css({ @@ -27026,11 +26127,11 @@ }); } else if (alpha === 0 || alpha === 100) { if (isLessThanIE7) { - var _src = obj.attr('pngSrc'); + const src = obj.attr('pngSrc'); - if (!isNullish$1(_src) && (_src.includes('AlphaBar.png') || _src.includes('Bars.png') || _src.includes('Maps.png'))) { + if (!isNullish$1(src) && (src.includes('AlphaBar.png') || src.includes('Bars.png') || src.includes('Maps.png'))) { obj.css({ - filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + _src + '\', sizingMethod=\'scale\')' + filter: 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + src + '\', sizingMethod=\'scale\')' }); } else obj.css({ opacity: '' @@ -27116,7 +26217,7 @@ function currentColorChanged(ui) { - var hex = ui.val('hex'); + const hex = ui.val('hex'); currentPreview.css({ backgroundColor: hex && '#' + hex || 'transparent' }); @@ -27129,8 +26230,8 @@ function expandableColorChanged(ui) { - var hex = ui.val('hex'); - var va = ui.val('va'); + const hex = ui.val('hex'); + const va = ui.val('va'); iconColor.css({ backgroundColor: hex && '#' + hex || 'transparent' }); @@ -27222,7 +26323,7 @@ function attachIFrame() { if (!settings.window.expandable || $.support.boxModel) return; - var table = container.find('table:first'); + const table = container.find('table:first'); container.before('<iframe/>'); container.prev().css({ width: table.width(), @@ -27299,8 +26400,8 @@ function initialize() { - var win = settings.window, - popup = win.expandable ? $(that).next().find('.Container:first') : null; + const win = settings.window, + popup = win.expandable ? $(that).next().find('.Container:first') : null; container = win.expandable ? $('<div/>') : $(that); container.addClass('jPicker Container'); if (win.expandable) container.hide(); @@ -27312,9 +26413,49 @@ // this control really is tabular data, so I believe it is the right move - var all = color.active.val('all'); + const all = color.active.val('all'); if (win.alphaPrecision < 0) win.alphaPrecision = 0;else if (win.alphaPrecision > 2) win.alphaPrecision = 2; - var controlHtml = "<table class=\"jPicker\" cellpadding=\"0\" cellspacing=\"0\">\n <tbody>\n ".concat(win.expandable ? '<tr><td class="Move" colspan="5"> </td></tr>' : '', "\n <tr>\n <td rowspan=\"9\"><h2 class=\"Title\">").concat(win.title || localization.text.title, "</h2><div class=\"Map\"><span class=\"Map1\"> </span><span class=\"Map2\"> </span><span class=\"Map3\"> </span><img src=\"").concat(images.clientPath + images.colorMap.arrow.file, "\" class=\"Arrow\"/></div></td>\n <td rowspan=\"9\"><div class=\"Bar\"><span class=\"Map1\"> </span><span class=\"Map2\"> </span><span class=\"Map3\"> </span><span class=\"Map4\"> </span><span class=\"Map5\"> </span><span class=\"Map6\"> </span><img src=\"").concat(images.clientPath + images.colorBar.arrow.file, "\" class=\"Arrow\"/></div></td>\n <td colspan=\"2\" class=\"Preview\">").concat(localization.text.newColor, "<div><span class=\"Active\" title=\"").concat(localization.tooltips.colors.newColor, "\"> </span><span class=\"Current\" title=\"").concat(localization.tooltips.colors.currentColor, "\"> </span></div>").concat(localization.text.currentColor, "</td>\n <td rowspan=\"9\" class=\"Button\"><input type=\"button\" class=\"Ok\" value=\"").concat(localization.text.ok, "\" title=\"").concat(localization.tooltips.buttons.ok, "\"/><input type=\"button\" class=\"Cancel\" value=\"").concat(localization.text.cancel, "\" title=\"").concat(localization.tooltips.buttons.cancel, "\"/><hr/><div class=\"Grid\"> </div></td>\n </tr>\n <tr class=\"Hue\">\n <td class=\"Radio\"><label title=\"").concat(localization.tooltips.hue.radio, "\"><input type=\"radio\" value=\"h\"").concat(settings.color.mode === 'h' ? ' checked="checked"' : '', "/>H:</label></td>\n <td class=\"Text\"><input type=\"text\" maxlength=\"3\" value=\"").concat(!isNullish$1(all) ? all.h : '', "\" title=\"").concat(localization.tooltips.hue.textbox, "\"/> °</td>\n </tr>\n <tr class=\"Saturation\">\n <td class=\"Radio\"><label title=\"").concat(localization.tooltips.saturation.radio, "\"><input type=\"radio\" value=\"s\"").concat(settings.color.mode === 's' ? ' checked="checked"' : '', "/>S:</label></td>\n <td class=\"Text\"><input type=\"text\" maxlength=\"3\" value=\"").concat(!isNullish$1(all) ? all.s : '', "\" title=\"").concat(localization.tooltips.saturation.textbox, "\"/> %</td>\n </tr>\n <tr class=\"Value\">\n <td class=\"Radio\"><label title=\"").concat(localization.tooltips.value.radio, "\"><input type=\"radio\" value=\"v\"").concat(settings.color.mode === 'v' ? ' checked="checked"' : '', "/>V:</label><br/><br/></td>\n <td class=\"Text\"><input type=\"text\" maxlength=\"3\" value=\"").concat(!isNullish$1(all) ? all.v : '', "\" title=\"").concat(localization.tooltips.value.textbox, "\"/> %<br/><br/></td>\n </tr>\n <tr class=\"Red\">\n <td class=\"Radio\"><label title=\"").concat(localization.tooltips.red.radio, "\"><input type=\"radio\" value=\"r\"").concat(settings.color.mode === 'r' ? ' checked="checked"' : '', "/>R:</label></td>\n <td class=\"Text\"><input type=\"text\" maxlength=\"3\" value=\"").concat(!isNullish$1(all) ? all.r : '', "\" title=\"").concat(localization.tooltips.red.textbox, "\"/></td>\n </tr>\n <tr class=\"Green\">\n <td class=\"Radio\"><label title=\"").concat(localization.tooltips.green.radio, "\"><input type=\"radio\" value=\"g\"").concat(settings.color.mode === 'g' ? ' checked="checked"' : '', "/>G:</label></td>\n <td class=\"Text\"><input type=\"text\" maxlength=\"3\" value=\"").concat(!isNullish$1(all) ? all.g : '', "\" title=\"").concat(localization.tooltips.green.textbox, "\"/></td>\n </tr>\n <tr class=\"Blue\">\n <td class=\"Radio\"><label title=\"").concat(localization.tooltips.blue.radio, "\"><input type=\"radio\" value=\"b\"").concat(settings.color.mode === 'b' ? ' checked="checked"' : '', "/>B:</label></td>\n <td class=\"Text\"><input type=\"text\" maxlength=\"3\" value=\"").concat(!isNullish$1(all) ? all.b : '', "\" title=\"").concat(localization.tooltips.blue.textbox, "\"/></td>\n </tr>\n <tr class=\"Alpha\">\n <td class=\"Radio\">").concat(win.alphaSupport ? "<label title=\"".concat(localization.tooltips.alpha.radio, "\"><input type=\"radio\" value=\"a\"").concat(settings.color.mode === 'a' ? ' checked="checked"' : '', "/>A:</label>") : ' ', "</td>\n <td class=\"Text\">").concat(win.alphaSupport ? "<input type=\"text\" maxlength=\"".concat(3 + win.alphaPrecision, "\" value=\"").concat(!isNullish$1(all) ? toFixedNumeric(all.a * 100 / 255, win.alphaPrecision) : '', "\" title=\"").concat(localization.tooltips.alpha.textbox, "\"/> %") : ' ', "</td>\n </tr>\n <tr class=\"Hex\">\n <td colspan=\"2\" class=\"Text\"><label title=\"").concat(localization.tooltips.hex.textbox, "\">#:<input type=\"text\" maxlength=\"6\" class=\"Hex\" value=\"").concat(!isNullish$1(all) ? all.hex : '', "\"/></label>").concat(win.alphaSupport ? "<input type=\"text\" maxlength=\"2\" class=\"AHex\" value=\"".concat(!isNullish$1(all) ? all.ahex.substring(6) : '', "\" title=\"").concat(localization.tooltips.hex.alpha, "\"/></td>") : ' ', "\n </tr>\n </tbody></table>"); + const controlHtml = `<table class="jPicker" cellpadding="0" cellspacing="0"> + <tbody> + ${win.expandable ? '<tr><td class="Move" colspan="5"> </td></tr>' : ''} + <tr> + <td rowspan="9"><h2 class="Title">${win.title || localization.text.title}</h2><div class="Map"><span class="Map1"> </span><span class="Map2"> </span><span class="Map3"> </span><img src="${images.clientPath + images.colorMap.arrow.file}" class="Arrow"/></div></td> + <td rowspan="9"><div class="Bar"><span class="Map1"> </span><span class="Map2"> </span><span class="Map3"> </span><span class="Map4"> </span><span class="Map5"> </span><span class="Map6"> </span><img src="${images.clientPath + images.colorBar.arrow.file}" class="Arrow"/></div></td> + <td colspan="2" class="Preview">${localization.text.newColor}<div><span class="Active" title="${localization.tooltips.colors.newColor}"> </span><span class="Current" title="${localization.tooltips.colors.currentColor}"> </span></div>${localization.text.currentColor}</td> + <td rowspan="9" class="Button"><input type="button" class="Ok" value="${localization.text.ok}" title="${localization.tooltips.buttons.ok}"/><input type="button" class="Cancel" value="${localization.text.cancel}" title="${localization.tooltips.buttons.cancel}"/><hr/><div class="Grid"> </div></td> + </tr> + <tr class="Hue"> + <td class="Radio"><label title="${localization.tooltips.hue.radio}"><input type="radio" value="h"${settings.color.mode === 'h' ? ' checked="checked"' : ''}/>H:</label></td> + <td class="Text"><input type="text" maxlength="3" value="${!isNullish$1(all) ? all.h : ''}" title="${localization.tooltips.hue.textbox}"/> °</td> + </tr> + <tr class="Saturation"> + <td class="Radio"><label title="${localization.tooltips.saturation.radio}"><input type="radio" value="s"${settings.color.mode === 's' ? ' checked="checked"' : ''}/>S:</label></td> + <td class="Text"><input type="text" maxlength="3" value="${!isNullish$1(all) ? all.s : ''}" title="${localization.tooltips.saturation.textbox}"/> %</td> + </tr> + <tr class="Value"> + <td class="Radio"><label title="${localization.tooltips.value.radio}"><input type="radio" value="v"${settings.color.mode === 'v' ? ' checked="checked"' : ''}/>V:</label><br/><br/></td> + <td class="Text"><input type="text" maxlength="3" value="${!isNullish$1(all) ? all.v : ''}" title="${localization.tooltips.value.textbox}"/> %<br/><br/></td> + </tr> + <tr class="Red"> + <td class="Radio"><label title="${localization.tooltips.red.radio}"><input type="radio" value="r"${settings.color.mode === 'r' ? ' checked="checked"' : ''}/>R:</label></td> + <td class="Text"><input type="text" maxlength="3" value="${!isNullish$1(all) ? all.r : ''}" title="${localization.tooltips.red.textbox}"/></td> + </tr> + <tr class="Green"> + <td class="Radio"><label title="${localization.tooltips.green.radio}"><input type="radio" value="g"${settings.color.mode === 'g' ? ' checked="checked"' : ''}/>G:</label></td> + <td class="Text"><input type="text" maxlength="3" value="${!isNullish$1(all) ? all.g : ''}" title="${localization.tooltips.green.textbox}"/></td> + </tr> + <tr class="Blue"> + <td class="Radio"><label title="${localization.tooltips.blue.radio}"><input type="radio" value="b"${settings.color.mode === 'b' ? ' checked="checked"' : ''}/>B:</label></td> + <td class="Text"><input type="text" maxlength="3" value="${!isNullish$1(all) ? all.b : ''}" title="${localization.tooltips.blue.textbox}"/></td> + </tr> + <tr class="Alpha"> + <td class="Radio">${win.alphaSupport ? `<label title="${localization.tooltips.alpha.radio}"><input type="radio" value="a"${settings.color.mode === 'a' ? ' checked="checked"' : ''}/>A:</label>` : ' '}</td> + <td class="Text">${win.alphaSupport ? `<input type="text" maxlength="${3 + win.alphaPrecision}" value="${!isNullish$1(all) ? toFixedNumeric(all.a * 100 / 255, win.alphaPrecision) : ''}" title="${localization.tooltips.alpha.textbox}"/> %` : ' '}</td> + </tr> + <tr class="Hex"> + <td colspan="2" class="Text"><label title="${localization.tooltips.hex.textbox}">#:<input type="text" maxlength="6" class="Hex" value="${!isNullish$1(all) ? all.hex : ''}"/></label>${win.alphaSupport ? `<input type="text" maxlength="2" class="AHex" value="${!isNullish$1(all) ? all.ahex.substring(6) : ''}" title="${localization.tooltips.hex.alpha}"/></td>` : ' '} + </tr> + </tbody></table>`; if (win.expandable) { container.html(controlHtml); @@ -27345,11 +26486,11 @@ } // initialize the objects to the source code just injected - var tbody = container.find('tbody:first'); + const tbody = container.find('tbody:first'); colorMapDiv = tbody.find('div.Map:first'); colorBarDiv = tbody.find('div.Bar:first'); - var MapMaps = colorMapDiv.find('span'); - var BarMaps = colorBarDiv.find('span'); + const MapMaps = colorMapDiv.find('span'); + const BarMaps = colorBarDiv.find('span'); colorMapL1 = MapMaps.filter('.Map1:first'); colorMapL2 = MapMaps.filter('.Map2:first'); colorMapL3 = MapMaps.filter('.Map3:first'); @@ -27385,9 +26526,9 @@ }); colorBar.bind(colorBarValueChanged); colorPicker = new ColorValuePicker(tbody, color.active, win.expandable && win.bindToInput ? win.input : null, win.alphaPrecision); - var hex = !isNullish$1(all) ? all.hex : null, - preview = tbody.find('.Preview'), - button = tbody.find('.Button'); + const hex = !isNullish$1(all) ? all.hex : null, + preview = tbody.find('.Preview'), + button = tbody.find('.Button'); activePreview = preview.find('.Active:first').css({ backgroundColor: hex && '#' + hex || 'transparent' }); @@ -27413,24 +26554,22 @@ tbody.find('td.Radio input').bind('click', radioClicked); // initialize quick list if (color.quickList && color.quickList.length > 0) { - var html = ''; + let html = ''; - for (var i = 0; i < color.quickList.length; i++) { + for (let i = 0; i < color.quickList.length; i++) { /* if default colors are hex strings, change them to color objects */ - if (_typeof(color.quickList[i]).toString().toLowerCase() === 'string') { + if ((typeof color.quickList[i]).toString().toLowerCase() === 'string') { color.quickList[i] = new Color({ hex: color.quickList[i] }); } - var _alpha = color.quickList[i].val('a'); - - var _ahex = color.quickList[i].val('ahex'); - - if (!win.alphaSupport && _ahex) _ahex = _ahex.substring(0, 6) + 'ff'; - var quickHex = color.quickList[i].val('hex'); - if (!_ahex) _ahex = '00000000'; - html += '<span class="QuickColor"' + (' title="#' + _ahex + '"') + ' style="background-color:' + (quickHex && '#' + quickHex || '') + ';' + (quickHex ? '' : 'background-image:url(' + images.clientPath + 'NoColor.png)') + (win.alphaSupport && _alpha && _alpha < 255 ? ';opacity:' + toFixedNumeric(_alpha / 255, 4) + ';filter:Alpha(opacity=' + toFixedNumeric(_alpha / 2.55, 4) + ')' : '') + '"> </span>'; + const alpha = color.quickList[i].val('a'); + let ahex = color.quickList[i].val('ahex'); + if (!win.alphaSupport && ahex) ahex = ahex.substring(0, 6) + 'ff'; + const quickHex = color.quickList[i].val('hex'); + if (!ahex) ahex = '00000000'; + html += '<span class="QuickColor"' + (' title="#' + ahex + '"') + ' style="background-color:' + (quickHex && '#' + quickHex || '') + ';' + (quickHex ? '' : 'background-image:url(' + images.clientPath + 'NoColor.png)') + (win.alphaSupport && alpha && alpha < 255 ? ';opacity:' + toFixedNumeric(alpha / 255, 4) + ';filter:Alpha(opacity=' + toFixedNumeric(alpha / 2.55, 4) + ')' : '') + '"> </span>'; } setImg.call(that, grid, images.clientPath + 'bar-opacity.png'); @@ -27512,7 +26651,7 @@ liveCallback = null; container.html(''); - for (var i = 0; i < List.length; i++) { + for (let i = 0; i < List.length; i++) { if (List[i] === that) { List.splice(i, 1); i--; // Decrement to ensure we don't miss next item (lgtm warning) @@ -27520,16 +26659,18 @@ } } - var images = settings.images, - localization = settings.localization; // local copies for YUI compressor + const { + images, + localization + } = settings; // local copies for YUI compressor - var color = { - active: _typeof(settings.color.active).toString().toLowerCase() === 'string' ? new Color({ + const color = { + active: (typeof settings.color.active).toString().toLowerCase() === 'string' ? new Color({ ahex: !settings.window.alphaSupport && settings.color.active ? settings.color.active.substring(0, 6) + 'ff' : settings.color.active }) : new Color({ ahex: !settings.window.alphaSupport && settings.color.active.val('ahex') ? settings.color.active.val('ahex').substring(0, 6) + 'ff' : settings.color.active.val('ahex') }), - current: _typeof(settings.color.active).toString().toLowerCase() === 'string' ? new Color({ + current: (typeof settings.color.active).toString().toLowerCase() === 'string' ? new Color({ ahex: !settings.window.alphaSupport && settings.color.active ? settings.color.active.substring(0, 6) + 'ff' : settings.color.active }) : new Color({ ahex: !settings.window.alphaSupport && settings.color.active.val('ahex') ? settings.color.active.val('ahex').substring(0, 6) + 'ff' : settings.color.active.val('ahex') @@ -27549,7 +26690,7 @@ cancelCallback = null; } - var elementStartX = null, + let elementStartX = null, // Used to record the starting css positions for dragging the control elementStartY = null, pageStartX = null, @@ -27589,16 +26730,16 @@ $.extend(true, that, { // public properties, methods, and callbacks - commitCallback: commitCallback, + commitCallback, // commitCallback function can be overridden to return the selected color to a method you specify when the user clicks "OK" - liveCallback: liveCallback, + liveCallback, // liveCallback function can be overridden to return the selected color to a method you specify in live mode (continuous update) - cancelCallback: cancelCallback, + cancelCallback, // cancelCallback function can be overridden to a method you specify when the user clicks "Cancel" - color: color, - show: show, - hide: hide, - destroy: destroy // destroys this control entirely, removing all events and objects, and removing itself from the List + color, + show, + hide, + destroy // destroys this control entirely, removing all events and objects, and removing itself from the List }); List.push(that); @@ -28088,8 +27229,9 @@ return $; }; - var $$a = jQuery; - var langParam; + /* eslint-disable unicorn/no-fn-reference-in-iterator */ + const $$b = jQuery; + let langParam; /** * Looks for elements to localize using the supplied `obj` to indicate * on which selectors (or IDs if `ids` is set to `true`) to set its @@ -28111,14 +27253,10 @@ * @returns {void} */ - var setStrings = function setStrings(type, obj, ids) { + const setStrings = function (type, obj, ids) { // Root element to look for element from - var parent = $$a('#svg_editor').parent(); - Object.entries(obj).forEach(function (_ref) { - var _ref2 = _slicedToArray(_ref, 2), - sel = _ref2[0], - val = _ref2[1]; - + const parent = $$b('#svg_editor').parent(); + Object.entries(obj).forEach(([sel, val]) => { if (!val) { console.log(sel); // eslint-disable-line no-console @@ -28129,10 +27267,10 @@ sel = '#' + sel; } - var $elem = parent.find(sel); + const $elem = parent.find(sel); if ($elem.length) { - var elem = $elem[0]; + const elem = $elem[0]; switch (type) { case 'aria-label': @@ -28140,7 +27278,7 @@ break; case 'content': - _toConsumableArray(elem.childNodes).some(function (node) { + [...elem.childNodes].some(node => { if (node.nodeType === 3 /* Node.TEXT_NODE */ && node.textContent.trim()) { @@ -28150,7 +27288,6 @@ return false; }); - break; case 'title': @@ -28179,7 +27316,7 @@ * @returns {module:locale.AddLangExtensionLocaleData} */ - var editor_; + let editor_; /** * Sets the current editor instance (on which `addLangData`) exists. * @function init @@ -28188,7 +27325,7 @@ * @returns {void} */ - var init$7 = function init(editor) { + const init$7 = editor => { editor_ = editor; }; /** @@ -28204,245 +27341,218 @@ * @returns {Promise<module:locale.LangAndData>} Resolves to [`LangAndData`]{@link module:locale.LangAndData} */ - var readLang = /*#__PURE__*/function () { - var _ref3 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(langData) { - var more, _langData, tools, properties, config, layers, common, ui, opts, ariaLabels; + const readLang = async function (langData) { + const more = await editor_.addLangData(langParam); + $$b.each(more, function (i, m) { + if (m.data) { + langData = $$b.merge(langData, m.data); + } + }); // Old locale file, do nothing for now. - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - _context.next = 2; - return editor_.addLangData(langParam); + if (!langData.tools) { + return undefined; + } - case 2: - more = _context.sent; - $$a.each(more, function (i, m) { - if (m.data) { - langData = $$a.merge(langData, m.data); - } - }); // Old locale file, do nothing for now. + const { + tools, + // misc, + properties, + config, + layers, + common, + ui + } = langData; + setStrings('content', { + // Todo: Add this powered by (probably by default) but with config to remove + // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html + curve_segments: properties.curve_segments, + fitToContent: tools.fitToContent, + fit_to_all: tools.fit_to_all, + fit_to_canvas: tools.fit_to_canvas, + fit_to_layer_content: tools.fit_to_layer_content, + fit_to_sel: tools.fit_to_sel, + icon_large: config.icon_large, + icon_medium: config.icon_medium, + icon_small: config.icon_small, + icon_xlarge: config.icon_xlarge, + image_opt_embed: config.image_opt_embed, + image_opt_ref: config.image_opt_ref, + includedImages: config.included_images, + largest_object: tools.largest_object, + layersLabel: layers.layers, + page: tools.page, + relativeToLabel: tools.relativeTo, + selLayerLabel: layers.move_elems_to, + selectedPredefined: config.select_predefined, + selected_objects: tools.selected_objects, + smallest_object: tools.smallest_object, + straight_segments: properties.straight_segments, + svginfo_bg_url: config.editor_img_url + ':', + svginfo_bg_note: config.editor_bg_note, + svginfo_change_background: config.background, + svginfo_dim: config.doc_dims, + svginfo_editor_prefs: config.editor_prefs, + svginfo_height: common.height, + svginfo_icons: config.icon_size, + svginfo_image_props: config.image_props, + svginfo_lang: config.language, + svginfo_title: config.doc_title, + svginfo_width: common.width, + tool_docprops_cancel: common.cancel, + tool_docprops_save: common.ok, + tool_source_cancel: common.cancel, + tool_source_save: common.ok, + tool_prefs_cancel: common.cancel, + tool_prefs_save: common.ok, + sidepanel_handle: layers.layers.split('').join(' '), + tool_clear: tools.new_doc, + tool_docprops: tools.docprops, + tool_export: tools.export_img, + tool_import: tools.import_doc, + tool_open: tools.open_doc, + tool_save: tools.save_doc, + tool_editor_prefs: config.editor_prefs, + tool_editor_homepage: tools.editor_homepage, + svginfo_units_rulers: config.units_and_rulers, + svginfo_rulers_onoff: config.show_rulers, + svginfo_unit: config.base_unit, + svginfo_grid_settings: config.grid, + svginfo_snap_onoff: config.snapping_onoff, + svginfo_snap_step: config.snapping_stepsize, + svginfo_grid_color: config.grid_color + }, true); // Context menus - if (langData.tools) { - _context.next = 6; - break; - } - - return _context.abrupt("return", undefined); - - case 6: - _langData = langData, tools = _langData.tools, properties = _langData.properties, config = _langData.config, layers = _langData.layers, common = _langData.common, ui = _langData.ui; - setStrings('content', { - // Todo: Add this powered by (probably by default) but with config to remove - // copyrightLabel: misc.powered_by, // Currently commented out in svg-editor.html - curve_segments: properties.curve_segments, - fitToContent: tools.fitToContent, - fit_to_all: tools.fit_to_all, - fit_to_canvas: tools.fit_to_canvas, - fit_to_layer_content: tools.fit_to_layer_content, - fit_to_sel: tools.fit_to_sel, - icon_large: config.icon_large, - icon_medium: config.icon_medium, - icon_small: config.icon_small, - icon_xlarge: config.icon_xlarge, - image_opt_embed: config.image_opt_embed, - image_opt_ref: config.image_opt_ref, - includedImages: config.included_images, - largest_object: tools.largest_object, - layersLabel: layers.layers, - page: tools.page, - relativeToLabel: tools.relativeTo, - selLayerLabel: layers.move_elems_to, - selectedPredefined: config.select_predefined, - selected_objects: tools.selected_objects, - smallest_object: tools.smallest_object, - straight_segments: properties.straight_segments, - svginfo_bg_url: config.editor_img_url + ':', - svginfo_bg_note: config.editor_bg_note, - svginfo_change_background: config.background, - svginfo_dim: config.doc_dims, - svginfo_editor_prefs: config.editor_prefs, - svginfo_height: common.height, - svginfo_icons: config.icon_size, - svginfo_image_props: config.image_props, - svginfo_lang: config.language, - svginfo_title: config.doc_title, - svginfo_width: common.width, - tool_docprops_cancel: common.cancel, - tool_docprops_save: common.ok, - tool_source_cancel: common.cancel, - tool_source_save: common.ok, - tool_prefs_cancel: common.cancel, - tool_prefs_save: common.ok, - sidepanel_handle: layers.layers.split('').join(' '), - tool_clear: tools.new_doc, - tool_docprops: tools.docprops, - tool_export: tools.export_img, - tool_import: tools.import_doc, - tool_open: tools.open_doc, - tool_save: tools.save_doc, - tool_editor_prefs: config.editor_prefs, - tool_editor_homepage: tools.editor_homepage, - svginfo_units_rulers: config.units_and_rulers, - svginfo_rulers_onoff: config.show_rulers, - svginfo_unit: config.base_unit, - svginfo_grid_settings: config.grid, - svginfo_snap_onoff: config.snapping_onoff, - svginfo_snap_step: config.snapping_stepsize, - svginfo_grid_color: config.grid_color - }, true); // Context menus - - opts = {}; - ['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'].forEach(function (item) { - opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item]; - }); - ['dupe', 'merge_down', 'merge_all'].forEach(function (item) { - opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item]; - }); - opts['#cmenu_layers a[href="#delete"]'] = layers.del; - setStrings('content', opts); - ariaLabels = {}; - Object.entries({ - tool_blur: properties.blur, - tool_position: tools.align_to_page, - tool_font_family: properties.font_family, - zoom_panel: ui.zoom_level, - stroke_linejoin: properties.linejoin_miter, - stroke_linecap: properties.linecap_butt, - tool_opacity: properties.opacity - }).forEach(function (_ref4) { - var _ref5 = _slicedToArray(_ref4, 2), - id = _ref5[0], - value = _ref5[1]; - - ariaLabels['#' + id + ' button'] = value; - }); - Object.entries({ - group_opacity: properties.opacity, - zoom: ui.zoom_level - }).forEach(function (_ref6) { - var _ref7 = _slicedToArray(_ref6, 2), - id = _ref7[0], - value = _ref7[1]; - - ariaLabels['#' + id] = value; - }); - setStrings('aria-label', ariaLabels); - setStrings('title', { - align_relative_to: tools.align_relative_to, - circle_cx: properties.circle_cx, - circle_cy: properties.circle_cy, - circle_r: properties.circle_r, - cornerRadiusLabel: properties.corner_radius, - ellipse_cx: properties.ellipse_cx, - ellipse_cy: properties.ellipse_cy, - ellipse_rx: properties.ellipse_rx, - ellipse_ry: properties.ellipse_ry, - fill_color: properties.fill_color, - font_family: properties.font_family, - idLabel: properties.id, - image_height: properties.image_height, - image_url: properties.image_url, - image_width: properties.image_width, - layer_delete: layers.del, - layer_down: layers.move_down, - layer_new: layers["new"], - layer_rename: layers.rename, - layer_moreopts: common.more_opts, - layer_up: layers.move_up, - line_x1: properties.line_x1, - line_x2: properties.line_x2, - line_y1: properties.line_y1, - line_y2: properties.line_y2, - linecap_butt: properties.linecap_butt, - linecap_round: properties.linecap_round, - linecap_square: properties.linecap_square, - linejoin_bevel: properties.linejoin_bevel, - linejoin_miter: properties.linejoin_miter, - linejoin_round: properties.linejoin_round, - main_icon: tools.main_menu, - palette: ui.palette_info, - zoom_panel: ui.zoom_level, - path_node_x: properties.node_x, - path_node_y: properties.node_y, - rect_height_tool: properties.rect_height, - rect_width_tool: properties.rect_width, - seg_type: properties.seg_type, - selLayerNames: layers.move_selected, - selected_x: properties.pos_x, - selected_y: properties.pos_y, - stroke_color: properties.stroke_color, - stroke_style: properties.stroke_style, - stroke_width: properties.stroke_width, - svginfo_title: config.doc_title, - text: properties.text_contents, - toggle_stroke_tools: ui.toggle_stroke_tools, - tool_add_subpath: tools.add_subpath, - tool_alignbottom: tools.align_bottom, - tool_aligncenter: tools.align_center, - tool_alignleft: tools.align_left, - tool_alignmiddle: tools.align_middle, - tool_alignright: tools.align_right, - tool_aligntop: tools.align_top, - tool_angle: properties.angle, - tool_blur: properties.blur, - tool_bold: properties.bold, - tool_circle: tools.mode_circle, - tool_clone: tools.clone, - tool_clone_multi: tools.clone, - tool_delete: tools.del, - tool_delete_multi: tools.del, - tool_ellipse: tools.mode_ellipse, - tool_fhellipse: tools.mode_fhellipse, - tool_fhpath: tools.mode_fhpath, - tool_fhrect: tools.mode_fhrect, - tool_font_size: properties.font_size, - tool_group_elements: tools.group_elements, - tool_make_link: tools.make_link, - tool_link_url: tools.set_link_url, - tool_image: tools.mode_image, - tool_italic: properties.italic, - tool_line: tools.mode_line, - tool_move_bottom: tools.move_bottom, - tool_move_top: tools.move_top, - tool_node_clone: tools.node_clone, - tool_node_delete: tools.node_delete, - tool_node_link: tools.node_link, - tool_opacity: properties.opacity, - tool_openclose_path: tools.openclose_path, - tool_path: tools.mode_path, - tool_position: tools.align_to_page, - tool_rect: tools.mode_rect, - tool_redo: tools.redo, - tool_reorient: tools.reorient_path, - tool_select: tools.mode_select, - tool_source: tools.source_save, - tool_square: tools.mode_square, - tool_text: tools.mode_text, - tool_topath: tools.to_path, - tool_undo: tools.undo, - tool_ungroup: tools.ungroup, - tool_wireframe: tools.wireframe_mode, - tool_zoom: tools.mode_zoom, - url_notice: tools.no_embed - }, true); - return _context.abrupt("return", { - langParam: langParam, - langData: langData - }); - - case 19: - case "end": - return _context.stop(); - } - } - }, _callee); - })); - - return function readLang(_x) { - return _ref3.apply(this, arguments); + const opts = {}; + ['cut', 'copy', 'paste', 'paste_in_place', 'delete', 'group', 'ungroup', 'move_front', 'move_up', 'move_down', 'move_back'].forEach(item => { + opts['#cmenu_canvas a[href="#' + item + '"]'] = tools[item]; + }); + ['dupe', 'merge_down', 'merge_all'].forEach(item => { + opts['#cmenu_layers a[href="#' + item + '"]'] = layers[item]; + }); + opts['#cmenu_layers a[href="#delete"]'] = layers.del; + setStrings('content', opts); + const ariaLabels = {}; + Object.entries({ + tool_blur: properties.blur, + tool_position: tools.align_to_page, + tool_font_family: properties.font_family, + zoom_panel: ui.zoom_level, + stroke_linejoin: properties.linejoin_miter, + stroke_linecap: properties.linecap_butt, + tool_opacity: properties.opacity + }).forEach(([id, value]) => { + ariaLabels['#' + id + ' button'] = value; + }); + Object.entries({ + group_opacity: properties.opacity, + zoom: ui.zoom_level + }).forEach(([id, value]) => { + ariaLabels['#' + id] = value; + }); + setStrings('aria-label', ariaLabels); + setStrings('title', { + align_relative_to: tools.align_relative_to, + circle_cx: properties.circle_cx, + circle_cy: properties.circle_cy, + circle_r: properties.circle_r, + cornerRadiusLabel: properties.corner_radius, + ellipse_cx: properties.ellipse_cx, + ellipse_cy: properties.ellipse_cy, + ellipse_rx: properties.ellipse_rx, + ellipse_ry: properties.ellipse_ry, + fill_color: properties.fill_color, + font_family: properties.font_family, + idLabel: properties.id, + image_height: properties.image_height, + image_url: properties.image_url, + image_width: properties.image_width, + layer_delete: layers.del, + layer_down: layers.move_down, + layer_new: layers.new, + layer_rename: layers.rename, + layer_moreopts: common.more_opts, + layer_up: layers.move_up, + line_x1: properties.line_x1, + line_x2: properties.line_x2, + line_y1: properties.line_y1, + line_y2: properties.line_y2, + linecap_butt: properties.linecap_butt, + linecap_round: properties.linecap_round, + linecap_square: properties.linecap_square, + linejoin_bevel: properties.linejoin_bevel, + linejoin_miter: properties.linejoin_miter, + linejoin_round: properties.linejoin_round, + main_icon: tools.main_menu, + palette: ui.palette_info, + zoom_panel: ui.zoom_level, + path_node_x: properties.node_x, + path_node_y: properties.node_y, + rect_height_tool: properties.rect_height, + rect_width_tool: properties.rect_width, + seg_type: properties.seg_type, + selLayerNames: layers.move_selected, + selected_x: properties.pos_x, + selected_y: properties.pos_y, + stroke_color: properties.stroke_color, + stroke_style: properties.stroke_style, + stroke_width: properties.stroke_width, + svginfo_title: config.doc_title, + text: properties.text_contents, + toggle_stroke_tools: ui.toggle_stroke_tools, + tool_add_subpath: tools.add_subpath, + tool_alignbottom: tools.align_bottom, + tool_aligncenter: tools.align_center, + tool_alignleft: tools.align_left, + tool_alignmiddle: tools.align_middle, + tool_alignright: tools.align_right, + tool_aligntop: tools.align_top, + tool_angle: properties.angle, + tool_blur: properties.blur, + tool_bold: properties.bold, + tool_circle: tools.mode_circle, + tool_clone: tools.clone, + tool_clone_multi: tools.clone, + tool_delete: tools.del, + tool_delete_multi: tools.del, + tool_ellipse: tools.mode_ellipse, + tool_fhellipse: tools.mode_fhellipse, + tool_fhpath: tools.mode_fhpath, + tool_fhrect: tools.mode_fhrect, + tool_font_size: properties.font_size, + tool_group_elements: tools.group_elements, + tool_make_link: tools.make_link, + tool_link_url: tools.set_link_url, + tool_image: tools.mode_image, + tool_italic: properties.italic, + tool_line: tools.mode_line, + tool_move_bottom: tools.move_bottom, + tool_move_top: tools.move_top, + tool_node_clone: tools.node_clone, + tool_node_delete: tools.node_delete, + tool_node_link: tools.node_link, + tool_opacity: properties.opacity, + tool_openclose_path: tools.openclose_path, + tool_path: tools.mode_path, + tool_position: tools.align_to_page, + tool_rect: tools.mode_rect, + tool_redo: tools.redo, + tool_reorient: tools.reorient_path, + tool_select: tools.mode_select, + tool_source: tools.source_save, + tool_square: tools.mode_square, + tool_text: tools.mode_text, + tool_topath: tools.to_path, + tool_undo: tools.undo, + tool_ungroup: tools.ungroup, + tool_wireframe: tools.wireframe_mode, + tool_zoom: tools.mode_zoom, + url_notice: tools.no_embed + }, true); + return { + langParam, + langData }; - }(); + }; /** * * @function module:locale.putLocale @@ -28455,63 +27565,41 @@ * @returns {Promise<module:locale.LangAndData>} Resolves to result of {@link module:locale.readLang} */ - var putLocale = /*#__PURE__*/function () { - var _ref8 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(givenParam, goodLangs, conf) { - var url; - return regeneratorRuntime.wrap(function _callee2$(_context2) { - while (1) { - switch (_context2.prev = _context2.next) { - case 0: - if (givenParam) { - langParam = givenParam; - } else if (navigator.userLanguage) { - // Explorer - langParam = navigator.userLanguage; - } else if (navigator.language) { - // FF, Opera, ... - langParam = navigator.language; - } + const putLocale = async function (givenParam, goodLangs, conf) { + if (givenParam) { + langParam = givenParam; + } else if (navigator.userLanguage) { + // Explorer + langParam = navigator.userLanguage; + } else if (navigator.language) { + // FF, Opera, ... + langParam = navigator.language; + } - console.log('Lang: ' + langParam); // eslint-disable-line no-console - // Set to English if language is not in list of good langs + console.log('Lang: ' + langParam); // eslint-disable-line no-console + // Set to English if language is not in list of good langs - if (!goodLangs.includes(langParam) && langParam !== 'test') { - langParam = 'en'; - } + if (!goodLangs.includes(langParam) && langParam !== 'test') { + langParam = 'en'; + } - url = conf.langPath + 'lang.' + langParam + '.js'; - _context2.t0 = readLang; - _context2.next = 7; - return importSetGlobalDefault(url, { - global: 'svgEditorLang_' + langParam.replace(/-/g, '_') - }); - - case 7: - _context2.t1 = _context2.sent; - return _context2.abrupt("return", (0, _context2.t0)(_context2.t1)); - - case 9: - case "end": - return _context2.stop(); - } - } - }, _callee2); + const url = conf.langPath + 'lang.' + langParam + '.js'; + return readLang( // Todo: Replace this with `return import(url);` when + // `import()` widely supported + await importSetGlobalDefault(url, { + global: 'svgEditorLang_' + langParam.replace(/-/g, '_') })); + }; - return function putLocale(_x2, _x3, _x4) { - return _ref8.apply(this, arguments); - }; - }(); - - function _slicedToArray$1(arr, i) { - return _arrayWithHoles$1(arr) || _iterableToArrayLimit$1(arr, i) || _nonIterableRest$1(); + function _slicedToArray(arr, i) { + return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } - function _arrayWithHoles$1(arr) { + function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } - function _iterableToArrayLimit$1(arr, i) { + function _iterableToArrayLimit(arr, i) { if (!(Symbol.iterator in Object(arr) || Object.prototype.toString.call(arr) === "[object Arguments]")) { return; } @@ -28541,7 +27629,7 @@ return _arr; } - function _nonIterableRest$1() { + function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } @@ -28563,7 +27651,7 @@ if (Array.isArray(stylesheetURL)) { var _stylesheetURL = stylesheetURL; - var _stylesheetURL2 = _slicedToArray$1(_stylesheetURL, 2); + var _stylesheetURL2 = _slicedToArray(_stylesheetURL, 2); stylesheetURL = _stylesheetURL2[0]; var _stylesheetURL2$ = _stylesheetURL2[1]; @@ -28664,29 +27752,31 @@ })); } - var editor = {}; - var $$b = [jQueryPluginJSHotkeys, jQueryPluginSVGIcons, jQueryPluginJGraduate, jQueryPluginSpinButton, jQueryPluginSVG, jQueryContextMenu, jPicker].reduce(function (jq, func) { - return func(jq); - }, jQuery); + /* globals jQuery */ + const { + $q: $q$1 + } = Utils; + const editor = {}; + const $$c = [jQueryPluginJSHotkeys, jQueryPluginSVGIcons, jQueryPluginJGraduate, jQueryPluginSpinButton, jQueryPluginSVG, jQueryContextMenu, jPicker].reduce((jq, func) => func(jq), jQuery); /* if (!$.loadingStylesheets) { $.loadingStylesheets = []; } */ - var homePage = 'https://github.com/SVG-Edit/svgedit'; - var stylesheet = 'svg-editor.css'; + const homePage = 'https://github.com/SVG-Edit/svgedit'; + const stylesheet = 'svg-editor.css'; - if (!$$b.loadingStylesheets.includes(stylesheet)) { - $$b.loadingStylesheets.push(stylesheet); + if (!$$c.loadingStylesheets.includes(stylesheet)) { + $$c.loadingStylesheets.push(stylesheet); } - var favicon = 'images/logo.png'; + const favicon = 'images/logo.png'; - if ($$b.loadingStylesheets.some(function (item) { + if ($$c.loadingStylesheets.some(item => { return !Array.isArray(item) || item[0] !== favicon; })) { - $$b.loadingStylesheets.push([favicon, { + $$c.loadingStylesheets.push([favicon, { favicon: true }]); } // EDITOR PROPERTIES: (defined below) @@ -28722,7 +27812,7 @@ */ editor.storagePromptState = 'ignore'; - var callbacks = [], + const callbacks = [], /** * @typedef {"s"|"m"|"l"|"xl"|Float} module:SVGEditor.IconSize @@ -28932,7 +28022,7 @@ * @type {PlainObject} */ uiStrings$1 = editor.uiStrings = {}; - var svgCanvas, + let svgCanvas, urldata = {}, isReady = false, customExportImage = false, @@ -28974,8 +28064,21 @@ * loading fails and `noAlert` is truthy. */ - function loadSvgString(_x) { - return _loadSvgString.apply(this, arguments); + async function loadSvgString(str, { + noAlert + } = {}) { + const success = svgCanvas.setSvgString(str) !== false; + + if (success) { + return; + } + + if (!noAlert) { + await $$c.alert(uiStrings$1.notification.errorLoadingSVG); + return; + } + + throw new Error('Error loading SVG'); } /** * @function module:SVGEditor~getImportLocale @@ -28986,56 +28089,10 @@ */ - function _loadSvgString() { - _loadSvgString = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee23(str) { - var _ref42, - noAlert, - success, - _args23 = arguments; - - return regeneratorRuntime.wrap(function _callee23$(_context23) { - while (1) { - switch (_context23.prev = _context23.next) { - case 0: - _ref42 = _args23.length > 1 && _args23[1] !== undefined ? _args23[1] : {}, noAlert = _ref42.noAlert; - success = svgCanvas.setSvgString(str) !== false; - - if (!success) { - _context23.next = 4; - break; - } - - return _context23.abrupt("return"); - - case 4: - if (noAlert) { - _context23.next = 8; - break; - } - - _context23.next = 7; - return $$b.alert(uiStrings$1.notification.errorLoadingSVG); - - case 7: - return _context23.abrupt("return"); - - case 8: - throw new Error('Error loading SVG'); - - case 9: - case "end": - return _context23.stop(); - } - } - }, _callee23); - })); - return _loadSvgString.apply(this, arguments); - } - - function getImportLocale(_ref) { - var defaultLang = _ref.defaultLang, - defaultName = _ref.defaultName; - + function getImportLocale({ + defaultLang, + defaultName + }) { /** * @function module:SVGEditor~ImportLocale * @param {PlainObject} localeInfo @@ -29043,54 +28100,28 @@ * @param {string} [localeInfo.lang=defaultLang] Defaults to `defaultLang` of {@link module:SVGEditor~getImportLocale} * @returns {Promise<module:locale.LocaleStrings>} Resolves to {@link module:locale.LocaleStrings} */ - return /*#__PURE__*/function () { - var _importLocaleDefaulting = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() { - var _ref2, - _ref2$name, - name, - _ref2$lang, - lang, - importLocale, - _args = arguments; - - return regeneratorRuntime.wrap(function _callee$(_context) { - while (1) { - switch (_context.prev = _context.next) { - case 0: - importLocale = function _importLocale(language) { - var url = "".concat(curConfig.extPath, "ext-locale/").concat(name, "/").concat(language, ".js"); - return importSetGlobalDefault(url, { - global: "svgEditorExtensionLocale_".concat(name, "_").concat(language.replace(/-/g, '_')) - }); - }; - - _ref2 = _args.length > 0 && _args[0] !== undefined ? _args[0] : {}, _ref2$name = _ref2.name, name = _ref2$name === void 0 ? defaultName : _ref2$name, _ref2$lang = _ref2.lang, lang = _ref2$lang === void 0 ? defaultLang : _ref2$lang; - _context.prev = 2; - _context.next = 5; - return importLocale(lang); - - case 5: - return _context.abrupt("return", _context.sent); - - case 8: - _context.prev = 8; - _context.t0 = _context["catch"](2); - return _context.abrupt("return", importLocale('en')); - - case 11: - case "end": - return _context.stop(); - } - } - }, _callee, null, [[2, 8]]); - })); - - function importLocaleDefaulting() { - return _importLocaleDefaulting.apply(this, arguments); + return async function importLocaleDefaulting({ + name = defaultName, + lang = defaultLang + } = {}) { + /** + * + * @param {string} language + * @returns {Promise<module:locale.LocaleStrings>} Resolves to {@link module:locale.LocaleStrings} + */ + function importLocale(language) { + const url = `${curConfig.extPath}ext-locale/${name}/${language}.js`; + return importSetGlobalDefault(url, { + global: `svgEditorExtensionLocale_${name}_${language.replace(/-/g, '_')}` + }); } - return importLocaleDefaulting; - }(); + try { + return await importLocale(lang); + } catch (err) { + return importLocale('en'); + } + }; } /** * EXPORTS. @@ -29163,9 +28194,8 @@ if (editor.storage && ( // Cookies do not have enough available memory to hold large documents curConfig.forceStorage || !curConfig.noStorageOnLoad && document.cookie.match(/(?:^|;\s*)svgeditstore=prefsAndContent/))) { - var _name = 'svgedit-' + curConfig.canvasName; - - var cached = editor.storage.getItem(_name); + const name = 'svgedit-' + curConfig.canvasName; + const cached = editor.storage.getItem(name); if (cached) { editor.loadFromString(cached); @@ -29173,11 +28203,11 @@ } // LOAD PREFS - Object.keys(defaultPrefs).forEach(function (key) { - var storeKey = 'svg-edit-' + key; + Object.keys(defaultPrefs).forEach(key => { + const storeKey = 'svg-edit-' + key; if (editor.storage) { - var val = editor.storage.getItem(storeKey); + const val = editor.storage.getItem(storeKey); if (val) { defaultPrefs[key] = String(val); // Convert to string for FF (.value fails in Webkit) @@ -29185,7 +28215,7 @@ } else if (window.widget) { defaultPrefs[key] = window.widget.preferenceForKey(storeKey); } else { - var result = document.cookie.match(new RegExp('(?:^|;\\s*)' + regexEscape(encodeURIComponent(storeKey)) + '=([^;]+)')); + const result = document.cookie.match(new RegExp('(?:^|;\\s*)' + regexEscape(encodeURIComponent(storeKey)) + '=([^;]+)')); defaultPrefs[key] = result ? decodeURIComponent(result[1]) : ''; } }); @@ -29224,18 +28254,14 @@ */ function extendOrAdd(cfgObj, key, val) { - if (cfgObj[key] && _typeof(cfgObj[key]) === 'object') { - $$b.extend(true, cfgObj[key], val); + if (cfgObj[key] && typeof cfgObj[key] === 'object') { + $$c.extend(true, cfgObj[key], val); } else { cfgObj[key] = val; } } - Object.entries(opts).forEach(function (_ref3) { - var _ref4 = _slicedToArray(_ref3, 2), - key = _ref4[0], - val = _ref4[1]; - + Object.entries(opts).forEach(function ([key, val]) { // Only allow prefs defined in defaultPrefs or... if ({}.hasOwnProperty.call(defaultPrefs, key)) { if (cfgCfg.overwrite === false && (curConfig.preventAllURLConfig || {}.hasOwnProperty.call(curPrefs, key))) { @@ -29268,9 +28294,9 @@ extendOrAdd(curConfig, key, val); } else if (cfgCfg.allowInitialUserOverride === true) { extendOrAdd(defaultConfig, key, val); - } else if (defaultConfig[key] && _typeof(defaultConfig[key]) === 'object') { + } else if (defaultConfig[key] && typeof defaultConfig[key] === 'object') { curConfig[key] = Array.isArray(defaultConfig[key]) ? [] : {}; - $$b.extend(true, curConfig[key], val); // Merge properties recursively, e.g., on initFill, initStroke objects + $$c.extend(true, curConfig[key], val); // Merge properties recursively, e.g., on initFill, initStroke objects } else { curConfig[key] = val; } @@ -29346,8 +28372,8 @@ editor.setCustomHandlers = function (opts) { return editor.ready(function () { if (opts.open) { - $$b('#tool_open > input[type="file"]').remove(); - $$b('#tool_open').show(); + $$c('#tool_open > input[type="file"]').remove(); + $$c('#tool_open').show(); svgCanvas.open = opts.open; } @@ -29385,7 +28411,7 @@ editor.init = function () { - var modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; + const modularVersion = !('svgEditor' in window) || !window.svgEditor || window.svgEditor.modules !== false; if (!modularVersion) { Object.assign(defaultConfig, { @@ -29418,8 +28444,8 @@ } catch (err) {} // Todo: Avoid const-defined functions and group functions together, etc. where possible - var goodLangs = []; - $$b('#lang_select option').each(function () { + const goodLangs = []; + $$c('#lang_select option').each(function () { goodLangs.push(this.value); }); /** @@ -29428,7 +28454,7 @@ */ function setupCurPrefs() { - curPrefs = $$b.extend(true, {}, defaultPrefs, curPrefs); // Now safe to merge with priority for curPrefs in the event any are already set + curPrefs = $$c.extend(true, {}, defaultPrefs, curPrefs); // Now safe to merge with priority for curPrefs in the event any are already set // Export updated prefs editor.curPrefs = curPrefs; @@ -29440,7 +28466,7 @@ function setupCurConfig() { - curConfig = $$b.extend(true, {}, defaultConfig, curConfig); // Now safe to merge with priority for curConfig in the event any are already set + curConfig = $$c.extend(true, {}, defaultConfig, curConfig); // Now safe to merge with priority for curConfig in the event any are already set // Now deal with extensions and other array config if (!curConfig.noDefaultExtensions) { @@ -29449,7 +28475,7 @@ ['extensions', 'stylesheets', 'allowedOrigins'].forEach(function (cfg) { - curConfig[cfg] = $$b.grep(curConfig[cfg], function (n, i) { + curConfig[cfg] = $$c.grep(curConfig[cfg], function (n, i) { // Supposedly faster than filter per http://amandeep1986.blogspot.hk/2015/02/jquery-grep-vs-js-filter.html return i === curConfig[cfg].indexOf(n); }); @@ -29458,19 +28484,20 @@ editor.curConfig = curConfig; } - (function () { + (() => { // Load config/data from URL if given - var _URL = new URL(location), - search = _URL.search, - searchParams = _URL.searchParams; + const { + search, + searchParams + } = new URL(location); if (search) { urldata = deparam(searchParams.toString(), true); - ['initStroke', 'initFill'].forEach(function (prop) { - if (searchParams.has("".concat(prop, "[color]"))) { + ['initStroke', 'initFill'].forEach(prop => { + if (searchParams.has(`${prop}[color]`)) { // Restore back to original non-deparamed value to avoid color // strings being converted to numbers - urldata[prop].color = searchParams.get("".concat(prop, "[color]")); + urldata[prop].color = searchParams.get(`${prop}[color]`); } }); @@ -29505,12 +28532,13 @@ setupCurConfig(); if (!curConfig.preventURLContentLoading) { - var _urldata = urldata, - source = _urldata.source; + let { + source + } = urldata; if (!source) { // urldata.source may have been null if it ended with '=' - var src = searchParams.get('source'); + const src = searchParams.get('source'); if (src && src.startsWith('data:')) { source = src; @@ -29552,8 +28580,8 @@ * @returns {void} */ - var setIcon = editor.setIcon = function (elem, iconId, forcedSize) { - var icon = typeof iconId === 'string' ? $$b.getSvgIcon(iconId, true) : iconId.clone(); + const setIcon = editor.setIcon = function (elem, iconId, forcedSize) { + const icon = typeof iconId === 'string' ? $$c.getSvgIcon(iconId, true) : iconId.clone(); if (!icon) { // Todo: Investigate why this still occurs in some cases @@ -29562,7 +28590,7 @@ return; } - $$b(elem).empty().append(icon); + $$c(elem).empty().append(icon); }; /** * @fires module:svgcanvas.SvgCanvas#event:ext_addLangData @@ -29573,158 +28601,108 @@ */ - var extAndLocaleFunc = /*#__PURE__*/function () { - var _ref5 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee3() { - var _yield$editor$putLoca, langParam, langData, _uiStrings$common, ok, cancel; + const extAndLocaleFunc = async function () { + // const lang = ('lang' in curPrefs) ? curPrefs.lang : null; + const { + langParam, + langData + } = await editor.putLocale(editor.pref('lang'), goodLangs, curConfig); + await setLang(langParam, langData); + const { + ok, + cancel + } = uiStrings$1.common; + jQueryPluginDBox($$c, { + ok, + cancel + }); + setIcons(); // Wait for dbox as needed for i18n - return regeneratorRuntime.wrap(function _callee3$(_context3) { - while (1) { - switch (_context3.prev = _context3.next) { - case 0: - _context3.next = 2; - return editor.putLocale(editor.pref('lang'), goodLangs, curConfig); + try { + await Promise.all(curConfig.extensions.map(async extname => { + const extName = extname.match(/^ext-(.+)\.js/); // const {extName} = extname.match(/^ext-(?<extName>.+)\.js/).groups; - case 2: - _yield$editor$putLoca = _context3.sent; - langParam = _yield$editor$putLoca.langParam; - langData = _yield$editor$putLoca.langData; - _context3.next = 7; - return setLang(langParam, langData); - - case 7: - _uiStrings$common = uiStrings$1.common, ok = _uiStrings$common.ok, cancel = _uiStrings$common.cancel; - jQueryPluginDBox($$b, { - ok: ok, - cancel: cancel - }); - setIcons(); // Wait for dbox as needed for i18n - - _context3.prev = 10; - _context3.next = 13; - return Promise.all(curConfig.extensions.map( /*#__PURE__*/function () { - var _ref6 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee2(extname) { - var extName, url, imported, _imported$name, _name2, init, importLocale; - - return regeneratorRuntime.wrap(function _callee2$(_context2) { - while (1) { - switch (_context2.prev = _context2.next) { - case 0: - extName = extname.match(/^ext-(.+)\.js/); // const {extName} = extname.match(/^ext-(?<extName>.+)\.js/).groups; - - if (extName) { - _context2.next = 3; - break; - } - - return _context2.abrupt("return", undefined); - - case 3: - url = curConfig.extPath + extname; // Todo: Replace this with `return import(url);` when - // `import()` widely supported - - /** - * @tutorial ExtensionDocs - * @typedef {PlainObject} module:SVGEditor.ExtensionObject - * @property {string} [name] Name of the extension. Used internally; no need for i18n. Defaults to extension name without beginning "ext-" or ending ".js". - * @property {module:svgcanvas.ExtensionInitCallback} [init] - */ - - _context2.prev = 4; - _context2.next = 7; - return importSetGlobalDefault(url, { - global: 'svgEditorExtension_' + extName[1].replace(/-/g, '_') // global: 'svgEditorExtension_' + extName.replace(/-/g, '_') - - }); - - case 7: - imported = _context2.sent; - _imported$name = imported.name, _name2 = _imported$name === void 0 ? extName[1] : _imported$name, init = imported.init; // const {name = extName, init} = imported; - - importLocale = getImportLocale({ - defaultLang: langParam, - defaultName: _name2 - }); - return _context2.abrupt("return", editor.addExtension(_name2, init && init.bind(editor), { - $: $$b, - importLocale: importLocale - })); - - case 13: - _context2.prev = 13; - _context2.t0 = _context2["catch"](4); - // Todo: Add config to alert any errors - console.log(_context2.t0); // eslint-disable-line no-console - - console.error('Extension failed to load: ' + extname + '; ' + _context2.t0); // eslint-disable-line no-console - - return _context2.abrupt("return", undefined); - - case 18: - case "end": - return _context2.stop(); - } - } - }, _callee2, null, [[4, 13]]); - })); - - return function (_x2) { - return _ref6.apply(this, arguments); - }; - }())); - - case 13: - svgCanvas.bind('extensions_added', - /** - * @param {external:Window} win - * @param {module:svgcanvas.SvgCanvas#event:extensions_added} data - * @listens module:svgcanvas.SvgCanvas#event:extensions_added - * @returns {void} - */ - function (win, data) { - extensionsAdded = true; - Actions.setAll(); - $$b('.flyout_arrow_horiz:empty').each(function () { - $$b(this).append($$b.getSvgIcon('arrow_right', true).width(5).height(5)); - }); - - if (editor.storagePromptState === 'ignore') { - updateCanvas(true); - } - - messageQueue.forEach( - /** - * @param {module:svgcanvas.SvgCanvas#event:message} messageObj - * @fires module:svgcanvas.SvgCanvas#event:message - * @returns {void} - */ - function (messageObj) { - svgCanvas.call('message', messageObj); - }); - }); - svgCanvas.call('extensions_added'); - _context3.next = 20; - break; - - case 17: - _context3.prev = 17; - _context3.t0 = _context3["catch"](10); - // Todo: Report errors through the UI - console.log(_context3.t0); // eslint-disable-line no-console - - case 20: - case "end": - return _context3.stop(); - } + if (!extName) { + // Ensure URL cannot specify some other unintended file in the extPath + return undefined; } - }, _callee3, null, [[10, 17]]); - })); - return function extAndLocaleFunc() { - return _ref5.apply(this, arguments); - }; - }(); + const url = curConfig.extPath + extname; // Todo: Replace this with `return import(url);` when + // `import()` widely supported - var stateObj = { + /** + * @tutorial ExtensionDocs + * @typedef {PlainObject} module:SVGEditor.ExtensionObject + * @property {string} [name] Name of the extension. Used internally; no need for i18n. Defaults to extension name without beginning "ext-" or ending ".js". + * @property {module:svgcanvas.ExtensionInitCallback} [init] + */ + + try { + /** + * @type {module:SVGEditor.ExtensionObject} + */ + const imported = await importSetGlobalDefault(url, { + global: 'svgEditorExtension_' + extName[1].replace(/-/g, '_') // global: 'svgEditorExtension_' + extName.replace(/-/g, '_') + + }); + const { + name = extName[1], + init + } = imported; // const {name = extName, init} = imported; + + const importLocale = getImportLocale({ + defaultLang: langParam, + defaultName: name + }); + return editor.addExtension(name, init && init.bind(editor), { + $: $$c, + importLocale + }); + } catch (err) { + // Todo: Add config to alert any errors + console.log(err); // eslint-disable-line no-console + + console.error('Extension failed to load: ' + extname + '; ' + err); // eslint-disable-line no-console + + return undefined; + } + })); + svgCanvas.bind('extensions_added', + /** + * @param {external:Window} win + * @param {module:svgcanvas.SvgCanvas#event:extensions_added} data + * @listens module:svgcanvas.SvgCanvas#event:extensions_added + * @returns {void} + */ + (win, data) => { + extensionsAdded = true; + Actions.setAll(); + $$c('.flyout_arrow_horiz:empty').each(function () { + $$c(this).append($$c.getSvgIcon('arrow_right', true).width(5).height(5)); + }); + + if (editor.storagePromptState === 'ignore') { + updateCanvas(true); + } + + messageQueue.forEach( + /** + * @param {module:svgcanvas.SvgCanvas#event:message} messageObj + * @fires module:svgcanvas.SvgCanvas#event:message + * @returns {void} + */ + messageObj => { + svgCanvas.call('message', messageObj); + }); + }); + svgCanvas.call('extensions_added'); + } catch (err) { + // Todo: Report errors through the UI + console.log(err); // eslint-disable-line no-console + } + }; + + const stateObj = { tool_scale: editor.tool_scale }; /** @@ -29732,18 +28710,17 @@ * @returns {void} */ - var setFlyoutPositions = function setFlyoutPositions() { - $$b('.tools_flyout').each(function () { - var shower = $$b('#' + this.id + '_show'); - - var _shower$offset = shower.offset(), - left = _shower$offset.left, - top = _shower$offset.top; - - var w = shower.outerWidth(); - $$b(this).css({ + const setFlyoutPositions = function () { + $$c('.tools_flyout').each(function () { + const shower = $$c('#' + this.id + '_show'); + const { + left, + top + } = shower.offset(); + const w = shower.outerWidth(); + $$c(this).css({ left: (left + w) * editor.tool_scale, - top: top + top }); }); }; @@ -29752,11 +28729,11 @@ */ - var uaPrefix = function () { - var regex = /^(?:Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/; - var someScript = document.getElementsByTagName('script')[0]; + const uaPrefix = function () { + const regex = /^(?:Moz|Webkit|Khtml|O|ms|Icab)(?=[A-Z])/; + const someScript = document.getElementsByTagName('script')[0]; - for (var prop in someScript.style) { + for (const prop in someScript.style) { if (regex.test(prop)) { // test is faster than match, so it's better to perform // that on the lot and match only when necessary @@ -29782,19 +28759,19 @@ */ - var scaleElements = function scaleElements(elems, scale) { + const scaleElements = function (elems, scale) { // const prefix = '-' + uaPrefix.toLowerCase() + '-'; // Currently unused - var sides = ['top', 'left', 'bottom', 'right']; + const sides = ['top', 'left', 'bottom', 'right']; elems.each(function () { // Handled in CSS // this.style[uaPrefix + 'Transform'] = 'scale(' + scale + ')'; - var el = $$b(this); - var w = el.outerWidth() * (scale - 1); - var h = el.outerHeight() * (scale - 1); // const margins = {}; // Currently unused + const el = $$c(this); + const w = el.outerWidth() * (scale - 1); + const h = el.outerHeight() * (scale - 1); // const margins = {}; // Currently unused - for (var i = 0; i < 4; i++) { - var s = sides[i]; - var cur = el.data('orig_margin-' + s); + for (let i = 0; i < 4; i++) { + const s = sides[i]; + let cur = el.data('orig_margin-' + s); if (isNullish(cur)) { cur = Number.parseInt(el.css('margin-' + s)); // Cache the original margin @@ -29802,7 +28779,7 @@ el.data('orig_margin-' + s, cur); } - var val = cur * scale; + let val = cur * scale; if (s === 'right') { val += w; @@ -29822,16 +28799,16 @@ */ - var setIconSize = editor.setIconSize = function (size) { + const setIconSize = editor.setIconSize = function (size) { // const elems = $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open'); - var selToscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,' + ' #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,' + ' #g_panel > *, #tool_font_size > *, .tools_flyout'; - var elems = $$b(selToscale); - var scale = 1; + const selToscale = '#tools_top .toolset, #editor_panel > *, #history_panel > *,' + ' #main_button, #tools_left > *, #path_node_panel > *, #multiselected_panel > *,' + ' #g_panel > *, #tool_font_size > *, .tools_flyout'; + const elems = $$c(selToscale); + let scale = 1; if (typeof size === 'number') { scale = size; } else { - var iconSizes = { + const iconSizes = { s: 0.75, m: 1, l: 1.25, @@ -29850,13 +28827,13 @@ // // const scale = .75; - var hiddenPs = elems.parents(':hidden'); + const hiddenPs = elems.parents(':hidden'); hiddenPs.css('visibility', 'hidden').show(); scaleElements(elems, scale); hiddenPs.css('visibility', 'visible').hide(); // return; editor.pref('iconsize', size); - $$b('#iconsize').val(size); // Change icon size + $$c('#iconsize').val(size); // Change icon size // $('.tool_button, .push_button, .tool_button_current, .disabled, .icon_label, #url_notice, #tool_open') // .find('> svg, > img').each(function () { // this.setAttribute('width',size_num); @@ -29873,7 +28850,7 @@ // } // Note that all rules will be prefixed with '#svg_editor' when parsed - var cssResizeRules = { + const cssResizeRules = { // '.tool_button,\ // .push_button,\ // .tool_button_current,\ @@ -29894,7 +28871,7 @@ // height: {s: '22px', l: '42px', xl: '64px'} // }, '#tools_top': { - left: 50 + $$b('#main_button').width(), + left: 50 + $$c('#main_button').width(), height: 72 }, '#tools_left': { @@ -29988,21 +28965,21 @@ // } }; - var ruleElem = $$b('#tool_size_rules'); + let ruleElem = $$c('#tool_size_rules'); if (!ruleElem.length) { - ruleElem = $$b('<style id="tool_size_rules"></style>').appendTo('head'); + ruleElem = $$c('<style id="tool_size_rules"></style>').appendTo('head'); } else { ruleElem.empty(); } if (size !== 'm') { - var styleStr = ''; - $$b.each(cssResizeRules, function (selector, rules) { + let styleStr = ''; + $$c.each(cssResizeRules, function (selector, rules) { selector = '#svg_editor ' + selector.replace(/,/g, ', #svg_editor'); styleStr += selector + '{'; - $$b.each(rules, function (prop, values) { - var val; + $$c.each(rules, function (prop, values) { + let val; if (typeof values === 'number') { val = values * scale + 'px'; @@ -30015,7 +28992,7 @@ styleStr += '}'; }); // this.style[uaPrefix + 'Transform'] = 'scale(' + scale + ')'; - var prefix = '-' + uaPrefix.toLowerCase() + '-'; + const prefix = '-' + uaPrefix.toLowerCase() + '-'; styleStr += selToscale + '{' + prefix + 'transform: scale(' + scale + ');}' + ' #svg_editor div.toolset .toolset {' + prefix + 'transform: scale(1); margin: 1px !important;}' + // Hack for markers ' #svg_editor .ui-slider {' + prefix + 'transform: scale(' + 1 / scale + ');}' // Hack for sliders ; @@ -30031,7 +29008,7 @@ function setIcons() { - $$b.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { + $$c.svgIcons(curConfig.imgPath + 'svg_edit_icons.svg', { w: 24, h: 24, id_match: false, @@ -30067,16 +29044,16 @@ opacity: 'opacity.png', new_image: 'clear.png', save: 'save.png', - "export": 'export.png', + export: 'export.png', open: 'open.png', - "import": 'import.png', + import: 'import.png', docprops: 'document-properties.png', source: 'source.png', wireframe: 'wireframe.png', undo: 'undo.png', redo: 'redo.png', clone: 'clone.png', - "delete": 'delete.png', + delete: 'delete.png', go_up: 'go-up.png', go_down: 'go-down.png', context_menu: 'context_menu.png', @@ -30205,116 +29182,101 @@ '.stroke_tool div div .svg_icon': 20, '#tools_bottom label .svg_icon': 18 }, - callback: function callback(icons) { - return _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee4() { - var tleft, minHeight, size, getStylesheetPriority, stylesheets, idx, _stylesheets; - return regeneratorRuntime.wrap(function _callee4$(_context4) { - while (1) { - switch (_context4.prev = _context4.next) { - case 0: - getStylesheetPriority = function _getStylesheetPriorit(stylesheetFile) { - switch (stylesheetFile) { - case 'jgraduate/css/jPicker.css': - return 1; + async callback(icons) { + $$c('.toolbar_button button > svg, .toolbar_button button > img').each(function () { + $$c(this).parent().prepend(this); + }); + const tleft = $$c('#tools_left'); + let minHeight; - case 'jgraduate/css/jGraduate.css': - return 2; + if (tleft.length) { + minHeight = tleft.offset().top + tleft.outerHeight(); + } - case 'svg-editor.css': - return 3; + const size = editor.pref('iconsize'); + editor.setIconSize(size || ($$c(window).height() < minHeight ? 's' : 'm')); // Look for any missing flyout icons from plugins - case 'spinbtn/jQuery.SpinButton.css': - return 4; + $$c('.tools_flyout').each(function () { + const shower = $$c('#' + this.id + '_show'); + const sel = shower.attr('data-curopt'); // Check if there's an icon here - default: - return Infinity; - } - }; + if (!shower.children('svg, img').length) { + const clone = $$c(sel).children().clone(); - $$b('.toolbar_button button > svg, .toolbar_button button > img').each(function () { - $$b(this).parent().prepend(this); - }); - tleft = $$b('#tools_left'); + if (clone.length) { + clone[0].removeAttribute('style'); // Needed for Opera - if (tleft.length) { - minHeight = tleft.offset().top + tleft.outerHeight(); - } - - size = editor.pref('iconsize'); - editor.setIconSize(size || ($$b(window).height() < minHeight ? 's' : 'm')); // Look for any missing flyout icons from plugins - - $$b('.tools_flyout').each(function () { - var shower = $$b('#' + this.id + '_show'); - var sel = shower.attr('data-curopt'); // Check if there's an icon here - - if (!shower.children('svg, img').length) { - var clone = $$b(sel).children().clone(); - - if (clone.length) { - clone[0].removeAttribute('style'); // Needed for Opera - - shower.append(clone); - } - } - }); - /** - * Since stylesheets may be added out of order, we indicate the desired order - * for defaults and others after them (in an indeterminate order). - * @param {string} stylesheetFile - * @returns {Integer|PositiveInfinity} - */ - - stylesheets = $$b.loadingStylesheets.sort(function (a, b) { - var priorityA = getStylesheetPriority(a); - var priorityB = getStylesheetPriority(b); - - if (priorityA === priorityB) { - return 0; - } - - return priorityA > priorityB; - }); - - if (curConfig.stylesheets.length) { - // Ensure a copy with unique items - stylesheets = _toConsumableArray(new Set(curConfig.stylesheets)); - idx = stylesheets.indexOf('@default'); - - if (idx > -1) { - (_stylesheets = stylesheets).splice.apply(_stylesheets, [idx, 1].concat(_toConsumableArray($$b.loadingStylesheets))); - } - } - - _context4.next = 11; - return loadStylesheets(stylesheets, { - acceptErrors: function acceptErrors(_ref7) { - var stylesheetURL = _ref7.stylesheetURL, - reject = _ref7.reject, - resolve = _ref7.resolve; - - if ($$b.loadingStylesheets.includes(stylesheetURL)) { - reject(new Error("Missing expected stylesheet: ".concat(stylesheetURL))); - return; - } - - resolve(); - } - }); - - case 11: - $$b('#svg_container')[0].style.visibility = 'visible'; - _context4.next = 14; - return editor.runCallbacks(); - - case 14: - case "end": - return _context4.stop(); - } + shower.append(clone); } - }, _callee4); - }))(); + } + }); + /** + * Since stylesheets may be added out of order, we indicate the desired order + * for defaults and others after them (in an indeterminate order). + * @param {string} stylesheetFile + * @returns {Integer|PositiveInfinity} + */ + + function getStylesheetPriority(stylesheetFile) { + switch (stylesheetFile) { + case 'jgraduate/css/jPicker.css': + return 1; + + case 'jgraduate/css/jGraduate.css': + return 2; + + case 'svg-editor.css': + return 3; + + case 'spinbtn/jQuery.SpinButton.css': + return 4; + + default: + return Infinity; + } + } + + let stylesheets = $$c.loadingStylesheets.sort((a, b) => { + const priorityA = getStylesheetPriority(a); + const priorityB = getStylesheetPriority(b); + + if (priorityA === priorityB) { + return 0; + } + + return priorityA > priorityB; + }); + + if (curConfig.stylesheets.length) { + // Ensure a copy with unique items + stylesheets = [...new Set(curConfig.stylesheets)]; + const idx = stylesheets.indexOf('@default'); + + if (idx > -1) { + stylesheets.splice(idx, 1, ...$$c.loadingStylesheets); + } + } + + await loadStylesheets(stylesheets, { + acceptErrors({ + stylesheetURL, + reject, + resolve + }) { + if ($$c.loadingStylesheets.includes(stylesheetURL)) { + reject(new Error(`Missing expected stylesheet: ${stylesheetURL}`)); + return; + } + + resolve(); + } + + }); + $$c('#svg_container')[0].style.visibility = 'visible'; + await editor.runCallbacks(); } + }); } /** @@ -30324,20 +29286,23 @@ editor.canvas = svgCanvas = new SvgCanvas(document.getElementById('svgcanvas'), curConfig); - var palette = [// Todo: Make into configuration item? + const palette = [// Todo: Make into configuration item? '#000000', '#3f3f3f', '#7f7f7f', '#bfbfbf', '#ffffff', '#ff0000', '#ff7f00', '#ffff00', '#7fff00', '#00ff00', '#00ff7f', '#00ffff', '#007fff', '#0000ff', '#7f00ff', '#ff00ff', '#ff007f', '#7f0000', '#7f3f00', '#7f7f00', '#3f7f00', '#007f00', '#007f3f', '#007f7f', '#003f7f', '#00007f', '#3f007f', '#7f007f', '#7f003f', '#ffaaaa', '#ffd4aa', '#ffffaa', '#d4ffaa', '#aaffaa', '#aaffd4', '#aaffff', '#aad4ff', '#aaaaff', '#d4aaff', '#ffaaff', '#ffaad4'], - modKey = isMac() ? 'meta+' : 'ctrl+', - path = svgCanvas.pathActions, - _svgCanvas = svgCanvas, - undoMgr = _svgCanvas.undoMgr, - workarea = $$b('#workarea'), - canvMenu = $$b('#cmenu_canvas'), - paintBox = { + modKey = isMac() ? 'meta+' : 'ctrl+', + // ⌘ + path = svgCanvas.pathActions, + { + undoMgr + } = svgCanvas, + workarea = $$c('#workarea'), + canvMenu = $$c('#cmenu_canvas'), + // layerMenu = $('#cmenu_layers'), // Unused + paintBox = { fill: null, stroke: null }; - var resizeTimer, curScrollPos; - var exportWindow = null, + let resizeTimer, curScrollPos; + let exportWindow = null, defaultImageURL = curConfig.imgPath + 'logo.png', zoomInIcon = 'crosshair', zoomOutIcon = 'crosshair', @@ -30345,7 +29310,7 @@ (function () { // let the opener know SVG Edit is ready (now that config is set up) - var w = window.opener || window.parent; + const w = window.opener || window.parent; if (w) { try { @@ -30362,7 +29327,7 @@ * @name module:SVGEditor.svgEditorReadyEvent * @type {module:SVGEditor#event:svgEditorReadyEvent} */ - var svgEditorReadyEvent = new w.CustomEvent('svgEditorReady', { + const svgEditorReadyEvent = new w.CustomEvent('svgEditorReady', { bubbles: true, cancelable: true }); @@ -30376,13 +29341,21 @@ */ - var setSelectMode = function setSelectMode() { - var curr = $$b('.tool_button_current'); + const setSelectMode = function () { + const curr = $$c('.tool_button_current'); if (curr.length && curr[0].id !== 'tool_select') { curr.removeClass('tool_button_current').addClass('tool_button'); - $$b('#tool_select').addClass('tool_button_current').removeClass('tool_button'); - $$b('#styleoverrides').text("\n #svgcanvas svg * {\n cursor: move;\n pointer-events: all;\n }\n #svgcanvas svg {\n cursor: default;\n }\n "); + $$c('#tool_select').addClass('tool_button_current').removeClass('tool_button'); + $$c('#styleoverrides').text(` + #svgcanvas svg * { + cursor: move; + pointer-events: all; + } + #svgcanvas svg { + cursor: default; + } + `); } svgCanvas.setMode('select'); @@ -30392,11 +29365,11 @@ // let textBeingEntered = false; // Currently unused - var origTitle = $$b('title:first').text(); // Make [1,2,5] array + const origTitle = $$c('title:first').text(); // Make [1,2,5] array - var rIntervals = []; + const rIntervals = []; - for (var i = 0.1; i < 1e5; i *= 10) { + for (let i = 0.1; i < 1e5; i *= 10) { rIntervals.push(i); rIntervals.push(2 * i); rIntervals.push(5 * i); @@ -30409,23 +29382,23 @@ */ - var toggleHighlightLayer = function toggleHighlightLayer(layerNameToHighlight) { - var i; - var curNames = [], - numLayers = svgCanvas.getCurrentDrawing().getNumLayers(); + const toggleHighlightLayer = function (layerNameToHighlight) { + let i; + const curNames = [], + numLayers = svgCanvas.getCurrentDrawing().getNumLayers(); for (i = 0; i < numLayers; i++) { curNames[i] = svgCanvas.getCurrentDrawing().getLayerName(i); } if (layerNameToHighlight) { - curNames.forEach(function (curName) { + curNames.forEach(curName => { if (curName !== layerNameToHighlight) { svgCanvas.getCurrentDrawing().setLayerOpacity(curName, 0.5); } }); } else { - curNames.forEach(function (curName) { + curNames.forEach(curName => { svgCanvas.getCurrentDrawing().setLayerOpacity(curName, 1.0); }); } @@ -30436,37 +29409,36 @@ */ - var populateLayers = function populateLayers() { + const populateLayers = function () { svgCanvas.clearSelection(); - var layerlist = $$b('#layerlist tbody').empty(); - var selLayerNames = $$b('#selLayerNames').empty(); - var drawing = svgCanvas.getCurrentDrawing(); - var currentLayerName = drawing.getCurrentLayerName(); - var icon = $$b.getSvgIcon('eye'); - var layer = svgCanvas.getCurrentDrawing().getNumLayers(); // we get the layers in the reverse z-order (the layer rendered on top is listed first) + const layerlist = $$c('#layerlist tbody').empty(); + const selLayerNames = $$c('#selLayerNames').empty(); + const drawing = svgCanvas.getCurrentDrawing(); + const currentLayerName = drawing.getCurrentLayerName(); + const icon = $$c.getSvgIcon('eye'); + let layer = svgCanvas.getCurrentDrawing().getNumLayers(); // we get the layers in the reverse z-order (the layer rendered on top is listed first) while (layer--) { - var _name3 = drawing.getLayerName(layer); - - var layerTr = $$b('<tr class="layer">').toggleClass('layersel', _name3 === currentLayerName); - var layerVis = $$b('<td class="layervis">').toggleClass('layerinvis', !drawing.getLayerVisibility(_name3)); - var layerName = $$b('<td class="layername">' + _name3 + '</td>'); + const name = drawing.getLayerName(layer); + const layerTr = $$c('<tr class="layer">').toggleClass('layersel', name === currentLayerName); + const layerVis = $$c('<td class="layervis">').toggleClass('layerinvis', !drawing.getLayerVisibility(name)); + const layerName = $$c('<td class="layername">' + name + '</td>'); layerlist.append(layerTr.append(layerVis, layerName)); - selLayerNames.append('<option value="' + _name3 + '">' + _name3 + '</option>'); + selLayerNames.append('<option value="' + name + '">' + name + '</option>'); } if (icon !== undefined) { - var copy = icon.clone(); - $$b('td.layervis', layerlist).append(copy); - $$b.resizeSvgIcons({ + const copy = icon.clone(); + $$c('td.layervis', layerlist).append(copy); + $$c.resizeSvgIcons({ 'td.layervis .svg_icon': 14 }); } // handle selection of layer - $$b('#layerlist td.layername').mouseup(function (evt) { - $$b('#layerlist tr.layer').removeClass('layersel'); - $$b(this.parentNode).addClass('layersel'); + $$c('#layerlist td.layername').mouseup(function (evt) { + $$c('#layerlist tr.layer').removeClass('layersel'); + $$c(this.parentNode).addClass('layersel'); svgCanvas.setCurrentLayer(this.textContent); evt.preventDefault(); }).mouseover(function () { @@ -30474,15 +29446,15 @@ }).mouseout(function () { toggleHighlightLayer(); }); - $$b('#layerlist td.layervis').click(function () { - var row = $$b(this.parentNode).prevAll().length; - var name = $$b('#layerlist tr.layer:eq(' + row + ') td.layername').text(); - var vis = $$b(this).hasClass('layerinvis'); + $$c('#layerlist td.layervis').click(function () { + const row = $$c(this.parentNode).prevAll().length; + const name = $$c('#layerlist tr.layer:eq(' + row + ') td.layername').text(); + const vis = $$c(this).hasClass('layerinvis'); svgCanvas.setLayerVisibility(name, vis); - $$b(this).toggleClass('layerinvis'); + $$c(this).toggleClass('layerinvis'); }); // if there were too few rows, let's add a few to make it not so lonely - var num = 5 - $$b('#layerlist tr.layer').size(); + let num = 5 - $$c('#layerlist tr.layer').size(); while (num-- > 0) { // TODO: there must a better way to do this @@ -30490,44 +29462,44 @@ } }; - var editingsource = false; - var origSource = ''; + let editingsource = false; + let origSource = ''; /** * @param {Event} [e] Not used. * @param {boolean} forSaving * @returns {void} */ - var showSourceEditor = function showSourceEditor(e, forSaving) { + const showSourceEditor = function (e, forSaving) { if (editingsource) { return; } editingsource = true; origSource = svgCanvas.getSvgString(); - $$b('#save_output_btns').toggle(Boolean(forSaving)); - $$b('#tool_source_back').toggle(!forSaving); - $$b('#svg_source_textarea').val(origSource); - $$b('#svg_source_editor').fadeIn(); - $$b('#svg_source_textarea').focus(); + $$c('#save_output_btns').toggle(Boolean(forSaving)); + $$c('#tool_source_back').toggle(!forSaving); + $$c('#svg_source_textarea').val(origSource); + $$c('#svg_source_editor').fadeIn(); + $$c('#svg_source_textarea').focus(); }; - var selectedElement = null; - var multiselected = false; + let selectedElement = null; + let multiselected = false; /** * @param {boolean} editmode * @param {module:svgcanvas.SvgCanvas#event:selected} elems * @returns {void} */ - var togglePathEditMode = function togglePathEditMode(editmode, elems) { - $$b('#path_node_panel').toggle(editmode); - $$b('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); + const togglePathEditMode = function (editmode, elems) { + $$c('#path_node_panel').toggle(editmode); + $$c('#tools_bottom_2,#tools_bottom_3').toggle(!editmode); if (editmode) { // Change select icon - $$b('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $$b('#tool_select').addClass('tool_button_current').removeClass('tool_button'); + $$c('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); + $$c('#tool_select').addClass('tool_button_current').removeClass('tool_button'); setIcon('#tool_select', 'select_node'); multiselected = false; @@ -30535,7 +29507,7 @@ selectedElement = elems[0]; } } else { - setTimeout(function () { + setTimeout(() => { setIcon('#tool_select', 'select'); }, 1000); } @@ -30549,7 +29521,7 @@ */ - var saveHandler = function saveHandler(wind, svg) { + const saveHandler = function (wind, svg) { editor.showSaveWarning = false; // by default, we add the XML prolog back, systems integrating SVG-edit (wikis, CMSs) // can just provide their own custom save handler and might not want the XML prolog @@ -30563,7 +29535,7 @@ // https://stackoverflow.com/questions/45603201/window-is-not-allowed-to-navigate-top-frame-navigations-to-data-urls - var a = document.createElement('a'); + const a = document.createElement('a'); a.href = 'data:image/svg+xml;base64,' + encode64(svg); a.download = 'icon.svg'; a.style.display = 'none'; @@ -30572,10 +29544,10 @@ a.click(); // Alert will only appear the first time saved OR the // first time the bug is encountered - var done = editor.pref('save_notice_done'); + let done = editor.pref('save_notice_done'); if (done !== 'all') { - var note = uiStrings$1.notification.saveFromBrowser.replace('%s', 'SVG'); // Check if FF and has <defs/> + let note = uiStrings$1.notification.saveFromBrowser.replace('%s', 'SVG'); // Check if FF and has <defs/> if (isGecko()) { if (svg.includes('<defs')) { @@ -30591,7 +29563,7 @@ } if (done !== 'part') { - $$b.alert(note); + $$c.alert(note); } } }; @@ -30603,25 +29575,27 @@ */ - var exportHandler = function exportHandler(win, data) { - var issues = data.issues, - exportWindowName = data.exportWindowName; + const exportHandler = function (win, data) { + const { + issues, + exportWindowName + } = data; exportWindow = window.open(blankPageObjectURL || '', exportWindowName); // A hack to get the window via JSON-able name without opening a new one if (!exportWindow || exportWindow.closed) { /* await */ - $$b.alert(uiStrings$1.notification.popupWindowBlocked); + $$c.alert(uiStrings$1.notification.popupWindowBlocked); return; } exportWindow.location.href = data.bloburl || data.datauri; - var done = editor.pref('export_notice_done'); + const done = editor.pref('export_notice_done'); if (done !== 'all') { - var note = uiStrings$1.notification.saveFromBrowser.replace('%s', data.type); // Check if there are issues + let note = uiStrings$1.notification.saveFromBrowser.replace('%s', data.type); // Check if there are issues if (issues.length) { - var pre = "\n \u2022 "; + const pre = '\n \u2022 '; note += '\n\n' + uiStrings$1.notification.noteTheseIssues + pre + issues.join(pre); } // Note that this will also prevent the notice even though new issues may appear later. // May want to find a way to deal with that without annoying the user @@ -30637,13 +29611,13 @@ */ - var operaRepaint = function operaRepaint() { + const operaRepaint = function () { // Repaints canvas in Opera. Needed for stroke-dasharray change as well as fill change if (!window.opera) { return; } - $$b('<p/>').hide().appendTo('body').remove(); + $$c('<p/>').hide().appendTo('body').remove(); }; /** * @@ -30654,12 +29628,11 @@ function setStrokeOpt(opt, changeElem) { - var id = opt.id; - var bits = id.split('_'); - - var _bits = _slicedToArray(bits, 2), - pre = _bits[0], - val = _bits[1]; + const { + id + } = opt; + const bits = id.split('_'); + const [pre, val] = bits; if (changeElem) { svgCanvas.setStrokeAttr('stroke-' + pre, val); @@ -30667,7 +29640,7 @@ operaRepaint(); setIcon('#cur_' + pre, id, 20); - $$b(opt).addClass('current').siblings().removeClass('current'); + $$c(opt).addClass('current').siblings().removeClass('current'); } /** * This is a common function used when a tool has been clicked (chosen). @@ -30682,25 +29655,25 @@ */ - var toolButtonClick = editor.toolButtonClick = function (button, noHiding) { - if ($$b(button).hasClass('disabled')) { + const toolButtonClick = editor.toolButtonClick = function (button, noHiding) { + if ($$c(button).hasClass('disabled')) { return false; } - if ($$b(button).parent().hasClass('tools_flyout')) { + if ($$c(button).parent().hasClass('tools_flyout')) { return true; } - var fadeFlyouts = 'normal'; + const fadeFlyouts = 'normal'; if (!noHiding) { - $$b('.tools_flyout').fadeOut(fadeFlyouts); + $$c('.tools_flyout').fadeOut(fadeFlyouts); } - $$b('#styleoverrides').text(''); + $$c('#styleoverrides').text(''); workarea.css('cursor', 'auto'); - $$b('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); - $$b(button).addClass('tool_button_current').removeClass('tool_button'); + $$c('.tool_button_current').removeClass('tool_button_current').addClass('tool_button'); + $$c(button).addClass('tool_button_current').removeClass('tool_button'); return true; }; /** @@ -30711,10 +29684,18 @@ */ - var clickSelect = editor.clickSelect = function () { + const clickSelect = editor.clickSelect = function () { if (toolButtonClick('#tool_select')) { svgCanvas.setMode('select'); - $$b('#styleoverrides').text("\n #svgcanvas svg * {\n cursor: move;\n pointer-events: all;\n }\n #svgcanvas svg {\n cursor: default;\n }\n "); + $$c('#styleoverrides').text(` + #svgcanvas svg * { + cursor: move; + pointer-events: all; + } + #svgcanvas svg { + cursor: default; + } + `); } }; /** @@ -30725,27 +29706,27 @@ */ - var setImageURL = editor.setImageURL = function (url) { + const setImageURL = editor.setImageURL = function (url) { if (!url) { url = defaultImageURL; } svgCanvas.setImageURL(url); - $$b('#image_url').val(url); + $$c('#image_url').val(url); if (url.startsWith('data:')) { // data URI found - $$b('#image_url').hide(); - $$b('#change_image_url').show(); + $$c('#image_url').hide(); + $$c('#change_image_url').show(); } else { // regular URL svgCanvas.embedImage(url, function (dataURI) { // Couldn't embed, so show warning - $$b('#url_notice').toggle(!dataURI); + $$c('#url_notice').toggle(!dataURI); defaultImageURL = url; }); - $$b('#image_url').show(); - $$b('#change_image_url').hide(); + $$c('#image_url').show(); + $$c('#change_image_url').hide(); } }; /** @@ -30770,8 +29751,18 @@ */ - function promptImgURL() { - return _promptImgURL.apply(this, arguments); + async function promptImgURL({ + cancelDeletes = false + } = {}) { + let curhref = svgCanvas.getHref(selectedElement); + curhref = curhref.startsWith('data:') ? '' : curhref; + const url = await $$c.prompt(uiStrings$1.notification.enterNewImgURL, curhref); + + if (url) { + setImageURL(url); + } else if (cancelDeletes) { + svgCanvas.deleteSelectedElements(); + } } /** * @param {Element} elem @@ -30779,47 +29770,9 @@ */ - function _promptImgURL() { - _promptImgURL = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee18() { - var _ref28, - _ref28$cancelDeletes, - cancelDeletes, - curhref, - url, - _args18 = arguments; - - return regeneratorRuntime.wrap(function _callee18$(_context18) { - while (1) { - switch (_context18.prev = _context18.next) { - case 0: - _ref28 = _args18.length > 0 && _args18[0] !== undefined ? _args18[0] : {}, _ref28$cancelDeletes = _ref28.cancelDeletes, cancelDeletes = _ref28$cancelDeletes === void 0 ? false : _ref28$cancelDeletes; - curhref = svgCanvas.getHref(selectedElement); - curhref = curhref.startsWith('data:') ? '' : curhref; - _context18.next = 5; - return $$b.prompt(uiStrings$1.notification.enterNewImgURL, curhref); - - case 5: - url = _context18.sent; - - if (url) { - setImageURL(url); - } else if (cancelDeletes) { - svgCanvas.deleteSelectedElements(); - } - - case 7: - case "end": - return _context18.stop(); - } - } - }, _callee18); - })); - return _promptImgURL.apply(this, arguments); - } - - var setInputWidth = function setInputWidth(elem) { - var w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300); - $$b(elem).width(w); + const setInputWidth = function (elem) { + const w = Math.min(Math.max(12 + elem.value.length * 6, 50), 300); + $$c(elem).width(w); }; /** * @@ -30835,34 +29788,32 @@ } if (!scanvas) { - scanvas = $$b('#svgcanvas'); + scanvas = $$c('#svgcanvas'); } - var d, i; - var limit = 30000; - var contentElem = svgCanvas.getContentElem(); - var units = getTypeMap(); - var unit = units[curConfig.baseUnit]; // 1 = 1px + let d, i; + const limit = 30000; + const contentElem = svgCanvas.getContentElem(); + const units = getTypeMap(); + const unit = units[curConfig.baseUnit]; // 1 = 1px // draw x ruler then y ruler for (d = 0; d < 2; d++) { - var isX = d === 0; - var dim = isX ? 'x' : 'y'; - var lentype = isX ? 'width' : 'height'; - var contentDim = Number(contentElem.getAttribute(dim)); - var $hcanvOrig = $$b('#ruler_' + dim + ' canvas:first'); // Bit of a hack to fully clear the canvas in Safari & IE9 + const isX = d === 0; + const dim = isX ? 'x' : 'y'; + const lentype = isX ? 'width' : 'height'; + const contentDim = Number(contentElem.getAttribute(dim)); + const $hcanvOrig = $$c('#ruler_' + dim + ' canvas:first'); // Bit of a hack to fully clear the canvas in Safari & IE9 - var $hcanv = $hcanvOrig.clone(); + const $hcanv = $hcanvOrig.clone(); $hcanvOrig.replaceWith($hcanv); - var hcanv = $hcanv[0]; // Set the canvas size to the width of the container + const hcanv = $hcanv[0]; // Set the canvas size to the width of the container - var rulerLen = scanvas[lentype](); - var totalLen = rulerLen; + let rulerLen = scanvas[lentype](); + const totalLen = rulerLen; hcanv.parentNode.style[lentype] = totalLen + 'px'; - var ctx = hcanv.getContext('2d'); - var ctxArr = void 0, - num = void 0, - ctxArrNum = void 0; + let ctx = hcanv.getContext('2d'); + let ctxArr, num, ctxArrNum; ctx.fillStyle = 'rgb(200,0,0)'; ctx.fillRect(0, 0, hcanv.width, hcanv.height); // Remove any existing canvasses @@ -30872,7 +29823,7 @@ ctxArrNum = Number.parseInt(rulerLen / limit) + 1; ctxArr = []; ctxArr[0] = ctx; - var copy = void 0; + let copy; for (i = 1; i < ctxArrNum; i++) { hcanv[lentype] = limit; @@ -30887,10 +29838,10 @@ } hcanv[lentype] = rulerLen; - var uMulti = unit * zoom; // Calculate the main number interval + const uMulti = unit * zoom; // Calculate the main number interval - var rawM = 50 / uMulti; - var multi = 1; + const rawM = 50 / uMulti; + let multi = 1; for (i = 0; i < rIntervals.length; i++) { num = rIntervals[i]; @@ -30901,17 +29852,17 @@ } } - var bigInt = multi * uMulti; + const bigInt = multi * uMulti; ctx.font = '9px sans-serif'; - var rulerD = contentDim / uMulti % multi * uMulti; - var labelPos = rulerD - bigInt; // draw big intervals + let rulerD = contentDim / uMulti % multi * uMulti; + let labelPos = rulerD - bigInt; // draw big intervals - var ctxNum = 0; + let ctxNum = 0; while (rulerD < totalLen) { labelPos += bigInt; // const realD = rulerD - contentDim; // Currently unused - var curD = Math.round(rulerD) + 0.5; + const curD = Math.round(rulerD) + 0.5; if (isX) { ctx.moveTo(curD, 15); @@ -30922,12 +29873,12 @@ } num = (labelPos - contentDim) / uMulti; - var label = void 0; + let label; if (multi >= 1) { label = Math.round(num); } else { - var decs = String(multi).split('.')[1].length; + const decs = String(multi).split('.')[1].length; label = num.toFixed(decs); } // Change 1000s to Ks @@ -30940,17 +29891,17 @@ ctx.fillText(label, rulerD + 2, 8); } else { // draw label vertically - var _str = String(label).split(''); + const str = String(label).split(''); - for (i = 0; i < _str.length; i++) { - ctx.fillText(_str[i], 1, rulerD + 9 + i * 9); + for (i = 0; i < str.length; i++) { + ctx.fillText(str[i], 1, rulerD + 9 + i * 9); } } - var part = bigInt / 10; // draw the small intervals + const part = bigInt / 10; // draw the small intervals for (i = 1; i < 10; i++) { - var subD = Math.round(rulerD + part * i) + 0.5; + let subD = Math.round(rulerD + part * i) + 0.5; if (ctxArr && subD > rulerLen) { ctxNum++; @@ -30968,7 +29919,7 @@ } // odd lines are slighly longer - var lineNum = i % 2 ? 12 : 10; + const lineNum = i % 2 ? 12 : 10; if (isX) { ctx.moveTo(subD, 15); @@ -30994,19 +29945,19 @@ */ - var updateCanvas = editor.updateCanvas = function (center, newCtr) { - var zoom = svgCanvas.getZoom(); - var wArea = workarea; - var cnvs = $$b('#svgcanvas'); - var w = workarea.width(), + const updateCanvas = editor.updateCanvas = function (center, newCtr) { + const zoom = svgCanvas.getZoom(); + const wArea = workarea; + const cnvs = $$c('#svgcanvas'); + let w = workarea.width(), h = workarea.height(); - var wOrig = w, - hOrig = h; - var oldCtr = { + const wOrig = w, + hOrig = h; + const oldCtr = { x: wArea[0].scrollLeft + wOrig / 2, y: wArea[0].scrollTop + hOrig / 2 }; - var multi = curConfig.canvas_expansion; + const multi = curConfig.canvas_expansion; w = Math.max(wOrig, svgCanvas.contentW * zoom * multi); h = Math.max(hOrig, svgCanvas.contentH * zoom * multi); @@ -31016,22 +29967,22 @@ workarea.css('overflow', 'scroll'); } - var oldCanY = cnvs.height() / 2; - var oldCanX = cnvs.width() / 2; + const oldCanY = cnvs.height() / 2; + const oldCanX = cnvs.width() / 2; cnvs.width(w).height(h); - var newCanY = h / 2; - var newCanX = w / 2; - var offset = svgCanvas.updateCanvas(w, h); - var ratio = newCanX / oldCanX; - var scrollX = w / 2 - wOrig / 2; // eslint-disable-line no-shadow + const newCanY = h / 2; + const newCanX = w / 2; + const offset = svgCanvas.updateCanvas(w, h); + const ratio = newCanX / oldCanX; + const scrollX = w / 2 - wOrig / 2; // eslint-disable-line no-shadow - var scrollY = h / 2 - hOrig / 2; // eslint-disable-line no-shadow + const scrollY = h / 2 - hOrig / 2; // eslint-disable-line no-shadow if (!newCtr) { - var oldDistX = oldCtr.x - oldCanX; - var newX = newCanX + oldDistX * ratio; - var oldDistY = oldCtr.y - oldCanY; - var newY = newCanY + oldDistY * ratio; + const oldDistX = oldCtr.x - oldCanX; + const newX = newCanX + oldDistX * ratio; + const oldDistY = oldCtr.y - oldCanY; + const newY = newCanY + oldDistY * ratio; newCtr = { x: newX, y: newY @@ -31063,7 +30014,7 @@ } if (urldata.storagePrompt !== true && editor.storagePromptState === 'ignore') { - $$b('#dialog_box').hide(); + $$c('#dialog_box').hide(); } }; /** @@ -31072,37 +30023,37 @@ */ - var updateToolButtonState = function updateToolButtonState() { - var bNoFill = svgCanvas.getColor('fill') === 'none'; - var bNoStroke = svgCanvas.getColor('stroke') === 'none'; - var buttonsNeedingStroke = ['#tool_fhpath', '#tool_line']; - var buttonsNeedingFillAndStroke = ['#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; + const updateToolButtonState = function () { + const bNoFill = svgCanvas.getColor('fill') === 'none'; + const bNoStroke = svgCanvas.getColor('stroke') === 'none'; + const buttonsNeedingStroke = ['#tool_fhpath', '#tool_line']; + const buttonsNeedingFillAndStroke = ['#tools_rect .tool_button', '#tools_ellipse .tool_button', '#tool_text', '#tool_path']; if (bNoStroke) { - buttonsNeedingStroke.forEach(function (btn) { - if ($$b(btn).hasClass('tool_button_current')) { + buttonsNeedingStroke.forEach(btn => { + if ($$c(btn).hasClass('tool_button_current')) { clickSelect(); } - $$b(btn).addClass('disabled'); + $$c(btn).addClass('disabled'); }); } else { - buttonsNeedingStroke.forEach(function (btn) { - $$b(btn).removeClass('disabled'); + buttonsNeedingStroke.forEach(btn => { + $$c(btn).removeClass('disabled'); }); } if (bNoStroke && bNoFill) { - buttonsNeedingFillAndStroke.forEach(function (btn) { - if ($$b(btn).hasClass('tool_button_current')) { + buttonsNeedingFillAndStroke.forEach(btn => { + if ($$c(btn).hasClass('tool_button_current')) { clickSelect(); } - $$b(btn).addClass('disabled'); + $$c(btn).addClass('disabled'); }); } else { - buttonsNeedingFillAndStroke.forEach(function (btn) { - $$b(btn).removeClass('disabled'); + buttonsNeedingFillAndStroke.forEach(btn => { + $$c(btn).removeClass('disabled'); }); } @@ -31113,11 +30064,11 @@ nostroke: bNoStroke }); // Disable flyouts if all inside are disabled - $$b('.tools_flyout').each(function () { - var shower = $$b('#' + this.id + '_show'); - var hasEnabled = false; - $$b(this).children().each(function () { - if (!$$b(this).hasClass('disabled')) { + $$c('.tools_flyout').each(function () { + const shower = $$c('#' + this.id + '_show'); + let hasEnabled = false; + $$c(this).children().each(function () { + if (!$$c(this).hasClass('disabled')) { hasEnabled = true; } }); @@ -31133,8 +30084,8 @@ */ - var updateToolbar = function updateToolbar() { - var i, len; + const updateToolbar = function () { + let i, len; if (!isNullish(selectedElement)) { switch (selectedElement.tagName) { @@ -31147,11 +30098,11 @@ case 'a': { // Look for common styles - var childs = selectedElement.getElementsByTagName('*'); - var gWidth = null; + const childs = selectedElement.getElementsByTagName('*'); + let gWidth = null; for (i = 0, len = childs.length; i < len; i++) { - var swidth = childs[i].getAttribute('stroke-width'); + const swidth = childs[i].getAttribute('stroke-width'); if (i === 0) { gWidth = swidth; @@ -31160,7 +30111,7 @@ } } - $$b('#stroke_width').val(gWidth === null ? '' : gWidth); + $$c('#stroke_width').val(gWidth === null ? '' : gWidth); paintBox.fill.update(true); paintBox.stroke.update(true); break; @@ -31170,18 +30121,18 @@ { paintBox.fill.update(true); paintBox.stroke.update(true); - $$b('#stroke_width').val(selectedElement.getAttribute('stroke-width') || 1); - $$b('#stroke_style').val(selectedElement.getAttribute('stroke-dasharray') || 'none'); - var attr = selectedElement.getAttribute('stroke-linejoin') || 'miter'; + $$c('#stroke_width').val(selectedElement.getAttribute('stroke-width') || 1); + $$c('#stroke_style').val(selectedElement.getAttribute('stroke-dasharray') || 'none'); + let attr = selectedElement.getAttribute('stroke-linejoin') || 'miter'; - if ($$b('#linejoin_' + attr).length) { - setStrokeOpt($$b('#linejoin_' + attr)[0]); + if ($$c('#linejoin_' + attr).length) { + setStrokeOpt($$c('#linejoin_' + attr)[0]); } attr = selectedElement.getAttribute('stroke-linecap') || 'butt'; - if ($$b('#linecap_' + attr).length) { - setStrokeOpt($$b('#linecap_' + attr)[0]); + if ($$c('#linecap_' + attr).length) { + setStrokeOpt($$c('#linecap_' + attr)[0]); } } } @@ -31189,11 +30140,11 @@ if (!isNullish(selectedElement)) { - var opacPerc = (selectedElement.getAttribute('opacity') || 1.0) * 100; - $$b('#group_opacity').val(opacPerc); - $$b('#opac_slider').slider('option', 'value', opacPerc); - $$b('#elem_id').val(selectedElement.id); - $$b('#elem_class').val(selectedElement.getAttribute('class')); + const opacPerc = (selectedElement.getAttribute('opacity') || 1.0) * 100; + $$c('#group_opacity').val(opacPerc); + $$c('#opac_slider').slider('option', 'value', opacPerc); + $$c('#elem_id').val(selectedElement.id); + $$c('#elem_class').val(selectedElement.getAttribute('class')); } updateToolButtonState(); @@ -31204,33 +30155,33 @@ */ - var updateContextPanel = function updateContextPanel() { - var elem = selectedElement; // If element has just been deleted, consider it null + const updateContextPanel = function () { + let elem = selectedElement; // If element has just been deleted, consider it null if (!isNullish(elem) && !elem.parentNode) { elem = null; } - var currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); - var currentMode = svgCanvas.getMode(); - var unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; - var isNode = currentMode === 'pathedit'; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false; + const currentLayerName = svgCanvas.getCurrentDrawing().getCurrentLayerName(); + const currentMode = svgCanvas.getMode(); + const unit = curConfig.baseUnit !== 'px' ? curConfig.baseUnit : null; + const isNode = currentMode === 'pathedit'; // elem ? (elem.id && elem.id.startsWith('pathpointgrip')) : false; - var menuItems = $$b('#cmenu_canvas li'); - $$b('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,' + '#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel,' + ' #use_panel, #a_panel').hide(); + const menuItems = $$c('#cmenu_canvas li'); + $$c('#selected_panel, #multiselected_panel, #g_panel, #rect_panel, #circle_panel,' + '#ellipse_panel, #line_panel, #text_panel, #image_panel, #container_panel,' + ' #use_panel, #a_panel').hide(); if (!isNullish(elem)) { - var elname = elem.nodeName; // If this is a link with no transform and one child, pretend + const elname = elem.nodeName; // If this is a link with no transform and one child, pretend // its child is selected // if (elname === 'a') { // && !$(elem).attr('transform')) { // elem = elem.firstChild; // } - var angle = svgCanvas.getRotationAngle(elem); - $$b('#angle').val(angle); - var blurval = svgCanvas.getBlur(elem); - $$b('#blur').val(blurval); - $$b('#blur_slider').slider('option', 'value', blurval); + const angle = svgCanvas.getRotationAngle(elem); + $$c('#angle').val(angle); + const blurval = svgCanvas.getBlur(elem); + $$c('#blur').val(blurval); + $$c('#blur_slider').slider('option', 'value', blurval); if (svgCanvas.addedNew) { if (elname === 'image' && svgCanvas.getMode() === 'image') { @@ -31249,19 +30200,21 @@ } if (!isNode && currentMode !== 'pathedit') { - $$b('#selected_panel').show(); // Elements in this array already have coord fields + $$c('#selected_panel').show(); // Elements in this array already have coord fields if (['line', 'circle', 'ellipse'].includes(elname)) { - $$b('#xy_panel').hide(); + $$c('#xy_panel').hide(); } else { - var x, y; // Get BBox vals for g, polyline and path + let x, y; // Get BBox vals for g, polyline and path if (['g', 'polyline', 'path'].includes(elname)) { - var bb = svgCanvas.getStrokedBBox([elem]); + const bb = svgCanvas.getStrokedBBox([elem]); if (bb) { - x = bb.x; - y = bb.y; + ({ + x, + y + } = bb); } } else { x = elem.getAttribute('x'); @@ -31273,33 +30226,33 @@ y = convertUnit(y); } - $$b('#selected_x').val(x || 0); - $$b('#selected_y').val(y || 0); - $$b('#xy_panel').show(); + $$c('#selected_x').val(x || 0); + $$c('#selected_y').val(y || 0); + $$c('#xy_panel').show(); } // Elements in this array cannot be converted to a path - var noPath = !['image', 'text', 'path', 'g', 'use'].includes(elname); - $$b('#tool_topath').toggle(noPath); - $$b('#tool_reorient').toggle(elname === 'path'); - $$b('#tool_reorient').toggleClass('disabled', angle === 0); + const noPath = !['image', 'text', 'path', 'g', 'use'].includes(elname); + $$c('#tool_topath').toggle(noPath); + $$c('#tool_reorient').toggle(elname === 'path'); + $$c('#tool_reorient').toggleClass('disabled', angle === 0); } else { - var point = path.getNodePoint(); - $$b('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); - $$b('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); // Show open/close button based on selected point + const point = path.getNodePoint(); + $$c('#tool_add_subpath').removeClass('push_button_pressed').addClass('tool_button'); + $$c('#tool_node_delete').toggleClass('disabled', !path.canDeleteNodes); // Show open/close button based on selected point setIcon('#tool_openclose_path', path.closed_subpath ? 'open_path' : 'close_path'); if (point) { - var segType = $$b('#seg_type'); + const segType = $$c('#seg_type'); if (unit) { point.x = convertUnit(point.x); point.y = convertUnit(point.y); } - $$b('#path_node_x').val(point.x); - $$b('#path_node_y').val(point.y); + $$c('#path_node_x').val(point.x); + $$c('#path_node_y').val(point.y); if (point.type) { segType.val(point.type).removeAttr('disabled'); @@ -31312,7 +30265,7 @@ } // update contextual tools here - var panels = { + const panels = { g: [], a: [], rect: ['rx', 'width', 'height'], @@ -31323,106 +30276,107 @@ text: [], use: [] }; - var _elem = elem, - tagName = _elem.tagName; // if ($(elem).data('gsvg')) { + const { + tagName + } = elem; // if ($(elem).data('gsvg')) { // $('#g_panel').show(); // } - var linkHref = null; + let linkHref = null; if (tagName === 'a') { linkHref = svgCanvas.getHref(elem); - $$b('#g_panel').show(); + $$c('#g_panel').show(); } if (elem.parentNode.tagName === 'a') { - if (!$$b(elem).siblings().length) { - $$b('#a_panel').show(); + if (!$$c(elem).siblings().length) { + $$c('#a_panel').show(); linkHref = svgCanvas.getHref(elem.parentNode); } } // Hide/show the make_link buttons - $$b('#tool_make_link, #tool_make_link').toggle(!linkHref); + $$c('#tool_make_link, #tool_make_link').toggle(!linkHref); if (linkHref) { - $$b('#link_url').val(linkHref); + $$c('#link_url').val(linkHref); } if (panels[tagName]) { - var curPanel = panels[tagName]; - $$b('#' + tagName + '_panel').show(); - $$b.each(curPanel, function (i, item) { - var attrVal = elem.getAttribute(item); + const curPanel = panels[tagName]; + $$c('#' + tagName + '_panel').show(); + $$c.each(curPanel, function (i, item) { + let attrVal = elem.getAttribute(item); if (curConfig.baseUnit !== 'px' && elem[item]) { - var bv = elem[item].baseVal.value; + const bv = elem[item].baseVal.value; attrVal = convertUnit(bv); } - $$b('#' + tagName + '_' + item).val(attrVal || 0); + $$c('#' + tagName + '_' + item).val(attrVal || 0); }); if (tagName === 'text') { - $$b('#text_panel').css('display', 'inline'); - $$b('#tool_font_size').css('display', 'inline'); + $$c('#text_panel').css('display', 'inline'); + $$c('#tool_font_size').css('display', 'inline'); if (svgCanvas.getItalic()) { - $$b('#tool_italic').addClass('push_button_pressed').removeClass('tool_button'); + $$c('#tool_italic').addClass('push_button_pressed').removeClass('tool_button'); } else { - $$b('#tool_italic').removeClass('push_button_pressed').addClass('tool_button'); + $$c('#tool_italic').removeClass('push_button_pressed').addClass('tool_button'); } if (svgCanvas.getBold()) { - $$b('#tool_bold').addClass('push_button_pressed').removeClass('tool_button'); + $$c('#tool_bold').addClass('push_button_pressed').removeClass('tool_button'); } else { - $$b('#tool_bold').removeClass('push_button_pressed').addClass('tool_button'); + $$c('#tool_bold').removeClass('push_button_pressed').addClass('tool_button'); } - $$b('#font_family').val(elem.getAttribute('font-family')); - $$b('#font_size').val(elem.getAttribute('font-size')); - $$b('#text').val(elem.textContent); + $$c('#font_family').val(elem.getAttribute('font-family')); + $$c('#font_size').val(elem.getAttribute('font-size')); + $$c('#text').val(elem.textContent); if (svgCanvas.addedNew) { // Timeout needed for IE9 setTimeout(function () { - $$b('#text').focus().select(); + $$c('#text').focus().select(); }, 100); } // text } else if (tagName === 'image' && svgCanvas.getMode() === 'image') { setImageURL(svgCanvas.getHref(elem)); // image } else if (tagName === 'g' || tagName === 'use') { - $$b('#container_panel').show(); - var title = svgCanvas.getTitle(); - var label = $$b('#g_title')[0]; + $$c('#container_panel').show(); + const title = svgCanvas.getTitle(); + const label = $$c('#g_title')[0]; label.value = title; setInputWidth(label); - $$b('#g_title').prop('disabled', tagName === 'use'); + $$c('#g_title').prop('disabled', tagName === 'use'); } } menuItems[(tagName === 'g' ? 'en' : 'dis') + 'ableContextMenuItems']('#ungroup'); menuItems[(tagName === 'g' || !multiselected ? 'dis' : 'en') + 'ableContextMenuItems']('#group'); // if (!Utils.isNullish(elem)) } else if (multiselected) { - $$b('#multiselected_panel').show(); + $$c('#multiselected_panel').show(); menuItems.enableContextMenuItems('#group').disableContextMenuItems('#ungroup'); } else { menuItems.disableContextMenuItems('#delete,#cut,#copy,#group,#ungroup,#move_front,#move_up,#move_down,#move_back'); } // update history buttons - $$b('#tool_undo').toggleClass('disabled', undoMgr.getUndoStackSize() === 0); - $$b('#tool_redo').toggleClass('disabled', undoMgr.getRedoStackSize() === 0); + $$c('#tool_undo').toggleClass('disabled', undoMgr.getUndoStackSize() === 0); + $$c('#tool_redo').toggleClass('disabled', undoMgr.getRedoStackSize() === 0); svgCanvas.addedNew = false; if (elem && !isNode || multiselected) { // update the selected elements' layer - $$b('#selLayerNames').removeAttr('disabled').val(currentLayerName); // Enable regular menu options + $$c('#selLayerNames').removeAttr('disabled').val(currentLayerName); // Enable regular menu options canvMenu.enableContextMenuItems('#delete,#cut,#copy,#move_front,#move_up,#move_down,#move_back'); } else { - $$b('#selLayerNames').attr('disabled', 'disabled'); + $$c('#selLayerNames').attr('disabled', 'disabled'); } }; /** @@ -31431,30 +30385,34 @@ */ - var updateWireFrame = function updateWireFrame() { + const updateWireFrame = function () { // Test support if (supportsNonSS) { return; } - var rule = "\n #workarea.wireframe #svgcontent * {\n stroke-width: ".concat(1 / svgCanvas.getZoom(), "px;\n }\n "); - $$b('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ''); + const rule = ` + #workarea.wireframe #svgcontent * { + stroke-width: ${1 / svgCanvas.getZoom()}px; + } + `; + $$c('#wireframe_rules').text(workarea.hasClass('wireframe') ? rule : ''); }; - var curContext = ''; + let curContext = ''; /** * @param {string} [title=svgCanvas.getDocumentTitle()] * @returns {void} */ - var updateTitle = function updateTitle(title) { + const updateTitle = function (title) { title = title || svgCanvas.getDocumentTitle(); - var newTitle = origTitle + (title ? ': ' + title : ''); // Remove title update with current context info, isn't really necessary + const newTitle = origTitle + (title ? ': ' + title : ''); // Remove title update with current context info, isn't really necessary // if (curContext) { // new_title = new_title + curContext; // } - $$b('title:first').text(newTitle); + $$c('title:first').text(newTitle); }; // called when we've selected a different element /** @@ -31467,14 +30425,14 @@ */ - var selectedChanged = function selectedChanged(win, elems) { - var mode = svgCanvas.getMode(); + const selectedChanged = function (win, elems) { + const mode = svgCanvas.getMode(); if (mode === 'select') { setSelectMode(); } - var isNode = mode === 'pathedit'; // if elems[1] is present, then we have more than one element + const isNode = mode === 'pathedit'; // if elems[1] is present, then we have more than one element selectedElement = elems.length === 1 || isNullish(elems[1]) ? elems[0] : null; multiselected = elems.length >= 2 && !isNullish(elems[1]); @@ -31495,9 +30453,9 @@ svgCanvas.runExtensions('selectedChanged', /** @type {module:svgcanvas.SvgCanvas#event:ext_selectedChanged} */ { - elems: elems, - selectedElement: selectedElement, - multiselected: multiselected + elems, + selectedElement, + multiselected }); }; // Call when part of element is in process of changing, generally // on mousemove actions like rotate, move, etc. @@ -31511,9 +30469,9 @@ */ - var elementTransition = function elementTransition(win, elems) { - var mode = svgCanvas.getMode(); - var elem = elems[0]; + const elementTransition = function (win, elems) { + const mode = svgCanvas.getMode(); + const elem = elems[0]; if (!elem) { return; @@ -31525,9 +30483,9 @@ switch (mode) { case 'rotate': { - var ang = svgCanvas.getRotationAngle(elem); - $$b('#angle').val(ang); - $$b('#tool_reorient').toggleClass('disabled', ang === 0); + const ang = svgCanvas.getRotationAngle(elem); + $$c('#angle').val(ang); + $$c('#tool_reorient').toggleClass('disabled', ang === 0); break; // TODO: Update values that change on move/resize, etc // } case 'select': { // } case 'resize': { @@ -31540,7 +30498,7 @@ svgCanvas.runExtensions('elementTransition', /** @type {module:svgcanvas.SvgCanvas#event:ext_elementTransition} */ { - elems: elems + elems }); }; /** @@ -31563,15 +30521,15 @@ */ - var elementChanged = function elementChanged(win, elems) { - var mode = svgCanvas.getMode(); + const elementChanged = function (win, elems) { + const mode = svgCanvas.getMode(); if (mode === 'select') { setSelectMode(); } - elems.forEach(function (elem) { - var isSvgElem = elem && elem.tagName === 'svg'; + elems.forEach(elem => { + const isSvgElem = elem && elem.tagName === 'svg'; if (isSvgElem || isLayer(elem)) { populateLayers(); // if the element changed was the svg, then it could be a resolution change @@ -31603,7 +30561,7 @@ svgCanvas.runExtensions('elementChanged', /** @type {module:svgcanvas.SvgCanvas#event:ext_elementChanged} */ { - elems: elems + elems }); }; /** @@ -31611,7 +30569,7 @@ */ - var zoomDone = function zoomDone() { + const zoomDone = function () { updateWireFrame(); // updateCanvas(); // necessary? }; /** @@ -31635,19 +30593,19 @@ */ - var zoomChanged = svgCanvas.zoomChanged = function (win, bbox, autoCenter) { - var scrbar = 15, - // res = svgCanvas.getResolution(), // Currently unused + const zoomChanged = svgCanvas.zoomChanged = function (win, bbox, autoCenter) { + const scrbar = 15, + // res = svgCanvas.getResolution(), // Currently unused wArea = workarea; // const canvasPos = $('#svgcanvas').position(); // Currently unused - var zInfo = svgCanvas.setBBoxZoom(bbox, wArea.width() - scrbar, wArea.height() - scrbar); + const zInfo = svgCanvas.setBBoxZoom(bbox, wArea.width() - scrbar, wArea.height() - scrbar); if (!zInfo) { return; } - var zoomlevel = zInfo.zoom, - bb = zInfo.bbox; + const zoomlevel = zInfo.zoom, + bb = zInfo.bbox; if (zoomlevel < 0.001) { changeZoom({ @@ -31656,7 +30614,7 @@ return; } - $$b('#zoom').val((zoomlevel * 100).toFixed(1)); + $$c('#zoom').val((zoomlevel * 100).toFixed(1)); if (autoCenter) { updateCanvas(); @@ -31679,16 +30637,16 @@ */ - var changeZoom = function changeZoom(ctl) { - var zoomlevel = ctl.value / 100; + const changeZoom = function (ctl) { + const zoomlevel = ctl.value / 100; if (zoomlevel < 0.001) { ctl.value = 0.1; return; } - var zoom = svgCanvas.getZoom(); - var wArea = workarea; + const zoom = svgCanvas.getZoom(); + const wArea = workarea; zoomChanged(window, { width: 0, height: 0, @@ -31699,8 +30657,8 @@ }, true); }; - $$b('#cur_context_panel').delegate('a', 'click', function () { - var link = $$b(this); + $$c('#cur_context_panel').delegate('a', 'click', function () { + const link = $$c(this); if (link.attr('data-root')) { svgCanvas.leaveContext(); @@ -31718,15 +30676,15 @@ * @returns {void} */ - var contextChanged = function contextChanged(win, context) { - var linkStr = ''; + const contextChanged = function (win, context) { + let linkStr = ''; if (context) { - var _str2 = ''; + let str = ''; linkStr = '<a href="#" data-root="y">' + svgCanvas.getCurrentDrawing().getCurrentLayerName() + '</a>'; - $$b(context).parentsUntil('#svgcontent > g').andSelf().each(function () { + $$c(context).parentsUntil('#svgcontent > g').andSelf().each(function () { if (this.id) { - _str2 += ' > ' + this.id; + str += ' > ' + this.id; if (this !== context) { linkStr += ' > <a href="#">' + this.id + '</a>'; @@ -31735,12 +30693,12 @@ } } }); - curContext = _str2; + curContext = str; } else { curContext = null; } - $$b('#cur_context_panel').toggle(Boolean(context)).html(linkStr); + $$c('#cur_context_panel').toggle(Boolean(context)).html(linkStr); updateTitle(); }; /** @@ -31749,68 +30707,58 @@ */ - var prepPaints = function prepPaints() { + const prepPaints = function () { paintBox.fill.prep(); paintBox.stroke.prep(); }; - var flyoutFuncs = {}; + const flyoutFuncs = {}; /** * * @returns {void} */ - var setFlyoutTitles = function setFlyoutTitles() { - $$b('.tools_flyout').each(function () { - var shower = $$b('#' + this.id + '_show'); + const setFlyoutTitles = function () { + $$c('.tools_flyout').each(function () { + const shower = $$c('#' + this.id + '_show'); if (shower.data('isLibrary')) { return; } - var tooltips = $$b(this).children().map(function () { + const tooltips = $$c(this).children().map(function () { return this.title; }).get(); shower[0].title = tooltips.join(' / '); }); }; - var allHolders = {}; + const allHolders = {}; /** * @param {PlainObject<string, module:SVGEditor.ToolButton>} holders Key is a selector * @returns {void} */ - var setupFlyouts = function setupFlyouts(holders) { - $$b.each(holders, function (holdSel, btnOpts) { - var _allHolders$holdSel; - + const setupFlyouts = function (holders) { + $$c.each(holders, function (holdSel, btnOpts) { if (!allHolders[holdSel]) { allHolders[holdSel] = []; } - (_allHolders$holdSel = allHolders[holdSel]).push.apply(_allHolders$holdSel, _toConsumableArray(btnOpts)); - - var buttons = $$b(holdSel).children().not('.tool_button_evt_handled'); - var showSel = holdSel + '_show'; - var shower = $$b(showSel); - var def = false; + allHolders[holdSel].push(...btnOpts); + const buttons = $$c(holdSel).children().not('.tool_button_evt_handled'); + const showSel = holdSel + '_show'; + const shower = $$c(showSel); + let def = false; buttons.addClass('tool_button tool_button_evt_handled').unbind('click mousedown mouseup') // may not be necessary .each(function () { // Get this button's options - var idSel = '#' + this.getAttribute('id'); - - var _Object$entries$find = Object.entries(btnOpts).find(function (_ref8) { - var _ref9 = _slicedToArray(_ref8, 2), - _ = _ref9[0], - sel = _ref9[1].sel; - + const idSel = '#' + this.getAttribute('id'); + const [i, opts] = Object.entries(btnOpts).find(([_, { + sel + }]) => { return sel === idSel; - }), - _Object$entries$find2 = _slicedToArray(_Object$entries$find, 2), - i = _Object$entries$find2[0], - opts = _Object$entries$find2[1]; // Remember the function that goes with this ID - + }); // Remember the function that goes with this ID flyoutFuncs[opts.sel] = opts.fn; @@ -31824,17 +30772,13 @@ */ - var flyoutAction = function flyoutAction(ev) { - var options = opts; // Find the currently selected tool if comes from keystroke + const flyoutAction = function (ev) { + let options = opts; // Find the currently selected tool if comes from keystroke if (ev.type === 'keydown') { - var flyoutIsSelected = $$b(options.parent + '_show').hasClass('tool_button_current'); - var currentOperation = $$b(options.parent + '_show').attr('data-curopt'); - Object.entries(holders[opts.parent]).some(function (_ref10) { - var _ref11 = _slicedToArray(_ref10, 2), - j = _ref11[0], - tool = _ref11[1]; - + const flyoutIsSelected = $$c(options.parent + '_show').hasClass('tool_button_current'); + const currentOperation = $$c(options.parent + '_show').attr('data-curopt'); + Object.entries(holders[opts.parent]).some(([j, tool]) => { if (tool.sel !== currentOperation) { return false; } @@ -31852,7 +30796,7 @@ }); } - if ($$b(this).hasClass('disabled')) { + if ($$c(this).hasClass('disabled')) { return false; } @@ -31860,12 +30804,12 @@ options.fn(); } - var icon; + let icon; if (options.icon) { - icon = $$b.getSvgIcon(options.icon, true); + icon = $$c.getSvgIcon(options.icon, true); } else { - icon = $$b(options.sel).children().eq(0).clone(); + icon = $$c(options.sel).children().eq(0).clone(); } icon[0].setAttribute('width', shower.width()); @@ -31876,10 +30820,10 @@ return true; }; - $$b(this).mouseup(flyoutAction); + $$c(this).mouseup(flyoutAction); if (opts.key) { - $$b(document).bind('keydown', opts.key[0] + ' shift+' + opts.key[0], flyoutAction); + $$c(document).bind('keydown', opts.key[0] + ' shift+' + opts.key[0], flyoutAction); } return true; @@ -31892,18 +30836,18 @@ shower.attr('data-curopt', btnOpts[0].sel); } - var timer; // Clicking the "show" icon should set the current mode + let timer; // Clicking the "show" icon should set the current mode shower.mousedown(function (evt) { if (shower.hasClass('disabled')) { return false; } - var holder = $$b(holdSel); - var pos = $$b(showSel).position(); - var l = pos.left + 34; - var w = holder.width() * -1; - var time = holder.data('shown_popop') ? 200 : 0; + const holder = $$c(holdSel); + const pos = $$c(showSel).position(); + const l = pos.left + 34; + const w = holder.width() * -1; + const time = holder.data('shown_popop') ? 200 : 0; timer = setTimeout(function () { // Show corresponding menu if (!shower.data('isLibrary')) { @@ -31920,9 +30864,9 @@ return true; }).mouseup(function (evt) { clearTimeout(timer); - var opt = $$b(this).attr('data-curopt'); // Is library and popped up, so do nothing + const opt = $$c(this).attr('data-curopt'); // Is library and popped up, so do nothing - if (shower.data('isLibrary') && $$b(showSel.replace('_show', '')).is(':visible')) { + if (shower.data('isLibrary') && $$c(showSel.replace('_show', '')).is(':visible')) { toolButtonClick(showSel, true); return; } @@ -31942,10 +30886,10 @@ */ - var makeFlyoutHolder = function makeFlyoutHolder(id, child) { - var div = $$b('<div>', { - "class": 'tools_flyout', - id: id + const makeFlyoutHolder = function (id, child) { + const div = $$c('<div>', { + class: 'tools_flyout', + id }).appendTo('#svg_editor').append(child); return div; }; @@ -31962,29 +30906,27 @@ */ - var addAltDropDown = function addAltDropDown(elemSel, listSel, callback, opts) { - var button = $$b(elemSel); - var dropUp = opts.dropUp; - var list = $$b(listSel); + const addAltDropDown = function (elemSel, listSel, callback, opts) { + const button = $$c(elemSel); + const { + dropUp + } = opts; + const list = $$c(listSel); if (dropUp) { - $$b(elemSel).addClass('dropup'); + $$c(elemSel).addClass('dropup'); } - list.find('li').bind('mouseup', function () { + list.find('li').bind('mouseup', function (...args) { if (opts.seticon) { - setIcon('#cur_' + button[0].id, $$b(this).children()); - $$b(this).addClass('current').siblings().removeClass('current'); + setIcon('#cur_' + button[0].id, $$c(this).children()); + $$c(this).addClass('current').siblings().removeClass('current'); } - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - callback.apply.apply(callback, [this].concat(args)); + callback.apply(this, ...args); }); - var onButton = false; - $$b(window).mouseup(function (evt) { + let onButton = false; + $$c(window).mouseup(function (evt) { if (!onButton) { button.removeClass('down'); list.hide(); @@ -31998,7 +30940,7 @@ }); // const height = list.height(); // Currently unused button.bind('mousedown', function () { - var off = button.offset(); + const off = button.offset(); if (dropUp) { off.top -= list.height(); @@ -32035,7 +30977,7 @@ } }; - var extsPreLang = []; + const extsPreLang = []; /** * @param {external:Window} win * @param {module:svgcanvas.SvgCanvas#event:extension_added} ext @@ -32043,491 +30985,463 @@ * @returns {Promise<void>|void} Resolves to `undefined` */ - var extAdded = /*#__PURE__*/function () { - var _ref12 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee5(win, ext) { - var cbCalled, resizeDone, lang, prepResize, runCallback, btnSelects, svgicons, fallbackObj, altsObj, placementObj, holders; - return regeneratorRuntime.wrap(function _callee5$(_context5) { - while (1) { - switch (_context5.prev = _context5.next) { - case 0: - prepResize = function _prepResize() { - if (resizeTimer) { - clearTimeout(resizeTimer); - resizeTimer = null; - } + const extAdded = async function (win, ext) { + if (!ext) { + return undefined; + } - if (!resizeDone) { - resizeTimer = setTimeout(function () { - resizeDone = true; - setIconSize(editor.pref('iconsize')); - }, 50); - } - }; + let cbCalled = false; + let resizeDone = false; - if (ext) { - _context5.next = 3; - break; + if (ext.langReady) { + if (editor.langChanged) { + // We check for this since the "lang" pref could have been set by storage + const lang = editor.pref('lang'); + await ext.langReady({ + lang, + uiStrings: uiStrings$1, + importLocale: getImportLocale({ + defaultLang: lang, + defaultName: ext.name + }) + }); + loadedExtensionNames.push(ext.name); + } else { + extsPreLang.push(ext); + } + } + /** + * Clear resize timer if present and if not previously performed, + * perform an icon resize. + * @returns {void} + */ + + + function prepResize() { + if (resizeTimer) { + clearTimeout(resizeTimer); + resizeTimer = null; + } + + if (!resizeDone) { + resizeTimer = setTimeout(function () { + resizeDone = true; + setIconSize(editor.pref('iconsize')); + }, 50); + } + } + /** + * + * @returns {void} + */ + + + const runCallback = function () { + if (ext.callback && !cbCalled) { + cbCalled = true; + ext.callback.call(editor); + } + }; + + const btnSelects = []; + /** + * @typedef {PlainObject} module:SVGEditor.ContextTool + * @property {string} panel The ID of the existing panel to which the tool is being added. Required. + * @property {string} id The ID of the actual tool element. Required. + * @property {PlainObject<string, external:jQuery.Function>|PlainObject<"change", external:jQuery.Function>} events DOM event names keyed to associated functions. Example: `{change () { alert('Option was changed') } }`. "change" event is one specifically handled for the "button-select" type. Required. + * @property {string} title The tooltip text that will appear when the user hovers over the tool. Required. + * @property {"tool_button"|"select"|"button-select"|"input"|string} type The type of tool being added. Expected. + * @property {PlainObject<string, string>} [options] List of options and their labels for select tools. Example: `{1: 'One', 2: 'Two', all: 'All' }`. Required by "select" tools. + * @property {string} [container_id] The ID to be given to the tool's container element. + * @property {string} [defval] Default value + * @property {string|Integer} [colnum] Added as part of the option list class. + * @property {string} [label] Label associated with the tool, visible in the UI + * @property {Integer} [size] Value of the "size" attribute of the tool input + * @property {module:jQuerySpinButton.SpinButtonConfig} [spindata] When added to a tool of type "input", this tool becomes a "spinner" which allows the number to be in/decreased. + */ + + if (ext.context_tools) { + $$c.each(ext.context_tools, function (i, tool) { + // Add select tool + const contId = tool.container_id ? ' id="' + tool.container_id + '"' : ''; + let panel = $$c('#' + tool.panel); // create the panel if it doesn't exist + + if (!panel.length) { + panel = $$c('<div>', { + id: tool.panel + }).appendTo('#tools_top'); + } + + let html; // TODO: Allow support for other types, or adding to existing tool + + switch (tool.type) { + case 'tool_button': + { + html = '<div class="tool_button">' + tool.id + '</div>'; + const div = $$c(html).appendTo(panel); + + if (tool.events) { + $$c.each(tool.events, function (evt, func) { + $$c(div).bind(evt, func); + }); } - return _context5.abrupt("return", undefined); - - case 3: - cbCalled = false; - resizeDone = false; - - if (!ext.langReady) { - _context5.next = 14; - break; - } - - if (!editor.langChanged) { - _context5.next = 13; - break; - } - - // We check for this since the "lang" pref could have been set by storage - lang = editor.pref('lang'); - _context5.next = 10; - return ext.langReady({ - lang: lang, - uiStrings: uiStrings$1, - importLocale: getImportLocale({ - defaultLang: lang, - defaultName: ext.name - }) - }); - - case 10: - loadedExtensionNames.push(ext.name); - _context5.next = 14; break; - - case 13: - extsPreLang.push(ext); - - case 14: - /** - * - * @returns {void} - */ - runCallback = function runCallback() { - if (ext.callback && !cbCalled) { - cbCalled = true; - ext.callback.call(editor); - } - }; - - btnSelects = []; - /** - * @typedef {PlainObject} module:SVGEditor.ContextTool - * @property {string} panel The ID of the existing panel to which the tool is being added. Required. - * @property {string} id The ID of the actual tool element. Required. - * @property {PlainObject<string, external:jQuery.Function>|PlainObject<"change", external:jQuery.Function>} events DOM event names keyed to associated functions. Example: `{change () { alert('Option was changed') } }`. "change" event is one specifically handled for the "button-select" type. Required. - * @property {string} title The tooltip text that will appear when the user hovers over the tool. Required. - * @property {"tool_button"|"select"|"button-select"|"input"|string} type The type of tool being added. Expected. - * @property {PlainObject<string, string>} [options] List of options and their labels for select tools. Example: `{1: 'One', 2: 'Two', all: 'All' }`. Required by "select" tools. - * @property {string} [container_id] The ID to be given to the tool's container element. - * @property {string} [defval] Default value - * @property {string|Integer} [colnum] Added as part of the option list class. - * @property {string} [label] Label associated with the tool, visible in the UI - * @property {Integer} [size] Value of the "size" attribute of the tool input - * @property {module:jQuerySpinButton.SpinButtonConfig} [spindata] When added to a tool of type "input", this tool becomes a "spinner" which allows the number to be in/decreased. - */ - - if (ext.context_tools) { - $$b.each(ext.context_tools, function (i, tool) { - // Add select tool - var contId = tool.container_id ? ' id="' + tool.container_id + '"' : ''; - var panel = $$b('#' + tool.panel); // create the panel if it doesn't exist - - if (!panel.length) { - panel = $$b('<div>', { - id: tool.panel - }).appendTo('#tools_top'); - } - - var html; // TODO: Allow support for other types, or adding to existing tool - - switch (tool.type) { - case 'tool_button': - { - html = '<div class="tool_button">' + tool.id + '</div>'; - var div = $$b(html).appendTo(panel); - - if (tool.events) { - $$b.each(tool.events, function (evt, func) { - $$b(div).bind(evt, func); - }); - } - - break; - } - - case 'select': - { - html = '<label' + contId + '>' + '<select id="' + tool.id + '">'; - $$b.each(tool.options, function (val, text) { - var sel = val === tool.defval ? ' selected' : ''; - html += '<option value="' + val + '"' + sel + '>' + text + '</option>'; - }); - html += '</select></label>'; // Creates the tool, hides & adds it, returns the select element - - var sel = $$b(html).appendTo(panel).find('select'); - $$b.each(tool.events, function (evt, func) { - $$b(sel).bind(evt, func); - }); - break; - } - - case 'button-select': - { - html = '<div id="' + tool.id + '" class="dropdown toolset" title="' + tool.title + '">' + '<div id="cur_' + tool.id + '" class="icon_label"></div><button></button></div>'; - var list = $$b('<ul id="' + tool.id + '_opts"></ul>').appendTo('#option_lists'); - - if (tool.colnum) { - list.addClass('optcols' + tool.colnum); - } // Creates the tool, hides & adds it, returns the select element - - /* const dropdown = */ - - - $$b(html).appendTo(panel).children(); - btnSelects.push({ - elem: '#' + tool.id, - list: '#' + tool.id + '_opts', - title: tool.title, - callback: tool.events.change, - cur: '#cur_' + tool.id - }); - break; - } - - case 'input': - { - html = '<label' + contId + '>' + '<span id="' + tool.id + '_label">' + tool.label + ':</span>' + '<input id="' + tool.id + '" title="' + tool.title + '" size="' + (tool.size || '4') + '" value="' + (tool.defval || '') + '" type="text"/></label>'; // Creates the tool, hides & adds it, returns the select element - // Add to given tool.panel - - var inp = $$b(html).appendTo(panel).find('input'); - - if (tool.spindata) { - inp.SpinButton(tool.spindata); - } - - if (tool.events) { - $$b.each(tool.events, function (evt, func) { - inp.bind(evt, func); - }); - } - - break; - } - } - }); - } - - svgicons = ext.svgicons; - - if (!ext.buttons) { - _context5.next = 24; - break; - } - - fallbackObj = {}, altsObj = {}, placementObj = {}, holders = {}; - /** - * @typedef {GenericArray} module:SVGEditor.KeyArray - * @property {string} 0 The key to bind (on `keydown`) - * @property {boolean} 1 Whether to `preventDefault` on the `keydown` event - * @property {boolean} 2 Not apparently in use (NoDisableInInput) - */ - - /** - * @typedef {string|module:SVGEditor.KeyArray} module:SVGEditor.Key - */ - - /** - * @typedef {PlainObject} module:SVGEditor.Button - * @property {string} id A unique identifier for this button. If SVG icons are used, this must match the ID used in the icon file. Required. - * @property {"mode_flyout"|"mode"|"context"|"app_menu"} type Type of button. Required. - * @property {string} title The tooltip text that will appear when the user hovers over the icon. Required. - * @property {PlainObject<string, external:jQuery.Function>|PlainObject<"click", external:jQuery.Function>} events DOM event names with associated functions. Example: `{click () { alert('Button was clicked') } }`. Click is used with `includeWith` and `type` of "mode_flyout" (and "mode"); any events may be added if `list` is not present. Expected. - * @property {string} panel The ID of the context panel to be included, if type is "context". Required only if type is "context". - * @property {string} icon The file path to the raster version of the icon image source. Required only if no `svgicons` is supplied from [ExtensionInitResponse]{@link module:svgcanvas.ExtensionInitResponse}. - * @property {string} [svgicon] If absent, will utilize the button "id"; used to set "placement" on the `svgIcons` call - * @property {string} [list] Points to the "id" of a `context_tools` item of type "button-select" into which the button will be added as a panel list item - * @property {Integer} [position] The numeric index for placement; defaults to last position (as of the time of extension addition) if not present. For use with {@link http://api.jquery.com/eq/}. - * @property {boolean} [isDefault] Whether or not the button is the default. Used with `list`. - * @property {PlainObject} [includeWith] Object with flyout menu data - * @property {boolean} [includeWith.isDefault] Indicates whether button is default in flyout list or not. - * @property {string} includeWith.button jQuery selector of the existing button to be joined. Example: '#tool_line'. Required if `includeWith` is used. - * @property {"last"|Integer} [includeWith.position] Position of icon in flyout list; will be added to end if not indicated. Integer is for use with {@link http://api.jquery.com/eq/}. - * @property {module:SVGEditor.Key} [key] The key to bind to the button - */ - // Add buttons given by extension - - $$b.each(ext.buttons, function (i, - /** @type {module:SVGEditor.Button} */ - btn) { - var id = btn.id; - var num = i; // Give button a unique ID - - while ($$b('#' + id).length) { - id = btn.id + '_' + ++num; - } - - var icon; - - if (!svgicons) { - icon = $$b('<img src="' + btn.icon + (btn.title ? '" alt="' + btn.title : '') + '">'); - } else { - fallbackObj[id] = btn.icon; - altsObj[id] = btn.title; - var svgicon = btn.svgicon || btn.id; - - if (btn.type === 'app_menu') { - placementObj['#' + id + ' > div'] = svgicon; - } else { - placementObj['#' + id] = svgicon; - } - } - - var cls, parent; // Set button up according to its type - - switch (btn.type) { - case 'mode_flyout': - case 'mode': - cls = 'tool_button'; - parent = '#tools_left'; - break; - - case 'context': - cls = 'tool_button'; - parent = '#' + btn.panel; // create the panel if it doesn't exist - - if (!$$b(parent).length) { - $$b('<div>', { - id: btn.panel - }).appendTo('#tools_top'); - } - - break; - - case 'app_menu': - cls = ''; - parent = '#main_menu ul'; - break; - } - - var flyoutHolder, showBtn, refData, refBtn; - var button = $$b(btn.list || btn.type === 'app_menu' ? '<li/>' : '<div/>').attr('id', id).attr('title', btn.title).addClass(cls); - - if (!btn.includeWith && !btn.list) { - if ('position' in btn) { - if ($$b(parent).children().eq(btn.position).length) { - $$b(parent).children().eq(btn.position).before(button); - } else { - $$b(parent).children().last().after(button); - } - } else { - button.appendTo(parent); - } - - if (btn.type === 'mode_flyout') { - // Add to flyout menu / make flyout menu - // const opts = btn.includeWith; - // // opts.button, default, position - refBtn = $$b(button); - flyoutHolder = refBtn.parent(); // Create a flyout menu if there isn't one already - - var tlsId; - - if (!refBtn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - tlsId = refBtn[0].id.replace('tool_', 'tools_'); - showBtn = refBtn.clone().attr('id', tlsId + '_show').append($$b('<div>', { - "class": 'flyout_arrow_horiz' - })); - refBtn.before(showBtn); // Create a flyout div - - flyoutHolder = makeFlyoutHolder(tlsId, refBtn); - flyoutHolder.data('isLibrary', true); - showBtn.data('isLibrary', true); - } // refData = Actions.getButtonData(opts.button); - - - placementObj['#' + tlsId + '_show'] = btn.id; // TODO: Find way to set the current icon using the iconloader if this is not default - // Include data for extension button as well as ref button - - /* curH = */ - - holders['#' + flyoutHolder[0].id] = [{ - sel: '#' + id, - fn: btn.events.click, - icon: btn.id, - // key: btn.key, - isDefault: true - }]; // , refData - // - // // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} - // - // const pos = ('position' in opts)?opts.position:'last'; - // const len = flyoutHolder.children().length; - // - // // Add at given position or end - // if (!isNaN(pos) && pos >= 0 && pos < len) { - // flyoutHolder.children().eq(pos).before(button); - // } else { - // flyoutHolder.append(button); - // curH.reverse(); - // } - } else if (btn.type === 'app_menu') { - button.append('<div>').append(btn.title); - } - } else if (btn.list) { - // Add button to list - button.addClass('push_button'); - $$b('#' + btn.list + '_opts').append(button); - - if (btn.isDefault) { - $$b('#cur_' + btn.list).append(button.children().clone()); - - var _svgicon = btn.svgicon || btn.id; - - placementObj['#cur_' + btn.list] = _svgicon; - } - } else if (btn.includeWith) { - // Add to flyout menu / make flyout menu - var opts = btn.includeWith; // opts.button, default, position - - refBtn = $$b(opts.button); - flyoutHolder = refBtn.parent(); // Create a flyout menu if there isn't one already - - var _tlsId; - - if (!refBtn.parent().hasClass('tools_flyout')) { - // Create flyout placeholder - _tlsId = refBtn[0].id.replace('tool_', 'tools_'); - showBtn = refBtn.clone().attr('id', _tlsId + '_show').append($$b('<div>', { - "class": 'flyout_arrow_horiz' - })); - refBtn.before(showBtn); // Create a flyout div - - flyoutHolder = makeFlyoutHolder(_tlsId, refBtn); - } - - refData = Actions.getButtonData(opts.button); - - if (opts.isDefault) { - placementObj['#' + _tlsId + '_show'] = btn.id; - } // TODO: Find way to set the current icon using the iconloader if this is not default - // Include data for extension button as well as ref button - - - var curH = holders['#' + flyoutHolder[0].id] = [{ - sel: '#' + id, - fn: btn.events.click, - icon: btn.id, - key: btn.key, - isDefault: Boolean(btn.includeWith && btn.includeWith.isDefault) - }, refData]; // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} - - var pos = 'position' in opts ? opts.position : 'last'; - var len = flyoutHolder.children().length; // Add at given position or end - - if (!isNaN(pos) && pos >= 0 && pos < len) { - flyoutHolder.children().eq(pos).before(button); - } else { - flyoutHolder.append(button); - curH.reverse(); - } - } - - if (!svgicons) { - button.append(icon); - } - - if (!btn.list) { - // Add given events to button - $$b.each(btn.events, function (name, func) { - if (name === 'click' && btn.type === 'mode') { - // `touch.js` changes `touchstart` to `mousedown`, - // so we must map extension click events as well - if (isTouch() && name === 'click') { - name = 'mousedown'; - } - - if (btn.includeWith) { - button.bind(name, func); - } else { - button.bind(name, function () { - if (toolButtonClick(button)) { - func(); - } - }); - } - - if (btn.key) { - $$b(document).bind('keydown', btn.key, func); - - if (btn.title) { - button.attr('title', btn.title + ' [' + btn.key + ']'); - } - } - } else { - button.bind(name, func); - } - }); - } - - setupFlyouts(holders); - }); - $$b.each(btnSelects, function () { - addAltDropDown(this.elem, this.list, this.callback, { - seticon: true - }); + } + + case 'select': + { + html = '<label' + contId + '>' + '<select id="' + tool.id + '">'; + $$c.each(tool.options, function (val, text) { + const sel = val === tool.defval ? ' selected' : ''; + html += '<option value="' + val + '"' + sel + '>' + text + '</option>'; }); + html += '</select></label>'; // Creates the tool, hides & adds it, returns the select element - if (!svgicons) { - _context5.next = 24; - break; + const sel = $$c(html).appendTo(panel).find('select'); + $$c.each(tool.events, function (evt, func) { + $$c(sel).bind(evt, func); + }); + break; + } + + case 'button-select': + { + html = '<div id="' + tool.id + '" class="dropdown toolset" title="' + tool.title + '">' + '<div id="cur_' + tool.id + '" class="icon_label"></div><button></button></div>'; + const list = $$c('<ul id="' + tool.id + '_opts"></ul>').appendTo('#option_lists'); + + if (tool.colnum) { + list.addClass('optcols' + tool.colnum); + } // Creates the tool, hides & adds it, returns the select element + + /* const dropdown = */ + + + $$c(html).appendTo(panel).children(); + btnSelects.push({ + elem: '#' + tool.id, + list: '#' + tool.id + '_opts', + title: tool.title, + callback: tool.events.change, + cur: '#cur_' + tool.id + }); + break; + } + + case 'input': + { + html = '<label' + contId + '>' + '<span id="' + tool.id + '_label">' + tool.label + ':</span>' + '<input id="' + tool.id + '" title="' + tool.title + '" size="' + (tool.size || '4') + '" value="' + (tool.defval || '') + '" type="text"/></label>'; // Creates the tool, hides & adds it, returns the select element + // Add to given tool.panel + + const inp = $$c(html).appendTo(panel).find('input'); + + if (tool.spindata) { + inp.SpinButton(tool.spindata); } - return _context5.abrupt("return", new Promise(function (resolve, reject) { - // eslint-disable-line promise/avoid-new - $$b.svgIcons(svgicons, { - w: 24, - h: 24, - id_match: false, - no_img: !isWebkit(), - fallback: fallbackObj, - placement: placementObj, - callback: function callback(icons) { - // Non-ideal hack to make the icon match the current size - // if (curPrefs.iconsize && curPrefs.iconsize !== 'm') { - if (editor.pref('iconsize') !== 'm') { - prepResize(); - } - - runCallback(); - resolve(); - } + if (tool.events) { + $$c.each(tool.events, function (evt, func) { + inp.bind(evt, func); }); - })); + } - case 24: - return _context5.abrupt("return", runCallback()); + break; + } + } + }); + } - case 25: - case "end": - return _context5.stop(); + const { + svgicons + } = ext; + + if (ext.buttons) { + const fallbackObj = {}, + altsObj = {}, + placementObj = {}, + holders = {}; + /** + * @typedef {GenericArray} module:SVGEditor.KeyArray + * @property {string} 0 The key to bind (on `keydown`) + * @property {boolean} 1 Whether to `preventDefault` on the `keydown` event + * @property {boolean} 2 Not apparently in use (NoDisableInInput) + */ + + /** + * @typedef {string|module:SVGEditor.KeyArray} module:SVGEditor.Key + */ + + /** + * @typedef {PlainObject} module:SVGEditor.Button + * @property {string} id A unique identifier for this button. If SVG icons are used, this must match the ID used in the icon file. Required. + * @property {"mode_flyout"|"mode"|"context"|"app_menu"} type Type of button. Required. + * @property {string} title The tooltip text that will appear when the user hovers over the icon. Required. + * @property {PlainObject<string, external:jQuery.Function>|PlainObject<"click", external:jQuery.Function>} events DOM event names with associated functions. Example: `{click () { alert('Button was clicked') } }`. Click is used with `includeWith` and `type` of "mode_flyout" (and "mode"); any events may be added if `list` is not present. Expected. + * @property {string} panel The ID of the context panel to be included, if type is "context". Required only if type is "context". + * @property {string} icon The file path to the raster version of the icon image source. Required only if no `svgicons` is supplied from [ExtensionInitResponse]{@link module:svgcanvas.ExtensionInitResponse}. + * @property {string} [svgicon] If absent, will utilize the button "id"; used to set "placement" on the `svgIcons` call + * @property {string} [list] Points to the "id" of a `context_tools` item of type "button-select" into which the button will be added as a panel list item + * @property {Integer} [position] The numeric index for placement; defaults to last position (as of the time of extension addition) if not present. For use with {@link http://api.jquery.com/eq/}. + * @property {boolean} [isDefault] Whether or not the button is the default. Used with `list`. + * @property {PlainObject} [includeWith] Object with flyout menu data + * @property {boolean} [includeWith.isDefault] Indicates whether button is default in flyout list or not. + * @property {string} includeWith.button jQuery selector of the existing button to be joined. Example: '#tool_line'. Required if `includeWith` is used. + * @property {"last"|Integer} [includeWith.position] Position of icon in flyout list; will be added to end if not indicated. Integer is for use with {@link http://api.jquery.com/eq/}. + * @property {module:SVGEditor.Key} [key] The key to bind to the button + */ + // Add buttons given by extension + + $$c.each(ext.buttons, function (i, + /** @type {module:SVGEditor.Button} */ + btn) { + let { + id + } = btn; + let num = i; // Give button a unique ID + + while ($$c('#' + id).length) { + id = btn.id + '_' + ++num; + } + + let icon; + + if (!svgicons) { + icon = $$c('<img src="' + btn.icon + (btn.title ? '" alt="' + btn.title : '') + '">'); + } else { + fallbackObj[id] = btn.icon; + altsObj[id] = btn.title; + const svgicon = btn.svgicon || btn.id; + + if (btn.type === 'app_menu') { + placementObj['#' + id + ' > div'] = svgicon; + } else { + placementObj['#' + id] = svgicon; } } - }, _callee5); - })); - return function extAdded(_x3, _x4) { - return _ref12.apply(this, arguments); - }; - }(); + let cls, parent; // Set button up according to its type + + switch (btn.type) { + case 'mode_flyout': + case 'mode': + cls = 'tool_button'; + parent = '#tools_left'; + break; + + case 'context': + cls = 'tool_button'; + parent = '#' + btn.panel; // create the panel if it doesn't exist + + if (!$$c(parent).length) { + $$c('<div>', { + id: btn.panel + }).appendTo('#tools_top'); + } + + break; + + case 'app_menu': + cls = ''; + parent = '#main_menu ul'; + break; + } + + let flyoutHolder, showBtn, refData, refBtn; + const button = $$c(btn.list || btn.type === 'app_menu' ? '<li/>' : '<div/>').attr('id', id).attr('title', btn.title).addClass(cls); + + if (!btn.includeWith && !btn.list) { + if ('position' in btn) { + if ($$c(parent).children().eq(btn.position).length) { + $$c(parent).children().eq(btn.position).before(button); + } else { + $$c(parent).children().last().after(button); + } + } else { + button.appendTo(parent); + } + + if (btn.type === 'mode_flyout') { + // Add to flyout menu / make flyout menu + // const opts = btn.includeWith; + // // opts.button, default, position + refBtn = $$c(button); + flyoutHolder = refBtn.parent(); // Create a flyout menu if there isn't one already + + let tlsId; + + if (!refBtn.parent().hasClass('tools_flyout')) { + // Create flyout placeholder + tlsId = refBtn[0].id.replace('tool_', 'tools_'); + showBtn = refBtn.clone().attr('id', tlsId + '_show').append($$c('<div>', { + class: 'flyout_arrow_horiz' + })); + refBtn.before(showBtn); // Create a flyout div + + flyoutHolder = makeFlyoutHolder(tlsId, refBtn); + flyoutHolder.data('isLibrary', true); + showBtn.data('isLibrary', true); + } // refData = Actions.getButtonData(opts.button); + + + placementObj['#' + tlsId + '_show'] = btn.id; // TODO: Find way to set the current icon using the iconloader if this is not default + // Include data for extension button as well as ref button + + /* curH = */ + + holders['#' + flyoutHolder[0].id] = [{ + sel: '#' + id, + fn: btn.events.click, + icon: btn.id, + // key: btn.key, + isDefault: true + }]; // , refData + // + // // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} + // + // const pos = ('position' in opts)?opts.position:'last'; + // const len = flyoutHolder.children().length; + // + // // Add at given position or end + // if (!isNaN(pos) && pos >= 0 && pos < len) { + // flyoutHolder.children().eq(pos).before(button); + // } else { + // flyoutHolder.append(button); + // curH.reverse(); + // } + } else if (btn.type === 'app_menu') { + button.append('<div>').append(btn.title); + } + } else if (btn.list) { + // Add button to list + button.addClass('push_button'); + $$c('#' + btn.list + '_opts').append(button); + + if (btn.isDefault) { + $$c('#cur_' + btn.list).append(button.children().clone()); + const svgicon = btn.svgicon || btn.id; + placementObj['#cur_' + btn.list] = svgicon; + } + } else if (btn.includeWith) { + // Add to flyout menu / make flyout menu + const opts = btn.includeWith; // opts.button, default, position + + refBtn = $$c(opts.button); + flyoutHolder = refBtn.parent(); // Create a flyout menu if there isn't one already + + let tlsId; + + if (!refBtn.parent().hasClass('tools_flyout')) { + // Create flyout placeholder + tlsId = refBtn[0].id.replace('tool_', 'tools_'); + showBtn = refBtn.clone().attr('id', tlsId + '_show').append($$c('<div>', { + class: 'flyout_arrow_horiz' + })); + refBtn.before(showBtn); // Create a flyout div + + flyoutHolder = makeFlyoutHolder(tlsId, refBtn); + } + + refData = Actions.getButtonData(opts.button); + + if (opts.isDefault) { + placementObj['#' + tlsId + '_show'] = btn.id; + } // TODO: Find way to set the current icon using the iconloader if this is not default + // Include data for extension button as well as ref button + + + const curH = holders['#' + flyoutHolder[0].id] = [{ + sel: '#' + id, + fn: btn.events.click, + icon: btn.id, + key: btn.key, + isDefault: Boolean(btn.includeWith && btn.includeWith.isDefault) + }, refData]; // {sel:'#tool_rect', fn: clickRect, evt: 'mouseup', key: 4, parent: '#tools_rect', icon: 'rect'} + + const pos = 'position' in opts ? opts.position : 'last'; + const len = flyoutHolder.children().length; // Add at given position or end + + if (!isNaN(pos) && pos >= 0 && pos < len) { + flyoutHolder.children().eq(pos).before(button); + } else { + flyoutHolder.append(button); + curH.reverse(); + } + } + + if (!svgicons) { + button.append(icon); + } + + if (!btn.list) { + // Add given events to button + $$c.each(btn.events, function (name, func) { + if (name === 'click' && btn.type === 'mode') { + // `touch.js` changes `touchstart` to `mousedown`, + // so we must map extension click events as well + if (isTouch() && name === 'click') { + name = 'mousedown'; + } + + if (btn.includeWith) { + button.bind(name, func); + } else { + button.bind(name, function () { + if (toolButtonClick(button)) { + func(); + } + }); + } + + if (btn.key) { + $$c(document).bind('keydown', btn.key, func); + + if (btn.title) { + button.attr('title', btn.title + ' [' + btn.key + ']'); + } + } + } else { + button.bind(name, func); + } + }); + } + + setupFlyouts(holders); + }); + $$c.each(btnSelects, function () { + addAltDropDown(this.elem, this.list, this.callback, { + seticon: true + }); + }); + + if (svgicons) { + return new Promise((resolve, reject) => { + // eslint-disable-line promise/avoid-new + $$c.svgIcons(svgicons, { + w: 24, + h: 24, + id_match: false, + no_img: !isWebkit(), + fallback: fallbackObj, + placement: placementObj, + + callback(icons) { + // Non-ideal hack to make the icon match the current size + // if (curPrefs.iconsize && curPrefs.iconsize !== 'm') { + if (editor.pref('iconsize') !== 'm') { + prepResize(); + } + + runCallback(); + resolve(); + } + + }); + }); + } + } + + return runCallback(); + }; /** * @param {string} color * @param {Float} opac @@ -32536,19 +31450,19 @@ */ - var getPaint = function getPaint(color, opac, type) { + const getPaint = function (color, opac, type) { // update the editor's fill paint - var opts = { + const opts = { alpha: opac }; if (color.startsWith('url(#')) { - var refElem = svgCanvas.getRefElem(color); + let refElem = svgCanvas.getRefElem(color); if (refElem) { refElem = refElem.cloneNode(true); } else { - refElem = $$b('#' + type + '_color defs *')[0]; + refElem = $$c('#' + type + '_color defs *')[0]; } opts[refElem.tagName] = refElem; @@ -32558,7 +31472,7 @@ opts.solidColor = 'none'; } - return new $$b.jGraduate.Paint(opts); + return new $$c.jGraduate.Paint(opts); }; // $('#text').focus(function () { textBeingEntered = true; }); // $('#text').blur(function () { textBeingEntered = false; }); // bind the selected event to our function that handles updates to the UI @@ -32575,7 +31489,9 @@ return; } - var exportWindowName = data.exportWindowName; + const { + exportWindowName + } = data; if (exportWindowName) { exportWindow = window.open('', exportWindowName); // A hack to get the window via JSON-able name without opening a new one @@ -32583,7 +31499,7 @@ if (!exportWindow || exportWindow.closed) { /* await */ - $$b.alert(uiStrings$1.notification.popupWindowBlocked); + $$c.alert(uiStrings$1.notification.popupWindowBlocked); return; } @@ -32600,46 +31516,47 @@ * @listens module:svgcanvas.SvgCanvas#event:updateCanvas * @returns {void} */ - function (win, _ref13) { - var center = _ref13.center, - newCtr = _ref13.newCtr; + function (win, { + center, + newCtr + }) { updateCanvas(center, newCtr); }); svgCanvas.bind('contextset', contextChanged); svgCanvas.bind('extension_added', extAdded); - svgCanvas.textActions.setInputElem($$b('#text')[0]); - var str = '<div class="palette_item" data-rgb="none"></div>'; - $$b.each(palette, function (i, item) { + svgCanvas.textActions.setInputElem($$c('#text')[0]); + let str = '<div class="palette_item" data-rgb="none"></div>'; + $$c.each(palette, function (i, item) { str += '<div class="palette_item" style="background-color: ' + item + ';" data-rgb="' + item + '"></div>'; }); - $$b('#palette').append(str); // Set up editor background functionality + $$c('#palette').append(str); // Set up editor background functionality - var colorBlocks = ['#FFF', '#888', '#000', 'chessboard']; + const colorBlocks = ['#FFF', '#888', '#000', 'chessboard']; str = ''; - $$b.each(colorBlocks, function (i, e) { + $$c.each(colorBlocks, function (i, e) { if (e === 'chessboard') { str += '<div class="color_block" data-bgcolor="' + e + '" style="background-image:url(data:image/gif;base64,R0lGODlhEAAQAIAAAP///9bW1iH5BAAAAAAALAAAAAAQABAAAAIfjG+gq4jM3IFLJgpswNly/XkcBpIiVaInlLJr9FZWAQA7);"></div>'; } else { str += '<div class="color_block" data-bgcolor="' + e + '" style="background-color:' + e + ';"></div>'; } }); - $$b('#bg_blocks').append(str); - var blocks = $$b('#bg_blocks div'); - var curBg = 'cur_background'; + $$c('#bg_blocks').append(str); + const blocks = $$c('#bg_blocks div'); + const curBg = 'cur_background'; blocks.each(function () { - var blk = $$b(this); + const blk = $$c(this); blk.click(function () { blocks.removeClass(curBg); - $$b(this).addClass(curBg); + $$c(this).addClass(curBg); }); }); setBackground(editor.pref('bkgd_color'), editor.pref('bkgd_url')); - $$b('#image_save_opts input').val([editor.pref('img_save')]); + $$c('#image_save_opts input').val([editor.pref('img_save')]); /** * @type {module:jQuerySpinButton.ValueCallback} */ - var changeRectRadius = function changeRectRadius(ctl) { + const changeRectRadius = function (ctl) { svgCanvas.setRectRadius(ctl.value); }; /** @@ -32647,7 +31564,7 @@ */ - var changeFontSize = function changeFontSize(ctl) { + const changeFontSize = function (ctl) { svgCanvas.setFontSize(ctl.value); }; /** @@ -32655,8 +31572,8 @@ */ - var changeStrokeWidth = function changeStrokeWidth(ctl) { - var val = ctl.value; + const changeStrokeWidth = function (ctl) { + let val = ctl.value; if (val === 0 && selectedElement && ['line', 'polyline'].includes(selectedElement.nodeName)) { val = ctl.value = 1; @@ -32669,9 +31586,9 @@ */ - var changeRotationAngle = function changeRotationAngle(ctl) { + const changeRotationAngle = function (ctl) { svgCanvas.setRotationAngle(ctl.value); - $$b('#tool_reorient').toggleClass('disabled', Number.parseInt(ctl.value) === 0); + $$c('#tool_reorient').toggleClass('disabled', Number.parseInt(ctl.value) === 0); }; /** * @param {external:jQuery.fn.SpinButton} ctl Spin Button @@ -32680,15 +31597,15 @@ */ - var changeOpacity = function changeOpacity(ctl, val) { + const changeOpacity = function (ctl, val) { if (isNullish(val)) { val = ctl.value; } - $$b('#group_opacity').val(val); + $$c('#group_opacity').val(val); if (!ctl || !ctl.handle) { - $$b('#opac_slider').slider('option', 'value', val); + $$c('#opac_slider').slider('option', 'value', val); } svgCanvas.setOpacity(val / 100); @@ -32701,16 +31618,16 @@ */ - var changeBlur = function changeBlur(ctl, val, noUndo) { + const changeBlur = function (ctl, val, noUndo) { if (isNullish(val)) { val = ctl.value; } - $$b('#blur').val(val); - var complete = false; + $$c('#blur').val(val); + let complete = false; if (!ctl || !ctl.handle) { - $$b('#blur_slider').slider('option', 'value', val); + $$c('#blur_slider').slider('option', 'value', val); complete = true; } @@ -32721,114 +31638,85 @@ } }; - $$b('#stroke_style').change(function () { - svgCanvas.setStrokeAttr('stroke-dasharray', $$b(this).val()); + $$c('#stroke_style').change(function () { + svgCanvas.setStrokeAttr('stroke-dasharray', $$c(this).val()); operaRepaint(); }); - $$b('#stroke_linejoin').change(function () { - svgCanvas.setStrokeAttr('stroke-linejoin', $$b(this).val()); + $$c('#stroke_linejoin').change(function () { + svgCanvas.setStrokeAttr('stroke-linejoin', $$c(this).val()); operaRepaint(); }); // Lose focus for select elements when changed (Allows keyboard shortcuts to work better) - $$b('select').change(function () { - $$b(this).blur(); + $$c('select').change(function () { + $$c(this).blur(); }); // fired when user wants to move elements to another layer - var promptMoveLayerOnce = false; - $$b('#selLayerNames').change( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee6() { - var destLayer, confirmStr, moveToLayer, ok; - return regeneratorRuntime.wrap(function _callee6$(_context6) { - while (1) { - switch (_context6.prev = _context6.next) { - case 0: - destLayer = this.options[this.selectedIndex].value; - confirmStr = uiStrings$1.notification.QmoveElemsToLayer.replace('%s', destLayer); - /** - * @param {boolean} ok - * @returns {void} - */ + let promptMoveLayerOnce = false; + $$c('#selLayerNames').change(async function () { + const destLayer = this.options[this.selectedIndex].value; + const confirmStr = uiStrings$1.notification.QmoveElemsToLayer.replace('%s', destLayer); + /** + * @param {boolean} ok + * @returns {void} + */ - moveToLayer = function moveToLayer(ok) { - if (!ok) { - return; - } - - promptMoveLayerOnce = true; - svgCanvas.moveSelectedToLayer(destLayer); - svgCanvas.clearSelection(); - populateLayers(); - }; - - if (!destLayer) { - _context6.next = 14; - break; - } - - if (!promptMoveLayerOnce) { - _context6.next = 8; - break; - } - - moveToLayer(true); - _context6.next = 14; - break; - - case 8: - _context6.next = 10; - return $$b.confirm(confirmStr); - - case 10: - ok = _context6.sent; - - if (ok) { - _context6.next = 13; - break; - } - - return _context6.abrupt("return"); - - case 13: - moveToLayer(true); - - case 14: - case "end": - return _context6.stop(); - } + const moveToLayer = function (ok) { + if (!ok) { + return; } - }, _callee6, this); - }))); - $$b('#font_family').change(function () { + + promptMoveLayerOnce = true; + svgCanvas.moveSelectedToLayer(destLayer); + svgCanvas.clearSelection(); + populateLayers(); + }; + + if (destLayer) { + if (promptMoveLayerOnce) { + moveToLayer(true); + } else { + const ok = await $$c.confirm(confirmStr); + + if (!ok) { + return; + } + + moveToLayer(true); + } + } + }); + $$c('#font_family').change(function () { svgCanvas.setFontFamily(this.value); }); - $$b('#seg_type').change(function () { - svgCanvas.setSegType($$b(this).val()); + $$c('#seg_type').change(function () { + svgCanvas.setSegType($$c(this).val()); }); - $$b('#text').bind('keyup input', function () { + $$c('#text').bind('keyup input', function () { svgCanvas.setTextContent(this.value); }); - $$b('#image_url').change(function () { + $$c('#image_url').change(function () { setImageURL(this.value); }); - $$b('#link_url').change(function () { + $$c('#link_url').change(function () { if (this.value.length) { svgCanvas.setLinkURL(this.value); } else { svgCanvas.removeHyperlink(); } }); - $$b('#g_title').change(function () { + $$c('#g_title').change(function () { svgCanvas.setGroupTitle(this.value); }); - $$b('.attr_changer').change(function () { - var attr = this.getAttribute('data-attr'); - var val = this.value; - var valid = isValidUnit(attr, val, selectedElement); + $$c('.attr_changer').change(function () { + const attr = this.getAttribute('data-attr'); + let val = this.value; + const valid = isValidUnit(attr, val, selectedElement); if (!valid) { this.value = selectedElement.getAttribute(attr); /* await */ - $$b.alert(uiStrings$1.notification.invalidAttrValGiven); + $$c.alert(uiStrings$1.notification.invalidAttrValGiven); return false; } @@ -32837,7 +31725,7 @@ val = svgCanvas.convertToNum(attr, val); } else if (curConfig.baseUnit !== 'px') { // Convert unitless value to one with given unit - var unitData = getTypeMap(); + const unitData = getTypeMap(); if (selectedElement[attr] || svgCanvas.getMode() === 'pathedit' || attr === 'x' || attr === 'y') { val *= unitData[curConfig.baseUnit]; @@ -32848,7 +31736,7 @@ if (attr === 'id') { - var elem = selectedElement; + const elem = selectedElement; svgCanvas.clearSelection(); elem.id = val; svgCanvas.addToSelection([elem], true); @@ -32860,22 +31748,22 @@ return true; }); // Prevent selection of elements when shift-clicking - $$b('#palette').mouseover(function () { - var inp = $$b('<input type="hidden">'); - $$b(this).append(inp); + $$c('#palette').mouseover(function () { + const inp = $$c('<input type="hidden">'); + $$c(this).append(inp); inp.focus().remove(); }); - $$b('.palette_item').mousedown(function (evt) { + $$c('.palette_item').mousedown(function (evt) { // shift key or right click for stroke - var picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill'; - var color = $$b(this).data('rgb'); - var paint; // Webkit-based browsers returned 'initial' here for no stroke + const picker = evt.shiftKey || evt.button === 2 ? 'stroke' : 'fill'; + let color = $$c(this).data('rgb'); + let paint; // Webkit-based browsers returned 'initial' here for no stroke if (color === 'none' || color === 'transparent' || color === 'initial') { color = 'none'; - paint = new $$b.jGraduate.Paint(); + paint = new $$c.jGraduate.Paint(); } else { - paint = new $$b.jGraduate.Paint({ + paint = new $$c.jGraduate.Paint({ alpha: 100, solidColor: color.substr(1) }); @@ -32892,17 +31780,17 @@ }).bind('contextmenu', function (e) { e.preventDefault(); }); - $$b('#toggle_stroke_tools').on('click', function () { - $$b('#tools_bottom').toggleClass('expanded'); + $$c('#toggle_stroke_tools').on('click', function () { + $$c('#tools_bottom').toggleClass('expanded'); }); (function () { - var wArea = workarea[0]; - var lastX = null, + const wArea = workarea[0]; + let lastX = null, lastY = null, panning = false, keypan = false; - $$b('#svgcanvas').bind('mousemove mouseup', function (evt) { + $$c('#svgcanvas').bind('mousemove mouseup', function (evt) { if (panning === false) { return true; } @@ -32927,10 +31815,10 @@ return true; }); - $$b(window).mouseup(function () { + $$c(window).mouseup(function () { panning = false; }); - $$b(document).bind('keydown', 'space', function (evt) { + $$c(document).bind('keydown', 'space', function (evt) { svgCanvas.spaceKey = keypan = true; evt.preventDefault(); }).bind('keyup', 'space', function (evt) { @@ -32957,13 +31845,13 @@ })(); (function () { - var button = $$b('#main_icon'); - var overlay = $$b('#main_icon span'); - var list = $$b('#main_menu'); - var onButton = false; - var height = 0; - var jsHover = true; - var setClick = false; + const button = $$c('#main_icon'); + const overlay = $$c('#main_icon span'); + const list = $$c('#main_menu'); + let onButton = false; + let height = 0; + let jsHover = true; + let setClick = false; /* // Currently unused const hideMenu = function () { @@ -32971,7 +31859,7 @@ }; */ - $$b(window).mouseup(function (evt) { + $$c(window).mouseup(function (evt) { if (!onButton) { button.removeClass('buttondown'); // do not hide if it was the file input as that input needs to be visible // for its change event to fire @@ -32980,7 +31868,7 @@ list.fadeOut(200); } else if (!setClick) { setClick = true; - $$b(evt.target).click(function () { + $$c(evt.target).click(function () { list.css('margin-left', '-9999px').show(); }); } @@ -32989,10 +31877,10 @@ onButton = false; }).mousedown(function (evt) { // $('.contextMenu').hide(); - var islib = $$b(evt.target).closest('div.tools_flyout, .contextMenu').length; + const islib = $$c(evt.target).closest('div.tools_flyout, .contextMenu').length; if (!islib) { - $$b('.tools_flyout:visible,.contextMenu').fadeOut(250); + $$c('.tools_flyout:visible,.contextMenu').fadeOut(250); } }); overlay.bind('mousedown', function () { @@ -33006,7 +31894,7 @@ list.css('height', 0).animate({ - height: height + height }, 200); onButton = true; } else { @@ -33019,10 +31907,10 @@ }).mouseout(function () { onButton = false; }); - var listItems = $$b('#main_menu li'); // Check if JS method of hovering needs to be used (Webkit bug) + const listItems = $$c('#main_menu li'); // Check if JS method of hovering needs to be used (Webkit bug) listItems.mouseover(function () { - jsHover = $$b(this).css('background-color') === 'rgba(0, 0, 0, 0)'; + jsHover = $$c(this).css('background-color') === 'rgba(0, 0, 0, 0)'; listItems.unbind('mouseover'); if (jsHover) { @@ -33055,24 +31943,24 @@ editor.addDropDown = function (elem, callback, dropUp) { - if (!$$b(elem).length) { + if (!$$c(elem).length) { return; } // Quit if called on non-existent element - var button = $$b(elem).find('button'); - var list = $$b(elem).find('ul').attr('id', $$b(elem)[0].id + '-list'); + const button = $$c(elem).find('button'); + const list = $$c(elem).find('ul').attr('id', $$c(elem)[0].id + '-list'); if (dropUp) { - $$b(elem).addClass('dropup'); + $$c(elem).addClass('dropup'); } else { // Move list to place where it can overflow container - $$b('#option_lists').append(list); + $$c('#option_lists').append(list); } list.find('li').bind('mouseup', callback); - var onButton = false; - $$b(window).mouseup(function (evt) { + let onButton = false; + $$c(window).mouseup(function (evt) { if (!onButton) { button.removeClass('down'); list.hide(); @@ -33083,7 +31971,7 @@ button.bind('mousedown', function () { if (!button.hasClass('down')) { if (!dropUp) { - var pos = $$b(elem).position(); + const pos = $$c(elem).position(); list.css({ top: pos.top + 24, left: pos.left - 10 @@ -33105,50 +31993,57 @@ }; editor.addDropDown('#font_family_dropdown', function () { - $$b('#font_family').val($$b(this).text()).change(); + $$c('#font_family').val($$c(this).text()).change(); }); editor.addDropDown('#opacity_dropdown', function () { - if ($$b(this).find('div').length) { + if ($$c(this).find('div').length) { return; } - var perc = Number.parseInt($$b(this).text().split('%')[0]); + const perc = Number.parseInt($$c(this).text().split('%')[0]); changeOpacity(false, perc); }, true); // For slider usage, see: http://jqueryui.com/demos/slider/ - $$b('#opac_slider').slider({ - start: function start() { - $$b('#opacity_dropdown li:not(.special)').hide(); + $$c('#opac_slider').slider({ + start() { + $$c('#opacity_dropdown li:not(.special)').hide(); }, - stop: function stop() { - $$b('#opacity_dropdown li').show(); - $$b(window).mouseup(); + + stop() { + $$c('#opacity_dropdown li').show(); + $$c(window).mouseup(); }, - slide: function slide(evt, ui) { + + slide(evt, ui) { changeOpacity(ui); } + }); - editor.addDropDown('#blur_dropdown', $$b.noop); - var slideStart = false; - $$b('#blur_slider').slider({ + editor.addDropDown('#blur_dropdown', $$c.noop); + let slideStart = false; + $$c('#blur_slider').slider({ max: 10, step: 0.1, - stop: function stop(evt, ui) { + + stop(evt, ui) { slideStart = false; changeBlur(ui); - $$b('#blur_dropdown li').show(); - $$b(window).mouseup(); + $$c('#blur_dropdown li').show(); + $$c(window).mouseup(); }, - start: function start() { + + start() { slideStart = true; }, - slide: function slide(evt, ui) { + + slide(evt, ui) { changeBlur(ui, null, slideStart); } + }); editor.addDropDown('#zoom_dropdown', function () { - var item = $$b(this); - var val = item.data('val'); + const item = $$c(this); + const val = item.data('val'); if (val) { zoomChanged(window, val); @@ -33169,7 +32064,7 @@ dropUp: true }); addAltDropDown('#tool_position', '#position_opts', function () { - var letter = this.id.replace('tool_pos', '').charAt(0); + const letter = this.id.replace('tool_pos', '').charAt(0); svgCanvas.alignSelectedElements(letter, 'page'); }, { multiclick: true @@ -33189,17 +32084,17 @@ // Unfocus text input when workarea is mousedowned. (function () { - var inp; + let inp; /** * * @returns {void} */ - var unfocus = function unfocus() { - $$b(inp).blur(); + const unfocus = function () { + $$c(inp).blur(); }; - $$b('#svg_editor').find('button, select, input:not(#text)').focus(function () { + $$c('#svg_editor').find('button, select, input:not(#text)').focus(function () { inp = this; // eslint-disable-line consistent-this uiContext = 'toolbars'; @@ -33209,7 +32104,7 @@ workarea.unbind('mousedown', unfocus); // Go back to selecting text if in textedit mode if (svgCanvas.getMode() === 'textedit') { - $$b('#text').focus(); + $$c('#text').focus(); } }); })(); @@ -33219,7 +32114,7 @@ */ - var clickFHPath = function clickFHPath() { + const clickFHPath = function () { if (toolButtonClick('#tool_fhpath')) { svgCanvas.setMode('fhpath'); } @@ -33230,7 +32125,7 @@ */ - var clickLine = function clickLine() { + const clickLine = function () { if (toolButtonClick('#tool_line')) { svgCanvas.setMode('line'); } @@ -33241,7 +32136,7 @@ */ - var clickSquare = function clickSquare() { + const clickSquare = function () { if (toolButtonClick('#tool_square')) { svgCanvas.setMode('square'); } @@ -33252,7 +32147,7 @@ */ - var clickRect = function clickRect() { + const clickRect = function () { if (toolButtonClick('#tool_rect')) { svgCanvas.setMode('rect'); } @@ -33263,7 +32158,7 @@ */ - var clickFHRect = function clickFHRect() { + const clickFHRect = function () { if (toolButtonClick('#tool_fhrect')) { svgCanvas.setMode('fhrect'); } @@ -33274,7 +32169,7 @@ */ - var clickCircle = function clickCircle() { + const clickCircle = function () { if (toolButtonClick('#tool_circle')) { svgCanvas.setMode('circle'); } @@ -33285,7 +32180,7 @@ */ - var clickEllipse = function clickEllipse() { + const clickEllipse = function () { if (toolButtonClick('#tool_ellipse')) { svgCanvas.setMode('ellipse'); } @@ -33296,7 +32191,7 @@ */ - var clickFHEllipse = function clickFHEllipse() { + const clickFHEllipse = function () { if (toolButtonClick('#tool_fhellipse')) { svgCanvas.setMode('fhellipse'); } @@ -33307,7 +32202,7 @@ */ - var clickImage = function clickImage() { + const clickImage = function () { if (toolButtonClick('#tool_image')) { svgCanvas.setMode('image'); } @@ -33318,7 +32213,7 @@ */ - var clickZoom = function clickZoom() { + const clickZoom = function () { if (toolButtonClick('#tool_zoom')) { svgCanvas.setMode('zoom'); workarea.css('cursor', zoomInIcon); @@ -33330,11 +32225,11 @@ */ - var zoomImage = function zoomImage(multiplier) { - var res = svgCanvas.getResolution(); + const zoomImage = function (multiplier) { + const res = svgCanvas.getResolution(); multiplier = multiplier ? res.zoom * multiplier : 1; // setResolution(res.w * multiplier, res.h * multiplier, true); - $$b('#zoom').val(multiplier * 100); + $$c('#zoom').val(multiplier * 100); svgCanvas.setZoom(multiplier); zoomDone(); updateCanvas(true); @@ -33345,7 +32240,7 @@ */ - var dblclickZoom = function dblclickZoom() { + const dblclickZoom = function () { if (toolButtonClick('#tool_zoom')) { zoomImage(); setSelectMode(); @@ -33357,7 +32252,7 @@ */ - var clickText = function clickText() { + const clickText = function () { if (toolButtonClick('#tool_text')) { svgCanvas.setMode('text'); } @@ -33368,7 +32263,7 @@ */ - var clickPath = function clickPath() { + const clickPath = function () { if (toolButtonClick('#tool_path')) { svgCanvas.setMode('path'); } @@ -33380,7 +32275,7 @@ */ - var deleteSelected = function deleteSelected() { + const deleteSelected = function () { if (!isNullish(selectedElement) || multiselected) { svgCanvas.deleteSelectedElements(); } @@ -33391,7 +32286,7 @@ */ - var cutSelected = function cutSelected() { + const cutSelected = function () { if (!isNullish(selectedElement) || multiselected) { svgCanvas.cutSelectedElements(); } @@ -33402,7 +32297,7 @@ */ - var copySelected = function copySelected() { + const copySelected = function () { if (!isNullish(selectedElement) || multiselected) { svgCanvas.copySelectedElements(); } @@ -33413,10 +32308,10 @@ */ - var pasteInCenter = function pasteInCenter() { - var zoom = svgCanvas.getZoom(); - var x = (workarea[0].scrollLeft + workarea.width() / 2) / zoom - svgCanvas.contentW; - var y = (workarea[0].scrollTop + workarea.height() / 2) / zoom - svgCanvas.contentH; + const pasteInCenter = function () { + const zoom = svgCanvas.getZoom(); + const x = (workarea[0].scrollLeft + workarea.width() / 2) / zoom - svgCanvas.contentW; + const y = (workarea[0].scrollTop + workarea.height() / 2) / zoom - svgCanvas.contentH; svgCanvas.pasteElements('point', x, y); }; /** @@ -33425,7 +32320,7 @@ */ - var moveToTopSelected = function moveToTopSelected() { + const moveToTopSelected = function () { if (!isNullish(selectedElement)) { svgCanvas.moveToTopSelectedElement(); } @@ -33436,7 +32331,7 @@ */ - var moveToBottomSelected = function moveToBottomSelected() { + const moveToBottomSelected = function () { if (!isNullish(selectedElement)) { svgCanvas.moveToBottomSelectedElement(); } @@ -33447,7 +32342,7 @@ */ - var moveUpDownSelected = function moveUpDownSelected(dir) { + const moveUpDownSelected = function (dir) { if (!isNullish(selectedElement)) { svgCanvas.moveUpDownSelected(dir); } @@ -33458,7 +32353,7 @@ */ - var convertToPath = function convertToPath() { + const convertToPath = function () { if (!isNullish(selectedElement)) { svgCanvas.convertToPath(); } @@ -33469,7 +32364,7 @@ */ - var reorientPath = function reorientPath() { + const reorientPath = function () { if (!isNullish(selectedElement)) { path.reorient(); } @@ -33480,40 +32375,15 @@ */ - var makeHyperlink = /*#__PURE__*/function () { - var _ref15 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee7() { - var url; - return regeneratorRuntime.wrap(function _callee7$(_context7) { - while (1) { - switch (_context7.prev = _context7.next) { - case 0: - if (!(!isNullish(selectedElement) || multiselected)) { - _context7.next = 5; - break; - } + const makeHyperlink = async function () { + if (!isNullish(selectedElement) || multiselected) { + const url = await $$c.prompt(uiStrings$1.notification.enterNewLinkURL, 'http://'); - _context7.next = 3; - return $$b.prompt(uiStrings$1.notification.enterNewLinkURL, 'http://'); - - case 3: - url = _context7.sent; - - if (url) { - svgCanvas.makeHyperlink(url); - } - - case 5: - case "end": - return _context7.stop(); - } - } - }, _callee7); - })); - - return function makeHyperlink() { - return _ref15.apply(this, arguments); - }; - }(); + if (url) { + svgCanvas.makeHyperlink(url); + } + } + }; /** * @param {Float} dx * @param {Float} dy @@ -33521,11 +32391,11 @@ */ - var moveSelected = function moveSelected(dx, dy) { + const moveSelected = function (dx, dy) { if (!isNullish(selectedElement) || multiselected) { if (curConfig.gridSnapping) { // Use grid snap value regardless of zoom level - var multi = svgCanvas.getZoom() * curConfig.snappingStep; + const multi = svgCanvas.getZoom() * curConfig.snappingStep; dx *= multi; dy *= multi; } @@ -33539,9 +32409,9 @@ */ - var linkControlPoints = function linkControlPoints() { - $$b('#tool_node_link').toggleClass('push_button_pressed tool_button'); - var linked = $$b('#tool_node_link').hasClass('push_button_pressed'); + const linkControlPoints = function () { + $$c('#tool_node_link').toggleClass('push_button_pressed tool_button'); + const linked = $$c('#tool_node_link').hasClass('push_button_pressed'); path.linkControlPoints(linked); }; /** @@ -33550,7 +32420,7 @@ */ - var clonePathNode = function clonePathNode() { + const clonePathNode = function () { if (path.getNodePoint()) { path.clonePathNode(); } @@ -33561,7 +32431,7 @@ */ - var deletePathNode = function deletePathNode() { + const deletePathNode = function () { if (path.getNodePoint()) { path.deletePathNode(); } @@ -33572,9 +32442,9 @@ */ - var addSubPath = function addSubPath() { - var button = $$b('#tool_add_subpath'); - var sp = !button.hasClass('push_button_pressed'); + const addSubPath = function () { + const button = $$c('#tool_add_subpath'); + const sp = !button.hasClass('push_button_pressed'); button.toggleClass('push_button_pressed tool_button'); path.addSubPath(sp); }; @@ -33584,7 +32454,7 @@ */ - var opencloseSubPath = function opencloseSubPath() { + const opencloseSubPath = function () { path.opencloseSubPath(); }; /** @@ -33593,7 +32463,7 @@ */ - var selectNext = function selectNext() { + const selectNext = function () { svgCanvas.cycleElement(1); }; /** @@ -33602,7 +32472,7 @@ */ - var selectPrev = function selectPrev() { + const selectPrev = function () { svgCanvas.cycleElement(0); }; /** @@ -33612,7 +32482,7 @@ */ - var rotateSelected = function rotateSelected(cw, step) { + const rotateSelected = function (cw, step) { if (isNullish(selectedElement) || multiselected) { return; } @@ -33621,7 +32491,7 @@ step *= -1; } - var angle = Number.parseFloat($$b('#angle').val()) + step; + const angle = Number.parseFloat($$c('#angle').val()) + step; svgCanvas.setRotationAngle(angle); updateContextPanel(); }; @@ -33631,58 +32501,31 @@ */ - var clickClear = /*#__PURE__*/function () { - var _ref16 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee8() { - var _curConfig$dimensions, x, y, ok; + const clickClear = async function () { + const [x, y] = curConfig.dimensions; + const ok = await $$c.confirm(uiStrings$1.notification.QwantToClear); - return regeneratorRuntime.wrap(function _callee8$(_context8) { - while (1) { - switch (_context8.prev = _context8.next) { - case 0: - _curConfig$dimensions = _slicedToArray(curConfig.dimensions, 2), x = _curConfig$dimensions[0], y = _curConfig$dimensions[1]; - _context8.next = 3; - return $$b.confirm(uiStrings$1.notification.QwantToClear); + if (!ok) { + return; + } - case 3: - ok = _context8.sent; - - if (ok) { - _context8.next = 6; - break; - } - - return _context8.abrupt("return"); - - case 6: - setSelectMode(); - svgCanvas.clear(); - svgCanvas.setResolution(x, y); - updateCanvas(true); - zoomImage(); - populateLayers(); - updateContextPanel(); - prepPaints(); - svgCanvas.runExtensions('onNewDocument'); - - case 15: - case "end": - return _context8.stop(); - } - } - }, _callee8); - })); - - return function clickClear() { - return _ref16.apply(this, arguments); - }; - }(); + setSelectMode(); + svgCanvas.clear(); + svgCanvas.setResolution(x, y); + updateCanvas(true); + zoomImage(); + populateLayers(); + updateContextPanel(); + prepPaints(); + svgCanvas.runExtensions('onNewDocument'); + }; /** * * @returns {false} */ - var clickBold = function clickBold() { + const clickBold = function () { svgCanvas.setBold(!svgCanvas.getBold()); updateContextPanel(); return false; @@ -33693,7 +32536,7 @@ */ - var clickItalic = function clickItalic() { + const clickItalic = function () { svgCanvas.setItalic(!svgCanvas.getItalic()); updateContextPanel(); return false; @@ -33704,122 +32547,107 @@ */ - var clickSave = function clickSave() { + const clickSave = function () { // In the future, more options can be provided here - var saveOpts = { + const saveOpts = { images: editor.pref('img_save'), round_digits: 6 }; svgCanvas.save(saveOpts); }; - var loadingURL; + let loadingURL; /** * * @returns {Promise<void>} Resolves to `undefined` */ - var clickExport = /*#__PURE__*/function () { - var _ref17 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee9() { - var imgType, exportWindowName, openExportWindow, chrome, quality; - return regeneratorRuntime.wrap(function _callee9$(_context9) { - while (1) { - switch (_context9.prev = _context9.next) { - case 0: - openExportWindow = function _openExportWindow() { - var loadingImage = uiStrings$1.notification.loadingImage; + const clickExport = async function () { + const imgType = await $$c.select('Select an image type for export: ', [// See http://kangax.github.io/jstests/toDataUrl_mime_type_test/ for a useful list of MIME types and browser support + // 'ICO', // Todo: Find a way to preserve transparency in SVG-Edit if not working presently and do full packaging for x-icon; then switch back to position after 'PNG' + 'PNG', 'JPEG', 'BMP', 'WEBP', 'PDF'], function () { + const sel = $$c(this); - if (curConfig.exportWindowType === 'new') { - editor.exportWindowCt++; - } - - exportWindowName = curConfig.canvasName + editor.exportWindowCt; - var popHTML, popURL; - - if (loadingURL) { - popURL = loadingURL; - } else { - popHTML = "<!DOCTYPE html><html>\n <head>\n <meta charset=\"utf-8\">\n <title>".concat(loadingImage, "\n \n

").concat(loadingImage, "

\n "); - - if (typeof URL !== 'undefined' && URL.createObjectURL) { - var blob = new Blob([popHTML], { - type: 'text/html' - }); - popURL = URL.createObjectURL(blob); - } else { - popURL = 'data:text/html;base64;charset=utf-8,' + encode64(popHTML); - } - - loadingURL = popURL; - } - - exportWindow = window.open(popURL, exportWindowName); - }; - - _context9.next = 3; - return $$b.select('Select an image type for export: ', [// See http://kangax.github.io/jstests/toDataUrl_mime_type_test/ for a useful list of MIME types and browser support - // 'ICO', // Todo: Find a way to preserve transparency in SVG-Edit if not working presently and do full packaging for x-icon; then switch back to position after 'PNG' - 'PNG', 'JPEG', 'BMP', 'WEBP', 'PDF'], function () { - var sel = $$b(this); - - if (sel.val() === 'JPEG' || sel.val() === 'WEBP') { - if (!$$b('#image-slider').length) { - $$b("
")).appendTo(sel.parent()); - } - } else { - $$b('#image-slider').parent().remove(); - } - }); - - case 3: - imgType = _context9.sent; - - if (imgType) { - _context9.next = 6; - break; - } - - return _context9.abrupt("return"); - - case 6: - chrome = isChrome(); - - if (!(imgType === 'PDF')) { - _context9.next = 12; - break; - } - - if (!customExportPDF && !chrome) { - openExportWindow(); - } - - svgCanvas.exportPDF(exportWindowName); - _context9.next = 16; - break; - - case 12: - if (!customExportImage) { - openExportWindow(); - } - - quality = Number.parseInt($$b('#image-slider').val()) / 100; - /* const results = */ - - _context9.next = 16; - return svgCanvas.rasterExport(imgType, quality, exportWindowName); - - case 16: - case "end": - return _context9.stop(); - } + if (sel.val() === 'JPEG' || sel.val() === 'WEBP') { + if (!$$c('#image-slider').length) { + $$c(`
`).appendTo(sel.parent()); } - }, _callee9); - })); + } else { + $$c('#image-slider').parent().remove(); + } + }); // todo: replace hard-coded msg with uiStrings.notification. - return function clickExport() { - return _ref17.apply(this, arguments); - }; - }(); + if (!imgType) { + return; + } // Open placeholder window (prevents popup) + + + let exportWindowName; + /** + * + * @returns {void} + */ + + function openExportWindow() { + const { + loadingImage + } = uiStrings$1.notification; + + if (curConfig.exportWindowType === 'new') { + editor.exportWindowCt++; + } + + exportWindowName = curConfig.canvasName + editor.exportWindowCt; + let popHTML, popURL; + + if (loadingURL) { + popURL = loadingURL; + } else { + popHTML = ` + + + ${loadingImage} + +

${loadingImage}

+ `; + + if (typeof URL !== 'undefined' && URL.createObjectURL) { + const blob = new Blob([popHTML], { + type: 'text/html' + }); + popURL = URL.createObjectURL(blob); + } else { + popURL = 'data:text/html;base64;charset=utf-8,' + encode64(popHTML); + } + + loadingURL = popURL; + } + + exportWindow = window.open(popURL, exportWindowName); + } + + const chrome = isChrome(); + + if (imgType === 'PDF') { + if (!customExportPDF && !chrome) { + openExportWindow(); + } + + svgCanvas.exportPDF(exportWindowName); + } else { + if (!customExportImage) { + openExportWindow(); + } + + const quality = Number.parseInt($$c('#image-slider').val()) / 100; + /* const results = */ + + await svgCanvas.rasterExport(imgType, quality, exportWindowName); + } + }; /** * By default, svgCanvas.open() is a no-op. It is up to an extension * mechanism (opera widget, etc.) to call `setCustomHandlers()` which @@ -33828,7 +32656,7 @@ */ - var clickOpen = function clickOpen() { + const clickOpen = function () { svgCanvas.open(); }; /** @@ -33837,7 +32665,7 @@ */ - var clickImport = function clickImport() { + const clickImport = function () { /* */ }; /** @@ -33846,7 +32674,7 @@ */ - var clickUndo = function clickUndo() { + const clickUndo = function () { if (undoMgr.getUndoStackSize() > 0) { undoMgr.undo(); populateLayers(); @@ -33858,7 +32686,7 @@ */ - var clickRedo = function clickRedo() { + const clickRedo = function () { if (undoMgr.getRedoStackSize() > 0) { undoMgr.redo(); populateLayers(); @@ -33870,7 +32698,7 @@ */ - var clickGroup = function clickGroup() { + const clickGroup = function () { // group if (multiselected) { svgCanvas.groupSelectedElements(); // ungroup @@ -33884,7 +32712,7 @@ */ - var clickClone = function clickClone() { + const clickClone = function () { svgCanvas.cloneSelectedElements(20, 20); }; /** @@ -33893,9 +32721,9 @@ */ - var clickAlign = function clickAlign() { - var letter = this.id.replace('tool_align', '').charAt(0); - svgCanvas.alignSelectedElements(letter, $$b('#align_relative_to').val()); + const clickAlign = function () { + const letter = this.id.replace('tool_align', '').charAt(0); + svgCanvas.alignSelectedElements(letter, $$c('#align_relative_to').val()); }; /** * @@ -33903,19 +32731,19 @@ */ - var clickWireframe = function clickWireframe() { - $$b('#tool_wireframe').toggleClass('push_button_pressed tool_button'); + const clickWireframe = function () { + $$c('#tool_wireframe').toggleClass('push_button_pressed tool_button'); workarea.toggleClass('wireframe'); if (supportsNonSS) { return; } - var wfRules = $$b('#wireframe_rules'); + const wfRules = $$c('#wireframe_rules'); if (!wfRules.length) { /* wfRules = */ - $$b('').appendTo('head'); + $$c('').appendTo('head'); } else { wfRules.empty(); } @@ -33923,37 +32751,37 @@ updateWireFrame(); }; - $$b('#svg_docprops_container, #svg_prefs_container').draggable({ + $$c('#svg_docprops_container, #svg_prefs_container').draggable({ cancel: 'button,fieldset', containment: 'window' }).css('position', 'absolute'); - var docprops = false; - var preferences = false; + let docprops = false; + let preferences = false; /** * * @returns {void} */ - var showDocProperties = function showDocProperties() { + const showDocProperties = function () { if (docprops) { return; } docprops = true; // This selects the correct radio button by using the array notation - $$b('#image_save_opts input').val([editor.pref('img_save')]); // update resolution option with actual resolution + $$c('#image_save_opts input').val([editor.pref('img_save')]); // update resolution option with actual resolution - var res = svgCanvas.getResolution(); + const res = svgCanvas.getResolution(); if (curConfig.baseUnit !== 'px') { res.w = convertUnit(res.w) + curConfig.baseUnit; res.h = convertUnit(res.h) + curConfig.baseUnit; } - $$b('#canvas_width').val(res.w); - $$b('#canvas_height').val(res.h); - $$b('#canvas_title').val(svgCanvas.getDocumentTitle()); - $$b('#svg_docprops').show(); + $$c('#canvas_width').val(res.w); + $$c('#canvas_height').val(res.h); + $$c('#canvas_title').val(svgCanvas.getDocumentTitle()); + $$c('#svg_docprops').show(); }; /** * @@ -33961,19 +32789,19 @@ */ - var showPreferences = function showPreferences() { + const showPreferences = function () { if (preferences) { return; } preferences = true; - $$b('#main_menu').hide(); // Update background color with current one + $$c('#main_menu').hide(); // Update background color with current one - var canvasBg = curPrefs.bkgd_color; - var url = editor.pref('bkgd_url'); + const canvasBg = curPrefs.bkgd_color; + const url = editor.pref('bkgd_url'); blocks.each(function () { - var blk = $$b(this); - var isBg = blk.data('bgcolor') === canvasBg; + const blk = $$c(this); + const isBg = blk.data('bgcolor') === canvasBg; blk.toggleClass(curBg, isBg); }); @@ -33982,13 +32810,13 @@ } if (url) { - $$b('#canvas_bg_url').val(url); + $$c('#canvas_bg_url').val(url); } - $$b('#grid_snapping_on').prop('checked', curConfig.gridSnapping); - $$b('#grid_snapping_step').attr('value', curConfig.snappingStep); - $$b('#grid_color').attr('value', curConfig.gridColor); - $$b('#svg_prefs').show(); + $$c('#grid_snapping_on').prop('checked', curConfig.gridSnapping); + $$c('#grid_snapping_step').attr('value', curConfig.snappingStep); + $$c('#grid_color').attr('value', curConfig.gridColor); + $$c('#svg_prefs').show(); }; /** * @@ -33996,7 +32824,7 @@ */ - var openHomePage = function openHomePage() { + const openHomePage = function () { window.open(homePage, '_blank'); }; /** @@ -34005,10 +32833,10 @@ */ - var hideSourceEditor = function hideSourceEditor() { - $$b('#svg_source_editor').hide(); + const hideSourceEditor = function () { + $$c('#svg_source_editor').hide(); editingsource = false; - $$b('#svg_source_textarea').blur(); + $$c('#svg_source_textarea').blur(); }; /** * @@ -34016,79 +32844,45 @@ */ - var saveSourceEditor = /*#__PURE__*/function () { - var _ref18 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee10() { - var saveChanges, ok; - return regeneratorRuntime.wrap(function _callee10$(_context10) { - while (1) { - switch (_context10.prev = _context10.next) { - case 0: - if (editingsource) { - _context10.next = 2; - break; - } + const saveSourceEditor = async function () { + if (!editingsource) { + return; + } - return _context10.abrupt("return"); - - case 2: - saveChanges = function saveChanges() { - svgCanvas.clearSelection(); - hideSourceEditor(); - zoomImage(); - populateLayers(); - updateTitle(); - prepPaints(); - }; - - if (svgCanvas.setSvgString($$b('#svg_source_textarea').val())) { - _context10.next = 11; - break; - } - - _context10.next = 6; - return $$b.confirm(uiStrings$1.notification.QerrorsRevertToSource); - - case 6: - ok = _context10.sent; - - if (ok) { - _context10.next = 9; - break; - } - - return _context10.abrupt("return"); - - case 9: - saveChanges(); - return _context10.abrupt("return"); - - case 11: - saveChanges(); - setSelectMode(); - - case 13: - case "end": - return _context10.stop(); - } - } - }, _callee10); - })); - - return function saveSourceEditor() { - return _ref18.apply(this, arguments); + const saveChanges = function () { + svgCanvas.clearSelection(); + hideSourceEditor(); + zoomImage(); + populateLayers(); + updateTitle(); + prepPaints(); }; - }(); + + if (!svgCanvas.setSvgString($$c('#svg_source_textarea').val())) { + const ok = await $$c.confirm(uiStrings$1.notification.QerrorsRevertToSource); + + if (!ok) { + return; + } + + saveChanges(); + return; + } + + saveChanges(); + setSelectMode(); + }; /** * * @returns {void} */ - var hideDocProperties = function hideDocProperties() { - $$b('#svg_docprops').hide(); - $$b('#canvas_width,#canvas_height').removeAttr('disabled'); - $$b('#resolution')[0].selectedIndex = 0; - $$b('#image_save_opts input').val([editor.pref('img_save')]); + const hideDocProperties = function () { + $$c('#svg_docprops').hide(); + $$c('#canvas_width,#canvas_height').removeAttr('disabled'); + $$c('#resolution')[0].selectedIndex = 0; + $$c('#image_save_opts input').val([editor.pref('img_save')]); docprops = false; }; /** @@ -34097,8 +32891,8 @@ */ - var hidePreferences = function hidePreferences() { - $$b('#svg_prefs').hide(); + const hidePreferences = function () { + $$c('#svg_prefs').hide(); preferences = false; }; /** @@ -34107,22 +32901,22 @@ */ - var saveDocProperties = function saveDocProperties() { + const saveDocProperties = function () { // set title - var newTitle = $$b('#canvas_title').val(); + const newTitle = $$c('#canvas_title').val(); updateTitle(newTitle); svgCanvas.setDocumentTitle(newTitle); // update resolution - var width = $$b('#canvas_width'), - w = width.val(); - var height = $$b('#canvas_height'), - h = height.val(); + const width = $$c('#canvas_width'), + w = width.val(); + const height = $$c('#canvas_height'), + h = height.val(); if (w !== 'fit' && !isValidUnit('width', w)) { width.parent().addClass('error'); /* await */ - $$b.alert(uiStrings$1.notification.invalidAttrValGiven); + $$c.alert(uiStrings$1.notification.invalidAttrValGiven); return false; } @@ -34132,7 +32926,7 @@ height.parent().addClass('error'); /* await */ - $$b.alert(uiStrings$1.notification.invalidAttrValGiven); + $$c.alert(uiStrings$1.notification.invalidAttrValGiven); return false; } @@ -34140,12 +32934,12 @@ if (!svgCanvas.setResolution(w, h)) { /* await */ - $$b.alert(uiStrings$1.notification.noContentToFitTo); + $$c.alert(uiStrings$1.notification.noContentToFitTo); return false; } // Set image save option - editor.pref('img_save', $$b('#image_save_opts :checked').val()); + editor.pref('img_save', $$c('#image_save_opts :checked').val()); updateCanvas(); hideDocProperties(); return true; @@ -34157,148 +32951,83 @@ */ - var savePreferences = editor.savePreferences = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee11() { - var color, lang, _yield$editor$putLoca2, langParam, langData; + const savePreferences = editor.savePreferences = async function () { + // Set background + const color = $$c('#bg_blocks div.cur_background').data('bgcolor') || '#FFF'; + setBackground(color, $$c('#canvas_bg_url').val()); // set language - return regeneratorRuntime.wrap(function _callee11$(_context11) { - while (1) { - switch (_context11.prev = _context11.next) { - case 0: - // Set background - color = $$b('#bg_blocks div.cur_background').data('bgcolor') || '#FFF'; - setBackground(color, $$b('#canvas_bg_url').val()); // set language + const lang = $$c('#lang_select').val(); - lang = $$b('#lang_select').val(); + if (lang && lang !== editor.pref('lang')) { + const { + langParam, + langData + } = await editor.putLocale(lang, goodLangs, curConfig); + await setLang(langParam, langData); + } // set icon size - if (!(lang && lang !== editor.pref('lang'))) { - _context11.next = 11; - break; - } - _context11.next = 6; - return editor.putLocale(lang, goodLangs, curConfig); + setIconSize($$c('#iconsize').val()); // set grid setting - case 6: - _yield$editor$putLoca2 = _context11.sent; - langParam = _yield$editor$putLoca2.langParam; - langData = _yield$editor$putLoca2.langData; - _context11.next = 11; - return setLang(langParam, langData); + curConfig.gridSnapping = $$c('#grid_snapping_on')[0].checked; + curConfig.snappingStep = $$c('#grid_snapping_step').val(); + curConfig.gridColor = $$c('#grid_color').val(); + curConfig.showRulers = $$c('#show_rulers')[0].checked; + $$c('#rulers').toggle(curConfig.showRulers); - case 11: - // set icon size - setIconSize($$b('#iconsize').val()); // set grid setting + if (curConfig.showRulers) { + updateRulers(); + } - curConfig.gridSnapping = $$b('#grid_snapping_on')[0].checked; - curConfig.snappingStep = $$b('#grid_snapping_step').val(); - curConfig.gridColor = $$b('#grid_color').val(); - curConfig.showRulers = $$b('#show_rulers')[0].checked; - $$b('#rulers').toggle(curConfig.showRulers); + curConfig.baseUnit = $$c('#base_unit').val(); + svgCanvas.setConfig(curConfig); + updateCanvas(); + hidePreferences(); + }; - if (curConfig.showRulers) { - updateRulers(); - } - - curConfig.baseUnit = $$b('#base_unit').val(); - svgCanvas.setConfig(curConfig); - updateCanvas(); - hidePreferences(); - - case 22: - case "end": - return _context11.stop(); - } - } - }, _callee11); - })); - - var resetScrollPos = $$b.noop; + let resetScrollPos = $$c.noop; /** * * @returns {Promise} Resolves to `undefined` */ - var cancelOverlays = /*#__PURE__*/function () { - var _ref20 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee12() { - var ok; - return regeneratorRuntime.wrap(function _callee12$(_context12) { - while (1) { - switch (_context12.prev = _context12.next) { - case 0: - $$b('#dialog_box').hide(); + const cancelOverlays = async function () { + $$c('#dialog_box').hide(); - if (!(!editingsource && !docprops && !preferences)) { - _context12.next = 4; - break; - } + if (!editingsource && !docprops && !preferences) { + if (curContext) { + svgCanvas.leaveContext(); + } - if (curContext) { - svgCanvas.leaveContext(); - } + return; + } - return _context12.abrupt("return"); + if (editingsource) { + if (origSource !== $$c('#svg_source_textarea').val()) { + const ok = await $$c.confirm(uiStrings$1.notification.QignoreSourceChanges); - case 4: - if (!editingsource) { - _context12.next = 15; - break; - } - - if (!(origSource !== $$b('#svg_source_textarea').val())) { - _context12.next = 12; - break; - } - - _context12.next = 8; - return $$b.confirm(uiStrings$1.notification.QignoreSourceChanges); - - case 8: - ok = _context12.sent; - - if (ok) { - hideSourceEditor(); - } - - _context12.next = 13; - break; - - case 12: - hideSourceEditor(); - - case 13: - _context12.next = 16; - break; - - case 15: - if (docprops) { - hideDocProperties(); - } else if (preferences) { - hidePreferences(); - } - - case 16: - resetScrollPos(); - - case 17: - case "end": - return _context12.stop(); - } + if (ok) { + hideSourceEditor(); } - }, _callee12); - })); + } else { + hideSourceEditor(); + } + } else if (docprops) { + hideDocProperties(); + } else if (preferences) { + hidePreferences(); + } - return function cancelOverlays() { - return _ref20.apply(this, arguments); - }; - }(); + resetScrollPos(); + }; - var winWh = { - width: $$b(window).width(), - height: $$b(window).height() + const winWh = { + width: $$c(window).width(), + height: $$c(window).height() }; // Fix for Issue 781: Drawing area jumps to top-left corner on window resize (IE9) if (isIE()) { - resetScrollPos = function resetScrollPos() { + resetScrollPos = function () { if (workarea[0].scrollLeft === 0 && workarea[0].scrollTop === 0) { workarea[0].scrollLeft = curScrollPos.left; workarea[0].scrollTop = curScrollPos.top; @@ -34309,11 +33038,11 @@ left: workarea[0].scrollLeft, top: workarea[0].scrollTop }; - $$b(window).resize(resetScrollPos); + $$c(window).resize(resetScrollPos); editor.ready(function () { // TODO: Find better way to detect when to do this to minimize // flickering effect - return new Promise(function (resolve, reject) { + return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new setTimeout(function () { resetScrollPos(); @@ -34329,9 +33058,9 @@ }); } - $$b(window).resize(function (evt) { - $$b.each(winWh, function (type, val) { - var curval = $$b(window)[type](); + $$c(window).resize(function (evt) { + $$c.each(winWh, function (type, val) { + const curval = $$c(window)[type](); workarea[0]['scroll' + (type === 'width' ? 'Left' : 'Top')] -= (curval - val) / 2; winWh[type] = curval; }); @@ -34339,39 +33068,39 @@ }); workarea.scroll(function () { // TODO: jQuery's scrollLeft/Top() wouldn't require a null check - if ($$b('#ruler_x').length) { - $$b('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; + if ($$c('#ruler_x').length) { + $$c('#ruler_x')[0].scrollLeft = workarea[0].scrollLeft; } - if ($$b('#ruler_y').length) { - $$b('#ruler_y')[0].scrollTop = workarea[0].scrollTop; + if ($$c('#ruler_y').length) { + $$c('#ruler_y')[0].scrollTop = workarea[0].scrollTop; } }); - $$b('#url_notice').click(function () { + $$c('#url_notice').click(function () { /* await */ - $$b.alert(this.title); + $$c.alert(this.title); }); - $$b('#change_image_url').click(promptImgURL); // added these event handlers for all the push buttons so they + $$c('#change_image_url').click(promptImgURL); // added these event handlers for all the push buttons so they // behave more like buttons being pressed-in and not images (function () { - var toolnames = ['clear', 'open', 'save', 'source', 'delete', 'delete_multi', 'paste', 'clone', 'clone_multi', 'move_top', 'move_bottom']; - var curClass = 'tool_button_current'; - var allTools = ''; - $$b.each(toolnames, function (i, item) { + const toolnames = ['clear', 'open', 'save', 'source', 'delete', 'delete_multi', 'paste', 'clone', 'clone_multi', 'move_top', 'move_bottom']; + const curClass = 'tool_button_current'; + let allTools = ''; + $$c.each(toolnames, function (i, item) { allTools += (i ? ',' : '') + '#tool_' + item; }); - $$b(allTools).mousedown(function () { - $$b(this).addClass(curClass); + $$c(allTools).mousedown(function () { + $$c(this).addClass(curClass); }).bind('mousedown mouseout', function () { - $$b(this).removeClass(curClass); + $$c(this).removeClass(curClass); }); - $$b('#tool_undo, #tool_redo').mousedown(function () { - if (!$$b(this).hasClass('disabled')) { - $$b(this).addClass(curClass); + $$c('#tool_undo, #tool_redo').mousedown(function () { + if (!$$c(this).hasClass('disabled')) { + $$c(this).addClass(curClass); } }).bind('mousedown mouseout', function () { - $$b(this).removeClass(curClass); + $$c(this).removeClass(curClass); }); })(); // switch modifier key in tooltips if mac // NOTE: This code is not used yet until I can figure out how to successfully bind ctrl/meta @@ -34379,15 +33108,17 @@ if (isMac() && !window.opera) { - var shortcutButtons = ['tool_clear', 'tool_save', 'tool_source', 'tool_undo', 'tool_redo', 'tool_clone']; - var _i = shortcutButtons.length; + const shortcutButtons = ['tool_clear', 'tool_save', 'tool_source', 'tool_undo', 'tool_redo', 'tool_clone']; + let i = shortcutButtons.length; - while (_i--) { - var button = document.getElementById(shortcutButtons[_i]); + while (i--) { + const button = document.getElementById(shortcutButtons[i]); if (button) { - var title = button.title; - var index = title.indexOf('Ctrl+'); + const { + title + } = button; + const index = title.indexOf('Ctrl+'); button.title = [title.substr(0, index), 'Cmd+', title.substr(index + 5)].join(''); } } @@ -34400,21 +33131,23 @@ */ - var colorPicker = function colorPicker(elem) { - var picker = elem.attr('id') === 'stroke_color' ? 'stroke' : 'fill'; // const opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); + const colorPicker = function (elem) { + const picker = elem.attr('id') === 'stroke_color' ? 'stroke' : 'fill'; // const opacity = (picker == 'stroke' ? $('#stroke_opacity') : $('#fill_opacity')); - var title = picker === 'stroke' ? uiStrings$1.ui.pick_stroke_paint_opacity : uiStrings$1.ui.pick_fill_paint_opacity; // let wasNone = false; // Currently unused + const title = picker === 'stroke' ? uiStrings$1.ui.pick_stroke_paint_opacity : uiStrings$1.ui.pick_fill_paint_opacity; // let wasNone = false; // Currently unused - var pos = elem.offset(); - var paint = paintBox[picker].paint; - $$b('#color_picker').draggable({ + const pos = elem.offset(); + let { + paint + } = paintBox[picker]; + $$c('#color_picker').draggable({ cancel: '.jGraduate_tabs, .jGraduate_colPick, .jGraduate_gradPick, .jPicker', containment: 'window' }).css(curConfig.colorPickerCSS || { left: pos.left - 140, bottom: 40 }).jGraduate({ - paint: paint, + paint, window: { pickerTitle: title }, @@ -34423,12 +33156,12 @@ }, newstop: 'inverse' }, function (p) { - paint = new $$b.jGraduate.Paint(p); + paint = new $$c.jGraduate.Paint(p); paintBox[picker].setPaint(paint); svgCanvas.setPaint(picker, paint); - $$b('#color_picker').hide(); + $$c('#color_picker').hide(); }, function () { - $$b('#color_picker').hide(); + $$c('#color_picker').hide(); }); }; /** @@ -34436,24 +33169,26 @@ */ - var PaintBox = /*#__PURE__*/function () { + class PaintBox { /** * @param {string|Element|external:jQuery} container * @param {"fill"} type */ - function PaintBox(container, type) { - _classCallCheck(this, PaintBox); + constructor(container, type) { + const cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke']; // set up gradients to be used for the buttons - var cur = curConfig[type === 'fill' ? 'initFill' : 'initStroke']; // set up gradients to be used for the buttons - - var svgdocbox = new DOMParser().parseFromString("\n \n \n "), 'text/xml'); - var docElem = svgdocbox.documentElement; - docElem = $$b(container)[0].appendChild(document.importNode(docElem, true)); + const svgdocbox = new DOMParser().parseFromString(` + + + `, 'text/xml'); + let docElem = svgdocbox.documentElement; + docElem = $$c(container)[0].appendChild(document.importNode(docElem, true)); docElem.setAttribute('width', 16.5); this.rect = docElem.firstElementChild; this.defs = docElem.getElementsByTagName('defs')[0]; this.grad = this.defs.firstElementChild; - this.paint = new $$b.jGraduate.Paint({ + this.paint = new $$c.jGraduate.Paint({ solidColor: cur.color }); this.type = type; @@ -34465,161 +33200,157 @@ */ - _createClass(PaintBox, [{ - key: "setPaint", - value: function setPaint(paint, apply) { - this.paint = paint; - var ptype = paint.type; - var opac = paint.alpha / 100; - var fillAttr = 'none'; + setPaint(paint, apply) { + this.paint = paint; + const ptype = paint.type; + const opac = paint.alpha / 100; + let fillAttr = 'none'; - switch (ptype) { - case 'solidColor': - fillAttr = paint[ptype] !== 'none' ? '#' + paint[ptype] : paint[ptype]; + switch (ptype) { + case 'solidColor': + fillAttr = paint[ptype] !== 'none' ? '#' + paint[ptype] : paint[ptype]; + break; + + case 'linearGradient': + case 'radialGradient': + { + this.grad.remove(); + this.grad = this.defs.appendChild(paint[ptype]); + const id = this.grad.id = 'gradbox_' + this.type; + fillAttr = 'url(#' + id + ')'; break; - - case 'linearGradient': - case 'radialGradient': - { - this.grad.remove(); - this.grad = this.defs.appendChild(paint[ptype]); - var id = this.grad.id = 'gradbox_' + this.type; - fillAttr = 'url(#' + id + ')'; - break; - } - } - - this.rect.setAttribute('fill', fillAttr); - this.rect.setAttribute('opacity', opac); - - if (apply) { - svgCanvas.setColor(this.type, this._paintColor, true); - svgCanvas.setPaintOpacity(this.type, this._paintOpacity, true); - } + } } - /** - * @param {boolean} apply - * @returns {void} - */ - }, { - key: "update", - value: function update(apply) { - if (!selectedElement) { + this.rect.setAttribute('fill', fillAttr); + this.rect.setAttribute('opacity', opac); + + if (apply) { + svgCanvas.setColor(this.type, this._paintColor, true); + svgCanvas.setPaintOpacity(this.type, this._paintOpacity, true); + } + } + /** + * @param {boolean} apply + * @returns {void} + */ + + + update(apply) { + if (!selectedElement) { + return; + } + + const { + type + } = this; + + switch (selectedElement.tagName) { + case 'use': + case 'image': + case 'foreignObject': + // These elements don't have fill or stroke, so don't change + // the current value return; - } - var type = this.type; + case 'g': + case 'a': + { + const childs = selectedElement.getElementsByTagName('*'); + let gPaint = null; - switch (selectedElement.tagName) { - case 'use': - case 'image': - case 'foreignObject': - // These elements don't have fill or stroke, so don't change - // the current value - return; + for (let i = 0, len = childs.length; i < len; i++) { + const elem = childs[i]; + const p = elem.getAttribute(type); - case 'g': - case 'a': - { - var childs = selectedElement.getElementsByTagName('*'); - var gPaint = null; - - for (var _i2 = 0, len = childs.length; _i2 < len; _i2++) { - var elem = childs[_i2]; - var p = elem.getAttribute(type); - - if (_i2 === 0) { - gPaint = p; - } else if (gPaint !== p) { - gPaint = null; - break; - } + if (i === 0) { + gPaint = p; + } else if (gPaint !== p) { + gPaint = null; + break; } - - if (gPaint === null) { - // No common color, don't update anything - this._paintColor = null; - return; - } - - this._paintColor = gPaint; - this._paintOpacity = 1; - break; } - default: - { - this._paintOpacity = Number.parseFloat(selectedElement.getAttribute(type + '-opacity')); - - if (Number.isNaN(this._paintOpacity)) { - this._paintOpacity = 1.0; - } - - var defColor = type === 'fill' ? 'black' : 'none'; - this._paintColor = selectedElement.getAttribute(type) || defColor; + if (gPaint === null) { + // No common color, don't update anything + this._paintColor = null; + return; } - } - if (apply) { - svgCanvas.setColor(type, this._paintColor, true); - svgCanvas.setPaintOpacity(type, this._paintOpacity, true); - } + this._paintColor = gPaint; + this._paintOpacity = 1; + break; + } - this._paintOpacity *= 100; - var paint = getPaint(this._paintColor, this._paintOpacity, type); // update the rect inside #fill_color/#stroke_color + default: + { + this._paintOpacity = Number.parseFloat(selectedElement.getAttribute(type + '-opacity')); - this.setPaint(paint); + if (Number.isNaN(this._paintOpacity)) { + this._paintOpacity = 1.0; + } + + const defColor = type === 'fill' ? 'black' : 'none'; + this._paintColor = selectedElement.getAttribute(type) || defColor; + } } - /** - * @returns {void} - */ - }, { - key: "prep", - value: function prep() { - var ptype = this.paint.type; - - switch (ptype) { - case 'linearGradient': - case 'radialGradient': - { - var paint = new $$b.jGraduate.Paint({ - copy: this.paint - }); - svgCanvas.setPaint(this.type, paint); - break; - } - } + if (apply) { + svgCanvas.setColor(type, this._paintColor, true); + svgCanvas.setPaintOpacity(type, this._paintOpacity, true); } - }]); - return PaintBox; - }(); + this._paintOpacity *= 100; + const paint = getPaint(this._paintColor, this._paintOpacity, type); // update the rect inside #fill_color/#stroke_color + + this.setPaint(paint); + } + /** + * @returns {void} + */ + + + prep() { + const ptype = this.paint.type; + + switch (ptype) { + case 'linearGradient': + case 'radialGradient': + { + const paint = new $$c.jGraduate.Paint({ + copy: this.paint + }); + svgCanvas.setPaint(this.type, paint); + break; + } + } + } + + } PaintBox.ctr = 0; paintBox.fill = new PaintBox('#fill_color', 'fill'); paintBox.stroke = new PaintBox('#stroke_color', 'stroke'); - $$b('#stroke_width').val(curConfig.initStroke.width); - $$b('#group_opacity').val(curConfig.initOpacity * 100); // Use this SVG elem to test vectorEffect support + $$c('#stroke_width').val(curConfig.initStroke.width); + $$c('#group_opacity').val(curConfig.initOpacity * 100); // Use this SVG elem to test vectorEffect support - var testEl = paintBox.fill.rect.cloneNode(false); + const testEl = paintBox.fill.rect.cloneNode(false); testEl.setAttribute('style', 'vector-effect:non-scaling-stroke'); - var supportsNonSS = testEl.style.vectorEffect === 'non-scaling-stroke'; + const supportsNonSS = testEl.style.vectorEffect === 'non-scaling-stroke'; testEl.removeAttribute('style'); - var svgdocbox = paintBox.fill.rect.ownerDocument; // Use this to test support for blur element. Seems to work to test support in Webkit + const svgdocbox = paintBox.fill.rect.ownerDocument; // Use this to test support for blur element. Seems to work to test support in Webkit - var blurTest = svgdocbox.createElementNS(NS.SVG, 'feGaussianBlur'); + const blurTest = svgdocbox.createElementNS(NS.SVG, 'feGaussianBlur'); if (blurTest.stdDeviationX === undefined) { - $$b('#tool_blur').hide(); + $$c('#tool_blur').hide(); } - $$b(blurTest).remove(); // Test for zoom icon support + $$c(blurTest).remove(); // Test for zoom icon support (function () { - var pre = '-' + uaPrefix.toLowerCase() + '-zoom-'; - var zoom = pre + 'in'; + const pre = '-' + uaPrefix.toLowerCase() + '-zoom-'; + const zoom = pre + 'in'; workarea.css('cursor', zoom); if (workarea.css('cursor') === zoom) { @@ -34635,97 +33366,74 @@ svgCanvas.embedImage('images/logo.png', function (datauri) { if (!datauri) { // Disable option - $$b('#image_save_opts [value=embed]').attr('disabled', 'disabled'); - $$b('#image_save_opts input').val(['ref']); + $$c('#image_save_opts [value=embed]').attr('disabled', 'disabled'); + $$c('#image_save_opts input').val(['ref']); editor.pref('img_save', 'ref'); - $$b('#image_opt_embed').css('color', '#666').attr('title', uiStrings$1.notification.featNotSupported); + $$c('#image_opt_embed').css('color', '#666').attr('title', uiStrings$1.notification.featNotSupported); } }); }, 1000); - $$b('#fill_color, #tool_fill .icon_label').click(function () { - colorPicker($$b('#fill_color')); + $$c('#fill_color, #tool_fill .icon_label').click(function () { + colorPicker($$c('#fill_color')); updateToolButtonState(); }); - $$b('#stroke_color, #tool_stroke .icon_label').click(function () { - colorPicker($$b('#stroke_color')); + $$c('#stroke_color, #tool_stroke .icon_label').click(function () { + colorPicker($$c('#stroke_color')); updateToolButtonState(); }); - $$b('#group_opacityLabel').click(function () { - $$b('#opacity_dropdown button').mousedown(); - $$b(window).mouseup(); + $$c('#group_opacityLabel').click(function () { + $$c('#opacity_dropdown button').mousedown(); + $$c(window).mouseup(); }); - $$b('#zoomLabel').click(function () { - $$b('#zoom_dropdown button').mousedown(); - $$b(window).mouseup(); + $$c('#zoomLabel').click(function () { + $$c('#zoom_dropdown button').mousedown(); + $$c(window).mouseup(); }); - $$b('#tool_move_top').mousedown(function (evt) { - $$b('#tools_stacking').show(); + $$c('#tool_move_top').mousedown(function (evt) { + $$c('#tools_stacking').show(); evt.preventDefault(); }); - $$b('.layer_button').mousedown(function () { - $$b(this).addClass('layer_buttonpressed'); + $$c('.layer_button').mousedown(function () { + $$c(this).addClass('layer_buttonpressed'); }).mouseout(function () { - $$b(this).removeClass('layer_buttonpressed'); + $$c(this).removeClass('layer_buttonpressed'); }).mouseup(function () { - $$b(this).removeClass('layer_buttonpressed'); + $$c(this).removeClass('layer_buttonpressed'); }); - $$b('.push_button').mousedown(function () { - if (!$$b(this).hasClass('disabled')) { - $$b(this).addClass('push_button_pressed').removeClass('push_button'); + $$c('.push_button').mousedown(function () { + if (!$$c(this).hasClass('disabled')) { + $$c(this).addClass('push_button_pressed').removeClass('push_button'); } }).mouseout(function () { - $$b(this).removeClass('push_button_pressed').addClass('push_button'); + $$c(this).removeClass('push_button_pressed').addClass('push_button'); }).mouseup(function () { - $$b(this).removeClass('push_button_pressed').addClass('push_button'); + $$c(this).removeClass('push_button_pressed').addClass('push_button'); }); // ask for a layer name - $$b('#layer_new').click( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee13() { - var uniqName, i, newName; - return regeneratorRuntime.wrap(function _callee13$(_context13) { - while (1) { - switch (_context13.prev = _context13.next) { - case 0: - i = svgCanvas.getCurrentDrawing().getNumLayers(); + $$c('#layer_new').click(async function () { + let uniqName, + i = svgCanvas.getCurrentDrawing().getNumLayers(); - do { - uniqName = uiStrings$1.layers.layer + ' ' + ++i; - } while (svgCanvas.getCurrentDrawing().hasLayer(uniqName)); + do { + uniqName = uiStrings$1.layers.layer + ' ' + ++i; + } while (svgCanvas.getCurrentDrawing().hasLayer(uniqName)); - _context13.next = 4; - return $$b.prompt(uiStrings$1.notification.enterUniqueLayerName, uniqName); + const newName = await $$c.prompt(uiStrings$1.notification.enterUniqueLayerName, uniqName); - case 4: - newName = _context13.sent; + if (!newName) { + return; + } - if (newName) { - _context13.next = 7; - break; - } + if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { + /* await */ + $$c.alert(uiStrings$1.notification.dupeLayerName); + return; + } - return _context13.abrupt("return"); - - case 7: - if (!svgCanvas.getCurrentDrawing().hasLayer(newName)) { - _context13.next = 10; - break; - } - - /* await */ - $$b.alert(uiStrings$1.notification.dupeLayerName); - return _context13.abrupt("return"); - - case 10: - svgCanvas.createLayer(newName); - updateContextPanel(); - populateLayers(); - - case 13: - case "end": - return _context13.stop(); - } - } - }, _callee13); - }))); + svgCanvas.createLayer(newName); + updateContextPanel(); + populateLayers(); + }); /** * * @returns {void} @@ -34738,8 +33446,8 @@ // TODO: make this behavior less brittle (svg-editor should get which // layer is selected from the canvas and then select that one in the UI) - $$b('#layerlist tr.layer').removeClass('layersel'); - $$b('#layerlist tr.layer:first').addClass('layersel'); + $$c('#layerlist tr.layer').removeClass('layersel'); + $$c('#layerlist tr.layer:first').addClass('layersel'); } } /** @@ -34748,8 +33456,23 @@ */ - function cloneLayer() { - return _cloneLayer.apply(this, arguments); + async function cloneLayer() { + const name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy'; + const newName = await $$c.prompt(uiStrings$1.notification.enterUniqueLayerName, name); + + if (!newName) { + return; + } + + if (svgCanvas.getCurrentDrawing().hasLayer(newName)) { + /* await */ + $$c.alert(uiStrings$1.notification.dupeLayerName); + return; + } + + svgCanvas.cloneLayer(newName); + updateContextPanel(); + populateLayers(); } /** * @@ -34757,54 +33480,8 @@ */ - function _cloneLayer() { - _cloneLayer = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee19() { - var name, newName; - return regeneratorRuntime.wrap(function _callee19$(_context19) { - while (1) { - switch (_context19.prev = _context19.next) { - case 0: - name = svgCanvas.getCurrentDrawing().getCurrentLayerName() + ' copy'; - _context19.next = 3; - return $$b.prompt(uiStrings$1.notification.enterUniqueLayerName, name); - - case 3: - newName = _context19.sent; - - if (newName) { - _context19.next = 6; - break; - } - - return _context19.abrupt("return"); - - case 6: - if (!svgCanvas.getCurrentDrawing().hasLayer(newName)) { - _context19.next = 9; - break; - } - - /* await */ - $$b.alert(uiStrings$1.notification.dupeLayerName); - return _context19.abrupt("return"); - - case 9: - svgCanvas.cloneLayer(newName); - updateContextPanel(); - populateLayers(); - - case 12: - case "end": - return _context19.stop(); - } - } - }, _callee19); - })); - return _cloneLayer.apply(this, arguments); - } - function mergeLayer() { - if ($$b('#layerlist tr.layersel').index() === svgCanvas.getCurrentDrawing().getNumLayers() - 1) { + if ($$c('#layerlist tr.layersel').index() === svgCanvas.getCurrentDrawing().getNumLayers() - 1) { return; } @@ -34819,8 +33496,8 @@ function moveLayer(pos) { - var total = svgCanvas.getCurrentDrawing().getNumLayers(); - var curIndex = $$b('#layerlist tr.layersel').index(); + const total = svgCanvas.getCurrentDrawing().getNumLayers(); + let curIndex = $$c('#layerlist tr.layersel').index(); if (curIndex > 0 || curIndex < total - 1) { curIndex += pos; @@ -34829,58 +33506,34 @@ } } - $$b('#layer_delete').click(deleteLayer); - $$b('#layer_up').click(function () { + $$c('#layer_delete').click(deleteLayer); + $$c('#layer_up').click(() => { moveLayer(-1); }); - $$b('#layer_down').click(function () { + $$c('#layer_down').click(() => { moveLayer(1); }); - $$b('#layer_rename').click( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee14() { - var oldName, newName; - return regeneratorRuntime.wrap(function _callee14$(_context14) { - while (1) { - switch (_context14.prev = _context14.next) { - case 0: - // const curIndex = $('#layerlist tr.layersel').prevAll().length; // Currently unused - oldName = $$b('#layerlist tr.layersel td.layername').text(); - _context14.next = 3; - return $$b.prompt(uiStrings$1.notification.enterNewLayerName, ''); + $$c('#layer_rename').click(async function () { + // const curIndex = $('#layerlist tr.layersel').prevAll().length; // Currently unused + const oldName = $$c('#layerlist tr.layersel td.layername').text(); + const newName = await $$c.prompt(uiStrings$1.notification.enterNewLayerName, ''); - case 3: - newName = _context14.sent; + if (!newName) { + return; + } - if (newName) { - _context14.next = 6; - break; - } + if (oldName === newName || svgCanvas.getCurrentDrawing().hasLayer(newName)) { + /* await */ + $$c.alert(uiStrings$1.notification.layerHasThatName); + return; + } - return _context14.abrupt("return"); - - case 6: - if (!(oldName === newName || svgCanvas.getCurrentDrawing().hasLayer(newName))) { - _context14.next = 9; - break; - } - - /* await */ - $$b.alert(uiStrings$1.notification.layerHasThatName); - return _context14.abrupt("return"); - - case 9: - svgCanvas.renameCurrentLayer(newName); - populateLayers(); - - case 11: - case "end": - return _context14.stop(); - } - } - }, _callee14); - }))); - var SIDEPANEL_MAXWIDTH = 300; - var SIDEPANEL_OPENWIDTH = 150; - var sidedrag = -1, + svgCanvas.renameCurrentLayer(newName); + populateLayers(); + }); + const SIDEPANEL_MAXWIDTH = 300; + const SIDEPANEL_OPENWIDTH = 150; + let sidedrag = -1, sidedragging = false, allowmove = false; /** @@ -34889,10 +33542,10 @@ * @returns {void} */ - var changeSidePanelWidth = function changeSidePanelWidth(delta) { - var rulerX = $$b('#ruler_x'); - $$b('#sidepanels').width('+=' + delta); - $$b('#layerpanel').width('+=' + delta); + const changeSidePanelWidth = function (delta) { + const rulerX = $$c('#ruler_x'); + $$c('#sidepanels').width('+=' + delta); + $$c('#layerpanel').width('+=' + delta); rulerX.css('right', Number.parseInt(rulerX.css('right')) + delta); workarea.css('right', Number.parseInt(workarea.css('right')) + delta); svgCanvas.runExtensions('workareaResized'); @@ -34903,7 +33556,7 @@ */ - var resizeSidePanel = function resizeSidePanel(evt) { + const resizeSidePanel = function (evt) { if (!allowmove) { return; } @@ -34913,8 +33566,8 @@ } sidedragging = true; - var deltaX = sidedrag - evt.pageX; - var sideWidth = $$b('#sidepanels').width(); + let deltaX = sidedrag - evt.pageX; + const sideWidth = $$c('#sidepanels').width(); if (sideWidth + deltaX > SIDEPANEL_MAXWIDTH) { deltaX = SIDEPANEL_MAXWIDTH - sideWidth; // sideWidth = SIDEPANEL_MAXWIDTH; @@ -34936,18 +33589,18 @@ */ - var toggleSidePanel = function toggleSidePanel(close) { - var dpr = window.devicePixelRatio || 1; - var w = $$b('#sidepanels').width(); - var isOpened = (dpr < 1 ? w : w / dpr) > 2; - var zoomAdjustedSidepanelWidth = (dpr < 1 ? 1 : dpr) * SIDEPANEL_OPENWIDTH; - var deltaX = (isOpened || close ? 0 : zoomAdjustedSidepanelWidth) - w; + const toggleSidePanel = function (close) { + const dpr = window.devicePixelRatio || 1; + const w = $$c('#sidepanels').width(); + const isOpened = (dpr < 1 ? w : w / dpr) > 2; + const zoomAdjustedSidepanelWidth = (dpr < 1 ? 1 : dpr) * SIDEPANEL_OPENWIDTH; + const deltaX = (isOpened || close ? 0 : zoomAdjustedSidepanelWidth) - w; changeSidePanelWidth(deltaX); }; - $$b('#sidepanel_handle').mousedown(function (evt) { + $$c('#sidepanel_handle').mousedown(function (evt) { sidedrag = evt.pageX; - $$b(window).mousemove(resizeSidePanel); + $$c(window).mousemove(resizeSidePanel); allowmove = false; // Silly hack for Chrome, which always runs mousemove right after mousedown setTimeout(function () { @@ -34961,30 +33614,30 @@ sidedrag = -1; sidedragging = false; }); - $$b(window).mouseup(function () { + $$c(window).mouseup(function () { sidedrag = -1; sidedragging = false; - $$b('#svg_editor').unbind('mousemove', resizeSidePanel); + $$c('#svg_editor').unbind('mousemove', resizeSidePanel); }); populateLayers(); // function changeResolution (x,y) { // const {zoom} = svgCanvas.getResolution(); // setResolution(x * zoom, y * zoom); // } - var centerCanvas = function centerCanvas() { + const centerCanvas = () => { // this centers the canvas vertically in the workarea (horizontal handled in CSS) workarea.css('line-height', workarea.height() + 'px'); }; - $$b(window).bind('load resize', centerCanvas); + $$c(window).bind('load resize', centerCanvas); /** * @type {module:jQuerySpinButton.StepCallback} */ function stepFontSize(elem, step) { - var origVal = Number(elem.value); - var sugVal = origVal + step; - var increasing = sugVal >= origVal; + const origVal = Number(elem.value); + const sugVal = origVal + step; + const increasing = sugVal >= origVal; if (step === 0) { return origVal; @@ -35014,13 +33667,13 @@ function stepZoom(elem, step) { - var origVal = Number(elem.value); + const origVal = Number(elem.value); if (origVal === 0) { return 100; } - var sugVal = origVal + step; + const sugVal = origVal + step; if (step === 0) { return origVal; @@ -35052,25 +33705,25 @@ // } - $$b('#resolution').change(function () { - var wh = $$b('#canvas_width,#canvas_height'); + $$c('#resolution').change(function () { + const wh = $$c('#canvas_width,#canvas_height'); if (!this.selectedIndex) { - if ($$b('#canvas_width').val() === 'fit') { + if ($$c('#canvas_width').val() === 'fit') { wh.removeAttr('disabled').val(100); } } else if (this.value === 'content') { wh.val('fit').attr('disabled', 'disabled'); } else { - var dims = this.value.split('x'); - $$b('#canvas_width').val(dims[0]); - $$b('#canvas_height').val(dims[1]); + const dims = this.value.split('x'); + $$c('#canvas_width').val(dims[0]); + $$c('#canvas_height').val(dims[1]); wh.removeAttr('disabled'); } }); // Prevent browser from erroneously repopulating fields - $$b('input,select').attr('autocomplete', 'off'); - var dialogSelectors = ['#tool_source_cancel', '#tool_docprops_cancel', '#tool_prefs_cancel', '.overlay']; + $$c('input,select').attr('autocomplete', 'off'); + const dialogSelectors = ['#tool_source_cancel', '#tool_docprops_cancel', '#tool_prefs_cancel', '.overlay']; /* eslint-disable jsdoc/require-property */ /** @@ -35078,7 +33731,7 @@ * @namespace {PlainObject} module:SVGEditor~Actions */ - var Actions = function () { + const Actions = function () { /* eslint-enable jsdoc/require-property */ /** @@ -35098,7 +33751,7 @@ * @name module:SVGEditor~ToolButtons * @type {module:SVGEditor.ToolButton[]} */ - var toolButtons = [{ + const toolButtons = [{ sel: '#tool_select', fn: clickSelect, evt: 'click', @@ -35179,13 +33832,15 @@ key: ['N', true] }, { sel: '#tool_save', - fn: function fn() { + + fn() { if (editingsource) { saveSourceEditor(); } else { clickSave(); } }, + evt: 'mouseup', key: ['S', true] }, { @@ -35213,13 +33868,15 @@ key: ['F', true] }, { key: ['esc', false, false], - fn: function fn() { - if (dialogSelectors.every(function (sel) { - return $$b(sel + ':hidden').length; + + fn() { + if (dialogSelectors.every(sel => { + return $$c(sel + ':hidden').length; })) { svgCanvas.clearSelection(); } }, + hidekey: true }, { sel: dialogSelectors.join(','), @@ -35253,15 +33910,19 @@ evt: 'click' }, { sel: '#tool_open', - fn: function fn() { + + fn() { window.dispatchEvent(new CustomEvent('openImage')); }, + evt: 'click' }, { sel: '#tool_import', - fn: function fn() { + + fn() { window.dispatchEvent(new CustomEvent('importImage')); }, + evt: 'click' }, { sel: '#tool_delete,#tool_delete_multi', @@ -35362,24 +34023,32 @@ }, // Shortcuts not associated with buttons { key: 'ctrl+left', - fn: function fn() { + + fn() { rotateSelected(0, 1); } + }, { key: 'ctrl+right', - fn: function fn() { + + fn() { rotateSelected(1, 1); } + }, { key: 'ctrl+shift+left', - fn: function fn() { + + fn() { rotateSelected(0, 5); } + }, { key: 'ctrl+shift+right', - fn: function fn() { + + fn() { rotateSelected(1, 5); } + }, { key: 'shift+O', fn: selectPrev @@ -35388,114 +34057,158 @@ fn: selectNext }, { key: [modKey + 'up', true], - fn: function fn() { + + fn() { zoomImage(2); } + }, { key: [modKey + 'down', true], - fn: function fn() { + + fn() { zoomImage(0.5); } + }, { key: [modKey + ']', true], - fn: function fn() { + + fn() { moveUpDownSelected('Up'); } + }, { key: [modKey + '[', true], - fn: function fn() { + + fn() { moveUpDownSelected('Down'); } + }, { key: ['up', true], - fn: function fn() { + + fn() { moveSelected(0, -1); } + }, { key: ['down', true], - fn: function fn() { + + fn() { moveSelected(0, 1); } + }, { key: ['left', true], - fn: function fn() { + + fn() { moveSelected(-1, 0); } + }, { key: ['right', true], - fn: function fn() { + + fn() { moveSelected(1, 0); } + }, { key: 'shift+up', - fn: function fn() { + + fn() { moveSelected(0, -10); } + }, { key: 'shift+down', - fn: function fn() { + + fn() { moveSelected(0, 10); } + }, { key: 'shift+left', - fn: function fn() { + + fn() { moveSelected(-10, 0); } + }, { key: 'shift+right', - fn: function fn() { + + fn() { moveSelected(10, 0); } + }, { key: ['alt+up', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(0, -1); } + }, { key: ['alt+down', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(0, 1); } + }, { key: ['alt+left', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(-1, 0); } + }, { key: ['alt+right', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(1, 0); } + }, { key: ['alt+shift+up', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(0, -10); } + }, { key: ['alt+shift+down', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(0, 10); } + }, { key: ['alt+shift+left', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(-10, 0); } + }, { key: ['alt+shift+right', true], - fn: function fn() { + + fn() { svgCanvas.cloneSelectedElements(10, 0); } + }, { key: 'a', - fn: function fn() { + + fn() { svgCanvas.selectAllInCurrentLayer(); } + }, { key: modKey + 'a', - fn: function fn() { + + fn() { svgCanvas.selectAllInCurrentLayer(); } + }, // Standard shortcuts { key: modKey + 'z', @@ -35517,7 +34230,7 @@ fn: pasteInCenter }]; // Tooltips not directly associated with a single function - var keyAssocs = { + const keyAssocs = { '4/Shift+4': '#tools_rect_show', '5/Shift+5': '#tools_ellipse_show' }; @@ -35527,16 +34240,16 @@ /** * @returns {void} */ - setAll: function setAll() { - var flyouts = {}; - var keyHandler = {}; // will contain the action for each pressed key + setAll() { + const flyouts = {}; + const keyHandler = {}; // will contain the action for each pressed key - toolButtons.forEach(function (opts) { + toolButtons.forEach(opts => { // Bind function to button - var btn; + let btn; if (opts.sel) { - btn = document.querySelector(opts.sel); + btn = $q$1(opts.sel); if (btn === null) { return true; @@ -35554,8 +34267,8 @@ } // Add to parent flyout menu, if able to be displayed - if (opts.parent && $$b(opts.parent + '_show').length) { - var fH = $$b(opts.parent); + if (opts.parent && $$c(opts.parent + '_show').length) { + let fH = $$c(opts.parent); if (!fH.length) { fH = makeFlyoutHolder(opts.parent.substr(1)); @@ -35578,8 +34291,8 @@ if (opts.key) { // Set shortcut based on options - var keyval = opts.key; - var pd = false; + let keyval = opts.key; + let pd = false; if (Array.isArray(opts.key)) { keyval = opts.key[0]; @@ -35590,16 +34303,18 @@ } keyval = String(keyval); - var fn = opts.fn; - keyval.split('/').forEach(function (key) { + const { + fn + } = opts; + keyval.split('/').forEach(key => { keyHandler[key] = { - fn: fn, - pd: pd + fn, + pd }; }); // Put shortcut in title if (opts.sel && !opts.hidekey && btn.title) { - var newTitle = "".concat(btn.title.split('[')[0], " (").concat(keyval, ")"); + const newTitle = `${btn.title.split('[')[0]} (${keyval})`; keyAssocs[keyval] = opts.sel; // Disregard for menu items if (btn.closest('#main_menu') === null) { @@ -35611,11 +34326,11 @@ return true; }); // register the keydown event - document.addEventListener('keydown', function (e) { + document.addEventListener('keydown', e => { // only track keyboard shortcuts for the body containing the SVG-Editor if (e.target.nodeName !== 'BODY') return; // normalize key - var key = "".concat(e.metaKey ? 'meta+' : '').concat(e.ctrlKey ? 'ctrl+' : '').concat(e.key.toLowerCase()); // return if no shortcut defined for this key + const key = `${e.metaKey ? 'meta+' : ''}${e.ctrlKey ? 'ctrl+' : ''}${e.key.toLowerCase()}`; // return if no shortcut defined for this key if (!keyHandler[key]) return; // launch associated handler and preventDefault if necessary @@ -35629,11 +34344,11 @@ setupFlyouts(flyouts); // Misc additional actions // Make 'return' keypress trigger the change event - $$b('.attr_changer, #image_url').bind('keydown', 'return', function (evt) { - $$b(this).change(); + $$c('.attr_changer, #image_url').bind('keydown', 'return', function (evt) { + $$c(this).change(); evt.preventDefault(); }); - $$b(window).bind('keydown', 'tab', function (e) { + $$c(window).bind('keydown', 'tab', function (e) { if (uiContext === 'canvas') { e.preventDefault(); selectNext(); @@ -35644,29 +34359,29 @@ selectPrev(); } }); - $$b('#tool_zoom').dblclick(dblclickZoom); + $$c('#tool_zoom').dblclick(dblclickZoom); }, /** * @returns {void} */ - setTitles: function setTitles() { - $$b.each(keyAssocs, function (keyval, sel) { - var menu = $$b(sel).parents('#main_menu').length; - $$b(sel).each(function () { - var t; + setTitles() { + $$c.each(keyAssocs, function (keyval, sel) { + const menu = $$c(sel).parents('#main_menu').length; + $$c(sel).each(function () { + let t; if (menu) { - t = $$b(this).text().split(' [')[0]; + t = $$c(this).text().split(' [')[0]; } else { t = this.title.split(' [')[0]; } - var keyStr = ''; // Shift+Up + let keyStr = ''; // Shift+Up - $$b.each(keyval.split('/'), function (i, key) { - var modBits = key.split('+'); - var mod = ''; + $$c.each(keyval.split('/'), function (i, key) { + const modBits = key.split('+'); + let mod = ''; if (modBits.length > 1) { mod = modBits[0] + '+'; @@ -35689,23 +34404,24 @@ * @param {string} sel Selector to match * @returns {module:SVGEditor.ToolButton} */ - getButtonData: function getButtonData(sel) { - return Object.values(toolButtons).find(function (btn) { + getButtonData(sel) { + return Object.values(toolButtons).find(btn => { return btn.sel === sel; }); } + }; }(); // Select given tool editor.ready(function () { - var tool; - var itool = curConfig.initTool, - container = $$b('#tools_left, #svg_editor .tools_flyout'), + let tool; + const itool = curConfig.initTool, + container = $$c('#tools_left, #svg_editor .tools_flyout'), /* eslint-disable unicorn/no-fn-reference-in-iterator */ preTool = container.find('#tool_' + itool), - regTool = container.find('#' + itool); + regTool = container.find('#' + itool); /* eslint-enable unicorn/no-fn-reference-in-iterator */ if (preTool.length) { @@ -35713,92 +34429,92 @@ } else if (regTool.length) { tool = regTool; } else { - tool = $$b('#tool_select'); + tool = $$c('#tool_select'); } tool.click().mouseup(); if (curConfig.wireframe) { - $$b('#tool_wireframe').click(); + $$c('#tool_wireframe').click(); } if (curConfig.showlayers) { toggleSidePanel(); } - $$b('#rulers').toggle(Boolean(curConfig.showRulers)); + $$c('#rulers').toggle(Boolean(curConfig.showRulers)); if (curConfig.showRulers) { - $$b('#show_rulers')[0].checked = true; + $$c('#show_rulers')[0].checked = true; } if (curConfig.baseUnit) { - $$b('#base_unit').val(curConfig.baseUnit); + $$c('#base_unit').val(curConfig.baseUnit); } if (curConfig.gridSnapping) { - $$b('#grid_snapping_on')[0].checked = true; + $$c('#grid_snapping_on')[0].checked = true; } if (curConfig.snappingStep) { - $$b('#grid_snapping_step').val(curConfig.snappingStep); + $$c('#grid_snapping_step').val(curConfig.snappingStep); } if (curConfig.gridColor) { - $$b('#grid_color').val(curConfig.gridColor); + $$c('#grid_color').val(curConfig.gridColor); } }); // init SpinButtons - $$b('#rect_rx').SpinButton({ + $$c('#rect_rx').SpinButton({ min: 0, max: 1000, - stateObj: stateObj, + stateObj, callback: changeRectRadius }); - $$b('#stroke_width').SpinButton({ + $$c('#stroke_width').SpinButton({ min: 0, max: 99, smallStep: 0.1, - stateObj: stateObj, + stateObj, callback: changeStrokeWidth }); - $$b('#angle').SpinButton({ + $$c('#angle').SpinButton({ min: -180, max: 180, step: 5, - stateObj: stateObj, + stateObj, callback: changeRotationAngle }); - $$b('#font_size').SpinButton({ + $$c('#font_size').SpinButton({ min: 0.001, stepfunc: stepFontSize, - stateObj: stateObj, + stateObj, callback: changeFontSize }); - $$b('#group_opacity').SpinButton({ + $$c('#group_opacity').SpinButton({ min: 0, max: 100, step: 5, - stateObj: stateObj, + stateObj, callback: changeOpacity }); - $$b('#blur').SpinButton({ + $$c('#blur').SpinButton({ min: 0, max: 10, step: 0.1, - stateObj: stateObj, + stateObj, callback: changeBlur }); - $$b('#zoom').SpinButton({ + $$c('#zoom').SpinButton({ min: 0.001, max: 10000, step: 50, stepfunc: stepZoom, - stateObj: stateObj, + stateObj, callback: changeZoom // Set default zoom }).val(svgCanvas.getZoom() * 100); - $$b('#workarea').contextMenu({ + $$c('#workarea').contextMenu({ menu: 'cmenu_canvas', inSpeed: 0 }, function (action, el, pos) { @@ -35864,7 +34580,7 @@ * @returns {void} */ - var lmenuFunc = function lmenuFunc(action, el, pos) { + const lmenuFunc = function (action, el, pos) { switch (action) { case 'dupe': /* await */ @@ -35887,26 +34603,26 @@ } }; - $$b('#layerlist').contextMenu({ + $$c('#layerlist').contextMenu({ menu: 'cmenu_layers', inSpeed: 0 }, lmenuFunc); - $$b('#layer_moreopts').contextMenu({ + $$c('#layer_moreopts').contextMenu({ menu: 'cmenu_layers', inSpeed: 0, allowLeft: true }, lmenuFunc); - $$b('.contextMenu li').mousedown(function (ev) { + $$c('.contextMenu li').mousedown(function (ev) { ev.preventDefault(); }); - $$b('#cmenu_canvas li').disableContextMenu(); + $$c('#cmenu_canvas li').disableContextMenu(); canvMenu.enableContextMenuItems('#delete,#cut,#copy'); /** * @returns {void} */ function enableOrDisableClipboard() { - var svgeditClipboard; + let svgeditClipboard; try { svgeditClipboard = localStorage.getItem('svgedit_clipboard'); @@ -35956,13 +34672,13 @@ editor.openPrep = function () { - $$b('#main_menu').hide(); + $$c('#main_menu').hide(); if (undoMgr.getUndoStackSize() === 0) { return true; } - return $$b.confirm(uiStrings$1.notification.QwantToOpen); + return $$c.confirm(uiStrings$1.notification.QwantToOpen); }; /** * @@ -36007,16 +34723,16 @@ * @param {Event} e * @returns {void} */ - var importImage = function importImage(e) { - $$b.process_cancel(uiStrings$1.notification.loadingImage); + const importImage = function (e) { + $$c.process_cancel(uiStrings$1.notification.loadingImage); e.stopPropagation(); e.preventDefault(); - $$b('#workarea').removeAttr('style'); - $$b('#main_menu').hide(); - var file = e.type === 'drop' ? e.dataTransfer.files[0] : this.files[0]; + $$c('#workarea').removeAttr('style'); + $$c('#main_menu').hide(); + const file = e.type === 'drop' ? e.dataTransfer.files[0] : this.files[0]; if (!file) { - $$b('#dialog_box').hide(); + $$c('#dialog_box').hide(); return; } /* if (file.type === 'application/pdf') { // Todo: Handle PDF imports @@ -36030,13 +34746,13 @@ // svg handling - var reader; + let reader; if (file.type.includes('svg')) { reader = new FileReader(); reader.onloadend = function (ev) { - var newElement = svgCanvas.importSvgString(ev.target.result, true); + const newElement = svgCanvas.importSvgString(ev.target.result, true); svgCanvas.ungroupSelectedElement(); svgCanvas.ungroupSelectedElement(); svgCanvas.groupSelectedElements(); @@ -36044,7 +34760,7 @@ svgCanvas.alignSelectedElements('c', 'page'); // highlight imported element, otherwise we get strange empty selectbox svgCanvas.selectOnly([newElement]); - $$b('#dialog_box').hide(); + $$c('#dialog_box').hide(); }; reader.readAsText(file); @@ -36052,23 +34768,25 @@ // bitmap handling reader = new FileReader(); - reader.onloadend = function (_ref23) { - var result = _ref23.target.result; - + reader.onloadend = function ({ + target: { + result + } + }) { /** * Insert the new image until we know its dimensions. * @param {Float} width * @param {Float} height * @returns {void} */ - var insertNewImage = function insertNewImage(width, height) { - var newImage = svgCanvas.addSVGElementFromJson({ + const insertNewImage = function (width, height) { + const newImage = svgCanvas.addSVGElementFromJson({ element: 'image', attr: { x: 0, y: 0, - width: width, - height: height, + width, + height, id: svgCanvas.getNextId(), style: 'pointer-events:inherit' } @@ -36078,13 +34796,13 @@ svgCanvas.alignSelectedElements('m', 'page'); svgCanvas.alignSelectedElements('c', 'page'); updateContextPanel(); - $$b('#dialog_box').hide(); + $$c('#dialog_box').hide(); }; // create dummy img so we know the default dimensions - var imgWidth = 100; - var imgHeight = 100; - var img = new Image(); + let imgWidth = 100; + let imgHeight = 100; + const img = new Image(); img.style.opacity = 0; img.addEventListener('load', function () { imgWidth = img.offsetWidth || img.naturalWidth || img.width; @@ -36102,91 +34820,41 @@ workarea[0].addEventListener('dragover', onDragOver); workarea[0].addEventListener('dragleave', onDragLeave); workarea[0].addEventListener('drop', importImage); - var open = $$b('').change( /*#__PURE__*/function () { - var _ref24 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee16(e) { - var ok, reader; - return regeneratorRuntime.wrap(function _callee16$(_context16) { - while (1) { - switch (_context16.prev = _context16.next) { - case 0: - _context16.next = 2; - return editor.openPrep(); + const open = $$c('').change(async function (e) { + const ok = await editor.openPrep(); - case 2: - ok = _context16.sent; + if (!ok) { + return; + } - if (ok) { - _context16.next = 5; - break; - } + svgCanvas.clear(); - return _context16.abrupt("return"); + if (this.files.length === 1) { + $$c.process_cancel(uiStrings$1.notification.loadingImage); + const reader = new FileReader(); - case 5: - svgCanvas.clear(); + reader.onloadend = async function ({ + target + }) { + await loadSvgString(target.result); + updateCanvas(); + }; - if (this.files.length === 1) { - $$b.process_cancel(uiStrings$1.notification.loadingImage); - reader = new FileReader(); - - reader.onloadend = /*#__PURE__*/function () { - var _ref26 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee15(_ref25) { - var target; - return regeneratorRuntime.wrap(function _callee15$(_context15) { - while (1) { - switch (_context15.prev = _context15.next) { - case 0: - target = _ref25.target; - _context15.next = 3; - return loadSvgString(target.result); - - case 3: - updateCanvas(); - - case 4: - case "end": - return _context15.stop(); - } - } - }, _callee15); - })); - - return function (_x6) { - return _ref26.apply(this, arguments); - }; - }(); - - reader.readAsText(this.files[0]); - } - - case 7: - case "end": - return _context16.stop(); - } - } - }, _callee16, this); - })); - - return function (_x5) { - return _ref24.apply(this, arguments); - }; - }()); - $$b('#tool_open').show(); - $$b(window).on('openImage', function () { - return open.click(); - }); - var imgImport = $$b('').change(importImage); - $$b('#tool_import').show(); - $$b(window).on('importImage', function () { - return imgImport.click(); + reader.readAsText(this.files[0]); + } }); + $$c('#tool_open').show(); + $$c(window).on('openImage', () => open.click()); + const imgImport = $$c('').change(importImage); + $$c('#tool_import').show(); + $$c(window).on('importImage', () => imgImport.click()); } updateCanvas(true); // const revnums = 'svg-editor.js ($Rev$) '; // revnums += svgCanvas.getVersion(); // $('#copyright')[0].setAttribute('title', revnums); - var loadedExtensionNames = []; + const loadedExtensionNames = []; /** * @function module:SVGEditor.setLang * @param {string} lang The language code @@ -36196,116 +34864,84 @@ * @returns {Promise} A Promise which resolves to `undefined` */ - var setLang = editor.setLang = /*#__PURE__*/function () { - var _ref27 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee17(lang, allStrings) { - var oldLayerName, renameLayer, elems; - return regeneratorRuntime.wrap(function _callee17$(_context17) { - while (1) { - switch (_context17.prev = _context17.next) { - case 0: - editor.langChanged = true; - editor.pref('lang', lang); - $$b('#lang_select').val(lang); + const setLang = editor.setLang = async function (lang, allStrings) { + editor.langChanged = true; + editor.pref('lang', lang); + $$c('#lang_select').val(lang); - if (allStrings) { - _context17.next = 5; - break; - } - - return _context17.abrupt("return"); - - case 5: - // Todo: Remove `allStrings.lang` property in locale in - // favor of just `lang`? - document.documentElement.lang = allStrings.lang; // lang; - // Todo: Add proper RTL Support! - // Todo: Use RTL detection instead and take out of locales? - // document.documentElement.dir = allStrings.dir; - - $$b.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused - // $.extend will only replace the given strings - - oldLayerName = $$b('#layerlist tr.layersel td.layername').text(); - renameLayer = oldLayerName === uiStrings$1.common.layer + ' 1'; - svgCanvas.setUiStrings(allStrings); - Actions.setTitles(); - - if (renameLayer) { - svgCanvas.renameCurrentLayer(uiStrings$1.common.layer + ' 1'); - populateLayers(); - } // In case extensions loaded before the locale, now we execute a callback on them + if (!allStrings) { + return; + } // Todo: Remove `allStrings.lang` property in locale in + // favor of just `lang`? - if (!extsPreLang.length) { - _context17.next = 18; - break; - } + document.documentElement.lang = allStrings.lang; // lang; + // Todo: Add proper RTL Support! + // Todo: Use RTL detection instead and take out of locales? + // document.documentElement.dir = allStrings.dir; - _context17.next = 15; - return Promise.all(extsPreLang.map(function (ext) { - loadedExtensionNames.push(ext.name); - return ext.langReady({ - lang: lang, - uiStrings: uiStrings$1, - importLocale: getImportLocale({ - defaultLang: lang, - defaultName: ext.name - }) - }); - })); + $$c.extend(uiStrings$1, allStrings); // const notif = allStrings.notification; // Currently unused + // $.extend will only replace the given strings - case 15: - extsPreLang.length = 0; - _context17.next = 19; - break; + const oldLayerName = $$c('#layerlist tr.layersel td.layername').text(); + const renameLayer = oldLayerName === uiStrings$1.common.layer + ' 1'; + svgCanvas.setUiStrings(allStrings); + Actions.setTitles(); - case 18: - loadedExtensionNames.forEach(function (loadedExtensionName) { - svgCanvas.runExtension(loadedExtensionName, 'langReady', - /** @type {module:svgcanvas.SvgCanvas#event:ext_langReady} */ - { - lang: lang, - uiStrings: uiStrings$1, - importLocale: getImportLocale({ - defaultLang: lang, - defaultName: loadedExtensionName - }) - }); - }); + if (renameLayer) { + svgCanvas.renameCurrentLayer(uiStrings$1.common.layer + ' 1'); + populateLayers(); + } // In case extensions loaded before the locale, now we execute a callback on them - case 19: - svgCanvas.runExtensions('langChanged', - /** @type {module:svgcanvas.SvgCanvas#event:ext_langChanged} */ - lang); // Update flyout tooltips - setFlyoutTitles(); // Copy title for certain tool elements + if (extsPreLang.length) { + await Promise.all(extsPreLang.map(ext => { + loadedExtensionNames.push(ext.name); + return ext.langReady({ + lang, + uiStrings: uiStrings$1, + importLocale: getImportLocale({ + defaultLang: lang, + defaultName: ext.name + }) + }); + })); + extsPreLang.length = 0; + } else { + loadedExtensionNames.forEach(loadedExtensionName => { + svgCanvas.runExtension(loadedExtensionName, 'langReady', + /** @type {module:svgcanvas.SvgCanvas#event:ext_langReady} */ + { + lang, + uiStrings: uiStrings$1, + importLocale: getImportLocale({ + defaultLang: lang, + defaultName: loadedExtensionName + }) + }); + }); + } - elems = { - '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', - '#fill_color': '#tool_fill label, #tool_fill .color_block', - '#linejoin_miter': '#cur_linejoin', - '#linecap_butt': '#cur_linecap' - }; - $$b.each(elems, function (source, dest) { - $$b(dest).attr('title', $$b(source)[0].title); - }); // Copy alignment titles + svgCanvas.runExtensions('langChanged', + /** @type {module:svgcanvas.SvgCanvas#event:ext_langChanged} */ + lang); // Update flyout tooltips - $$b('#multiselected_panel div[id^=tool_align]').each(function () { - $$b('#tool_pos' + this.id.substr(10))[0].title = this.title; - }); + setFlyoutTitles(); // Copy title for certain tool elements - case 24: - case "end": - return _context17.stop(); - } - } - }, _callee17); - })); - - return function (_x7, _x8) { - return _ref27.apply(this, arguments); + const elems = { + '#stroke_color': '#tool_stroke .icon_label, #tool_stroke .color_block', + '#fill_color': '#tool_fill label, #tool_fill .color_block', + '#linejoin_miter': '#cur_linejoin', + '#linecap_butt': '#cur_linecap' }; - }(); + $$c.each(elems, function (source, dest) { + $$c(dest).attr('title', $$c(source)[0].title); + }); // Copy alignment titles + + $$c('#multiselected_panel div[id^=tool_align]').each(function () { + $$c('#tool_pos' + this.id.substr(10))[0].title = this.title; + }); + }; init$7( /** @@ -36321,7 +34957,7 @@ * @todo Can we forego this in favor of `langReady` (or forego `langReady`)? * @returns {module:locale.AddLangExtensionLocaleData[]} */ - addLangData: function addLangData(langParam) { + addLangData(langParam) { return svgCanvas.runExtensions('addLangData', /** * @function @@ -36329,7 +34965,7 @@ * @param {string} name * @returns {module:svgcanvas.SvgCanvas#event:ext_addLangData} */ - function (name) { + name => { // We pass in a function as we don't know the extension name here when defining this `addLangData` method return { lang: langParam, @@ -36340,7 +34976,8 @@ }; }, true); }, - curConfig: curConfig + + curConfig }); // Load extensions // Bit of a hack to run extensions in local Opera/IE9 @@ -36370,7 +35007,7 @@ editor.ready = function (cb) { // eslint-disable-line promise/prefer-await-to-callbacks - return new Promise(function (resolve, reject) { + return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new if (isReady) { resolve(cb()); // eslint-disable-line node/callback-return, promise/prefer-await-to-callbacks @@ -36388,51 +35025,23 @@ */ - editor.runCallbacks = /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee20() { - return regeneratorRuntime.wrap(function _callee20$(_context20) { - while (1) { - switch (_context20.prev = _context20.next) { - case 0: - _context20.prev = 0; - _context20.next = 3; - return Promise.all(callbacks.map(function (_ref30) { - var _ref31 = _slicedToArray(_ref30, 1), - cb = _ref31[0]; + editor.runCallbacks = async function () { + try { + await Promise.all(callbacks.map(([cb]) => { + return cb(); // eslint-disable-line promise/prefer-await-to-callbacks + })); + } catch (err) { + callbacks.forEach(([,, reject]) => { + reject(); + }); + throw err; + } - return cb(); // eslint-disable-line promise/prefer-await-to-callbacks - })); - - case 3: - _context20.next = 9; - break; - - case 5: - _context20.prev = 5; - _context20.t0 = _context20["catch"](0); - callbacks.forEach(function (_ref32) { - var _ref33 = _slicedToArray(_ref32, 3), - reject = _ref33[2]; - - reject(); - }); - throw _context20.t0; - - case 9: - callbacks.forEach(function (_ref34) { - var _ref35 = _slicedToArray(_ref34, 2), - resolve = _ref35[1]; - - resolve(); - }); - isReady = true; - - case 11: - case "end": - return _context20.stop(); - } - } - }, _callee20, null, [[0, 5]]); - })); + callbacks.forEach(([, resolve]) => { + resolve(); + }); + isReady = true; + }; /** * @function module:SVGEditor.loadFromString * @param {string} str The SVG string to load @@ -36441,43 +35050,21 @@ * @returns {Promise} */ - editor.loadFromString = function (str) { - var _ref36 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - noAlert = _ref36.noAlert; - return editor.ready( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee21() { - return regeneratorRuntime.wrap(function _callee21$(_context21) { - while (1) { - switch (_context21.prev = _context21.next) { - case 0: - _context21.prev = 0; - _context21.next = 3; - return loadSvgString(str, { - noAlert: noAlert - }); - - case 3: - _context21.next = 9; - break; - - case 5: - _context21.prev = 5; - _context21.t0 = _context21["catch"](0); - - if (!noAlert) { - _context21.next = 9; - break; - } - - throw _context21.t0; - - case 9: - case "end": - return _context21.stop(); - } + editor.loadFromString = function (str, { + noAlert + } = {}) { + return editor.ready(async function () { + try { + await loadSvgString(str, { + noAlert + }); + } catch (err) { + if (noAlert) { + throw err; } - }, _callee21, null, [[0, 5]]); - }))); + } + }); }; /** * Not presently in use. @@ -36510,30 +35097,32 @@ */ - editor.loadFromURL = function (url) { - var _ref38 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - cache = _ref38.cache, - noAlert = _ref38.noAlert; - + editor.loadFromURL = function (url, { + cache, + noAlert + } = {}) { return editor.ready(function () { - return new Promise(function (resolve, reject) { + return new Promise((resolve, reject) => { // eslint-disable-line promise/avoid-new - $$b.ajax({ - url: url, + $$c.ajax({ + url, dataType: 'text', cache: Boolean(cache), - beforeSend: function beforeSend() { - $$b.process_cancel(uiStrings$1.notification.loadingImage); + + beforeSend() { + $$c.process_cancel(uiStrings$1.notification.loadingImage); }, - success: function success(str) { + + success(str) { resolve(loadSvgString(str, { - noAlert: noAlert + noAlert })); }, - error: function error(xhr, stat, err) { + + error(xhr, stat, err) { if (xhr.status !== 404 && xhr.responseText) { resolve(loadSvgString(xhr.responseText, { - noAlert: noAlert + noAlert })); return; } @@ -36543,12 +35132,14 @@ return; } - $$b.alert(uiStrings$1.notification.URLLoadFail + ': \n' + err); + $$c.alert(uiStrings$1.notification.URLLoadFail + ': \n' + err); resolve(); }, - complete: function complete() { - $$b('#dialog_box').hide(); + + complete() { + $$c('#dialog_box').hide(); } + }); }); }); @@ -36562,13 +35153,12 @@ */ - editor.loadFromDataURI = function (str) { - var _ref39 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}, - noAlert = _ref39.noAlert; - + editor.loadFromDataURI = function (str, { + noAlert + } = {}) { return editor.ready(function () { - var base64 = false; - var pre = str.match(/^data:image\/svg\+xml;base64,/); + let base64 = false; + let pre = str.match(/^data:image\/svg\+xml;base64,/); if (pre) { base64 = true; @@ -36580,9 +35170,9 @@ pre = pre[0]; } - var src = str.slice(pre.length); + const src = str.slice(pre.length); return loadSvgString(base64 ? decode64(src) : decodeURIComponent(src), { - noAlert: noAlert + noAlert }); }); }; @@ -36609,11 +35199,11 @@ // away once all context menu behavior is brought to context menu. - editor.ready(function () { + editor.ready(() => { injectExtendedContextMenuItemsIntoDom(); }); - var extensionsAdded = false; - var messageQueue = []; + let extensionsAdded = false; + const messageQueue = []; /** * @param {PlainObject} info * @param {any} info.data @@ -36622,14 +35212,15 @@ * @returns {void} */ - var messageListener = function messageListener(_ref40) { - var data = _ref40.data, - origin = _ref40.origin; + const messageListener = ({ + data, + origin + }) => { // eslint-disable-line no-shadow // console.log('data, origin, extensionsAdded', data, origin, extensionsAdded); - var messageObj = { - data: data, - origin: origin + const messageObj = { + data, + origin }; if (!extensionsAdded) { @@ -36644,36 +35235,17 @@ window.addEventListener('message', messageListener); // Run init once DOM is loaded // jQuery(editor.init); - _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee22() { - return regeneratorRuntime.wrap(function _callee22$(_context22) { - while (1) { - switch (_context22.prev = _context22.next) { - case 0: - _context22.prev = 0; - _context22.next = 3; - return Promise.resolve(); - - case 3: - editor.init(); - _context22.next = 9; - break; - - case 6: - _context22.prev = 6; - _context22.t0 = _context22["catch"](0); - console.error(_context22.t0); // eslint-disable-line no-console - - case 9: - case "end": - return _context22.stop(); - } - } - }, _callee22, null, [[0, 6]]); - }))(); + (async () => { + try { + // We wait a micro-task to let the svgEditor variable be defined for module checks + await Promise.resolve(); + editor.init(); + } catch (err) { + console.error(err); // eslint-disable-line no-console + } + })(); // TO BUILD AN IIFE VERSION OF THIS FILE (AS CAN WORK ON OLDER BROWSERS), - window.svgEditor = editor; - window.svgEditor.modules = false; // URL OVERRIDE CONFIG editor.setConfig({ /**